Klaus Demo nginx / 56ad960
The gRPC proxy module. The module allows passing requests to upstream gRPC servers. The module is built by default as long as HTTP/2 support is compiled in. Example configuration: grpc_pass 127.0.0.1:9000; Alternatively, the "grpc://" scheme can be used: grpc_pass grpc://127.0.0.1:9000; Keepalive support is available via the upstream keepalive module. Note that keepalive connections won't currently work with grpc-go as it fails to handle SETTINGS_HEADER_TABLE_SIZE. To use with SSL: grpc_pass grpcs://127.0.0.1:9000; SSL connections use ALPN "h2" when available. At least grpc-go works fine without ALPN, so if ALPN is not available we just establish a connection without it. Tested with grpc-c++ and grpc-go. Maxim Dounin 2 years ago
3 changed file(s) with 4584 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
743743 . auto/module
744744 fi
745745
746 if [ $HTTP_GRPC = YES -a $HTTP_V2 = YES ]; then
747 ngx_module_name=ngx_http_grpc_module
748 ngx_module_incs=
749 ngx_module_deps=
750 ngx_module_srcs=src/http/modules/ngx_http_grpc_module.c
751 ngx_module_libs=
752 ngx_module_link=$HTTP_GRPC
753
754 . auto/module
755 fi
756
746757 if [ $HTTP_PERL != NO ]; then
747758 ngx_module_name=ngx_http_perl_module
748759 ngx_module_incs=src/http/modules/perl
8585 HTTP_FASTCGI=YES
8686 HTTP_UWSGI=YES
8787 HTTP_SCGI=YES
88 HTTP_GRPC=YES
8889 HTTP_PERL=NO
8990 HTTP_MEMCACHED=YES
9091 HTTP_LIMIT_CONN=YES
261262 --without-http_fastcgi_module) HTTP_FASTCGI=NO ;;
262263 --without-http_uwsgi_module) HTTP_UWSGI=NO ;;
263264 --without-http_scgi_module) HTTP_SCGI=NO ;;
265 --without-http_grpc_module) HTTP_GRPC=NO ;;
264266 --without-http_memcached_module) HTTP_MEMCACHED=NO ;;
265267 --without-http_limit_conn_module) HTTP_LIMIT_CONN=NO ;;
266268 --without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;;
0
1 /*
2 * Copyright (C) Maxim Dounin
3 * Copyright (C) Nginx, Inc.
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 typedef struct {
13 ngx_array_t *flushes;
14 ngx_array_t *lengths;
15 ngx_array_t *values;
16 ngx_hash_t hash;
17 } ngx_http_grpc_headers_t;
18
19
20 typedef struct {
21 ngx_http_upstream_conf_t upstream;
22
23 ngx_http_grpc_headers_t headers;
24 ngx_array_t *headers_source;
25
26 ngx_str_t host;
27 ngx_uint_t host_set;
28
29 #if (NGX_HTTP_SSL)
30 ngx_uint_t ssl;
31 ngx_uint_t ssl_protocols;
32 ngx_str_t ssl_ciphers;
33 ngx_uint_t ssl_verify_depth;
34 ngx_str_t ssl_trusted_certificate;
35 ngx_str_t ssl_crl;
36 ngx_str_t ssl_certificate;
37 ngx_str_t ssl_certificate_key;
38 ngx_array_t *ssl_passwords;
39 #endif
40 } ngx_http_grpc_loc_conf_t;
41
42
43 typedef enum {
44 ngx_http_grpc_st_start = 0,
45 ngx_http_grpc_st_length_2,
46 ngx_http_grpc_st_length_3,
47 ngx_http_grpc_st_type,
48 ngx_http_grpc_st_flags,
49 ngx_http_grpc_st_stream_id,
50 ngx_http_grpc_st_stream_id_2,
51 ngx_http_grpc_st_stream_id_3,
52 ngx_http_grpc_st_stream_id_4,
53 ngx_http_grpc_st_payload,
54 ngx_http_grpc_st_padding
55 } ngx_http_grpc_state_e;
56
57
58 typedef struct {
59 size_t init_window;
60 size_t send_window;
61 size_t recv_window;
62 ngx_uint_t last_stream_id;
63 } ngx_http_grpc_conn_t;
64
65
66 typedef struct {
67 ngx_http_grpc_state_e state;
68 ngx_uint_t frame_state;
69 ngx_uint_t fragment_state;
70
71 ngx_chain_t *in;
72 ngx_chain_t *out;
73 ngx_chain_t *free;
74 ngx_chain_t *busy;
75
76 ngx_http_grpc_conn_t *connection;
77
78 ngx_uint_t id;
79
80 ssize_t send_window;
81 size_t recv_window;
82
83 size_t rest;
84 ngx_uint_t stream_id;
85 u_char type;
86 u_char flags;
87 u_char padding;
88
89 ngx_uint_t error;
90 ngx_uint_t window_update;
91
92 ngx_uint_t setting_id;
93 ngx_uint_t setting_value;
94
95 u_char ping_data[8];
96
97 ngx_uint_t index;
98 ngx_str_t name;
99 ngx_str_t value;
100
101 u_char *field_end;
102 size_t field_length;
103 size_t field_rest;
104 u_char field_state;
105
106 unsigned literal:1;
107 unsigned field_huffman:1;
108
109 unsigned header_sent:1;
110 unsigned output_closed:1;
111 unsigned parsing_headers:1;
112 unsigned end_stream:1;
113 unsigned status:1;
114
115 ngx_http_request_t *request;
116 } ngx_http_grpc_ctx_t;
117
118
119 typedef struct {
120 u_char length_0;
121 u_char length_1;
122 u_char length_2;
123 u_char type;
124 u_char flags;
125 u_char stream_id_0;
126 u_char stream_id_1;
127 u_char stream_id_2;
128 u_char stream_id_3;
129 } ngx_http_grpc_frame_t;
130
131
132 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r);
133 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r);
134 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in);
135 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r);
136 static ngx_int_t ngx_http_grpc_filter_init(void *data);
137 static ngx_int_t ngx_http_grpc_filter(void *data, ssize_t bytes);
138
139 static ngx_int_t ngx_http_grpc_parse_frame(ngx_http_request_t *r,
140 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
141 static ngx_int_t ngx_http_grpc_parse_header(ngx_http_request_t *r,
142 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
143 static ngx_int_t ngx_http_grpc_parse_fragment(ngx_http_request_t *r,
144 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
145 static ngx_int_t ngx_http_grpc_validate_header_name(ngx_http_request_t *r,
146 ngx_str_t *s);
147 static ngx_int_t ngx_http_grpc_validate_header_value(ngx_http_request_t *r,
148 ngx_str_t *s);
149 static ngx_int_t ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r,
150 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
151 static ngx_int_t ngx_http_grpc_parse_goaway(ngx_http_request_t *r,
152 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
153 static ngx_int_t ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
154 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
155 static ngx_int_t ngx_http_grpc_parse_settings(ngx_http_request_t *r,
156 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
157 static ngx_int_t ngx_http_grpc_parse_ping(ngx_http_request_t *r,
158 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
159
160 static ngx_int_t ngx_http_grpc_send_settings_ack(ngx_http_request_t *r,
161 ngx_http_grpc_ctx_t *ctx);
162 static ngx_int_t ngx_http_grpc_send_ping_ack(ngx_http_request_t *r,
163 ngx_http_grpc_ctx_t *ctx);
164 static ngx_int_t ngx_http_grpc_send_window_update(ngx_http_request_t *r,
165 ngx_http_grpc_ctx_t *ctx);
166
167 static ngx_chain_t *ngx_http_grpc_get_buf(ngx_http_request_t *r,
168 ngx_http_grpc_ctx_t *ctx);
169 static ngx_http_grpc_ctx_t *ngx_http_grpc_get_ctx(ngx_http_request_t *r);
170 static ngx_int_t ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
171 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc);
172 static void ngx_http_grpc_cleanup(void *data);
173
174 static void ngx_http_grpc_abort_request(ngx_http_request_t *r);
175 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
176 ngx_int_t rc);
177
178 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
179 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
180 void *parent, void *child);
181 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
182 ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers,
183 ngx_keyval_t *default_headers);
184
185 static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
186 void *conf);
187
188 #if (NGX_HTTP_SSL)
189 static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf,
190 ngx_command_t *cmd, void *conf);
191 static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf,
192 ngx_http_grpc_loc_conf_t *glcf);
193 #endif
194
195
196 static ngx_conf_bitmask_t ngx_http_grpc_next_upstream_masks[] = {
197 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
198 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
199 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
200 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
201 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
202 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
203 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
204 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
205 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
206 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
207 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
208 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
209 { ngx_null_string, 0 }
210 };
211
212
213 #if (NGX_HTTP_SSL)
214
215 static ngx_conf_bitmask_t ngx_http_grpc_ssl_protocols[] = {
216 { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
217 { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
218 { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
219 { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
220 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
221 { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
222 { ngx_null_string, 0 }
223 };
224
225 #endif
226
227
228 static ngx_command_t ngx_http_grpc_commands[] = {
229
230 { ngx_string("grpc_pass"),
231 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
232 ngx_http_grpc_pass,
233 NGX_HTTP_LOC_CONF_OFFSET,
234 0,
235 NULL },
236
237 { ngx_string("grpc_bind"),
238 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
239 ngx_http_upstream_bind_set_slot,
240 NGX_HTTP_LOC_CONF_OFFSET,
241 offsetof(ngx_http_grpc_loc_conf_t, upstream.local),
242 NULL },
243
244 { ngx_string("grpc_connect_timeout"),
245 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
246 ngx_conf_set_msec_slot,
247 NGX_HTTP_LOC_CONF_OFFSET,
248 offsetof(ngx_http_grpc_loc_conf_t, upstream.connect_timeout),
249 NULL },
250
251 { ngx_string("grpc_send_timeout"),
252 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
253 ngx_conf_set_msec_slot,
254 NGX_HTTP_LOC_CONF_OFFSET,
255 offsetof(ngx_http_grpc_loc_conf_t, upstream.send_timeout),
256 NULL },
257
258 { ngx_string("grpc_intercept_errors"),
259 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
260 ngx_conf_set_flag_slot,
261 NGX_HTTP_LOC_CONF_OFFSET,
262 offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors),
263 NULL },
264
265 { ngx_string("grpc_buffer_size"),
266 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
267 ngx_conf_set_size_slot,
268 NGX_HTTP_LOC_CONF_OFFSET,
269 offsetof(ngx_http_grpc_loc_conf_t, upstream.buffer_size),
270 NULL },
271
272 { ngx_string("grpc_read_timeout"),
273 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
274 ngx_conf_set_msec_slot,
275 NGX_HTTP_LOC_CONF_OFFSET,
276 offsetof(ngx_http_grpc_loc_conf_t, upstream.read_timeout),
277 NULL },
278
279 { ngx_string("grpc_next_upstream"),
280 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
281 ngx_conf_set_bitmask_slot,
282 NGX_HTTP_LOC_CONF_OFFSET,
283 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream),
284 &ngx_http_grpc_next_upstream_masks },
285
286 { ngx_string("grpc_next_upstream_tries"),
287 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
288 ngx_conf_set_num_slot,
289 NGX_HTTP_LOC_CONF_OFFSET,
290 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_tries),
291 NULL },
292
293 { ngx_string("grpc_next_upstream_timeout"),
294 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
295 ngx_conf_set_msec_slot,
296 NGX_HTTP_LOC_CONF_OFFSET,
297 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_timeout),
298 NULL },
299
300 { ngx_string("grpc_set_header"),
301 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
302 ngx_conf_set_keyval_slot,
303 NGX_HTTP_LOC_CONF_OFFSET,
304 offsetof(ngx_http_grpc_loc_conf_t, headers_source),
305 NULL },
306
307 { ngx_string("grpc_pass_header"),
308 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
309 ngx_conf_set_str_array_slot,
310 NGX_HTTP_LOC_CONF_OFFSET,
311 offsetof(ngx_http_grpc_loc_conf_t, upstream.pass_headers),
312 NULL },
313
314 { ngx_string("grpc_hide_header"),
315 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
316 ngx_conf_set_str_array_slot,
317 NGX_HTTP_LOC_CONF_OFFSET,
318 offsetof(ngx_http_grpc_loc_conf_t, upstream.hide_headers),
319 NULL },
320
321 { ngx_string("grpc_ignore_headers"),
322 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
323 ngx_conf_set_bitmask_slot,
324 NGX_HTTP_LOC_CONF_OFFSET,
325 offsetof(ngx_http_grpc_loc_conf_t, upstream.ignore_headers),
326 &ngx_http_upstream_ignore_headers_masks },
327
328 #if (NGX_HTTP_SSL)
329
330 { ngx_string("grpc_ssl_session_reuse"),
331 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
332 ngx_conf_set_flag_slot,
333 NGX_HTTP_LOC_CONF_OFFSET,
334 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_session_reuse),
335 NULL },
336
337 { ngx_string("grpc_ssl_protocols"),
338 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
339 ngx_conf_set_bitmask_slot,
340 NGX_HTTP_LOC_CONF_OFFSET,
341 offsetof(ngx_http_grpc_loc_conf_t, ssl_protocols),
342 &ngx_http_grpc_ssl_protocols },
343
344 { ngx_string("grpc_ssl_ciphers"),
345 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
346 ngx_conf_set_str_slot,
347 NGX_HTTP_LOC_CONF_OFFSET,
348 offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers),
349 NULL },
350
351 { ngx_string("grpc_ssl_name"),
352 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
353 ngx_http_set_complex_value_slot,
354 NGX_HTTP_LOC_CONF_OFFSET,
355 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_name),
356 NULL },
357
358 { ngx_string("grpc_ssl_server_name"),
359 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
360 ngx_conf_set_flag_slot,
361 NGX_HTTP_LOC_CONF_OFFSET,
362 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_server_name),
363 NULL },
364
365 { ngx_string("grpc_ssl_verify"),
366 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
367 ngx_conf_set_flag_slot,
368 NGX_HTTP_LOC_CONF_OFFSET,
369 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_verify),
370 NULL },
371
372 { ngx_string("grpc_ssl_verify_depth"),
373 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
374 ngx_conf_set_num_slot,
375 NGX_HTTP_LOC_CONF_OFFSET,
376 offsetof(ngx_http_grpc_loc_conf_t, ssl_verify_depth),
377 NULL },
378
379 { ngx_string("grpc_ssl_trusted_certificate"),
380 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
381 ngx_conf_set_str_slot,
382 NGX_HTTP_LOC_CONF_OFFSET,
383 offsetof(ngx_http_grpc_loc_conf_t, ssl_trusted_certificate),
384 NULL },
385
386 { ngx_string("grpc_ssl_crl"),
387 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
388 ngx_conf_set_str_slot,
389 NGX_HTTP_LOC_CONF_OFFSET,
390 offsetof(ngx_http_grpc_loc_conf_t, ssl_crl),
391 NULL },
392
393 { ngx_string("grpc_ssl_certificate"),
394 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
395 ngx_conf_set_str_slot,
396 NGX_HTTP_LOC_CONF_OFFSET,
397 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate),
398 NULL },
399
400 { ngx_string("grpc_ssl_certificate_key"),
401 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
402 ngx_conf_set_str_slot,
403 NGX_HTTP_LOC_CONF_OFFSET,
404 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key),
405 NULL },
406
407 { ngx_string("grpc_ssl_password_file"),
408 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
409 ngx_http_grpc_ssl_password_file,
410 NGX_HTTP_LOC_CONF_OFFSET,
411 0,
412 NULL },
413
414 #endif
415
416 ngx_null_command
417 };
418
419
420 static ngx_http_module_t ngx_http_grpc_module_ctx = {
421 NULL, /* preconfiguration */
422 NULL, /* postconfiguration */
423
424 NULL, /* create main configuration */
425 NULL, /* init main configuration */
426
427 NULL, /* create server configuration */
428 NULL, /* merge server configuration */
429
430 ngx_http_grpc_create_loc_conf, /* create location configuration */
431 ngx_http_grpc_merge_loc_conf /* merge location configuration */
432 };
433
434
435 ngx_module_t ngx_http_grpc_module = {
436 NGX_MODULE_V1,
437 &ngx_http_grpc_module_ctx, /* module context */
438 ngx_http_grpc_commands, /* module directives */
439 NGX_HTTP_MODULE, /* module type */
440 NULL, /* init master */
441 NULL, /* init module */
442 NULL, /* init process */
443 NULL, /* init thread */
444 NULL, /* exit thread */
445 NULL, /* exit process */
446 NULL, /* exit master */
447 NGX_MODULE_V1_PADDING
448 };
449
450
451 static u_char ngx_http_grpc_connection_start[] =
452 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* connection preface */
453
454 "\x00\x00\x12\x04\x00\x00\x00\x00\x00" /* settings frame */
455 "\x00\x01\x00\x00\x00\x00" /* header table size */
456 "\x00\x02\x00\x00\x00\x00" /* disable push */
457 "\x00\x04\x7f\xff\xff\xff" /* initial window */
458
459 "\x00\x00\x04\x08\x00\x00\x00\x00\x00" /* window update frame */
460 "\x7f\xff\x00\x00";
461
462
463 static ngx_keyval_t ngx_http_grpc_headers[] = {
464 { ngx_string("Content-Length"), ngx_string("$content_length") },
465 { ngx_string("Host"), ngx_string("") },
466 { ngx_string("Connection"), ngx_string("") },
467 { ngx_string("Transfer-Encoding"), ngx_string("") },
468 { ngx_string("TE"), ngx_string("") },
469 { ngx_string("Keep-Alive"), ngx_string("") },
470 { ngx_string("Expect"), ngx_string("") },
471 { ngx_string("Upgrade"), ngx_string("") },
472 { ngx_null_string, ngx_null_string }
473 };
474
475
476 static ngx_str_t ngx_http_grpc_hide_headers[] = {
477 ngx_string("Date"),
478 ngx_string("Server"),
479 ngx_string("X-Accel-Expires"),
480 ngx_string("X-Accel-Redirect"),
481 ngx_string("X-Accel-Limit-Rate"),
482 ngx_string("X-Accel-Buffering"),
483 ngx_string("X-Accel-Charset"),
484 ngx_null_string
485 };
486
487
488 static ngx_int_t
489 ngx_http_grpc_handler(ngx_http_request_t *r)
490 {
491 ngx_int_t rc;
492 ngx_http_upstream_t *u;
493 ngx_http_grpc_ctx_t *ctx;
494 ngx_http_grpc_loc_conf_t *glcf;
495
496 if (ngx_http_upstream_create(r) != NGX_OK) {
497 return NGX_HTTP_INTERNAL_SERVER_ERROR;
498 }
499
500 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
501
502 u = r->upstream;
503
504 #if (NGX_HTTP_SSL)
505 u->ssl = (glcf->upstream.ssl != NULL);
506
507 if (u->ssl) {
508 ngx_str_set(&u->schema, "grpcs://");
509
510 } else {
511 ngx_str_set(&u->schema, "grpc://");
512 }
513 #else
514 ngx_str_set(&u->schema, "grpc://");
515 #endif
516
517 u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;
518
519 u->conf = &glcf->upstream;
520
521 u->create_request = ngx_http_grpc_create_request;
522 u->reinit_request = ngx_http_grpc_reinit_request;
523 u->process_header = ngx_http_grpc_process_header;
524 u->abort_request = ngx_http_grpc_abort_request;
525 u->finalize_request = ngx_http_grpc_finalize_request;
526
527 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
528 if (ctx == NULL) {
529 return NGX_HTTP_INTERNAL_SERVER_ERROR;
530 }
531
532 ctx->request = r;
533
534 ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);
535
536 u->input_filter_init = ngx_http_grpc_filter_init;
537 u->input_filter = ngx_http_grpc_filter;
538 u->input_filter_ctx = ctx;
539
540 r->request_body_no_buffering = 1;
541
542 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
543
544 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
545 return rc;
546 }
547
548 return NGX_DONE;
549 }
550
551
552 static ngx_int_t
553 ngx_http_grpc_create_request(ngx_http_request_t *r)
554 {
555 u_char *p, *tmp, *key_tmp, *val_tmp, *headers_frame;
556 size_t len, tmp_len, key_len, val_len, uri_len;
557 uintptr_t escape;
558 ngx_buf_t *b;
559 ngx_uint_t i, next;
560 ngx_chain_t *cl, *body;
561 ngx_list_part_t *part;
562 ngx_table_elt_t *header;
563 ngx_http_upstream_t *u;
564 ngx_http_grpc_frame_t *f;
565 ngx_http_script_code_pt code;
566 ngx_http_grpc_loc_conf_t *glcf;
567 ngx_http_script_engine_t e, le;
568 ngx_http_script_len_code_pt lcode;
569
570 u = r->upstream;
571
572 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
573
574 len = sizeof(ngx_http_grpc_connection_start) - 1
575 + sizeof(ngx_http_grpc_frame_t); /* headers frame */
576
577 /* :method header */
578
579 if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) {
580 len += 1;
581 tmp_len = 0;
582
583 } else {
584 len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len;
585 tmp_len = r->method_name.len;
586 }
587
588 /* :scheme header */
589
590 len += 1;
591
592 /* :path header */
593
594 if (r->valid_unparsed_uri) {
595 escape = 0;
596 uri_len = r->unparsed_uri.len;
597
598 } else {
599 escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
600 NGX_ESCAPE_URI);
601 uri_len = r->uri.len + escape + sizeof("?") - 1 + r->args.len;
602 }
603
604 len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;
605
606 if (tmp_len < uri_len) {
607 tmp_len = uri_len;
608 }
609
610 /* :authority header */
611
612 if (!glcf->host_set) {
613 len += 1 + NGX_HTTP_V2_INT_OCTETS + glcf->host.len;
614
615 if (tmp_len < glcf->host.len) {
616 tmp_len = glcf->host.len;
617 }
618 }
619
620 /* other headers */
621
622 ngx_http_script_flush_no_cacheable_variables(r, glcf->headers.flushes);
623 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
624
625 le.ip = glcf->headers.lengths->elts;
626 le.request = r;
627 le.flushed = 1;
628
629 while (*(uintptr_t *) le.ip) {
630
631 lcode = *(ngx_http_script_len_code_pt *) le.ip;
632 key_len = lcode(&le);
633
634 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
635 lcode = *(ngx_http_script_len_code_pt *) le.ip;
636 }
637 le.ip += sizeof(uintptr_t);
638
639 if (val_len == 0) {
640 continue;
641 }
642
643 len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
644 + NGX_HTTP_V2_INT_OCTETS + val_len;
645
646 if (tmp_len < key_len) {
647 tmp_len = key_len;
648 }
649
650 if (tmp_len < val_len) {
651 tmp_len = val_len;
652 }
653 }
654
655 if (glcf->upstream.pass_request_headers) {
656 part = &r->headers_in.headers.part;
657 header = part->elts;
658
659 for (i = 0; /* void */; i++) {
660
661 if (i >= part->nelts) {
662 if (part->next == NULL) {
663 break;
664 }
665
666 part = part->next;
667 header = part->elts;
668 i = 0;
669 }
670
671 if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
672 header[i].lowcase_key, header[i].key.len))
673 {
674 continue;
675 }
676
677 len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
678 + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;
679
680 if (tmp_len < header[i].key.len) {
681 tmp_len = header[i].key.len;
682 }
683
684 if (tmp_len < header[i].value.len) {
685 tmp_len = header[i].value.len;
686 }
687 }
688 }
689
690 /* continuation frames */
691
692 len += sizeof(ngx_http_grpc_frame_t)
693 * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);
694
695
696 b = ngx_create_temp_buf(r->pool, len);
697 if (b == NULL) {
698 return NGX_ERROR;
699 }
700
701 cl = ngx_alloc_chain_link(r->pool);
702 if (cl == NULL) {
703 return NGX_ERROR;
704 }
705
706 cl->buf = b;
707 cl->next = NULL;
708
709 tmp = ngx_palloc(r->pool, tmp_len * 3);
710 if (tmp == NULL) {
711 return NGX_ERROR;
712 }
713
714 key_tmp = tmp + tmp_len;
715 val_tmp = tmp + 2 * tmp_len;
716
717 /* connection preface */
718
719 b->last = ngx_copy(b->last, ngx_http_grpc_connection_start,
720 sizeof(ngx_http_grpc_connection_start) - 1);
721
722 /* headers frame */
723
724 headers_frame = b->last;
725
726 f = (ngx_http_grpc_frame_t *) b->last;
727 b->last += sizeof(ngx_http_grpc_frame_t);
728
729 f->length_0 = 0;
730 f->length_1 = 0;
731 f->length_2 = 0;
732 f->type = NGX_HTTP_V2_HEADERS_FRAME;
733 f->flags = 0;
734 f->stream_id_0 = 0;
735 f->stream_id_1 = 0;
736 f->stream_id_2 = 0;
737 f->stream_id_3 = 1;
738
739 if (r->method == NGX_HTTP_GET) {
740 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);
741
742 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
743 "grpc header: \":method: GET\"");
744
745 } else if (r->method == NGX_HTTP_POST) {
746 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);
747
748 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
749 "grpc header: \":method: POST\"");
750
751 } else {
752 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
753 b->last = ngx_http_v2_write_value(b->last, r->method_name.data,
754 r->method_name.len, tmp);
755
756 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
757 "grpc header: \":method: %V\"", &r->method_name);
758 }
759
760 #if (NGX_HTTP_SSL)
761 if (glcf->ssl) {
762 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);
763
764 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
765 "grpc header: \":scheme: https\"");
766 } else
767 #endif
768 {
769 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
770
771 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
772 "grpc header: \":scheme: http\"");
773 }
774
775 if (r->valid_unparsed_uri) {
776
777 if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') {
778 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);
779
780 } else {
781 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
782 b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
783 r->unparsed_uri.len, tmp);
784 }
785
786 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
787 "grpc header: \":path: %V\"", &r->unparsed_uri);
788
789 } else if (escape || r->args.len > 0) {
790 p = val_tmp;
791
792 if (escape) {
793 p = (u_char *) ngx_escape_uri(p, r->uri.data, r->uri.len,
794 NGX_ESCAPE_URI);
795
796 } else {
797 p = ngx_copy(p, r->uri.data, r->uri.len);
798 }
799
800 if (r->args.len > 0) {
801 *p++ = '?';
802 p = ngx_copy(p, r->args.data, r->args.len);
803 }
804
805 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
806 b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp);
807
808 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
809 "grpc header: \":path: %*s\"", p - val_tmp, val_tmp);
810
811 } else {
812 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
813 b->last = ngx_http_v2_write_value(b->last, r->uri.data,
814 r->uri.len, tmp);
815
816 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
817 "grpc header: \":path: %V\"", &r->uri);
818 }
819
820 if (!glcf->host_set) {
821 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
822 b->last = ngx_http_v2_write_value(b->last, glcf->host.data,
823 glcf->host.len, tmp);
824
825 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
826 "grpc header: \":authority: %V\"", &glcf->host);
827 }
828
829 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
830
831 e.ip = glcf->headers.values->elts;
832 e.request = r;
833 e.flushed = 1;
834
835 le.ip = glcf->headers.lengths->elts;
836
837 while (*(uintptr_t *) le.ip) {
838
839 lcode = *(ngx_http_script_len_code_pt *) le.ip;
840 key_len = lcode(&le);
841
842 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
843 lcode = *(ngx_http_script_len_code_pt *) le.ip;
844 }
845 le.ip += sizeof(uintptr_t);
846
847 if (val_len == 0) {
848 e.skip = 1;
849
850 while (*(uintptr_t *) e.ip) {
851 code = *(ngx_http_script_code_pt *) e.ip;
852 code((ngx_http_script_engine_t *) &e);
853 }
854 e.ip += sizeof(uintptr_t);
855
856 e.skip = 0;
857
858 continue;
859 }
860
861 *b->last++ = 0;
862
863 e.pos = key_tmp;
864
865 code = *(ngx_http_script_code_pt *) e.ip;
866 code((ngx_http_script_engine_t *) &e);
867
868 b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp);
869
870 e.pos = val_tmp;
871
872 while (*(uintptr_t *) e.ip) {
873 code = *(ngx_http_script_code_pt *) e.ip;
874 code((ngx_http_script_engine_t *) &e);
875 }
876 e.ip += sizeof(uintptr_t);
877
878 b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp);
879
880 #if (NGX_DEBUG)
881 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
882 ngx_strlow(key_tmp, key_tmp, key_len);
883
884 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
885 "grpc header: \"%*s: %*s\"",
886 key_len, key_tmp, val_len, val_tmp);
887 }
888 #endif
889 }
890
891 if (glcf->upstream.pass_request_headers) {
892 part = &r->headers_in.headers.part;
893 header = part->elts;
894
895 for (i = 0; /* void */; i++) {
896
897 if (i >= part->nelts) {
898 if (part->next == NULL) {
899 break;
900 }
901
902 part = part->next;
903 header = part->elts;
904 i = 0;
905 }
906
907 if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
908 header[i].lowcase_key, header[i].key.len))
909 {
910 continue;
911 }
912
913 *b->last++ = 0;
914
915 b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
916 header[i].key.len, tmp);
917
918 b->last = ngx_http_v2_write_value(b->last, header[i].value.data,
919 header[i].value.len, tmp);
920
921 #if (NGX_DEBUG)
922 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
923 ngx_strlow(tmp, header[i].key.data, header[i].key.len);
924
925 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
926 "grpc header: \"%*s: %V\"",
927 header[i].key.len, tmp, &header[i].value);
928 }
929 #endif
930 }
931 }
932
933 /* update headers frame length */
934
935 len = b->last - headers_frame - sizeof(ngx_http_grpc_frame_t);
936
937 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
938 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
939 next = 1;
940
941 } else {
942 next = 0;
943 }
944
945 f = (ngx_http_grpc_frame_t *) headers_frame;
946
947 f->length_0 = (u_char) ((len >> 16) & 0xff);
948 f->length_1 = (u_char) ((len >> 8) & 0xff);
949 f->length_2 = (u_char) (len & 0xff);
950
951 /* create additional continuation frames */
952
953 p = headers_frame;
954
955 while (next) {
956 p += sizeof(ngx_http_grpc_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
957 len = b->last - p;
958
959 ngx_memmove(p + sizeof(ngx_http_grpc_frame_t), p, len);
960 b->last += sizeof(ngx_http_grpc_frame_t);
961
962 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
963 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
964 next = 1;
965
966 } else {
967 next = 0;
968 }
969
970 f = (ngx_http_grpc_frame_t *) p;
971
972 f->length_0 = (u_char) ((len >> 16) & 0xff);
973 f->length_1 = (u_char) ((len >> 8) & 0xff);
974 f->length_2 = (u_char) (len & 0xff);
975 f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
976 f->flags = 0;
977 f->stream_id_0 = 0;
978 f->stream_id_1 = 0;
979 f->stream_id_2 = 0;
980 f->stream_id_3 = 1;
981 }
982
983 f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;
984
985 #if (NGX_DEBUG)
986 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
987 u_char buf[512];
988 size_t n, m;
989
990 n = ngx_min(b->last - b->pos, 256);
991 m = ngx_hex_dump(buf, b->pos, n) - buf;
992
993 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
994 "grpc header: %*s%s, len: %uz",
995 m, buf, b->last - b->pos > 256 ? "..." : "",
996 b->last - b->pos);
997 }
998 #endif
999
1000 if (r->request_body_no_buffering) {
1001
1002 u->request_bufs = cl;
1003
1004 } else {
1005
1006 body = u->request_bufs;
1007 u->request_bufs = cl;
1008
1009 if (body == NULL) {
1010 f = (ngx_http_grpc_frame_t *) headers_frame;
1011 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1012 }
1013
1014 while (body) {
1015 b = ngx_alloc_buf(r->pool);
1016 if (b == NULL) {
1017 return NGX_ERROR;
1018 }
1019
1020 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1021
1022 cl->next = ngx_alloc_chain_link(r->pool);
1023 if (cl->next == NULL) {
1024 return NGX_ERROR;
1025 }
1026
1027 cl = cl->next;
1028 cl->buf = b;
1029
1030 body = body->next;
1031 }
1032
1033 b->last_buf = 1;
1034 }
1035
1036 u->output.output_filter = ngx_http_grpc_body_output_filter;
1037 u->output.filter_ctx = r;
1038
1039 b->flush = 1;
1040 cl->next = NULL;
1041
1042 return NGX_OK;
1043 }
1044
1045
1046 static ngx_int_t
1047 ngx_http_grpc_reinit_request(ngx_http_request_t *r)
1048 {
1049 ngx_http_grpc_ctx_t *ctx;
1050
1051 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
1052
1053 if (ctx == NULL) {
1054 return NGX_OK;
1055 }
1056
1057 ctx->state = 0;
1058 ctx->header_sent = 0;
1059 ctx->output_closed = 0;
1060 ctx->parsing_headers = 0;
1061 ctx->end_stream = 0;
1062 ctx->status = 0;
1063 ctx->connection = NULL;
1064
1065 return NGX_OK;
1066 }
1067
1068
1069 static ngx_int_t
1070 ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
1071 {
1072 ngx_http_request_t *r = data;
1073
1074 off_t file_pos;
1075 u_char *p, *pos, *start;
1076 size_t len, limit;
1077 ngx_buf_t *b;
1078 ngx_int_t rc;
1079 ngx_uint_t next, last;
1080 ngx_chain_t *cl, *out, **ll;
1081 ngx_http_grpc_ctx_t *ctx;
1082 ngx_http_grpc_frame_t *f;
1083
1084 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1085 "grpc output filter");
1086
1087 ctx = ngx_http_grpc_get_ctx(r);
1088
1089 if (ctx == NULL) {
1090 return NGX_ERROR;
1091 }
1092
1093 if (in) {
1094 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
1095 return NGX_ERROR;
1096 }
1097 }
1098
1099 out = NULL;
1100 ll = &out;
1101
1102 if (!ctx->header_sent) {
1103 /* first buffer contains headers */
1104
1105 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1106 "grpc output header");
1107
1108 ctx->header_sent = 1;
1109
1110 if (ctx->id != 1) {
1111 /*
1112 * keepalive connection: skip connection preface,
1113 * update stream identifiers
1114 */
1115
1116 b = ctx->in->buf;
1117 b->pos += sizeof(ngx_http_grpc_connection_start) - 1;
1118
1119 p = b->pos;
1120
1121 while (p < b->last) {
1122 f = (ngx_http_grpc_frame_t *) p;
1123 p += sizeof(ngx_http_grpc_frame_t);
1124
1125 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1126 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1127 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1128 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1129
1130 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
1131 }
1132 }
1133
1134 if (ctx->in->buf->last_buf) {
1135 ctx->output_closed = 1;
1136 }
1137
1138 *ll = ctx->in;
1139 ll = &ctx->in->next;
1140
1141 ctx->in = ctx->in->next;
1142 }
1143
1144 if (ctx->out) {
1145 /* queued control frames */
1146
1147 *ll = ctx->out;
1148
1149 for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
1150 ll = &cl->next;
1151 }
1152
1153 ctx->out = NULL;
1154 }
1155
1156 f = NULL;
1157 last = 0;
1158
1159 limit = ngx_max(0, ctx->send_window);
1160
1161 if (limit > ctx->connection->send_window) {
1162 limit = ctx->connection->send_window;
1163 }
1164
1165 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1166 "grpc output limit: %uz w:%z:%uz",
1167 limit, ctx->send_window, ctx->connection->send_window);
1168
1169 #if (NGX_SUPPRESS_WARN)
1170 file_pos = 0;
1171 pos = NULL;
1172 cl = NULL;
1173 #endif
1174
1175 in = ctx->in;
1176
1177 while (in && limit > 0) {
1178
1179 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1180 "grpc output in l:%d f:%d %p, pos %p, size: %z "
1181 "file: %O, size: %O",
1182 in->buf->last_buf,
1183 in->buf->in_file,
1184 in->buf->start, in->buf->pos,
1185 in->buf->last - in->buf->pos,
1186 in->buf->file_pos,
1187 in->buf->file_last - in->buf->file_pos);
1188
1189 if (ngx_buf_special(in->buf)) {
1190 goto next;
1191 }
1192
1193 if (in->buf->in_file) {
1194 file_pos = in->buf->file_pos;
1195
1196 } else {
1197 pos = in->buf->pos;
1198 }
1199
1200 next = 0;
1201
1202 do {
1203
1204 cl = ngx_http_grpc_get_buf(r, ctx);
1205 if (cl == NULL) {
1206 return NGX_ERROR;
1207 }
1208
1209 b = cl->buf;
1210
1211 f = (ngx_http_grpc_frame_t *) b->last;
1212 b->last += sizeof(ngx_http_grpc_frame_t);
1213
1214 *ll = cl;
1215 ll = &cl->next;
1216
1217 cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1218 if (cl == NULL) {
1219 return NGX_ERROR;
1220 }
1221
1222 b = cl->buf;
1223 start = b->start;
1224
1225 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1226
1227 /*
1228 * restore b->start to preserve memory allocated in the buffer,
1229 * to reuse it later for headers and control frames
1230 */
1231
1232 b->start = start;
1233
1234 if (in->buf->in_file) {
1235 b->file_pos = file_pos;
1236 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1237
1238 if (file_pos >= in->buf->file_last) {
1239 file_pos = in->buf->file_last;
1240 next = 1;
1241 }
1242
1243 b->file_last = file_pos;
1244 len = (ngx_uint_t) (file_pos - b->file_pos);
1245
1246 } else {
1247 b->pos = pos;
1248 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1249
1250 if (pos >= in->buf->last) {
1251 pos = in->buf->last;
1252 next = 1;
1253 }
1254
1255 b->last = pos;
1256 len = (ngx_uint_t) (pos - b->pos);
1257 }
1258
1259 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
1260 b->shadow = in->buf;
1261 b->last_shadow = next;
1262
1263 b->last_buf = 0;
1264 b->last_in_chain = 0;
1265
1266 *ll = cl;
1267 ll = &cl->next;
1268
1269 f->length_0 = (u_char) ((len >> 16) & 0xff);
1270 f->length_1 = (u_char) ((len >> 8) & 0xff);
1271 f->length_2 = (u_char) (len & 0xff);
1272 f->type = NGX_HTTP_V2_DATA_FRAME;
1273 f->flags = 0;
1274 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1275 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1276 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1277 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1278
1279 limit -= len;
1280 ctx->send_window -= len;
1281 ctx->connection->send_window -= len;
1282
1283 } while (!next && limit > 0);
1284
1285 if (!next) {
1286 /*
1287 * if the buffer wasn't fully sent due to flow control limits,
1288 * preserve position for future use
1289 */
1290
1291 if (in->buf->in_file) {
1292 in->buf->file_pos = file_pos;
1293
1294 } else {
1295 in->buf->pos = pos;
1296 }
1297
1298 break;
1299 }
1300
1301 next:
1302
1303 if (in->buf->last_buf) {
1304 last = 1;
1305 }
1306
1307 in = in->next;
1308 }
1309
1310 ctx->in = in;
1311
1312 if (last) {
1313
1314 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1315 "grpc output last");
1316
1317 ctx->output_closed = 1;
1318
1319 if (f) {
1320 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1321
1322 } else {
1323 cl = ngx_http_grpc_get_buf(r, ctx);
1324 if (cl == NULL) {
1325 return NGX_ERROR;
1326 }
1327
1328 b = cl->buf;
1329
1330 f = (ngx_http_grpc_frame_t *) b->last;
1331 b->last += sizeof(ngx_http_grpc_frame_t);
1332
1333 f->length_0 = 0;
1334 f->length_1 = 0;
1335 f->length_2 = 0;
1336 f->type = NGX_HTTP_V2_DATA_FRAME;
1337 f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
1338 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1339 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1340 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1341 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1342
1343 *ll = cl;
1344 ll = &cl->next;
1345 }
1346
1347 cl->buf->last_buf = 1;
1348 }
1349
1350 *ll = NULL;
1351
1352 #if (NGX_DEBUG)
1353
1354 for (cl = out; cl; cl = cl->next) {
1355 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1356 "grpc output out l:%d f:%d %p, pos %p, size: %z "
1357 "file: %O, size: %O",
1358 cl->buf->last_buf,
1359 cl->buf->in_file,
1360 cl->buf->start, cl->buf->pos,
1361 cl->buf->last - cl->buf->pos,
1362 cl->buf->file_pos,
1363 cl->buf->file_last - cl->buf->file_pos);
1364 }
1365
1366 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1367 "grpc output limit: %uz w:%z:%uz",
1368 limit, ctx->send_window, ctx->connection->send_window);
1369
1370 #endif
1371
1372 rc = ngx_chain_writer(&r->upstream->writer, out);
1373
1374 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1375 (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter);
1376
1377 for (cl = ctx->free; cl; cl = cl->next) {
1378
1379 /* mark original buffers as sent */
1380
1381 if (cl->buf->shadow) {
1382 if (cl->buf->last_shadow) {
1383 b = cl->buf->shadow;
1384 b->pos = b->last;
1385 }
1386
1387 cl->buf->shadow = NULL;
1388 }
1389 }
1390
1391 if (rc == NGX_OK && ctx->in) {
1392 rc = NGX_AGAIN;
1393 }
1394
1395 return rc;
1396 }
1397
1398
1399 static ngx_int_t
1400 ngx_http_grpc_process_header(ngx_http_request_t *r)
1401 {
1402 ngx_str_t *status_line;
1403 ngx_int_t rc, status;
1404 ngx_buf_t *b;
1405 ngx_table_elt_t *h;
1406 ngx_http_upstream_t *u;
1407 ngx_http_grpc_ctx_t *ctx;
1408 ngx_http_upstream_header_t *hh;
1409 ngx_http_upstream_main_conf_t *umcf;
1410
1411 u = r->upstream;
1412 b = &u->buffer;
1413
1414 #if (NGX_DEBUG)
1415 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1416 u_char buf[512];
1417 size_t n, m;
1418
1419 n = ngx_min(b->last - b->pos, 256);
1420 m = ngx_hex_dump(buf, b->pos, n) - buf;
1421
1422 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1423 "grpc response: %*s%s, len: %uz",
1424 m, buf, b->last - b->pos > 256 ? "..." : "",
1425 b->last - b->pos);
1426 }
1427 #endif
1428
1429 ctx = ngx_http_grpc_get_ctx(r);
1430
1431 if (ctx == NULL) {
1432 return NGX_ERROR;
1433 }
1434
1435 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1436
1437 for ( ;; ) {
1438
1439 if (ctx->state < ngx_http_grpc_st_payload) {
1440
1441 rc = ngx_http_grpc_parse_frame(r, ctx, b);
1442
1443 if (rc == NGX_AGAIN) {
1444
1445 /*
1446 * there can be a lot of window update frames,
1447 * so we reset buffer if it is empty and we haven't
1448 * started parsing headers yet
1449 */
1450
1451 if (!ctx->parsing_headers) {
1452 b->pos = b->start;
1453 b->last = b->pos;
1454 }
1455
1456 return NGX_AGAIN;
1457 }
1458
1459 if (rc == NGX_ERROR) {
1460 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1461 }
1462
1463 /*
1464 * RFC 7540 says that implementations MUST discard frames
1465 * that have unknown or unsupported types. However, extension
1466 * frames that appear in the middle of a header block are
1467 * not permitted. Also, for obvious reasons CONTINUATION frames
1468 * cannot appear before headers, and DATA frames are not expected
1469 * to appear before all headers are parsed.
1470 */
1471
1472 if (ctx->type == NGX_HTTP_V2_DATA_FRAME
1473 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
1474 && !ctx->parsing_headers)
1475 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
1476 && ctx->parsing_headers))
1477 {
1478 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1479 "upstream sent unexpected http2 frame: %d",
1480 ctx->type);
1481 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1482 }
1483
1484 if (ctx->stream_id && ctx->stream_id != ctx->id) {
1485 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1486 "upstream sent frame for unknown stream %ui",
1487 ctx->stream_id);
1488 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1489 }
1490 }
1491
1492 /* frame payload */
1493
1494 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
1495
1496 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
1497
1498 if (rc == NGX_AGAIN) {
1499 return NGX_AGAIN;
1500 }
1501
1502 if (rc == NGX_ERROR) {
1503 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1504 }
1505
1506 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1507 "upstream rejected request with error %ui",
1508 ctx->error);
1509
1510 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1511 }
1512
1513 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
1514
1515 rc = ngx_http_grpc_parse_goaway(r, ctx, b);
1516
1517 if (rc == NGX_AGAIN) {
1518 return NGX_AGAIN;
1519 }
1520
1521 if (rc == NGX_ERROR) {
1522 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1523 }
1524
1525 /*
1526 * If stream_id is lower than one we use, our
1527 * request won't be processed and needs to be retried.
1528 * If stream_id is greater or equal to the one we use,
1529 * we can continue normally (except we can't use this
1530 * connection for additional requests). If there is
1531 * a real error, the connection will be closed.
1532 */
1533
1534 if (ctx->stream_id < ctx->id) {
1535
1536 /* TODO: we can retry non-idempotent requests */
1537
1538 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1539 "upstream sent goaway with error %ui",
1540 ctx->error);
1541
1542 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1543 }
1544
1545 continue;
1546 }
1547
1548 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
1549
1550 rc = ngx_http_grpc_parse_window_update(r, ctx, b);
1551
1552 if (rc == NGX_AGAIN) {
1553 return NGX_AGAIN;
1554 }
1555
1556 if (rc == NGX_ERROR) {
1557 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1558 }
1559
1560 if (ctx->in) {
1561 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1562 }
1563
1564 continue;
1565 }
1566
1567 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
1568
1569 rc = ngx_http_grpc_parse_settings(r, ctx, b);
1570
1571 if (rc == NGX_AGAIN) {
1572 return NGX_AGAIN;
1573 }
1574
1575 if (rc == NGX_ERROR) {
1576 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1577 }
1578
1579 if (ctx->in) {
1580 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1581 }
1582
1583 continue;
1584 }
1585
1586 if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
1587
1588 rc = ngx_http_grpc_parse_ping(r, ctx, b);
1589
1590 if (rc == NGX_AGAIN) {
1591 return NGX_AGAIN;
1592 }
1593
1594 if (rc == NGX_ERROR) {
1595 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1596 }
1597
1598 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1599 continue;
1600 }
1601
1602 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
1603 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1604 "upstream sent unexpected push promise frame");
1605 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1606 }
1607
1608 if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
1609 && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
1610 {
1611 /* priority, unknown frames */
1612
1613 if (b->last - b->pos < (ssize_t) ctx->rest) {
1614 ctx->rest -= b->last - b->pos;
1615 b->pos = b->last;
1616 return NGX_AGAIN;
1617 }
1618
1619 b->pos += ctx->rest;
1620 ctx->rest = 0;
1621 ctx->state = ngx_http_grpc_st_start;
1622
1623 continue;
1624 }
1625
1626 /* headers */
1627
1628 for ( ;; ) {
1629
1630 rc = ngx_http_grpc_parse_header(r, ctx, b);
1631
1632 if (rc == NGX_AGAIN) {
1633 break;
1634 }
1635
1636 if (rc == NGX_OK) {
1637
1638 /* a header line has been parsed successfully */
1639
1640 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1641 "grpc header: \"%V: %V\"",
1642 &ctx->name, &ctx->value);
1643
1644 if (ctx->name.len && ctx->name.data[0] == ':') {
1645
1646 if (ctx->name.len != sizeof(":status") - 1
1647 || ngx_strncmp(ctx->name.data, ":status",
1648 sizeof(":status") - 1)
1649 != 0)
1650 {
1651 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1652 "upstream sent invalid header \"%V: %V\"",
1653 &ctx->name, &ctx->value);
1654 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1655 }
1656
1657 if (ctx->status) {
1658 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1659 "upstream sent duplicate :status header");
1660 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1661 }
1662
1663 status_line = &ctx->value;
1664
1665 if (status_line->len != 3) {
1666 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1667 "upstream sent invalid :status \"%V\"",
1668 status_line);
1669 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1670 }
1671
1672 status = ngx_atoi(status_line->data, 3);
1673
1674 if (status == NGX_ERROR) {
1675 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1676 "upstream sent invalid :status \"%V\"",
1677 status_line);
1678 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1679 }
1680
1681 if (status < NGX_HTTP_OK) {
1682 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1683 "upstream sent unexpected :status \"%V\"",
1684 status_line);
1685 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1686 }
1687
1688 u->headers_in.status_n = status;
1689
1690 if (u->state && u->state->status == 0) {
1691 u->state->status = status;
1692 }
1693
1694 ctx->status = 1;
1695
1696 continue;
1697
1698 } else if (!ctx->status) {
1699 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1700 "upstream sent no :status header");
1701 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1702 }
1703
1704 h = ngx_list_push(&u->headers_in.headers);
1705 if (h == NULL) {
1706 return NGX_ERROR;
1707 }
1708
1709 h->key = ctx->name;
1710 h->value = ctx->value;
1711 h->lowcase_key = h->key.data;
1712 h->hash = ngx_hash_key(h->key.data, h->key.len);
1713
1714 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1715 h->lowcase_key, h->key.len);
1716
1717 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1718 return NGX_ERROR;
1719 }
1720
1721 continue;
1722 }
1723
1724 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1725
1726 /* a whole header has been parsed successfully */
1727
1728 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1729 "grpc header done");
1730
1731 if (ctx->end_stream
1732 && ctx->in == NULL
1733 && ctx->out == NULL
1734 && ctx->output_closed
1735 && b->last == b->pos)
1736 {
1737 u->keepalive = 1;
1738 }
1739
1740 return NGX_OK;
1741 }
1742
1743 /* there was error while a header line parsing */
1744
1745 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1746 "upstream sent invalid header");
1747
1748 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1749 }
1750
1751 /* rc == NGX_AGAIN */
1752
1753 if (ctx->rest == 0) {
1754 ctx->state = ngx_http_grpc_st_start;
1755 continue;
1756 }
1757
1758 return NGX_AGAIN;
1759 }
1760 }
1761
1762
1763 static ngx_int_t
1764 ngx_http_grpc_filter_init(void *data)
1765 {
1766 ngx_http_grpc_ctx_t *ctx = data;
1767
1768 ngx_http_request_t *r;
1769 ngx_http_upstream_t *u;
1770
1771 r = ctx->request;
1772 u = r->upstream;
1773
1774 u->length = 1;
1775
1776 if (ctx->end_stream) {
1777 u->length = 0;
1778 }
1779
1780 return NGX_OK;
1781 }
1782
1783
1784 static ngx_int_t
1785 ngx_http_grpc_filter(void *data, ssize_t bytes)
1786 {
1787 ngx_http_grpc_ctx_t *ctx = data;
1788
1789 ngx_int_t rc;
1790 ngx_buf_t *b, *buf;
1791 ngx_chain_t *cl, **ll;
1792 ngx_table_elt_t *h;
1793 ngx_http_request_t *r;
1794 ngx_http_upstream_t *u;
1795
1796 r = ctx->request;
1797 u = r->upstream;
1798 b = &u->buffer;
1799
1800 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1801 "grpc filter bytes:%z", bytes);
1802
1803 b->pos = b->last;
1804 b->last += bytes;
1805
1806 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1807 ll = &cl->next;
1808 }
1809
1810 for ( ;; ) {
1811
1812 if (ctx->state < ngx_http_grpc_st_payload) {
1813
1814 rc = ngx_http_grpc_parse_frame(r, ctx, b);
1815
1816 if (rc == NGX_AGAIN) {
1817 return NGX_AGAIN;
1818 }
1819
1820 if (rc == NGX_ERROR) {
1821 return NGX_ERROR;
1822 }
1823
1824 if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
1825 && !ctx->parsing_headers)
1826 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
1827 && ctx->parsing_headers))
1828 {
1829 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1830 "upstream sent unexpected http2 frame: %d",
1831 ctx->type);
1832 return NGX_ERROR;
1833 }
1834
1835 if (ctx->type == NGX_HTTP_V2_DATA_FRAME) {
1836
1837 if (ctx->stream_id != ctx->id) {
1838 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1839 "upstream sent data frame "
1840 "for unknown stream %ui",
1841 ctx->stream_id);
1842 return NGX_ERROR;
1843 }
1844
1845 if (ctx->rest > ctx->recv_window) {
1846 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1847 "upstream violated stream flow control, "
1848 "received %uz data frame with window %uz",
1849 ctx->rest, ctx->recv_window);
1850 return NGX_ERROR;
1851 }
1852
1853 if (ctx->rest > ctx->connection->recv_window) {
1854 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1855 "upstream violated connection flow control, "
1856 "received %uz data frame with window %uz",
1857 ctx->rest, ctx->connection->recv_window);
1858 return NGX_ERROR;
1859 }
1860
1861 ctx->recv_window -= ctx->rest;
1862 ctx->connection->recv_window -= ctx->rest;
1863
1864 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
1865 || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
1866 {
1867 if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) {
1868 return NGX_ERROR;
1869 }
1870
1871 ngx_post_event(u->peer.connection->write,
1872 &ngx_posted_events);
1873 }
1874 }
1875
1876 if (ctx->stream_id && ctx->stream_id != ctx->id) {
1877 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1878 "upstream sent frame for unknown stream %ui",
1879 ctx->stream_id);
1880 return NGX_ERROR;
1881 }
1882
1883 ctx->padding = 0;
1884 }
1885
1886 if (ctx->state == ngx_http_grpc_st_padding) {
1887
1888 if (b->last - b->pos < (ssize_t) ctx->rest) {
1889 ctx->rest -= b->last - b->pos;
1890 b->pos = b->last;
1891 return NGX_AGAIN;
1892 }
1893
1894 b->pos += ctx->rest;
1895 ctx->rest = 0;
1896 ctx->state = ngx_http_grpc_st_start;
1897
1898 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
1899 u->length = 0;
1900
1901 if (ctx->in == NULL
1902 && ctx->out == NULL
1903 && ctx->output_closed
1904 && b->last == b->pos)
1905 {
1906 u->keepalive = 1;
1907 }
1908
1909 break;
1910 }
1911
1912 continue;
1913 }
1914
1915 /* frame payload */
1916
1917 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
1918
1919 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
1920
1921 if (rc == NGX_AGAIN) {
1922 return NGX_AGAIN;
1923 }
1924
1925 if (rc == NGX_ERROR) {
1926 return NGX_ERROR;
1927 }
1928
1929 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1930 "upstream rejected request with error %ui",
1931 ctx->error);
1932
1933 return NGX_ERROR;
1934 }
1935
1936 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
1937
1938 rc = ngx_http_grpc_parse_goaway(r, ctx, b);
1939
1940 if (rc == NGX_AGAIN) {
1941 return NGX_AGAIN;
1942 }
1943
1944 if (rc == NGX_ERROR) {
1945 return NGX_ERROR;
1946 }
1947
1948 /*
1949 * If stream_id is lower than one we use, our
1950 * request won't be processed and needs to be retried.
1951 * If stream_id is greater or equal to the one we use,
1952 * we can continue normally (except we can't use this
1953 * connection for additional requests). If there is
1954 * a real error, the connection will be closed.
1955 */
1956
1957 if (ctx->stream_id < ctx->id) {
1958
1959 /* TODO: we can retry non-idempotent requests */
1960
1961 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1962 "upstream sent goaway with error %ui",
1963 ctx->error);
1964
1965 return NGX_ERROR;
1966 }
1967
1968 continue;
1969 }
1970
1971 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
1972
1973 rc = ngx_http_grpc_parse_window_update(r, ctx, b);
1974
1975 if (rc == NGX_AGAIN) {
1976 return NGX_AGAIN;
1977 }
1978
1979 if (rc == NGX_ERROR) {
1980 return NGX_ERROR;
1981 }
1982
1983 if (ctx->in) {
1984 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1985 }
1986
1987 continue;
1988 }
1989
1990 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
1991
1992 rc = ngx_http_grpc_parse_settings(r, ctx, b);
1993
1994 if (rc == NGX_AGAIN) {
1995 return NGX_AGAIN;
1996 }
1997
1998 if (rc == NGX_ERROR) {
1999 return NGX_ERROR;
2000 }
2001
2002 if (ctx->in) {
2003 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2004 }
2005
2006 continue;
2007 }
2008
2009 if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
2010
2011 rc = ngx_http_grpc_parse_ping(r, ctx, b);
2012
2013 if (rc == NGX_AGAIN) {
2014 return NGX_AGAIN;
2015 }
2016
2017 if (rc == NGX_ERROR) {
2018 return NGX_ERROR;
2019 }
2020
2021 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2022 continue;
2023 }
2024
2025 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
2026 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2027 "upstream sent unexpected push promise frame");
2028 return NGX_ERROR;
2029 }
2030
2031 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
2032 || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
2033 {
2034 for ( ;; ) {
2035
2036 rc = ngx_http_grpc_parse_header(r, ctx, b);
2037
2038 if (rc == NGX_AGAIN) {
2039 break;
2040 }
2041
2042 if (rc == NGX_OK) {
2043
2044 /* a header line has been parsed successfully */
2045
2046 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2047 "grpc trailer: \"%V: %V\"",
2048 &ctx->name, &ctx->value);
2049
2050 if (ctx->name.len && ctx->name.data[0] == ':') {
2051 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2052 "upstream sent invalid "
2053 "trailer \"%V: %V\"",
2054 &ctx->name, &ctx->value);
2055 return NGX_ERROR;
2056 }
2057
2058 h = ngx_list_push(&u->headers_in.trailers);
2059 if (h == NULL) {
2060 return NGX_ERROR;
2061 }
2062
2063 h->key = ctx->name;
2064 h->value = ctx->value;
2065 h->lowcase_key = h->key.data;
2066 h->hash = ngx_hash_key(h->key.data, h->key.len);
2067
2068 continue;
2069 }
2070
2071 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2072
2073 /* a whole header has been parsed successfully */
2074
2075 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2076 "grpc trailer done");
2077
2078 if (ctx->end_stream) {
2079 u->length = 0;
2080
2081 if (ctx->in == NULL
2082 && ctx->out == NULL
2083 && ctx->output_closed
2084 && b->last == b->pos)
2085 {
2086 u->keepalive = 1;
2087 }
2088
2089 return NGX_OK;
2090 }
2091
2092 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2093 "upstream sent trailer without "
2094 "end stream flag");
2095 return NGX_ERROR;
2096 }
2097
2098 /* there was error while a header line parsing */
2099
2100 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2101 "upstream sent invalid trailer");
2102
2103 return NGX_ERROR;
2104 }
2105
2106 /* rc == NGX_AGAIN */
2107
2108 if (ctx->rest == 0) {
2109 ctx->state = ngx_http_grpc_st_start;
2110 continue;
2111 }
2112
2113 return NGX_AGAIN;
2114 }
2115
2116 if (ctx->type != NGX_HTTP_V2_DATA_FRAME) {
2117
2118 /* priority, unknown frames */
2119
2120 if (b->last - b->pos < (ssize_t) ctx->rest) {
2121 ctx->rest -= b->last - b->pos;
2122 b->pos = b->last;
2123 return NGX_AGAIN;
2124 }
2125
2126 b->pos += ctx->rest;
2127 ctx->rest = 0;
2128 ctx->state = ngx_http_grpc_st_start;
2129
2130 continue;
2131 }
2132
2133 /*
2134 * data frame:
2135 *
2136 * +---------------+
2137 * |Pad Length? (8)|
2138 * +---------------+-----------------------------------------------+
2139 * | Data (*) ...
2140 * +---------------------------------------------------------------+
2141 * | Padding (*) ...
2142 * +---------------------------------------------------------------+
2143 */
2144
2145 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2146
2147 if (ctx->rest == 0) {
2148 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2149 "upstream sent too short http2 frame");
2150 return NGX_ERROR;
2151 }
2152
2153 if (b->pos == b->last) {
2154 return NGX_AGAIN;
2155 }
2156
2157 ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
2158 ctx->padding = *b->pos++;
2159 ctx->rest -= 1;
2160
2161 if (ctx->padding > ctx->rest) {
2162 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2163 "upstream sent http2 frame with too long "
2164 "padding: %d in frame %uz",
2165 ctx->padding, ctx->rest);
2166 return NGX_ERROR;
2167 }
2168
2169 continue;
2170 }
2171
2172 if (ctx->rest == ctx->padding) {
2173 goto done;
2174 }
2175
2176 if (b->pos == b->last) {
2177 return NGX_AGAIN;
2178 }
2179
2180 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2181 if (cl == NULL) {
2182 return NGX_ERROR;
2183 }
2184
2185 *ll = cl;
2186 ll = &cl->next;
2187
2188 buf = cl->buf;
2189
2190 buf->flush = 1;
2191 buf->memory = 1;
2192
2193 buf->pos = b->pos;
2194 buf->tag = u->output.tag;
2195
2196 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2197 "grpc output buf %p", buf->pos);
2198
2199 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2200
2201 ctx->rest -= b->last - b->pos;
2202 b->pos = b->last;
2203 buf->last = b->pos;
2204
2205 return NGX_AGAIN;
2206 }
2207
2208 b->pos += ctx->rest - ctx->padding;
2209 buf->last = b->pos;
2210 ctx->rest = ctx->padding;
2211
2212 done:
2213
2214 if (ctx->padding) {
2215 ctx->state = ngx_http_grpc_st_padding;
2216 continue;
2217 }
2218
2219 ctx->state = ngx_http_grpc_st_start;
2220
2221 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2222 u->length = 0;
2223
2224 if (ctx->in == NULL
2225 && ctx->out == NULL
2226 && ctx->output_closed
2227 && b->last == b->pos)
2228 {
2229 u->keepalive = 1;
2230 }
2231
2232 break;
2233 }
2234 }
2235
2236 return NGX_OK;
2237 }
2238
2239
2240 static ngx_int_t
2241 ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2242 ngx_buf_t *b)
2243 {
2244 u_char ch, *p;
2245 ngx_http_grpc_state_e state;
2246
2247 state = ctx->state;
2248
2249 for (p = b->pos; p < b->last; p++) {
2250 ch = *p;
2251
2252 #if 0
2253 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2254 "grpc frame byte: %02Xd, s:%d", ch, state);
2255 #endif
2256
2257 switch (state) {
2258
2259 case ngx_http_grpc_st_start:
2260 ctx->rest = ch << 16;
2261 state = ngx_http_grpc_st_length_2;
2262 break;
2263
2264 case ngx_http_grpc_st_length_2:
2265 ctx->rest |= ch << 8;
2266 state = ngx_http_grpc_st_length_3;
2267 break;
2268
2269 case ngx_http_grpc_st_length_3:
2270 ctx->rest |= ch;
2271
2272 if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
2273 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2274 "upstream sent too large http2 frame: %uz",
2275 ctx->rest);
2276 return NGX_ERROR;
2277 }
2278
2279 state = ngx_http_grpc_st_type;
2280 break;
2281
2282 case ngx_http_grpc_st_type:
2283 ctx->type = ch;
2284 state = ngx_http_grpc_st_flags;
2285 break;
2286
2287 case ngx_http_grpc_st_flags:
2288 ctx->flags = ch;
2289 state = ngx_http_grpc_st_stream_id;
2290 break;
2291
2292 case ngx_http_grpc_st_stream_id:
2293 ctx->stream_id = (ch & 0x7f) << 24;
2294 state = ngx_http_grpc_st_stream_id_2;
2295 break;
2296
2297 case ngx_http_grpc_st_stream_id_2:
2298 ctx->stream_id |= ch << 16;
2299 state = ngx_http_grpc_st_stream_id_3;
2300 break;
2301
2302 case ngx_http_grpc_st_stream_id_3:
2303 ctx->stream_id |= ch << 8;
2304 state = ngx_http_grpc_st_stream_id_4;
2305 break;
2306
2307 case ngx_http_grpc_st_stream_id_4:
2308 ctx->stream_id |= ch;
2309
2310 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2311 "grpc frame: %d, len: %uz, f:%d, i:%ui",
2312 ctx->type, ctx->rest, ctx->flags, ctx->stream_id);
2313
2314 b->pos = p + 1;
2315
2316 ctx->state = ngx_http_grpc_st_payload;
2317 ctx->frame_state = 0;
2318
2319 return NGX_OK;
2320
2321 /* suppress warning */
2322 case ngx_http_grpc_st_payload:
2323 case ngx_http_grpc_st_padding:
2324 break;
2325 }
2326 }
2327
2328 b->pos = p;
2329 ctx->state = state;
2330
2331 return NGX_AGAIN;
2332 }
2333
2334
2335 static ngx_int_t
2336 ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2337 ngx_buf_t *b)
2338 {
2339 u_char ch, *p, *last;
2340 size_t min;
2341 ngx_int_t rc;
2342 enum {
2343 sw_start = 0,
2344 sw_padding_length,
2345 sw_dependency,
2346 sw_dependency_2,
2347 sw_dependency_3,
2348 sw_dependency_4,
2349 sw_weight,
2350 sw_fragment,
2351 sw_padding
2352 } state;
2353
2354 state = ctx->frame_state;
2355
2356 if (state == sw_start) {
2357
2358 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2359 "grpc parse header: start");
2360
2361 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
2362 ctx->parsing_headers = 1;
2363 ctx->fragment_state = 0;
2364
2365 min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0)
2366 + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0);
2367
2368 if (ctx->rest < min) {
2369 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2370 "upstream sent headers frame "
2371 "with invalid length: %uz",
2372 ctx->rest);
2373 return NGX_ERROR;
2374 }
2375
2376 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2377 ctx->end_stream = 1;
2378 }
2379
2380 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2381 state = sw_padding_length;
2382
2383 } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2384 state = sw_dependency;
2385
2386 } else {
2387 state = sw_fragment;
2388 }
2389
2390 } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
2391 state = sw_fragment;
2392 }
2393
2394 ctx->padding = 0;
2395 }
2396
2397 if (state < sw_fragment) {
2398
2399 if (b->last - b->pos < (ssize_t) ctx->rest) {
2400 last = b->last;
2401
2402 } else {
2403 last = b->pos + ctx->rest;
2404 }
2405
2406 for (p = b->pos; p < last; p++) {
2407 ch = *p;
2408
2409 #if 0
2410 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2411 "grpc header byte: %02Xd s:%d", ch, state);
2412 #endif
2413
2414 /*
2415 * headers frame:
2416 *
2417 * +---------------+
2418 * |Pad Length? (8)|
2419 * +-+-------------+----------------------------------------------+
2420 * |E| Stream Dependency? (31) |
2421 * +-+-------------+----------------------------------------------+
2422 * | Weight? (8) |
2423 * +-+-------------+----------------------------------------------+
2424 * | Header Block Fragment (*) ...
2425 * +--------------------------------------------------------------+
2426 * | Padding (*) ...
2427 * +--------------------------------------------------------------+
2428 */
2429
2430 switch (state) {
2431
2432 case sw_padding_length:
2433
2434 ctx->padding = ch;
2435
2436 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2437 state = sw_dependency;
2438 break;
2439 }
2440
2441 goto fragment;
2442
2443 case sw_dependency:
2444 state = sw_dependency_2;
2445 break;
2446
2447 case sw_dependency_2:
2448 state = sw_dependency_3;
2449 break;
2450
2451 case sw_dependency_3:
2452 state = sw_dependency_4;
2453 break;
2454
2455 case sw_dependency_4:
2456 state = sw_weight;
2457 break;
2458
2459 case sw_weight:
2460 goto fragment;
2461
2462 /* suppress warning */
2463 case sw_start:
2464 case sw_fragment:
2465 case sw_padding:
2466 break;
2467 }
2468 }
2469
2470 ctx->rest -= p - b->pos;
2471 b->pos = p;
2472
2473 ctx->frame_state = state;
2474 return NGX_AGAIN;
2475
2476 fragment:
2477
2478 p++;
2479 ctx->rest -= p - b->pos;
2480 b->pos = p;
2481
2482 if (ctx->padding > ctx->rest) {
2483 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2484 "upstream sent http2 frame with too long "
2485 "padding: %d in frame %uz",
2486 ctx->padding, ctx->rest);
2487 return NGX_ERROR;
2488 }
2489
2490 state = sw_fragment;
2491 ctx->frame_state = state;
2492 }
2493
2494 if (state == sw_fragment) {
2495
2496 rc = ngx_http_grpc_parse_fragment(r, ctx, b);
2497
2498 if (rc == NGX_AGAIN) {
2499 return NGX_AGAIN;
2500 }
2501
2502 if (rc == NGX_ERROR) {
2503 return NGX_ERROR;
2504 }
2505
2506 if (rc == NGX_OK) {
2507 return NGX_OK;
2508 }
2509
2510 /* rc == NGX_DONE */
2511
2512 state = sw_padding;
2513 ctx->frame_state = state;
2514 }
2515
2516 if (state == sw_padding) {
2517
2518 if (b->last - b->pos < (ssize_t) ctx->rest) {
2519
2520 ctx->rest -= b->last - b->pos;
2521 b->pos = b->last;
2522
2523 return NGX_AGAIN;
2524 }
2525
2526 b->pos += ctx->rest;
2527 ctx->rest = 0;
2528
2529 ctx->state = ngx_http_grpc_st_start;
2530
2531 if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
2532
2533 if (ctx->fragment_state) {
2534 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2535 "upstream sent truncated http2 header");
2536 return NGX_ERROR;
2537 }
2538
2539 ctx->parsing_headers = 0;
2540
2541 return NGX_HTTP_PARSE_HEADER_DONE;
2542 }
2543
2544 return NGX_AGAIN;
2545 }
2546
2547 /* unreachable */
2548
2549 return NGX_ERROR;
2550 }
2551
2552
2553 static ngx_int_t
2554 ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2555 ngx_buf_t *b)
2556 {
2557 u_char ch, *p, *last;
2558 size_t size;
2559 ngx_uint_t index, size_update;
2560 enum {
2561 sw_start = 0,
2562 sw_index,
2563 sw_name_length,
2564 sw_name_length_2,
2565 sw_name_length_3,
2566 sw_name_length_4,
2567 sw_name,
2568 sw_name_bytes,
2569 sw_value_length,
2570 sw_value_length_2,
2571 sw_value_length_3,
2572 sw_value_length_4,
2573 sw_value,
2574 sw_value_bytes
2575 } state;
2576
2577 /* header block fragment */
2578
2579 #if 0
2580 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2581 "grpc header fragment %p:%p rest:%uz",
2582 b->pos, b->last, ctx->rest);
2583 #endif
2584
2585 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2586 last = b->last;
2587
2588 } else {
2589 last = b->pos + ctx->rest - ctx->padding;
2590 }
2591
2592 state = ctx->fragment_state;
2593
2594 for (p = b->pos; p < last; p++) {
2595 ch = *p;
2596
2597 #if 0
2598 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2599 "grpc header byte: %02Xd s:%d", ch, state);
2600 #endif
2601
2602 switch (state) {
2603
2604 case sw_start:
2605 ctx->index = 0;
2606
2607 if ((ch & 0x80) == 0x80) {
2608 /*
2609 * indexed header:
2610 *
2611 * 0 1 2 3 4 5 6 7
2612 * +---+---+---+---+---+---+---+---+
2613 * | 1 | Index (7+) |
2614 * +---+---------------------------+
2615 */
2616
2617 index = ch & ~0x80;
2618
2619 if (index == 0 || index > 61) {
2620 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2621 "upstream sent invalid http2 "
2622 "table index: %ui", index);
2623 return NGX_ERROR;
2624 }
2625
2626 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2627 "grpc indexed header: %ui", index);
2628
2629 ctx->index = index;
2630 ctx->literal = 0;
2631
2632 goto done;
2633
2634 } else if ((ch & 0xc0) == 0x40) {
2635 /*
2636 * literal header with incremental indexing:
2637 *
2638 * 0 1 2 3 4 5 6 7
2639 * +---+---+---+---+---+---+---+---+
2640 * | 0 | 1 | Index (6+) |
2641 * +---+---+-----------------------+
2642 * | H | Value Length (7+) |
2643 * +---+---------------------------+
2644 * | Value String (Length octets) |
2645 * +-------------------------------+
2646 *
2647 * 0 1 2 3 4 5 6 7
2648 * +---+---+---+---+---+---+---+---+
2649 * | 0 | 1 | 0 |
2650 * +---+---+-----------------------+
2651 * | H | Name Length (7+) |
2652 * +---+---------------------------+
2653 * | Name String (Length octets) |
2654 * +---+---------------------------+
2655 * | H | Value Length (7+) |
2656 * +---+---------------------------+
2657 * | Value String (Length octets) |
2658 * +-------------------------------+
2659 */
2660
2661 index = ch & ~0xc0;
2662
2663 if (index > 61) {
2664 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2665 "upstream sent invalid http2 "
2666 "table index: %ui", index);
2667 return NGX_ERROR;
2668 }
2669
2670 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2671 "grpc literal header: %ui", index);
2672
2673 if (index == 0) {
2674 state = sw_name_length;
2675 break;
2676 }
2677
2678 ctx->index = index;
2679 ctx->literal = 1;
2680
2681 state = sw_value_length;
2682 break;
2683
2684 } else if ((ch & 0xe0) == 0x20) {
2685 /*
2686 * dynamic table size update:
2687 *
2688 * 0 1 2 3 4 5 6 7
2689 * +---+---+---+---+---+---+---+---+
2690 * | 0 | 0 | 1 | Max size (5+) |
2691 * +---+---------------------------+
2692 */
2693
2694 size_update = ch & ~0xe0;
2695
2696 if (size_update > 0) {
2697 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2698 "upstream sent invalid http2 "
2699 "dynamic table size update: %ui",
2700 size_update);
2701 return NGX_ERROR;
2702 }
2703
2704 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2705 "grpc table size update: %ui", size_update);
2706
2707 break;
2708
2709 } else if ((ch & 0xf0) == 0x10) {
2710 /*
2711 * literal header field never indexed:
2712 *
2713 * 0 1 2 3 4 5 6 7
2714 * +---+---+---+---+---+---+---+---+
2715 * | 0 | 0 | 0 | 1 | Index (4+) |
2716 * +---+---+-----------------------+
2717 * | H | Value Length (7+) |
2718 * +---+---------------------------+
2719 * | Value String (Length octets) |
2720 * +-------------------------------+
2721 *
2722 * 0 1 2 3 4 5 6 7
2723 * +---+---+---+---+---+---+---+---+
2724 * | 0 | 0 | 0 | 1 | 0 |
2725 * +---+---+-----------------------+
2726 * | H | Name Length (7+) |
2727 * +---+---------------------------+
2728 * | Name String (Length octets) |
2729 * +---+---------------------------+
2730 * | H | Value Length (7+) |
2731 * +---+---------------------------+
2732 * | Value String (Length octets) |
2733 * +-------------------------------+
2734 */
2735
2736 index = ch & ~0xf0;
2737
2738 if (index == 0x0f) {
2739 ctx->index = index;
2740 ctx->literal = 1;
2741 state = sw_index;
2742 break;
2743 }
2744
2745 if (index == 0) {
2746 state = sw_name_length;
2747 break;
2748 }
2749
2750 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2751 "grpc literal header never indexed: %ui",
2752 index);
2753
2754 ctx->index = index;
2755 ctx->literal = 1;
2756
2757 state = sw_value_length;
2758 break;
2759
2760 } else if ((ch & 0xf0) == 0x00) {
2761 /*
2762 * literal header field without indexing:
2763 *
2764 * 0 1 2 3 4 5 6 7
2765 * +---+---+---+---+---+---+---+---+
2766 * | 0 | 0 | 0 | 0 | Index (4+) |
2767 * +---+---+-----------------------+
2768 * | H | Value Length (7+) |
2769 * +---+---------------------------+
2770 * | Value String (Length octets) |
2771 * +-------------------------------+
2772 *
2773 * 0 1 2 3 4 5 6 7
2774 * +---+---+---+---+---+---+---+---+
2775 * | 0 | 0 | 0 | 0 | 0 |
2776 * +---+---+-----------------------+
2777 * | H | Name Length (7+) |
2778 * +---+---------------------------+
2779 * | Name String (Length octets) |
2780 * +---+---------------------------+
2781 * | H | Value Length (7+) |
2782 * +---+---------------------------+
2783 * | Value String (Length octets) |
2784 * +-------------------------------+
2785 */
2786
2787 index = ch & ~0xf0;
2788
2789 if (index == 0x0f) {
2790 ctx->index = index;
2791 ctx->literal = 1;
2792 state = sw_index;
2793 break;
2794 }
2795
2796 if (index == 0) {
2797 state = sw_name_length;
2798 break;
2799 }
2800
2801 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2802 "grpc literal header without indexing: %ui",
2803 index);
2804
2805 ctx->index = index;
2806 ctx->literal = 1;
2807
2808 state = sw_value_length;
2809 break;
2810 }
2811
2812 /* not reached */
2813
2814 return NGX_ERROR;
2815
2816 case sw_index:
2817 ctx->index = ctx->index + (ch & ~0x80);
2818
2819 if (ch & 0x80) {
2820 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2821 "upstream sent http2 table index "
2822 "with continuation flag");
2823 return NGX_ERROR;
2824 }
2825
2826 if (ctx->index > 61) {
2827 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2828 "upstream sent invalid http2 "
2829 "table index: %ui", ctx->index);
2830 return NGX_ERROR;
2831 }
2832
2833 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2834 "grpc header index: %ui", ctx->index);
2835
2836 state = sw_value_length;
2837 break;
2838
2839 case sw_name_length:
2840 ctx->field_huffman = ch & 0x80 ? 1 : 0;
2841 ctx->field_length = ch & ~0x80;
2842
2843 if (ctx->field_length == 0x7f) {
2844 state = sw_name_length_2;
2845 break;
2846 }
2847
2848 if (ctx->field_length == 0) {
2849 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2850 "upstream sent zero http2 "
2851 "header name length");
2852 return NGX_ERROR;
2853 }
2854
2855 state = sw_name;
2856 break;
2857
2858 case sw_name_length_2:
2859 ctx->field_length += ch & ~0x80;
2860
2861 if (ch & 0x80) {
2862 state = sw_name_length_3;
2863 break;
2864 }
2865
2866 state = sw_name;
2867 break;
2868
2869 case sw_name_length_3:
2870 ctx->field_length += (ch & ~0x80) << 7;
2871
2872 if (ch & 0x80) {
2873 state = sw_name_length_4;
2874 break;
2875 }
2876
2877 state = sw_name;
2878 break;
2879
2880 case sw_name_length_4:
2881 ctx->field_length += (ch & ~0x80) << 14;
2882
2883 if (ch & 0x80) {
2884 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2885 "upstream sent too large http2 "
2886 "header name length");
2887 return NGX_ERROR;
2888 }
2889
2890 state = sw_name;
2891 break;
2892
2893 case sw_name:
2894 ctx->name.len = ctx->field_huffman ?
2895 ctx->field_length * 8 / 5 : ctx->field_length;
2896
2897 ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
2898 if (ctx->name.data == NULL) {
2899 return NGX_ERROR;
2900 }
2901
2902 ctx->field_end = ctx->name.data;
2903 ctx->field_rest = ctx->field_length;
2904 ctx->field_state = 0;
2905
2906 state = sw_name_bytes;
2907
2908 /* fall through */
2909
2910 case sw_name_bytes:
2911
2912 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2913 "grpc name: len:%uz h:%d last:%uz, rest:%uz",
2914 ctx->field_length,
2915 ctx->field_huffman,
2916 last - p,
2917 ctx->rest - (p - b->pos));
2918
2919 size = ngx_min(last - p, (ssize_t) ctx->field_rest);
2920 ctx->field_rest -= size;
2921
2922 if (ctx->field_huffman) {
2923 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
2924 &ctx->field_end,
2925 ctx->field_rest == 0,
2926 r->connection->log)
2927 != NGX_OK)
2928 {
2929 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2930 "upstream sent invalid encoded header");
2931 return NGX_ERROR;
2932 }
2933
2934 ctx->name.len = ctx->field_end - ctx->name.data;
2935 ctx->name.data[ctx->name.len] = '\0';
2936
2937 } else {
2938 ngx_memcpy(ctx->field_end, p, size);
2939 ctx->name.data[ctx->name.len] = '\0';
2940 }
2941
2942 p += size - 1;
2943
2944 if (ctx->field_rest == 0) {
2945 state = sw_value_length;
2946 }
2947
2948 break;
2949
2950 case sw_value_length:
2951 ctx->field_huffman = ch & 0x80 ? 1 : 0;
2952 ctx->field_length = ch & ~0x80;
2953
2954 if (ctx->field_length == 0x7f) {
2955 state = sw_value_length_2;
2956 break;
2957 }
2958
2959 if (ctx->field_length == 0) {
2960 ngx_str_set(&ctx->value, "");
2961 goto done;
2962 }
2963
2964 state = sw_value;
2965 break;
2966
2967 case sw_value_length_2:
2968 ctx->field_length += ch & ~0x80;
2969
2970 if (ch & 0x80) {
2971 state = sw_value_length_3;
2972 break;
2973 }
2974
2975 state = sw_value;
2976 break;
2977
2978 case sw_value_length_3:
2979 ctx->field_length += (ch & ~0x80) << 7;
2980
2981 if (ch & 0x80) {
2982 state = sw_value_length_4;
2983 break;
2984 }
2985
2986 state = sw_value;
2987 break;
2988
2989 case sw_value_length_4:
2990 ctx->field_length += (ch & ~0x80) << 14;
2991
2992 if (ch & 0x80) {
2993 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2994 "upstream sent too large http2 "
2995 "header value length");
2996 return NGX_ERROR;
2997 }
2998
2999 state = sw_value;
3000 break;
3001
3002 case sw_value:
3003 ctx->value.len = ctx->field_huffman ?
3004 ctx->field_length * 8 / 5 : ctx->field_length;
3005
3006 ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
3007 if (ctx->value.data == NULL) {
3008 return NGX_ERROR;
3009 }
3010
3011 ctx->field_end = ctx->value.data;
3012 ctx->field_rest = ctx->field_length;
3013 ctx->field_state = 0;
3014
3015 state = sw_value_bytes;
3016
3017 /* fall through */
3018
3019 case sw_value_bytes:
3020
3021 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3022 "grpc value: len:%uz h:%d last:%uz, rest:%uz",
3023 ctx->field_length,
3024 ctx->field_huffman,
3025 last - p,
3026 ctx->rest - (p - b->pos));
3027
3028 size = ngx_min(last - p, (ssize_t) ctx->field_rest);
3029 ctx->field_rest -= size;
3030
3031 if (ctx->field_huffman) {
3032 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
3033 &ctx->field_end,
3034 ctx->field_rest == 0,
3035 r->connection->log)
3036 != NGX_OK)
3037 {
3038 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3039 "upstream sent invalid encoded header");
3040 return NGX_ERROR;
3041 }
3042
3043 ctx->value.len = ctx->field_end - ctx->value.data;
3044 ctx->value.data[ctx->value.len] = '\0';
3045
3046 } else {
3047 ngx_memcpy(ctx->field_end, p, size);
3048 ctx->value.data[ctx->value.len] = '\0';
3049 }
3050
3051 p += size - 1;
3052
3053 if (ctx->field_rest == 0) {
3054 goto done;
3055 }
3056
3057 break;
3058 }
3059
3060 continue;
3061
3062 done:
3063
3064 p++;
3065 ctx->rest -= p - b->pos;
3066 ctx->fragment_state = sw_start;
3067 b->pos = p;
3068
3069 if (ctx->index) {
3070 ctx->name = *ngx_http_v2_get_static_name(ctx->index);
3071 }
3072
3073 if (ctx->index && !ctx->literal) {
3074 ctx->value = *ngx_http_v2_get_static_value(ctx->index);
3075 }
3076
3077 if (!ctx->index) {
3078 if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) {
3079 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3080 "upstream sent invalid header: \"%V: %V\"",
3081 &ctx->name, &ctx->value);
3082 return NGX_ERROR;
3083 }
3084 }
3085
3086 if (!ctx->index || ctx->literal) {
3087 if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) {
3088 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3089 "upstream sent invalid header: \"%V: %V\"",