1
2 /*
3 * Copyright (C) Maxim Dounin
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11
12
13 typedef struct {
14 ngx_array_t *flushes;
15 ngx_array_t *lengths;
16 ngx_array_t *values;
17 ngx_hash_t hash;
18 } ngx_http_grpc_headers_t;
19
20
21 typedef struct {
22 ngx_http_upstream_conf_t upstream;
23
24 ngx_http_grpc_headers_t headers;
25 ngx_array_t *headers_source;
26
27 ngx_str_t host;
28 ngx_uint_t host_set;
29
30 #if (NGX_HTTP_SSL)
31 ngx_uint_t ssl;
32 ngx_uint_t ssl_protocols;
33 ngx_str_t ssl_ciphers;
34 ngx_uint_t ssl_verify_depth;
35 ngx_str_t ssl_trusted_certificate;
36 ngx_str_t ssl_crl;
37 ngx_str_t ssl_certificate;
38 ngx_str_t ssl_certificate_key;
39 ngx_array_t *ssl_passwords;
40 #endif
41 } ngx_http_grpc_loc_conf_t;
42
43
44 typedef enum {
45 ngx_http_grpc_st_start = 0,
46 ngx_http_grpc_st_length_2,
47 ngx_http_grpc_st_length_3,
48 ngx_http_grpc_st_type,
49 ngx_http_grpc_st_flags,
50 ngx_http_grpc_st_stream_id,
51 ngx_http_grpc_st_stream_id_2,
52 ngx_http_grpc_st_stream_id_3,
53 ngx_http_grpc_st_stream_id_4,
54 ngx_http_grpc_st_payload,
55 ngx_http_grpc_st_padding
56 } ngx_http_grpc_state_e;
57
58
59 typedef struct {
60 size_t init_window;
61 size_t send_window;
62 size_t recv_window;
63 ngx_uint_t last_stream_id;
64 } ngx_http_grpc_conn_t;
65
66
67 typedef struct {
68 ngx_http_grpc_state_e state;
69 ngx_uint_t frame_state;
70 ngx_uint_t fragment_state;
71
72 ngx_chain_t *in;
73 ngx_chain_t *out;
74 ngx_chain_t *free;
75 ngx_chain_t *busy;
76
77 ngx_http_grpc_conn_t *connection;
78
79 ngx_uint_t id;
80
81 ngx_uint_t pings;
82 ngx_uint_t settings;
83
84 ssize_t send_window;
85 size_t recv_window;
86
87 size_t rest;
88 ngx_uint_t stream_id;
89 u_char type;
90 u_char flags;
91 u_char padding;
92
93 ngx_uint_t error;
94 ngx_uint_t window_update;
95
96 ngx_uint_t setting_id;
97 ngx_uint_t setting_value;
98
99 u_char ping_data[8];
100
101 ngx_uint_t index;
102 ngx_str_t name;
103 ngx_str_t value;
104
105 u_char *field_end;
106 size_t field_length;
107 size_t field_rest;
108 u_char field_state;
109
110 unsigned literal:1;
111 unsigned field_huffman:1;
112
113 unsigned header_sent:1;
114 unsigned output_closed:1;
115 unsigned output_blocked:1;
116 unsigned parsing_headers:1;
117 unsigned end_stream:1;
118 unsigned done:1;
119 unsigned status:1;
120
121 ngx_http_request_t *request;
122 } ngx_http_grpc_ctx_t;
123
124
125 typedef struct {
126 u_char length_0;
127 u_char length_1;
128 u_char length_2;
129 u_char type;
130 u_char flags;
131 u_char stream_id_0;
132 u_char stream_id_1;
133 u_char stream_id_2;
134 u_char stream_id_3;
135 } ngx_http_grpc_frame_t;
136
137
138 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r);
139 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r);
140 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in);
141 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r);
142 static ngx_int_t ngx_http_grpc_filter_init(void *data);
143 static ngx_int_t ngx_http_grpc_filter(void *data, ssize_t bytes);
144
145 static ngx_int_t ngx_http_grpc_parse_frame(ngx_http_request_t *r,
146 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
147 static ngx_int_t ngx_http_grpc_parse_header(ngx_http_request_t *r,
148 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
149 static ngx_int_t ngx_http_grpc_parse_fragment(ngx_http_request_t *r,
150 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
151 static ngx_int_t ngx_http_grpc_validate_header_name(ngx_http_request_t *r,
152 ngx_str_t *s);
153 static ngx_int_t ngx_http_grpc_validate_header_value(ngx_http_request_t *r,
154 ngx_str_t *s);
155 static ngx_int_t ngx_http_grpc_parse_rst_stream(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_goaway(ngx_http_request_t *r,
158 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
159 static ngx_int_t ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
160 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
161 static ngx_int_t ngx_http_grpc_parse_settings(ngx_http_request_t *r,
162 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
163 static ngx_int_t ngx_http_grpc_parse_ping(ngx_http_request_t *r,
164 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
165
166 static ngx_int_t ngx_http_grpc_send_settings_ack(ngx_http_request_t *r,
167 ngx_http_grpc_ctx_t *ctx);
168 static ngx_int_t ngx_http_grpc_send_ping_ack(ngx_http_request_t *r,
169 ngx_http_grpc_ctx_t *ctx);
170 static ngx_int_t ngx_http_grpc_send_window_update(ngx_http_request_t *r,
171 ngx_http_grpc_ctx_t *ctx);
172
173 static ngx_chain_t *ngx_http_grpc_get_buf(ngx_http_request_t *r,
174 ngx_http_grpc_ctx_t *ctx);
175 static ngx_http_grpc_ctx_t *ngx_http_grpc_get_ctx(ngx_http_request_t *r);
176 static ngx_int_t ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
177 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc);
178 static void ngx_http_grpc_cleanup(void *data);
179
180 static void ngx_http_grpc_abort_request(ngx_http_request_t *r);
181 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
182 ngx_int_t rc);
183
184 static ngx_int_t ngx_http_grpc_internal_trailers_variable(
185 ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
186
187 static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf);
188 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
189 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
190 void *parent, void *child);
191 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
192 ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers,
193 ngx_keyval_t *default_headers);
194
195 static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
196 void *conf);
197
198 #if (NGX_HTTP_SSL)
199 static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf,
200 ngx_command_t *cmd, void *conf);
201 static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf,
202 ngx_http_grpc_loc_conf_t *glcf);
203 #endif
204
205
206 static ngx_conf_bitmask_t ngx_http_grpc_next_upstream_masks[] = {
207 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
208 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
209 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
210 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
211 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
212 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
213 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
214 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
215 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
216 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
217 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
218 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
219 { ngx_null_string, 0 }
220 };
221
222
223 #if (NGX_HTTP_SSL)
224
225 static ngx_conf_bitmask_t ngx_http_grpc_ssl_protocols[] = {
226 { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
227 { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
228 { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
229 { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
230 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
231 { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
232 { ngx_null_string, 0 }
233 };
234
235 #endif
236
237
238 static ngx_command_t ngx_http_grpc_commands[] = {
239
240 { ngx_string("grpc_pass"),
241 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
242 ngx_http_grpc_pass,
243 NGX_HTTP_LOC_CONF_OFFSET,
244 0,
245 NULL },
246
247 { ngx_string("grpc_bind"),
248 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
249 ngx_http_upstream_bind_set_slot,
250 NGX_HTTP_LOC_CONF_OFFSET,
251 offsetof(ngx_http_grpc_loc_conf_t, upstream.local),
252 NULL },
253
254 { ngx_string("grpc_socket_keepalive"),
255 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
256 ngx_conf_set_flag_slot,
257 NGX_HTTP_LOC_CONF_OFFSET,
258 offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive),
259 NULL },
260
261 { ngx_string("grpc_connect_timeout"),
262 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
263 ngx_conf_set_msec_slot,
264 NGX_HTTP_LOC_CONF_OFFSET,
265 offsetof(ngx_http_grpc_loc_conf_t, upstream.connect_timeout),
266 NULL },
267
268 { ngx_string("grpc_send_timeout"),
269 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
270 ngx_conf_set_msec_slot,
271 NGX_HTTP_LOC_CONF_OFFSET,
272 offsetof(ngx_http_grpc_loc_conf_t, upstream.send_timeout),
273 NULL },
274
275 { ngx_string("grpc_intercept_errors"),
276 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
277 ngx_conf_set_flag_slot,
278 NGX_HTTP_LOC_CONF_OFFSET,
279 offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors),
280 NULL },
281
282 { ngx_string("grpc_buffer_size"),
283 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
284 ngx_conf_set_size_slot,
285 NGX_HTTP_LOC_CONF_OFFSET,
286 offsetof(ngx_http_grpc_loc_conf_t, upstream.buffer_size),
287 NULL },
288
289 { ngx_string("grpc_read_timeout"),
290 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
291 ngx_conf_set_msec_slot,
292 NGX_HTTP_LOC_CONF_OFFSET,
293 offsetof(ngx_http_grpc_loc_conf_t, upstream.read_timeout),
294 NULL },
295
296 { ngx_string("grpc_next_upstream"),
297 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
298 ngx_conf_set_bitmask_slot,
299 NGX_HTTP_LOC_CONF_OFFSET,
300 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream),
301 &ngx_http_grpc_next_upstream_masks },
302
303 { ngx_string("grpc_next_upstream_tries"),
304 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
305 ngx_conf_set_num_slot,
306 NGX_HTTP_LOC_CONF_OFFSET,
307 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_tries),
308 NULL },
309
310 { ngx_string("grpc_next_upstream_timeout"),
311 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
312 ngx_conf_set_msec_slot,
313 NGX_HTTP_LOC_CONF_OFFSET,
314 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_timeout),
315 NULL },
316
317 { ngx_string("grpc_set_header"),
318 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
319 ngx_conf_set_keyval_slot,
320 NGX_HTTP_LOC_CONF_OFFSET,
321 offsetof(ngx_http_grpc_loc_conf_t, headers_source),
322 NULL },
323
324 { ngx_string("grpc_pass_header"),
325 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
326 ngx_conf_set_str_array_slot,
327 NGX_HTTP_LOC_CONF_OFFSET,
328 offsetof(ngx_http_grpc_loc_conf_t, upstream.pass_headers),
329 NULL },
330
331 { ngx_string("grpc_hide_header"),
332 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
333 ngx_conf_set_str_array_slot,
334 NGX_HTTP_LOC_CONF_OFFSET,
335 offsetof(ngx_http_grpc_loc_conf_t, upstream.hide_headers),
336 NULL },
337
338 { ngx_string("grpc_ignore_headers"),
339 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
340 ngx_conf_set_bitmask_slot,
341 NGX_HTTP_LOC_CONF_OFFSET,
342 offsetof(ngx_http_grpc_loc_conf_t, upstream.ignore_headers),
343 &ngx_http_upstream_ignore_headers_masks },
344
345 #if (NGX_HTTP_SSL)
346
347 { ngx_string("grpc_ssl_session_reuse"),
348 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
349 ngx_conf_set_flag_slot,
350 NGX_HTTP_LOC_CONF_OFFSET,
351 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_session_reuse),
352 NULL },
353
354 { ngx_string("grpc_ssl_protocols"),
355 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
356 ngx_conf_set_bitmask_slot,
357 NGX_HTTP_LOC_CONF_OFFSET,
358 offsetof(ngx_http_grpc_loc_conf_t, ssl_protocols),
359 &ngx_http_grpc_ssl_protocols },
360
361 { ngx_string("grpc_ssl_ciphers"),
362 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
363 ngx_conf_set_str_slot,
364 NGX_HTTP_LOC_CONF_OFFSET,
365 offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers),
366 NULL },
367
368 { ngx_string("grpc_ssl_name"),
369 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
370 ngx_http_set_complex_value_slot,
371 NGX_HTTP_LOC_CONF_OFFSET,
372 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_name),
373 NULL },
374
375 { ngx_string("grpc_ssl_server_name"),
376 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
377 ngx_conf_set_flag_slot,
378 NGX_HTTP_LOC_CONF_OFFSET,
379 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_server_name),
380 NULL },
381
382 { ngx_string("grpc_ssl_verify"),
383 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
384 ngx_conf_set_flag_slot,
385 NGX_HTTP_LOC_CONF_OFFSET,
386 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_verify),
387 NULL },
388
389 { ngx_string("grpc_ssl_verify_depth"),
390 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
391 ngx_conf_set_num_slot,
392 NGX_HTTP_LOC_CONF_OFFSET,
393 offsetof(ngx_http_grpc_loc_conf_t, ssl_verify_depth),
394 NULL },
395
396 { ngx_string("grpc_ssl_trusted_certificate"),
397 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
398 ngx_conf_set_str_slot,
399 NGX_HTTP_LOC_CONF_OFFSET,
400 offsetof(ngx_http_grpc_loc_conf_t, ssl_trusted_certificate),
401 NULL },
402
403 { ngx_string("grpc_ssl_crl"),
404 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
405 ngx_conf_set_str_slot,
406 NGX_HTTP_LOC_CONF_OFFSET,
407 offsetof(ngx_http_grpc_loc_conf_t, ssl_crl),
408 NULL },
409
410 { ngx_string("grpc_ssl_certificate"),
411 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
412 ngx_conf_set_str_slot,
413 NGX_HTTP_LOC_CONF_OFFSET,
414 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate),
415 NULL },
416
417 { ngx_string("grpc_ssl_certificate_key"),
418 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
419 ngx_conf_set_str_slot,
420 NGX_HTTP_LOC_CONF_OFFSET,
421 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key),
422 NULL },
423
424 { ngx_string("grpc_ssl_password_file"),
425 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
426 ngx_http_grpc_ssl_password_file,
427 NGX_HTTP_LOC_CONF_OFFSET,
428 0,
429 NULL },
430
431 #endif
432
433 ngx_null_command
434 };
435
436
437 static ngx_http_module_t ngx_http_grpc_module_ctx = {
438 ngx_http_grpc_add_variables, /* preconfiguration */
439 NULL, /* postconfiguration */
440
441 NULL, /* create main configuration */
442 NULL, /* init main configuration */
443
444 NULL, /* create server configuration */
445 NULL, /* merge server configuration */
446
447 ngx_http_grpc_create_loc_conf, /* create location configuration */
448 ngx_http_grpc_merge_loc_conf /* merge location configuration */
449 };
450
451
452 ngx_module_t ngx_http_grpc_module = {
453 NGX_MODULE_V1,
454 &ngx_http_grpc_module_ctx, /* module context */
455 ngx_http_grpc_commands, /* module directives */
456 NGX_HTTP_MODULE, /* module type */
457 NULL, /* init master */
458 NULL, /* init module */
459 NULL, /* init process */
460 NULL, /* init thread */
461 NULL, /* exit thread */
462 NULL, /* exit process */
463 NULL, /* exit master */
464 NGX_MODULE_V1_PADDING
465 };
466
467
468 static u_char ngx_http_grpc_connection_start[] =
469 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* connection preface */
470
471 "\x00\x00\x12\x04\x00\x00\x00\x00\x00" /* settings frame */
472 "\x00\x01\x00\x00\x00\x00" /* header table size */
473 "\x00\x02\x00\x00\x00\x00" /* disable push */
474 "\x00\x04\x7f\xff\xff\xff" /* initial window */
475
476 "\x00\x00\x04\x08\x00\x00\x00\x00\x00" /* window update frame */
477 "\x7f\xff\x00\x00";
478
479
480 static ngx_keyval_t ngx_http_grpc_headers[] = {
481 { ngx_string("Content-Length"), ngx_string("$content_length") },
482 { ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
483 { ngx_string("Host"), ngx_string("") },
484 { ngx_string("Connection"), ngx_string("") },
485 { ngx_string("Transfer-Encoding"), ngx_string("") },
486 { ngx_string("Keep-Alive"), ngx_string("") },
487 { ngx_string("Expect"), ngx_string("") },
488 { ngx_string("Upgrade"), ngx_string("") },
489 { ngx_null_string, ngx_null_string }
490 };
491
492
493 static ngx_str_t ngx_http_grpc_hide_headers[] = {
494 ngx_string("Date"),
495 ngx_string("Server"),
496 ngx_string("X-Accel-Expires"),
497 ngx_string("X-Accel-Redirect"),
498 ngx_string("X-Accel-Limit-Rate"),
499 ngx_string("X-Accel-Buffering"),
500 ngx_string("X-Accel-Charset"),
501 ngx_null_string
502 };
503
504
505 static ngx_http_variable_t ngx_http_grpc_vars[] = {
506
507 { ngx_string("grpc_internal_trailers"), NULL,
508 ngx_http_grpc_internal_trailers_variable, 0,
509 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
510
511 ngx_http_null_variable
512 };
513
514
515 static ngx_int_t
ngx_http_grpc_handler(ngx_http_request_t * r)516 ngx_http_grpc_handler(ngx_http_request_t *r)
517 {
518 ngx_int_t rc;
519 ngx_http_upstream_t *u;
520 ngx_http_grpc_ctx_t *ctx;
521 ngx_http_grpc_loc_conf_t *glcf;
522
523 if (ngx_http_upstream_create(r) != NGX_OK) {
524 return NGX_HTTP_INTERNAL_SERVER_ERROR;
525 }
526
527 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
528
529 u = r->upstream;
530
531 #if (NGX_HTTP_SSL)
532 u->ssl = (glcf->upstream.ssl != NULL);
533
534 if (u->ssl) {
535 ngx_str_set(&u->schema, "grpcs://");
536
537 } else {
538 ngx_str_set(&u->schema, "grpc://");
539 }
540 #else
541 ngx_str_set(&u->schema, "grpc://");
542 #endif
543
544 u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;
545
546 u->conf = &glcf->upstream;
547
548 u->create_request = ngx_http_grpc_create_request;
549 u->reinit_request = ngx_http_grpc_reinit_request;
550 u->process_header = ngx_http_grpc_process_header;
551 u->abort_request = ngx_http_grpc_abort_request;
552 u->finalize_request = ngx_http_grpc_finalize_request;
553
554 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
555 if (ctx == NULL) {
556 return NGX_HTTP_INTERNAL_SERVER_ERROR;
557 }
558
559 ctx->request = r;
560
561 ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);
562
563 u->input_filter_init = ngx_http_grpc_filter_init;
564 u->input_filter = ngx_http_grpc_filter;
565 u->input_filter_ctx = ctx;
566
567 r->request_body_no_buffering = 1;
568
569 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
570
571 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
572 return rc;
573 }
574
575 return NGX_DONE;
576 }
577
578
579 static ngx_int_t
ngx_http_grpc_create_request(ngx_http_request_t * r)580 ngx_http_grpc_create_request(ngx_http_request_t *r)
581 {
582 u_char *p, *tmp, *key_tmp, *val_tmp, *headers_frame;
583 size_t len, tmp_len, key_len, val_len, uri_len;
584 uintptr_t escape;
585 ngx_buf_t *b;
586 ngx_uint_t i, next;
587 ngx_chain_t *cl, *body;
588 ngx_list_part_t *part;
589 ngx_table_elt_t *header;
590 ngx_http_upstream_t *u;
591 ngx_http_grpc_frame_t *f;
592 ngx_http_script_code_pt code;
593 ngx_http_grpc_loc_conf_t *glcf;
594 ngx_http_script_engine_t e, le;
595 ngx_http_script_len_code_pt lcode;
596
597 u = r->upstream;
598
599 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
600
601 len = sizeof(ngx_http_grpc_connection_start) - 1
602 + sizeof(ngx_http_grpc_frame_t); /* headers frame */
603
604 /* :method header */
605
606 if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) {
607 len += 1;
608 tmp_len = 0;
609
610 } else {
611 len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len;
612 tmp_len = r->method_name.len;
613 }
614
615 /* :scheme header */
616
617 len += 1;
618
619 /* :path header */
620
621 if (r->valid_unparsed_uri) {
622 escape = 0;
623 uri_len = r->unparsed_uri.len;
624
625 } else {
626 escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
627 NGX_ESCAPE_URI);
628 uri_len = r->uri.len + escape + sizeof("?") - 1 + r->args.len;
629 }
630
631 len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;
632
633 if (tmp_len < uri_len) {
634 tmp_len = uri_len;
635 }
636
637 /* :authority header */
638
639 if (!glcf->host_set) {
640 len += 1 + NGX_HTTP_V2_INT_OCTETS + glcf->host.len;
641
642 if (tmp_len < glcf->host.len) {
643 tmp_len = glcf->host.len;
644 }
645 }
646
647 /* other headers */
648
649 ngx_http_script_flush_no_cacheable_variables(r, glcf->headers.flushes);
650 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
651
652 le.ip = glcf->headers.lengths->elts;
653 le.request = r;
654 le.flushed = 1;
655
656 while (*(uintptr_t *) le.ip) {
657
658 lcode = *(ngx_http_script_len_code_pt *) le.ip;
659 key_len = lcode(&le);
660
661 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
662 lcode = *(ngx_http_script_len_code_pt *) le.ip;
663 }
664 le.ip += sizeof(uintptr_t);
665
666 if (val_len == 0) {
667 continue;
668 }
669
670 len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
671 + NGX_HTTP_V2_INT_OCTETS + val_len;
672
673 if (tmp_len < key_len) {
674 tmp_len = key_len;
675 }
676
677 if (tmp_len < val_len) {
678 tmp_len = val_len;
679 }
680 }
681
682 if (glcf->upstream.pass_request_headers) {
683 part = &r->headers_in.headers.part;
684 header = part->elts;
685
686 for (i = 0; /* void */; i++) {
687
688 if (i >= part->nelts) {
689 if (part->next == NULL) {
690 break;
691 }
692
693 part = part->next;
694 header = part->elts;
695 i = 0;
696 }
697
698 if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
699 header[i].lowcase_key, header[i].key.len))
700 {
701 continue;
702 }
703
704 len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
705 + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;
706
707 if (tmp_len < header[i].key.len) {
708 tmp_len = header[i].key.len;
709 }
710
711 if (tmp_len < header[i].value.len) {
712 tmp_len = header[i].value.len;
713 }
714 }
715 }
716
717 /* continuation frames */
718
719 len += sizeof(ngx_http_grpc_frame_t)
720 * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);
721
722
723 b = ngx_create_temp_buf(r->pool, len);
724 if (b == NULL) {
725 return NGX_ERROR;
726 }
727
728 cl = ngx_alloc_chain_link(r->pool);
729 if (cl == NULL) {
730 return NGX_ERROR;
731 }
732
733 cl->buf = b;
734 cl->next = NULL;
735
736 tmp = ngx_palloc(r->pool, tmp_len * 3);
737 if (tmp == NULL) {
738 return NGX_ERROR;
739 }
740
741 key_tmp = tmp + tmp_len;
742 val_tmp = tmp + 2 * tmp_len;
743
744 /* connection preface */
745
746 b->last = ngx_copy(b->last, ngx_http_grpc_connection_start,
747 sizeof(ngx_http_grpc_connection_start) - 1);
748
749 /* headers frame */
750
751 headers_frame = b->last;
752
753 f = (ngx_http_grpc_frame_t *) b->last;
754 b->last += sizeof(ngx_http_grpc_frame_t);
755
756 f->length_0 = 0;
757 f->length_1 = 0;
758 f->length_2 = 0;
759 f->type = NGX_HTTP_V2_HEADERS_FRAME;
760 f->flags = 0;
761 f->stream_id_0 = 0;
762 f->stream_id_1 = 0;
763 f->stream_id_2 = 0;
764 f->stream_id_3 = 1;
765
766 if (r->method == NGX_HTTP_GET) {
767 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);
768
769 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
770 "grpc header: \":method: GET\"");
771
772 } else if (r->method == NGX_HTTP_POST) {
773 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);
774
775 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
776 "grpc header: \":method: POST\"");
777
778 } else {
779 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
780 b->last = ngx_http_v2_write_value(b->last, r->method_name.data,
781 r->method_name.len, tmp);
782
783 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
784 "grpc header: \":method: %V\"", &r->method_name);
785 }
786
787 #if (NGX_HTTP_SSL)
788 if (glcf->ssl) {
789 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);
790
791 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
792 "grpc header: \":scheme: https\"");
793 } else
794 #endif
795 {
796 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
797
798 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
799 "grpc header: \":scheme: http\"");
800 }
801
802 if (r->valid_unparsed_uri) {
803
804 if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') {
805 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);
806
807 } else {
808 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
809 b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
810 r->unparsed_uri.len, tmp);
811 }
812
813 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
814 "grpc header: \":path: %V\"", &r->unparsed_uri);
815
816 } else if (escape || r->args.len > 0) {
817 p = val_tmp;
818
819 if (escape) {
820 p = (u_char *) ngx_escape_uri(p, r->uri.data, r->uri.len,
821 NGX_ESCAPE_URI);
822
823 } else {
824 p = ngx_copy(p, r->uri.data, r->uri.len);
825 }
826
827 if (r->args.len > 0) {
828 *p++ = '?';
829 p = ngx_copy(p, r->args.data, r->args.len);
830 }
831
832 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
833 b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp);
834
835 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
836 "grpc header: \":path: %*s\"", p - val_tmp, val_tmp);
837
838 } else {
839 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
840 b->last = ngx_http_v2_write_value(b->last, r->uri.data,
841 r->uri.len, tmp);
842
843 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
844 "grpc header: \":path: %V\"", &r->uri);
845 }
846
847 if (!glcf->host_set) {
848 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
849 b->last = ngx_http_v2_write_value(b->last, glcf->host.data,
850 glcf->host.len, tmp);
851
852 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
853 "grpc header: \":authority: %V\"", &glcf->host);
854 }
855
856 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
857
858 e.ip = glcf->headers.values->elts;
859 e.request = r;
860 e.flushed = 1;
861
862 le.ip = glcf->headers.lengths->elts;
863
864 while (*(uintptr_t *) le.ip) {
865
866 lcode = *(ngx_http_script_len_code_pt *) le.ip;
867 key_len = lcode(&le);
868
869 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
870 lcode = *(ngx_http_script_len_code_pt *) le.ip;
871 }
872 le.ip += sizeof(uintptr_t);
873
874 if (val_len == 0) {
875 e.skip = 1;
876
877 while (*(uintptr_t *) e.ip) {
878 code = *(ngx_http_script_code_pt *) e.ip;
879 code((ngx_http_script_engine_t *) &e);
880 }
881 e.ip += sizeof(uintptr_t);
882
883 e.skip = 0;
884
885 continue;
886 }
887
888 *b->last++ = 0;
889
890 e.pos = key_tmp;
891
892 code = *(ngx_http_script_code_pt *) e.ip;
893 code((ngx_http_script_engine_t *) &e);
894
895 b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp);
896
897 e.pos = val_tmp;
898
899 while (*(uintptr_t *) e.ip) {
900 code = *(ngx_http_script_code_pt *) e.ip;
901 code((ngx_http_script_engine_t *) &e);
902 }
903 e.ip += sizeof(uintptr_t);
904
905 b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp);
906
907 #if (NGX_DEBUG)
908 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
909 ngx_strlow(key_tmp, key_tmp, key_len);
910
911 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
912 "grpc header: \"%*s: %*s\"",
913 key_len, key_tmp, val_len, val_tmp);
914 }
915 #endif
916 }
917
918 if (glcf->upstream.pass_request_headers) {
919 part = &r->headers_in.headers.part;
920 header = part->elts;
921
922 for (i = 0; /* void */; i++) {
923
924 if (i >= part->nelts) {
925 if (part->next == NULL) {
926 break;
927 }
928
929 part = part->next;
930 header = part->elts;
931 i = 0;
932 }
933
934 if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
935 header[i].lowcase_key, header[i].key.len))
936 {
937 continue;
938 }
939
940 *b->last++ = 0;
941
942 b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
943 header[i].key.len, tmp);
944
945 b->last = ngx_http_v2_write_value(b->last, header[i].value.data,
946 header[i].value.len, tmp);
947
948 #if (NGX_DEBUG)
949 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
950 ngx_strlow(tmp, header[i].key.data, header[i].key.len);
951
952 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
953 "grpc header: \"%*s: %V\"",
954 header[i].key.len, tmp, &header[i].value);
955 }
956 #endif
957 }
958 }
959
960 /* update headers frame length */
961
962 len = b->last - headers_frame - sizeof(ngx_http_grpc_frame_t);
963
964 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
965 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
966 next = 1;
967
968 } else {
969 next = 0;
970 }
971
972 f = (ngx_http_grpc_frame_t *) headers_frame;
973
974 f->length_0 = (u_char) ((len >> 16) & 0xff);
975 f->length_1 = (u_char) ((len >> 8) & 0xff);
976 f->length_2 = (u_char) (len & 0xff);
977
978 /* create additional continuation frames */
979
980 p = headers_frame;
981
982 while (next) {
983 p += sizeof(ngx_http_grpc_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
984 len = b->last - p;
985
986 ngx_memmove(p + sizeof(ngx_http_grpc_frame_t), p, len);
987 b->last += sizeof(ngx_http_grpc_frame_t);
988
989 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
990 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
991 next = 1;
992
993 } else {
994 next = 0;
995 }
996
997 f = (ngx_http_grpc_frame_t *) p;
998
999 f->length_0 = (u_char) ((len >> 16) & 0xff);
1000 f->length_1 = (u_char) ((len >> 8) & 0xff);
1001 f->length_2 = (u_char) (len & 0xff);
1002 f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
1003 f->flags = 0;
1004 f->stream_id_0 = 0;
1005 f->stream_id_1 = 0;
1006 f->stream_id_2 = 0;
1007 f->stream_id_3 = 1;
1008 }
1009
1010 f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;
1011
1012 #if (NGX_DEBUG)
1013 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1014 u_char buf[512];
1015 size_t n, m;
1016
1017 n = ngx_min(b->last - b->pos, 256);
1018 m = ngx_hex_dump(buf, b->pos, n) - buf;
1019
1020 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1021 "grpc header: %*s%s, len: %uz",
1022 m, buf, b->last - b->pos > 256 ? "..." : "",
1023 b->last - b->pos);
1024 }
1025 #endif
1026
1027 if (r->request_body_no_buffering) {
1028
1029 u->request_bufs = cl;
1030
1031 } else {
1032
1033 body = u->request_bufs;
1034 u->request_bufs = cl;
1035
1036 if (body == NULL) {
1037 f = (ngx_http_grpc_frame_t *) headers_frame;
1038 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1039 }
1040
1041 while (body) {
1042 b = ngx_alloc_buf(r->pool);
1043 if (b == NULL) {
1044 return NGX_ERROR;
1045 }
1046
1047 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1048
1049 cl->next = ngx_alloc_chain_link(r->pool);
1050 if (cl->next == NULL) {
1051 return NGX_ERROR;
1052 }
1053
1054 cl = cl->next;
1055 cl->buf = b;
1056
1057 body = body->next;
1058 }
1059
1060 b->last_buf = 1;
1061 }
1062
1063 u->output.output_filter = ngx_http_grpc_body_output_filter;
1064 u->output.filter_ctx = r;
1065
1066 b->flush = 1;
1067 cl->next = NULL;
1068
1069 return NGX_OK;
1070 }
1071
1072
1073 static ngx_int_t
ngx_http_grpc_reinit_request(ngx_http_request_t * r)1074 ngx_http_grpc_reinit_request(ngx_http_request_t *r)
1075 {
1076 ngx_http_grpc_ctx_t *ctx;
1077
1078 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
1079
1080 if (ctx == NULL) {
1081 return NGX_OK;
1082 }
1083
1084 ctx->state = 0;
1085 ctx->header_sent = 0;
1086 ctx->output_closed = 0;
1087 ctx->output_blocked = 0;
1088 ctx->parsing_headers = 0;
1089 ctx->end_stream = 0;
1090 ctx->done = 0;
1091 ctx->status = 0;
1092 ctx->connection = NULL;
1093
1094 return NGX_OK;
1095 }
1096
1097
1098 static ngx_int_t
ngx_http_grpc_body_output_filter(void * data,ngx_chain_t * in)1099 ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
1100 {
1101 ngx_http_request_t *r = data;
1102
1103 off_t file_pos;
1104 u_char *p, *pos, *start;
1105 size_t len, limit;
1106 ngx_buf_t *b;
1107 ngx_int_t rc;
1108 ngx_uint_t next, last;
1109 ngx_chain_t *cl, *out, **ll;
1110 ngx_http_upstream_t *u;
1111 ngx_http_grpc_ctx_t *ctx;
1112 ngx_http_grpc_frame_t *f;
1113
1114 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1115 "grpc output filter");
1116
1117 ctx = ngx_http_grpc_get_ctx(r);
1118
1119 if (ctx == NULL) {
1120 return NGX_ERROR;
1121 }
1122
1123 if (in) {
1124 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
1125 return NGX_ERROR;
1126 }
1127 }
1128
1129 out = NULL;
1130 ll = &out;
1131
1132 if (!ctx->header_sent) {
1133 /* first buffer contains headers */
1134
1135 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1136 "grpc output header");
1137
1138 ctx->header_sent = 1;
1139
1140 if (ctx->id != 1) {
1141 /*
1142 * keepalive connection: skip connection preface,
1143 * update stream identifiers
1144 */
1145
1146 b = ctx->in->buf;
1147 b->pos += sizeof(ngx_http_grpc_connection_start) - 1;
1148
1149 p = b->pos;
1150
1151 while (p < b->last) {
1152 f = (ngx_http_grpc_frame_t *) p;
1153 p += sizeof(ngx_http_grpc_frame_t);
1154
1155 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1156 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1157 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1158 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1159
1160 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
1161 }
1162 }
1163
1164 if (ctx->in->buf->last_buf) {
1165 ctx->output_closed = 1;
1166 }
1167
1168 *ll = ctx->in;
1169 ll = &ctx->in->next;
1170
1171 ctx->in = ctx->in->next;
1172 }
1173
1174 if (ctx->out) {
1175 /* queued control frames */
1176
1177 *ll = ctx->out;
1178
1179 for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
1180 ll = &cl->next;
1181 }
1182
1183 ctx->out = NULL;
1184 }
1185
1186 f = NULL;
1187 last = 0;
1188
1189 limit = ngx_max(0, ctx->send_window);
1190
1191 if (limit > ctx->connection->send_window) {
1192 limit = ctx->connection->send_window;
1193 }
1194
1195 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1196 "grpc output limit: %uz w:%z:%uz",
1197 limit, ctx->send_window, ctx->connection->send_window);
1198
1199 #if (NGX_SUPPRESS_WARN)
1200 file_pos = 0;
1201 pos = NULL;
1202 cl = NULL;
1203 #endif
1204
1205 in = ctx->in;
1206
1207 while (in && limit > 0) {
1208
1209 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1210 "grpc output in l:%d f:%d %p, pos %p, size: %z "
1211 "file: %O, size: %O",
1212 in->buf->last_buf,
1213 in->buf->in_file,
1214 in->buf->start, in->buf->pos,
1215 in->buf->last - in->buf->pos,
1216 in->buf->file_pos,
1217 in->buf->file_last - in->buf->file_pos);
1218
1219 if (ngx_buf_special(in->buf)) {
1220 goto next;
1221 }
1222
1223 if (in->buf->in_file) {
1224 file_pos = in->buf->file_pos;
1225
1226 } else {
1227 pos = in->buf->pos;
1228 }
1229
1230 next = 0;
1231
1232 do {
1233
1234 cl = ngx_http_grpc_get_buf(r, ctx);
1235 if (cl == NULL) {
1236 return NGX_ERROR;
1237 }
1238
1239 b = cl->buf;
1240
1241 f = (ngx_http_grpc_frame_t *) b->last;
1242 b->last += sizeof(ngx_http_grpc_frame_t);
1243
1244 *ll = cl;
1245 ll = &cl->next;
1246
1247 cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1248 if (cl == NULL) {
1249 return NGX_ERROR;
1250 }
1251
1252 b = cl->buf;
1253 start = b->start;
1254
1255 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1256
1257 /*
1258 * restore b->start to preserve memory allocated in the buffer,
1259 * to reuse it later for headers and control frames
1260 */
1261
1262 b->start = start;
1263
1264 if (in->buf->in_file) {
1265 b->file_pos = file_pos;
1266 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1267
1268 if (file_pos >= in->buf->file_last) {
1269 file_pos = in->buf->file_last;
1270 next = 1;
1271 }
1272
1273 b->file_last = file_pos;
1274 len = (ngx_uint_t) (file_pos - b->file_pos);
1275
1276 } else {
1277 b->pos = pos;
1278 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1279
1280 if (pos >= in->buf->last) {
1281 pos = in->buf->last;
1282 next = 1;
1283 }
1284
1285 b->last = pos;
1286 len = (ngx_uint_t) (pos - b->pos);
1287 }
1288
1289 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
1290 b->shadow = in->buf;
1291 b->last_shadow = next;
1292
1293 b->last_buf = 0;
1294 b->last_in_chain = 0;
1295
1296 *ll = cl;
1297 ll = &cl->next;
1298
1299 f->length_0 = (u_char) ((len >> 16) & 0xff);
1300 f->length_1 = (u_char) ((len >> 8) & 0xff);
1301 f->length_2 = (u_char) (len & 0xff);
1302 f->type = NGX_HTTP_V2_DATA_FRAME;
1303 f->flags = 0;
1304 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1305 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1306 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1307 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1308
1309 limit -= len;
1310 ctx->send_window -= len;
1311 ctx->connection->send_window -= len;
1312
1313 } while (!next && limit > 0);
1314
1315 if (!next) {
1316 /*
1317 * if the buffer wasn't fully sent due to flow control limits,
1318 * preserve position for future use
1319 */
1320
1321 if (in->buf->in_file) {
1322 in->buf->file_pos = file_pos;
1323
1324 } else {
1325 in->buf->pos = pos;
1326 }
1327
1328 break;
1329 }
1330
1331 next:
1332
1333 if (in->buf->last_buf) {
1334 last = 1;
1335 }
1336
1337 in = in->next;
1338 }
1339
1340 ctx->in = in;
1341
1342 if (last) {
1343
1344 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1345 "grpc output last");
1346
1347 ctx->output_closed = 1;
1348
1349 if (f) {
1350 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1351
1352 } else {
1353 cl = ngx_http_grpc_get_buf(r, ctx);
1354 if (cl == NULL) {
1355 return NGX_ERROR;
1356 }
1357
1358 b = cl->buf;
1359
1360 f = (ngx_http_grpc_frame_t *) b->last;
1361 b->last += sizeof(ngx_http_grpc_frame_t);
1362
1363 f->length_0 = 0;
1364 f->length_1 = 0;
1365 f->length_2 = 0;
1366 f->type = NGX_HTTP_V2_DATA_FRAME;
1367 f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
1368 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1369 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1370 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1371 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1372
1373 *ll = cl;
1374 ll = &cl->next;
1375 }
1376
1377 cl->buf->last_buf = 1;
1378 }
1379
1380 *ll = NULL;
1381
1382 #if (NGX_DEBUG)
1383
1384 for (cl = out; cl; cl = cl->next) {
1385 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1386 "grpc output out l:%d f:%d %p, pos %p, size: %z "
1387 "file: %O, size: %O",
1388 cl->buf->last_buf,
1389 cl->buf->in_file,
1390 cl->buf->start, cl->buf->pos,
1391 cl->buf->last - cl->buf->pos,
1392 cl->buf->file_pos,
1393 cl->buf->file_last - cl->buf->file_pos);
1394 }
1395
1396 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1397 "grpc output limit: %uz w:%z:%uz",
1398 limit, ctx->send_window, ctx->connection->send_window);
1399
1400 #endif
1401
1402 rc = ngx_chain_writer(&r->upstream->writer, out);
1403
1404 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1405 (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter);
1406
1407 for (cl = ctx->free; cl; cl = cl->next) {
1408
1409 /* mark original buffers as sent */
1410
1411 if (cl->buf->shadow) {
1412 if (cl->buf->last_shadow) {
1413 b = cl->buf->shadow;
1414 b->pos = b->last;
1415 }
1416
1417 cl->buf->shadow = NULL;
1418 }
1419 }
1420
1421 if (rc == NGX_OK && ctx->in) {
1422 rc = NGX_AGAIN;
1423 }
1424
1425 if (rc == NGX_AGAIN) {
1426 ctx->output_blocked = 1;
1427
1428 } else {
1429 ctx->output_blocked = 0;
1430 }
1431
1432 if (ctx->done) {
1433
1434 /*
1435 * We have already got the response and were sending some additional
1436 * control frames. Even if there is still something unsent, stop
1437 * here anyway.
1438 */
1439
1440 u = r->upstream;
1441 u->length = 0;
1442
1443 if (ctx->in == NULL
1444 && ctx->out == NULL
1445 && ctx->output_closed
1446 && !ctx->output_blocked
1447 && ctx->state == ngx_http_grpc_st_start)
1448 {
1449 u->keepalive = 1;
1450 }
1451
1452 ngx_post_event(u->peer.connection->read, &ngx_posted_events);
1453 }
1454
1455 return rc;
1456 }
1457
1458
1459 static ngx_int_t
ngx_http_grpc_process_header(ngx_http_request_t * r)1460 ngx_http_grpc_process_header(ngx_http_request_t *r)
1461 {
1462 ngx_str_t *status_line;
1463 ngx_int_t rc, status;
1464 ngx_buf_t *b;
1465 ngx_table_elt_t *h;
1466 ngx_http_upstream_t *u;
1467 ngx_http_grpc_ctx_t *ctx;
1468 ngx_http_upstream_header_t *hh;
1469 ngx_http_upstream_main_conf_t *umcf;
1470
1471 u = r->upstream;
1472 b = &u->buffer;
1473
1474 #if (NGX_DEBUG)
1475 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1476 u_char buf[512];
1477 size_t n, m;
1478
1479 n = ngx_min(b->last - b->pos, 256);
1480 m = ngx_hex_dump(buf, b->pos, n) - buf;
1481
1482 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1483 "grpc response: %*s%s, len: %uz",
1484 m, buf, b->last - b->pos > 256 ? "..." : "",
1485 b->last - b->pos);
1486 }
1487 #endif
1488
1489 ctx = ngx_http_grpc_get_ctx(r);
1490
1491 if (ctx == NULL) {
1492 return NGX_ERROR;
1493 }
1494
1495 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1496
1497 for ( ;; ) {
1498
1499 if (ctx->state < ngx_http_grpc_st_payload) {
1500
1501 rc = ngx_http_grpc_parse_frame(r, ctx, b);
1502
1503 if (rc == NGX_AGAIN) {
1504
1505 /*
1506 * there can be a lot of window update frames,
1507 * so we reset buffer if it is empty and we haven't
1508 * started parsing headers yet
1509 */
1510
1511 if (!ctx->parsing_headers) {
1512 b->pos = b->start;
1513 b->last = b->pos;
1514 }
1515
1516 return NGX_AGAIN;
1517 }
1518
1519 if (rc == NGX_ERROR) {
1520 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1521 }
1522
1523 /*
1524 * RFC 7540 says that implementations MUST discard frames
1525 * that have unknown or unsupported types. However, extension
1526 * frames that appear in the middle of a header block are
1527 * not permitted. Also, for obvious reasons CONTINUATION frames
1528 * cannot appear before headers, and DATA frames are not expected
1529 * to appear before all headers are parsed.
1530 */
1531
1532 if (ctx->type == NGX_HTTP_V2_DATA_FRAME
1533 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
1534 && !ctx->parsing_headers)
1535 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
1536 && ctx->parsing_headers))
1537 {
1538 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1539 "upstream sent unexpected http2 frame: %d",
1540 ctx->type);
1541 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1542 }
1543
1544 if (ctx->stream_id && ctx->stream_id != ctx->id) {
1545 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1546 "upstream sent frame for unknown stream %ui",
1547 ctx->stream_id);
1548 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1549 }
1550 }
1551
1552 /* frame payload */
1553
1554 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
1555
1556 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
1557
1558 if (rc == NGX_AGAIN) {
1559 return NGX_AGAIN;
1560 }
1561
1562 if (rc == NGX_ERROR) {
1563 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1564 }
1565
1566 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1567 "upstream rejected request with error %ui",
1568 ctx->error);
1569
1570 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1571 }
1572
1573 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
1574
1575 rc = ngx_http_grpc_parse_goaway(r, ctx, b);
1576
1577 if (rc == NGX_AGAIN) {
1578 return NGX_AGAIN;
1579 }
1580
1581 if (rc == NGX_ERROR) {
1582 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1583 }
1584
1585 /*
1586 * If stream_id is lower than one we use, our
1587 * request won't be processed and needs to be retried.
1588 * If stream_id is greater or equal to the one we use,
1589 * we can continue normally (except we can't use this
1590 * connection for additional requests). If there is
1591 * a real error, the connection will be closed.
1592 */
1593
1594 if (ctx->stream_id < ctx->id) {
1595
1596 /* TODO: we can retry non-idempotent requests */
1597
1598 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1599 "upstream sent goaway with error %ui",
1600 ctx->error);
1601
1602 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1603 }
1604
1605 continue;
1606 }
1607
1608 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
1609
1610 rc = ngx_http_grpc_parse_window_update(r, ctx, b);
1611
1612 if (rc == NGX_AGAIN) {
1613 return NGX_AGAIN;
1614 }
1615
1616 if (rc == NGX_ERROR) {
1617 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1618 }
1619
1620 if (ctx->in) {
1621 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1622 }
1623
1624 continue;
1625 }
1626
1627 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
1628
1629 rc = ngx_http_grpc_parse_settings(r, ctx, b);
1630
1631 if (rc == NGX_AGAIN) {
1632 return NGX_AGAIN;
1633 }
1634
1635 if (rc == NGX_ERROR) {
1636 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1637 }
1638
1639 if (ctx->in) {
1640 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1641 }
1642
1643 continue;
1644 }
1645
1646 if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
1647
1648 rc = ngx_http_grpc_parse_ping(r, ctx, b);
1649
1650 if (rc == NGX_AGAIN) {
1651 return NGX_AGAIN;
1652 }
1653
1654 if (rc == NGX_ERROR) {
1655 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1656 }
1657
1658 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1659 continue;
1660 }
1661
1662 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
1663 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1664 "upstream sent unexpected push promise frame");
1665 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1666 }
1667
1668 if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
1669 && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
1670 {
1671 /* priority, unknown frames */
1672
1673 if (b->last - b->pos < (ssize_t) ctx->rest) {
1674 ctx->rest -= b->last - b->pos;
1675 b->pos = b->last;
1676 return NGX_AGAIN;
1677 }
1678
1679 b->pos += ctx->rest;
1680 ctx->rest = 0;
1681 ctx->state = ngx_http_grpc_st_start;
1682
1683 continue;
1684 }
1685
1686 /* headers */
1687
1688 for ( ;; ) {
1689
1690 rc = ngx_http_grpc_parse_header(r, ctx, b);
1691
1692 if (rc == NGX_AGAIN) {
1693 break;
1694 }
1695
1696 if (rc == NGX_OK) {
1697
1698 /* a header line has been parsed successfully */
1699
1700 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1701 "grpc header: \"%V: %V\"",
1702 &ctx->name, &ctx->value);
1703
1704 if (ctx->name.len && ctx->name.data[0] == ':') {
1705
1706 if (ctx->name.len != sizeof(":status") - 1
1707 || ngx_strncmp(ctx->name.data, ":status",
1708 sizeof(":status") - 1)
1709 != 0)
1710 {
1711 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1712 "upstream sent invalid header \"%V: %V\"",
1713 &ctx->name, &ctx->value);
1714 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1715 }
1716
1717 if (ctx->status) {
1718 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1719 "upstream sent duplicate :status header");
1720 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1721 }
1722
1723 status_line = &ctx->value;
1724
1725 if (status_line->len != 3) {
1726 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1727 "upstream sent invalid :status \"%V\"",
1728 status_line);
1729 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1730 }
1731
1732 status = ngx_atoi(status_line->data, 3);
1733
1734 if (status == NGX_ERROR) {
1735 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1736 "upstream sent invalid :status \"%V\"",
1737 status_line);
1738 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1739 }
1740
1741 if (status < NGX_HTTP_OK) {
1742 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1743 "upstream sent unexpected :status \"%V\"",
1744 status_line);
1745 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1746 }
1747
1748 u->headers_in.status_n = status;
1749
1750 if (u->state && u->state->status == 0) {
1751 u->state->status = status;
1752 }
1753
1754 ctx->status = 1;
1755
1756 continue;
1757
1758 } else if (!ctx->status) {
1759 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1760 "upstream sent no :status header");
1761 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1762 }
1763
1764 h = ngx_list_push(&u->headers_in.headers);
1765 if (h == NULL) {
1766 return NGX_ERROR;
1767 }
1768
1769 h->key = ctx->name;
1770 h->value = ctx->value;
1771 h->lowcase_key = h->key.data;
1772 h->hash = ngx_hash_key(h->key.data, h->key.len);
1773
1774 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1775 h->lowcase_key, h->key.len);
1776
1777 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1778 return NGX_ERROR;
1779 }
1780
1781 continue;
1782 }
1783
1784 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1785
1786 /* a whole header has been parsed successfully */
1787
1788 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1789 "grpc header done");
1790
1791 if (ctx->end_stream) {
1792 u->headers_in.content_length_n = 0;
1793
1794 if (ctx->in == NULL
1795 && ctx->out == NULL
1796 && ctx->output_closed
1797 && !ctx->output_blocked
1798 && b->last == b->pos)
1799 {
1800 u->keepalive = 1;
1801 }
1802 }
1803
1804 return NGX_OK;
1805 }
1806
1807 /* there was error while a header line parsing */
1808
1809 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1810 "upstream sent invalid header");
1811
1812 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1813 }
1814
1815 /* rc == NGX_AGAIN */
1816
1817 if (ctx->rest == 0) {
1818 ctx->state = ngx_http_grpc_st_start;
1819 continue;
1820 }
1821
1822 return NGX_AGAIN;
1823 }
1824 }
1825
1826
1827 static ngx_int_t
ngx_http_grpc_filter_init(void * data)1828 ngx_http_grpc_filter_init(void *data)
1829 {
1830 ngx_http_grpc_ctx_t *ctx = data;
1831
1832 ngx_http_request_t *r;
1833 ngx_http_upstream_t *u;
1834
1835 r = ctx->request;
1836 u = r->upstream;
1837
1838 u->length = 1;
1839
1840 if (ctx->end_stream) {
1841 u->length = 0;
1842 }
1843
1844 return NGX_OK;
1845 }
1846
1847
1848 static ngx_int_t
ngx_http_grpc_filter(void * data,ssize_t bytes)1849 ngx_http_grpc_filter(void *data, ssize_t bytes)
1850 {
1851 ngx_http_grpc_ctx_t *ctx = data;
1852
1853 ngx_int_t rc;
1854 ngx_buf_t *b, *buf;
1855 ngx_chain_t *cl, **ll;
1856 ngx_table_elt_t *h;
1857 ngx_http_request_t *r;
1858 ngx_http_upstream_t *u;
1859
1860 r = ctx->request;
1861 u = r->upstream;
1862 b = &u->buffer;
1863
1864 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1865 "grpc filter bytes:%z", bytes);
1866
1867 b->pos = b->last;
1868 b->last += bytes;
1869
1870 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1871 ll = &cl->next;
1872 }
1873
1874 for ( ;; ) {
1875
1876 if (ctx->state < ngx_http_grpc_st_payload) {
1877
1878 rc = ngx_http_grpc_parse_frame(r, ctx, b);
1879
1880 if (rc == NGX_AGAIN) {
1881
1882 if (ctx->done) {
1883
1884 /*
1885 * We have finished parsing the response and the
1886 * remaining control frames. If there are unsent
1887 * control frames, post a write event to send them.
1888 */
1889
1890 if (ctx->out) {
1891 ngx_post_event(u->peer.connection->write,
1892 &ngx_posted_events);
1893 return NGX_AGAIN;
1894 }
1895
1896 u->length = 0;
1897
1898 if (ctx->in == NULL
1899 && ctx->output_closed
1900 && !ctx->output_blocked
1901 && ctx->state == ngx_http_grpc_st_start)
1902 {
1903 u->keepalive = 1;
1904 }
1905
1906 break;
1907 }
1908
1909 return NGX_AGAIN;
1910 }
1911
1912 if (rc == NGX_ERROR) {
1913 return NGX_ERROR;
1914 }
1915
1916 if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
1917 && !ctx->parsing_headers)
1918 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
1919 && ctx->parsing_headers))
1920 {
1921 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1922 "upstream sent unexpected http2 frame: %d",
1923 ctx->type);
1924 return NGX_ERROR;
1925 }
1926
1927 if (ctx->type == NGX_HTTP_V2_DATA_FRAME) {
1928
1929 if (ctx->stream_id != ctx->id) {
1930 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1931 "upstream sent data frame "
1932 "for unknown stream %ui",
1933 ctx->stream_id);
1934 return NGX_ERROR;
1935 }
1936
1937 if (ctx->rest > ctx->recv_window) {
1938 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1939 "upstream violated stream flow control, "
1940 "received %uz data frame with window %uz",
1941 ctx->rest, ctx->recv_window);
1942 return NGX_ERROR;
1943 }
1944
1945 if (ctx->rest > ctx->connection->recv_window) {
1946 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1947 "upstream violated connection flow control, "
1948 "received %uz data frame with window %uz",
1949 ctx->rest, ctx->connection->recv_window);
1950 return NGX_ERROR;
1951 }
1952
1953 ctx->recv_window -= ctx->rest;
1954 ctx->connection->recv_window -= ctx->rest;
1955
1956 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
1957 || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
1958 {
1959 if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) {
1960 return NGX_ERROR;
1961 }
1962
1963 ngx_post_event(u->peer.connection->write,
1964 &ngx_posted_events);
1965 }
1966 }
1967
1968 if (ctx->stream_id && ctx->stream_id != ctx->id) {
1969 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1970 "upstream sent frame for unknown stream %ui",
1971 ctx->stream_id);
1972 return NGX_ERROR;
1973 }
1974
1975 if (ctx->stream_id && ctx->done) {
1976 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1977 "upstream sent frame for closed stream %ui",
1978 ctx->stream_id);
1979 return NGX_ERROR;
1980 }
1981
1982 ctx->padding = 0;
1983 }
1984
1985 if (ctx->state == ngx_http_grpc_st_padding) {
1986
1987 if (b->last - b->pos < (ssize_t) ctx->rest) {
1988 ctx->rest -= b->last - b->pos;
1989 b->pos = b->last;
1990 return NGX_AGAIN;
1991 }
1992
1993 b->pos += ctx->rest;
1994 ctx->rest = 0;
1995 ctx->state = ngx_http_grpc_st_start;
1996
1997 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
1998 ctx->done = 1;
1999 }
2000
2001 continue;
2002 }
2003
2004 /* frame payload */
2005
2006 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
2007
2008 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
2009
2010 if (rc == NGX_AGAIN) {
2011 return NGX_AGAIN;
2012 }
2013
2014 if (rc == NGX_ERROR) {
2015 return NGX_ERROR;
2016 }
2017
2018 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2019 "upstream rejected request with error %ui",
2020 ctx->error);
2021
2022 return NGX_ERROR;
2023 }
2024
2025 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
2026
2027 rc = ngx_http_grpc_parse_goaway(r, ctx, b);
2028
2029 if (rc == NGX_AGAIN) {
2030 return NGX_AGAIN;
2031 }
2032
2033 if (rc == NGX_ERROR) {
2034 return NGX_ERROR;
2035 }
2036
2037 /*
2038 * If stream_id is lower than one we use, our
2039 * request won't be processed and needs to be retried.
2040 * If stream_id is greater or equal to the one we use,
2041 * we can continue normally (except we can't use this
2042 * connection for additional requests). If there is
2043 * a real error, the connection will be closed.
2044 */
2045
2046 if (ctx->stream_id < ctx->id) {
2047
2048 /* TODO: we can retry non-idempotent requests */
2049
2050 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2051 "upstream sent goaway with error %ui",
2052 ctx->error);
2053
2054 return NGX_ERROR;
2055 }
2056
2057 continue;
2058 }
2059
2060 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
2061
2062 rc = ngx_http_grpc_parse_window_update(r, ctx, b);
2063
2064 if (rc == NGX_AGAIN) {
2065 return NGX_AGAIN;
2066 }
2067
2068 if (rc == NGX_ERROR) {
2069 return NGX_ERROR;
2070 }
2071
2072 if (ctx->in) {
2073 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2074 }
2075
2076 continue;
2077 }
2078
2079 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
2080
2081 rc = ngx_http_grpc_parse_settings(r, ctx, b);
2082
2083 if (rc == NGX_AGAIN) {
2084 return NGX_AGAIN;
2085 }
2086
2087 if (rc == NGX_ERROR) {
2088 return NGX_ERROR;
2089 }
2090
2091 if (ctx->in) {
2092 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2093 }
2094
2095 continue;
2096 }
2097
2098 if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
2099
2100 rc = ngx_http_grpc_parse_ping(r, ctx, b);
2101
2102 if (rc == NGX_AGAIN) {
2103 return NGX_AGAIN;
2104 }
2105
2106 if (rc == NGX_ERROR) {
2107 return NGX_ERROR;
2108 }
2109
2110 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2111 continue;
2112 }
2113
2114 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
2115 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2116 "upstream sent unexpected push promise frame");
2117 return NGX_ERROR;
2118 }
2119
2120 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
2121 || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
2122 {
2123 for ( ;; ) {
2124
2125 rc = ngx_http_grpc_parse_header(r, ctx, b);
2126
2127 if (rc == NGX_AGAIN) {
2128 break;
2129 }
2130
2131 if (rc == NGX_OK) {
2132
2133 /* a header line has been parsed successfully */
2134
2135 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2136 "grpc trailer: \"%V: %V\"",
2137 &ctx->name, &ctx->value);
2138
2139 if (ctx->name.len && ctx->name.data[0] == ':') {
2140 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2141 "upstream sent invalid "
2142 "trailer \"%V: %V\"",
2143 &ctx->name, &ctx->value);
2144 return NGX_ERROR;
2145 }
2146
2147 h = ngx_list_push(&u->headers_in.trailers);
2148 if (h == NULL) {
2149 return NGX_ERROR;
2150 }
2151
2152 h->key = ctx->name;
2153 h->value = ctx->value;
2154 h->lowcase_key = h->key.data;
2155 h->hash = ngx_hash_key(h->key.data, h->key.len);
2156
2157 continue;
2158 }
2159
2160 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2161
2162 /* a whole header has been parsed successfully */
2163
2164 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2165 "grpc trailer done");
2166
2167 if (ctx->end_stream) {
2168 ctx->done = 1;
2169 break;
2170 }
2171
2172 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2173 "upstream sent trailer without "
2174 "end stream flag");
2175 return NGX_ERROR;
2176 }
2177
2178 /* there was error while a header line parsing */
2179
2180 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2181 "upstream sent invalid trailer");
2182
2183 return NGX_ERROR;
2184 }
2185
2186 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2187 continue;
2188 }
2189
2190 /* rc == NGX_AGAIN */
2191
2192 if (ctx->rest == 0) {
2193 ctx->state = ngx_http_grpc_st_start;
2194 continue;
2195 }
2196
2197 return NGX_AGAIN;
2198 }
2199
2200 if (ctx->type != NGX_HTTP_V2_DATA_FRAME) {
2201
2202 /* priority, unknown frames */
2203
2204 if (b->last - b->pos < (ssize_t) ctx->rest) {
2205 ctx->rest -= b->last - b->pos;
2206 b->pos = b->last;
2207 return NGX_AGAIN;
2208 }
2209
2210 b->pos += ctx->rest;
2211 ctx->rest = 0;
2212 ctx->state = ngx_http_grpc_st_start;
2213
2214 continue;
2215 }
2216
2217 /*
2218 * data frame:
2219 *
2220 * +---------------+
2221 * |Pad Length? (8)|
2222 * +---------------+-----------------------------------------------+
2223 * | Data (*) ...
2224 * +---------------------------------------------------------------+
2225 * | Padding (*) ...
2226 * +---------------------------------------------------------------+
2227 */
2228
2229 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2230
2231 if (ctx->rest == 0) {
2232 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2233 "upstream sent too short http2 frame");
2234 return NGX_ERROR;
2235 }
2236
2237 if (b->pos == b->last) {
2238 return NGX_AGAIN;
2239 }
2240
2241 ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
2242 ctx->padding = *b->pos++;
2243 ctx->rest -= 1;
2244
2245 if (ctx->padding > ctx->rest) {
2246 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2247 "upstream sent http2 frame with too long "
2248 "padding: %d in frame %uz",
2249 ctx->padding, ctx->rest);
2250 return NGX_ERROR;
2251 }
2252
2253 continue;
2254 }
2255
2256 if (ctx->rest == ctx->padding) {
2257 goto done;
2258 }
2259
2260 if (b->pos == b->last) {
2261 return NGX_AGAIN;
2262 }
2263
2264 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2265 if (cl == NULL) {
2266 return NGX_ERROR;
2267 }
2268
2269 *ll = cl;
2270 ll = &cl->next;
2271
2272 buf = cl->buf;
2273
2274 buf->flush = 1;
2275 buf->memory = 1;
2276
2277 buf->pos = b->pos;
2278 buf->tag = u->output.tag;
2279
2280 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2281 "grpc output buf %p", buf->pos);
2282
2283 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2284
2285 ctx->rest -= b->last - b->pos;
2286 b->pos = b->last;
2287 buf->last = b->pos;
2288
2289 return NGX_AGAIN;
2290 }
2291
2292 b->pos += ctx->rest - ctx->padding;
2293 buf->last = b->pos;
2294 ctx->rest = ctx->padding;
2295
2296 done:
2297
2298 if (ctx->padding) {
2299 ctx->state = ngx_http_grpc_st_padding;
2300 continue;
2301 }
2302
2303 ctx->state = ngx_http_grpc_st_start;
2304
2305 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2306 ctx->done = 1;
2307 }
2308 }
2309
2310 return NGX_OK;
2311 }
2312
2313
2314 static ngx_int_t
ngx_http_grpc_parse_frame(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)2315 ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2316 ngx_buf_t *b)
2317 {
2318 u_char ch, *p;
2319 ngx_http_grpc_state_e state;
2320
2321 state = ctx->state;
2322
2323 for (p = b->pos; p < b->last; p++) {
2324 ch = *p;
2325
2326 #if 0
2327 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2328 "grpc frame byte: %02Xd, s:%d", ch, state);
2329 #endif
2330
2331 switch (state) {
2332
2333 case ngx_http_grpc_st_start:
2334 ctx->rest = ch << 16;
2335 state = ngx_http_grpc_st_length_2;
2336 break;
2337
2338 case ngx_http_grpc_st_length_2:
2339 ctx->rest |= ch << 8;
2340 state = ngx_http_grpc_st_length_3;
2341 break;
2342
2343 case ngx_http_grpc_st_length_3:
2344 ctx->rest |= ch;
2345
2346 if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
2347 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2348 "upstream sent too large http2 frame: %uz",
2349 ctx->rest);
2350 return NGX_ERROR;
2351 }
2352
2353 state = ngx_http_grpc_st_type;
2354 break;
2355
2356 case ngx_http_grpc_st_type:
2357 ctx->type = ch;
2358 state = ngx_http_grpc_st_flags;
2359 break;
2360
2361 case ngx_http_grpc_st_flags:
2362 ctx->flags = ch;
2363 state = ngx_http_grpc_st_stream_id;
2364 break;
2365
2366 case ngx_http_grpc_st_stream_id:
2367 ctx->stream_id = (ch & 0x7f) << 24;
2368 state = ngx_http_grpc_st_stream_id_2;
2369 break;
2370
2371 case ngx_http_grpc_st_stream_id_2:
2372 ctx->stream_id |= ch << 16;
2373 state = ngx_http_grpc_st_stream_id_3;
2374 break;
2375
2376 case ngx_http_grpc_st_stream_id_3:
2377 ctx->stream_id |= ch << 8;
2378 state = ngx_http_grpc_st_stream_id_4;
2379 break;
2380
2381 case ngx_http_grpc_st_stream_id_4:
2382 ctx->stream_id |= ch;
2383
2384 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2385 "grpc frame: %d, len: %uz, f:%d, i:%ui",
2386 ctx->type, ctx->rest, ctx->flags, ctx->stream_id);
2387
2388 b->pos = p + 1;
2389
2390 ctx->state = ngx_http_grpc_st_payload;
2391 ctx->frame_state = 0;
2392
2393 return NGX_OK;
2394
2395 /* suppress warning */
2396 case ngx_http_grpc_st_payload:
2397 case ngx_http_grpc_st_padding:
2398 break;
2399 }
2400 }
2401
2402 b->pos = p;
2403 ctx->state = state;
2404
2405 return NGX_AGAIN;
2406 }
2407
2408
2409 static ngx_int_t
ngx_http_grpc_parse_header(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)2410 ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2411 ngx_buf_t *b)
2412 {
2413 u_char ch, *p, *last;
2414 size_t min;
2415 ngx_int_t rc;
2416 enum {
2417 sw_start = 0,
2418 sw_padding_length,
2419 sw_dependency,
2420 sw_dependency_2,
2421 sw_dependency_3,
2422 sw_dependency_4,
2423 sw_weight,
2424 sw_fragment,
2425 sw_padding
2426 } state;
2427
2428 state = ctx->frame_state;
2429
2430 if (state == sw_start) {
2431
2432 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2433 "grpc parse header: start");
2434
2435 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
2436 ctx->parsing_headers = 1;
2437 ctx->fragment_state = 0;
2438
2439 min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0)
2440 + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0);
2441
2442 if (ctx->rest < min) {
2443 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2444 "upstream sent headers frame "
2445 "with invalid length: %uz",
2446 ctx->rest);
2447 return NGX_ERROR;
2448 }
2449
2450 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2451 ctx->end_stream = 1;
2452 }
2453
2454 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2455 state = sw_padding_length;
2456
2457 } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2458 state = sw_dependency;
2459
2460 } else {
2461 state = sw_fragment;
2462 }
2463
2464 } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
2465 state = sw_fragment;
2466 }
2467
2468 ctx->padding = 0;
2469 ctx->frame_state = state;
2470 }
2471
2472 if (state < sw_fragment) {
2473
2474 if (b->last - b->pos < (ssize_t) ctx->rest) {
2475 last = b->last;
2476
2477 } else {
2478 last = b->pos + ctx->rest;
2479 }
2480
2481 for (p = b->pos; p < last; p++) {
2482 ch = *p;
2483
2484 #if 0
2485 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2486 "grpc header byte: %02Xd s:%d", ch, state);
2487 #endif
2488
2489 /*
2490 * headers frame:
2491 *
2492 * +---------------+
2493 * |Pad Length? (8)|
2494 * +-+-------------+----------------------------------------------+
2495 * |E| Stream Dependency? (31) |
2496 * +-+-------------+----------------------------------------------+
2497 * | Weight? (8) |
2498 * +-+-------------+----------------------------------------------+
2499 * | Header Block Fragment (*) ...
2500 * +--------------------------------------------------------------+
2501 * | Padding (*) ...
2502 * +--------------------------------------------------------------+
2503 */
2504
2505 switch (state) {
2506
2507 case sw_padding_length:
2508
2509 ctx->padding = ch;
2510
2511 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2512 state = sw_dependency;
2513 break;
2514 }
2515
2516 goto fragment;
2517
2518 case sw_dependency:
2519 state = sw_dependency_2;
2520 break;
2521
2522 case sw_dependency_2:
2523 state = sw_dependency_3;
2524 break;
2525
2526 case sw_dependency_3:
2527 state = sw_dependency_4;
2528 break;
2529
2530 case sw_dependency_4:
2531 state = sw_weight;
2532 break;
2533
2534 case sw_weight:
2535 goto fragment;
2536
2537 /* suppress warning */
2538 case sw_start:
2539 case sw_fragment:
2540 case sw_padding:
2541 break;
2542 }
2543 }
2544
2545 ctx->rest -= p - b->pos;
2546 b->pos = p;
2547
2548 ctx->frame_state = state;
2549 return NGX_AGAIN;
2550
2551 fragment:
2552
2553 p++;
2554 ctx->rest -= p - b->pos;
2555 b->pos = p;
2556
2557 if (ctx->padding > ctx->rest) {
2558 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2559 "upstream sent http2 frame with too long "
2560 "padding: %d in frame %uz",
2561 ctx->padding, ctx->rest);
2562 return NGX_ERROR;
2563 }
2564
2565 state = sw_fragment;
2566 ctx->frame_state = state;
2567 }
2568
2569 if (state == sw_fragment) {
2570
2571 rc = ngx_http_grpc_parse_fragment(r, ctx, b);
2572
2573 if (rc == NGX_AGAIN) {
2574 return NGX_AGAIN;
2575 }
2576
2577 if (rc == NGX_ERROR) {
2578 return NGX_ERROR;
2579 }
2580
2581 if (rc == NGX_OK) {
2582 return NGX_OK;
2583 }
2584
2585 /* rc == NGX_DONE */
2586
2587 state = sw_padding;
2588 ctx->frame_state = state;
2589 }
2590
2591 if (state == sw_padding) {
2592
2593 if (b->last - b->pos < (ssize_t) ctx->rest) {
2594
2595 ctx->rest -= b->last - b->pos;
2596 b->pos = b->last;
2597
2598 return NGX_AGAIN;
2599 }
2600
2601 b->pos += ctx->rest;
2602 ctx->rest = 0;
2603
2604 ctx->state = ngx_http_grpc_st_start;
2605
2606 if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
2607
2608 if (ctx->fragment_state) {
2609 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2610 "upstream sent truncated http2 header");
2611 return NGX_ERROR;
2612 }
2613
2614 ctx->parsing_headers = 0;
2615
2616 return NGX_HTTP_PARSE_HEADER_DONE;
2617 }
2618
2619 return NGX_AGAIN;
2620 }
2621
2622 /* unreachable */
2623
2624 return NGX_ERROR;
2625 }
2626
2627
2628 static ngx_int_t
ngx_http_grpc_parse_fragment(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)2629 ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2630 ngx_buf_t *b)
2631 {
2632 u_char ch, *p, *last;
2633 size_t size;
2634 ngx_uint_t index, size_update;
2635 enum {
2636 sw_start = 0,
2637 sw_index,
2638 sw_name_length,
2639 sw_name_length_2,
2640 sw_name_length_3,
2641 sw_name_length_4,
2642 sw_name,
2643 sw_name_bytes,
2644 sw_value_length,
2645 sw_value_length_2,
2646 sw_value_length_3,
2647 sw_value_length_4,
2648 sw_value,
2649 sw_value_bytes
2650 } state;
2651
2652 /* header block fragment */
2653
2654 #if 0
2655 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2656 "grpc header fragment %p:%p rest:%uz",
2657 b->pos, b->last, ctx->rest);
2658 #endif
2659
2660 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2661 last = b->last;
2662
2663 } else {
2664 last = b->pos + ctx->rest - ctx->padding;
2665 }
2666
2667 state = ctx->fragment_state;
2668
2669 for (p = b->pos; p < last; p++) {
2670 ch = *p;
2671
2672 #if 0
2673 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2674 "grpc header byte: %02Xd s:%d", ch, state);
2675 #endif
2676
2677 switch (state) {
2678
2679 case sw_start:
2680 ctx->index = 0;
2681
2682 if ((ch & 0x80) == 0x80) {
2683 /*
2684 * indexed header:
2685 *
2686 * 0 1 2 3 4 5 6 7
2687 * +---+---+---+---+---+---+---+---+
2688 * | 1 | Index (7+) |
2689 * +---+---------------------------+
2690 */
2691
2692 index = ch & ~0x80;
2693
2694 if (index == 0 || index > 61) {
2695 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2696 "upstream sent invalid http2 "
2697 "table index: %ui", index);
2698 return NGX_ERROR;
2699 }
2700
2701 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2702 "grpc indexed header: %ui", index);
2703
2704 ctx->index = index;
2705 ctx->literal = 0;
2706
2707 goto done;
2708
2709 } else if ((ch & 0xc0) == 0x40) {
2710 /*
2711 * literal header with incremental indexing:
2712 *
2713 * 0 1 2 3 4 5 6 7
2714 * +---+---+---+---+---+---+---+---+
2715 * | 0 | 1 | Index (6+) |
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 | 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 & ~0xc0;
2737
2738 if (index > 61) {
2739 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2740 "upstream sent invalid http2 "
2741 "table index: %ui", index);
2742 return NGX_ERROR;
2743 }
2744
2745 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2746 "grpc literal header: %ui", index);
2747
2748 if (index == 0) {
2749 state = sw_name_length;
2750 break;
2751 }
2752
2753 ctx->index = index;
2754 ctx->literal = 1;
2755
2756 state = sw_value_length;
2757 break;
2758
2759 } else if ((ch & 0xe0) == 0x20) {
2760 /*
2761 * dynamic table size update:
2762 *
2763 * 0 1 2 3 4 5 6 7
2764 * +---+---+---+---+---+---+---+---+
2765 * | 0 | 0 | 1 | Max size (5+) |
2766 * +---+---------------------------+
2767 */
2768
2769 size_update = ch & ~0xe0;
2770
2771 if (size_update > 0) {
2772 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2773 "upstream sent invalid http2 "
2774 "dynamic table size update: %ui",
2775 size_update);
2776 return NGX_ERROR;
2777 }
2778
2779 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2780 "grpc table size update: %ui", size_update);
2781
2782 break;
2783
2784 } else if ((ch & 0xf0) == 0x10) {
2785 /*
2786 * literal header field never indexed:
2787 *
2788 * 0 1 2 3 4 5 6 7
2789 * +---+---+---+---+---+---+---+---+
2790 * | 0 | 0 | 0 | 1 | Index (4+) |
2791 * +---+---+-----------------------+
2792 * | H | Value Length (7+) |
2793 * +---+---------------------------+
2794 * | Value String (Length octets) |
2795 * +-------------------------------+
2796 *
2797 * 0 1 2 3 4 5 6 7
2798 * +---+---+---+---+---+---+---+---+
2799 * | 0 | 0 | 0 | 1 | 0 |
2800 * +---+---+-----------------------+
2801 * | H | Name Length (7+) |
2802 * +---+---------------------------+
2803 * | Name String (Length octets) |
2804 * +---+---------------------------+
2805 * | H | Value Length (7+) |
2806 * +---+---------------------------+
2807 * | Value String (Length octets) |
2808 * +-------------------------------+
2809 */
2810
2811 index = ch & ~0xf0;
2812
2813 if (index == 0x0f) {
2814 ctx->index = index;
2815 ctx->literal = 1;
2816 state = sw_index;
2817 break;
2818 }
2819
2820 if (index == 0) {
2821 state = sw_name_length;
2822 break;
2823 }
2824
2825 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2826 "grpc literal header never indexed: %ui",
2827 index);
2828
2829 ctx->index = index;
2830 ctx->literal = 1;
2831
2832 state = sw_value_length;
2833 break;
2834
2835 } else if ((ch & 0xf0) == 0x00) {
2836 /*
2837 * literal header field without indexing:
2838 *
2839 * 0 1 2 3 4 5 6 7
2840 * +---+---+---+---+---+---+---+---+
2841 * | 0 | 0 | 0 | 0 | Index (4+) |
2842 * +---+---+-----------------------+
2843 * | H | Value Length (7+) |
2844 * +---+---------------------------+
2845 * | Value String (Length octets) |
2846 * +-------------------------------+
2847 *
2848 * 0 1 2 3 4 5 6 7
2849 * +---+---+---+---+---+---+---+---+
2850 * | 0 | 0 | 0 | 0 | 0 |
2851 * +---+---+-----------------------+
2852 * | H | Name Length (7+) |
2853 * +---+---------------------------+
2854 * | Name String (Length octets) |
2855 * +---+---------------------------+
2856 * | H | Value Length (7+) |
2857 * +---+---------------------------+
2858 * | Value String (Length octets) |
2859 * +-------------------------------+
2860 */
2861
2862 index = ch & ~0xf0;
2863
2864 if (index == 0x0f) {
2865 ctx->index = index;
2866 ctx->literal = 1;
2867 state = sw_index;
2868 break;
2869 }
2870
2871 if (index == 0) {
2872 state = sw_name_length;
2873 break;
2874 }
2875
2876 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2877 "grpc literal header without indexing: %ui",
2878 index);
2879
2880 ctx->index = index;
2881 ctx->literal = 1;
2882
2883 state = sw_value_length;
2884 break;
2885 }
2886
2887 /* not reached */
2888
2889 return NGX_ERROR;
2890
2891 case sw_index:
2892 ctx->index = ctx->index + (ch & ~0x80);
2893
2894 if (ch & 0x80) {
2895 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2896 "upstream sent http2 table index "
2897 "with continuation flag");
2898 return NGX_ERROR;
2899 }
2900
2901 if (ctx->index > 61) {
2902 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2903 "upstream sent invalid http2 "
2904 "table index: %ui", ctx->index);
2905 return NGX_ERROR;
2906 }
2907
2908 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2909 "grpc header index: %ui", ctx->index);
2910
2911 state = sw_value_length;
2912 break;
2913
2914 case sw_name_length:
2915 ctx->field_huffman = ch & 0x80 ? 1 : 0;
2916 ctx->field_length = ch & ~0x80;
2917
2918 if (ctx->field_length == 0x7f) {
2919 state = sw_name_length_2;
2920 break;
2921 }
2922
2923 if (ctx->field_length == 0) {
2924 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2925 "upstream sent zero http2 "
2926 "header name length");
2927 return NGX_ERROR;
2928 }
2929
2930 state = sw_name;
2931 break;
2932
2933 case sw_name_length_2:
2934 ctx->field_length += ch & ~0x80;
2935
2936 if (ch & 0x80) {
2937 state = sw_name_length_3;
2938 break;
2939 }
2940
2941 state = sw_name;
2942 break;
2943
2944 case sw_name_length_3:
2945 ctx->field_length += (ch & ~0x80) << 7;
2946
2947 if (ch & 0x80) {
2948 state = sw_name_length_4;
2949 break;
2950 }
2951
2952 state = sw_name;
2953 break;
2954
2955 case sw_name_length_4:
2956 ctx->field_length += (ch & ~0x80) << 14;
2957
2958 if (ch & 0x80) {
2959 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2960 "upstream sent too large http2 "
2961 "header name length");
2962 return NGX_ERROR;
2963 }
2964
2965 state = sw_name;
2966 break;
2967
2968 case sw_name:
2969 ctx->name.len = ctx->field_huffman ?
2970 ctx->field_length * 8 / 5 : ctx->field_length;
2971
2972 ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
2973 if (ctx->name.data == NULL) {
2974 return NGX_ERROR;
2975 }
2976
2977 ctx->field_end = ctx->name.data;
2978 ctx->field_rest = ctx->field_length;
2979 ctx->field_state = 0;
2980
2981 state = sw_name_bytes;
2982
2983 /* fall through */
2984
2985 case sw_name_bytes:
2986
2987 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2988 "grpc name: len:%uz h:%d last:%uz, rest:%uz",
2989 ctx->field_length,
2990 ctx->field_huffman,
2991 last - p,
2992 ctx->rest - (p - b->pos));
2993
2994 size = ngx_min(last - p, (ssize_t) ctx->field_rest);
2995 ctx->field_rest -= size;
2996
2997 if (ctx->field_huffman) {
2998 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
2999 &ctx->field_end,
3000 ctx->field_rest == 0,
3001 r->connection->log)
3002 != NGX_OK)
3003 {
3004 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3005 "upstream sent invalid encoded header");
3006 return NGX_ERROR;
3007 }
3008
3009 ctx->name.len = ctx->field_end - ctx->name.data;
3010 ctx->name.data[ctx->name.len] = '\0';
3011
3012 } else {
3013 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
3014 ctx->name.data[ctx->name.len] = '\0';
3015 }
3016
3017 p += size - 1;
3018
3019 if (ctx->field_rest == 0) {
3020 state = sw_value_length;
3021 }
3022
3023 break;
3024
3025 case sw_value_length:
3026 ctx->field_huffman = ch & 0x80 ? 1 : 0;
3027 ctx->field_length = ch & ~0x80;
3028
3029 if (ctx->field_length == 0x7f) {
3030 state = sw_value_length_2;
3031 break;
3032 }
3033
3034 if (ctx->field_length == 0) {
3035 ngx_str_set(&ctx->value, "");
3036 goto done;
3037 }
3038
3039 state = sw_value;
3040 break;
3041
3042 case sw_value_length_2:
3043 ctx->field_length += ch & ~0x80;
3044
3045 if (ch & 0x80) {
3046 state = sw_value_length_3;
3047 break;
3048 }
3049
3050 state = sw_value;
3051 break;
3052
3053 case sw_value_length_3:
3054 ctx->field_length += (ch & ~0x80) << 7;
3055
3056 if (ch & 0x80) {
3057 state = sw_value_length_4;
3058 break;
3059 }
3060
3061 state = sw_value;
3062 break;
3063
3064 case sw_value_length_4:
3065 ctx->field_length += (ch & ~0x80) << 14;
3066
3067 if (ch & 0x80) {
3068 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3069 "upstream sent too large http2 "
3070 "header value length");
3071 return NGX_ERROR;
3072 }
3073
3074 state = sw_value;
3075 break;
3076
3077 case sw_value:
3078 ctx->value.len = ctx->field_huffman ?
3079 ctx->field_length * 8 / 5 : ctx->field_length;
3080
3081 ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
3082 if (ctx->value.data == NULL) {
3083 return NGX_ERROR;
3084 }
3085
3086 ctx->field_end = ctx->value.data;
3087 ctx->field_rest = ctx->field_length;
3088 ctx->field_state = 0;
3089
3090 state = sw_value_bytes;
3091
3092 /* fall through */
3093
3094 case sw_value_bytes:
3095
3096 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3097 "grpc value: len:%uz h:%d last:%uz, rest:%uz",
3098 ctx->field_length,
3099 ctx->field_huffman,
3100 last - p,
3101 ctx->rest - (p - b->pos));
3102
3103 size = ngx_min(last - p, (ssize_t) ctx->field_rest);
3104 ctx->field_rest -= size;
3105
3106 if (ctx->field_huffman) {
3107 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
3108 &ctx->field_end,
3109 ctx->field_rest == 0,
3110 r->connection->log)
3111 != NGX_OK)
3112 {
3113 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3114 "upstream sent invalid encoded header");
3115 return NGX_ERROR;
3116 }
3117
3118 ctx->value.len = ctx->field_end - ctx->value.data;
3119 ctx->value.data[ctx->value.len] = '\0';
3120
3121 } else {
3122 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
3123 ctx->value.data[ctx->value.len] = '\0';
3124 }
3125
3126 p += size - 1;
3127
3128 if (ctx->field_rest == 0) {
3129 goto done;
3130 }
3131
3132 break;
3133 }
3134
3135 continue;
3136
3137 done:
3138
3139 p++;
3140 ctx->rest -= p - b->pos;
3141 ctx->fragment_state = sw_start;
3142 b->pos = p;
3143
3144 if (ctx->index) {
3145 ctx->name = *ngx_http_v2_get_static_name(ctx->index);
3146 }
3147
3148 if (ctx->index && !ctx->literal) {
3149 ctx->value = *ngx_http_v2_get_static_value(ctx->index);
3150 }
3151
3152 if (!ctx->index) {
3153 if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) {
3154 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3155 "upstream sent invalid header: \"%V: %V\"",
3156 &ctx->name, &ctx->value);
3157 return NGX_ERROR;
3158 }
3159 }
3160
3161 if (!ctx->index || ctx->literal) {
3162 if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) {
3163 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3164 "upstream sent invalid header: \"%V: %V\"",
3165 &ctx->name, &ctx->value);
3166 return NGX_ERROR;
3167 }
3168 }
3169
3170 return NGX_OK;
3171 }
3172
3173 ctx->rest -= p - b->pos;
3174 ctx->fragment_state = state;
3175 b->pos = p;
3176
3177 if (ctx->rest > ctx->padding) {
3178 return NGX_AGAIN;
3179 }
3180
3181 return NGX_DONE;
3182 }
3183
3184
3185 static ngx_int_t
ngx_http_grpc_validate_header_name(ngx_http_request_t * r,ngx_str_t * s)3186 ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
3187 {
3188 u_char ch;
3189 ngx_uint_t i;
3190
3191 for (i = 0; i < s->len; i++) {
3192 ch = s->data[i];
3193
3194 if (ch == ':' && i > 0) {
3195 return NGX_ERROR;
3196 }
3197
3198 if (ch >= 'A' && ch <= 'Z') {
3199 return NGX_ERROR;
3200 }
3201
3202 if (ch == '\0' || ch == CR || ch == LF) {
3203 return NGX_ERROR;
3204 }
3205 }
3206
3207 return NGX_OK;
3208 }
3209
3210
3211 static ngx_int_t
ngx_http_grpc_validate_header_value(ngx_http_request_t * r,ngx_str_t * s)3212 ngx_http_grpc_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
3213 {
3214 u_char ch;
3215 ngx_uint_t i;
3216
3217 for (i = 0; i < s->len; i++) {
3218 ch = s->data[i];
3219
3220 if (ch == '\0' || ch == CR || ch == LF) {
3221 return NGX_ERROR;
3222 }
3223 }
3224
3225 return NGX_OK;
3226 }
3227
3228
3229 static ngx_int_t
ngx_http_grpc_parse_rst_stream(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)3230 ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3231 ngx_buf_t *b)
3232 {
3233 u_char ch, *p, *last;
3234 enum {
3235 sw_start = 0,
3236 sw_error_2,
3237 sw_error_3,
3238 sw_error_4
3239 } state;
3240
3241 if (b->last - b->pos < (ssize_t) ctx->rest) {
3242 last = b->last;
3243
3244 } else {
3245 last = b->pos + ctx->rest;
3246 }
3247
3248 state = ctx->frame_state;
3249
3250 if (state == sw_start) {
3251 if (ctx->rest != 4) {
3252 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3253 "upstream sent rst stream frame "
3254 "with invalid length: %uz",
3255 ctx->rest);
3256 return NGX_ERROR;
3257 }
3258 }
3259
3260 for (p = b->pos; p < last; p++) {
3261 ch = *p;
3262
3263 #if 0
3264 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3265 "grpc rst byte: %02Xd s:%d", ch, state);
3266 #endif
3267
3268 switch (state) {
3269
3270 case sw_start:
3271 ctx->error = (ngx_uint_t) ch << 24;
3272 state = sw_error_2;
3273 break;
3274
3275 case sw_error_2:
3276 ctx->error |= ch << 16;
3277 state = sw_error_3;
3278 break;
3279
3280 case sw_error_3:
3281 ctx->error |= ch << 8;
3282 state = sw_error_4;
3283 break;
3284
3285 case sw_error_4:
3286 ctx->error |= ch;
3287 state = sw_start;
3288
3289 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3290 "grpc error: %ui", ctx->error);
3291
3292 break;
3293 }
3294 }
3295
3296 ctx->rest -= p - b->pos;
3297 ctx->frame_state = state;
3298 b->pos = p;
3299
3300 if (ctx->rest > 0) {
3301 return NGX_AGAIN;
3302 }
3303
3304 return NGX_OK;
3305 }
3306
3307
3308 static ngx_int_t
ngx_http_grpc_parse_goaway(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)3309 ngx_http_grpc_parse_goaway(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3310 ngx_buf_t *b)
3311 {
3312 u_char ch, *p, *last;
3313 enum {
3314 sw_start = 0,
3315 sw_last_stream_id_2,
3316 sw_last_stream_id_3,
3317 sw_last_stream_id_4,
3318 sw_error,
3319 sw_error_2,
3320 sw_error_3,
3321 sw_error_4,
3322 sw_debug
3323 } state;
3324
3325 if (b->last - b->pos < (ssize_t) ctx->rest) {
3326 last = b->last;
3327
3328 } else {
3329 last = b->pos + ctx->rest;
3330 }
3331
3332 state = ctx->frame_state;
3333
3334 if (state == sw_start) {
3335
3336 if (ctx->stream_id) {
3337 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3338 "upstream sent goaway frame "
3339 "with non-zero stream id: %ui",
3340 ctx->stream_id);
3341 return NGX_ERROR;
3342 }
3343
3344 if (ctx->rest < 8) {
3345 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3346 "upstream sent goaway frame "
3347 "with invalid length: %uz",
3348 ctx->rest);
3349 return NGX_ERROR;
3350 }
3351 }
3352
3353 for (p = b->pos; p < last; p++) {
3354 ch = *p;
3355
3356 #if 0
3357 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3358 "grpc goaway byte: %02Xd s:%d", ch, state);
3359 #endif
3360
3361 switch (state) {
3362
3363 case sw_start:
3364 ctx->stream_id = (ch & 0x7f) << 24;
3365 state = sw_last_stream_id_2;
3366 break;
3367
3368 case sw_last_stream_id_2:
3369 ctx->stream_id |= ch << 16;
3370 state = sw_last_stream_id_3;
3371 break;
3372
3373 case sw_last_stream_id_3:
3374 ctx->stream_id |= ch << 8;
3375 state = sw_last_stream_id_4;
3376 break;
3377
3378 case sw_last_stream_id_4:
3379 ctx->stream_id |= ch;
3380 state = sw_error;
3381 break;
3382
3383 case sw_error:
3384 ctx->error = (ngx_uint_t) ch << 24;
3385 state = sw_error_2;
3386 break;
3387
3388 case sw_error_2:
3389 ctx->error |= ch << 16;
3390 state = sw_error_3;
3391 break;
3392
3393 case sw_error_3:
3394 ctx->error |= ch << 8;
3395 state = sw_error_4;
3396 break;
3397
3398 case sw_error_4:
3399 ctx->error |= ch;
3400 state = sw_debug;
3401 break;
3402
3403 case sw_debug:
3404 break;
3405 }
3406 }
3407
3408 ctx->rest -= p - b->pos;
3409 ctx->frame_state = state;
3410 b->pos = p;
3411
3412 if (ctx->rest > 0) {
3413 return NGX_AGAIN;
3414 }
3415
3416 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3417 "grpc goaway: %ui, stream %ui",
3418 ctx->error, ctx->stream_id);
3419
3420 ctx->state = ngx_http_grpc_st_start;
3421
3422 return NGX_OK;
3423 }
3424
3425
3426 static ngx_int_t
ngx_http_grpc_parse_window_update(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)3427 ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
3428 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
3429 {
3430 u_char ch, *p, *last;
3431 enum {
3432 sw_start = 0,
3433 sw_size_2,
3434 sw_size_3,
3435 sw_size_4
3436 } state;
3437
3438 if (b->last - b->pos < (ssize_t) ctx->rest) {
3439 last = b->last;
3440
3441 } else {
3442 last = b->pos + ctx->rest;
3443 }
3444
3445 state = ctx->frame_state;
3446
3447 if (state == sw_start) {
3448 if (ctx->rest != 4) {
3449 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3450 "upstream sent window update frame "
3451 "with invalid length: %uz",
3452 ctx->rest);
3453 return NGX_ERROR;
3454 }
3455 }
3456
3457 for (p = b->pos; p < last; p++) {
3458 ch = *p;
3459
3460 #if 0
3461 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3462 "grpc window update byte: %02Xd s:%d", ch, state);
3463 #endif
3464
3465 switch (state) {
3466
3467 case sw_start:
3468 ctx->window_update = (ch & 0x7f) << 24;
3469 state = sw_size_2;
3470 break;
3471
3472 case sw_size_2:
3473 ctx->window_update |= ch << 16;
3474 state = sw_size_3;
3475 break;
3476
3477 case sw_size_3:
3478 ctx->window_update |= ch << 8;
3479 state = sw_size_4;
3480 break;
3481
3482 case sw_size_4:
3483 ctx->window_update |= ch;
3484 state = sw_start;
3485 break;
3486 }
3487 }
3488
3489 ctx->rest -= p - b->pos;
3490 ctx->frame_state = state;
3491 b->pos = p;
3492
3493 if (ctx->rest > 0) {
3494 return NGX_AGAIN;
3495 }
3496
3497 ctx->state = ngx_http_grpc_st_start;
3498
3499 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3500 "grpc window update: %ui", ctx->window_update);
3501
3502 if (ctx->stream_id) {
3503
3504 if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
3505 - ctx->send_window)
3506 {
3507 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3508 "upstream sent too large window update");
3509 return NGX_ERROR;
3510 }
3511
3512 ctx->send_window += ctx->window_update;
3513
3514 } else {
3515
3516 if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
3517 - ctx->connection->send_window)
3518 {
3519 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3520 "upstream sent too large window update");
3521 return NGX_ERROR;
3522 }
3523
3524 ctx->connection->send_window += ctx->window_update;
3525 }
3526
3527 return NGX_OK;
3528 }
3529
3530
3531 static ngx_int_t
ngx_http_grpc_parse_settings(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)3532 ngx_http_grpc_parse_settings(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3533 ngx_buf_t *b)
3534 {
3535 u_char ch, *p, *last;
3536 ssize_t window_update;
3537 enum {
3538 sw_start = 0,
3539 sw_id,
3540 sw_id_2,
3541 sw_value,
3542 sw_value_2,
3543 sw_value_3,
3544 sw_value_4
3545 } state;
3546
3547 if (b->last - b->pos < (ssize_t) ctx->rest) {
3548 last = b->last;
3549
3550 } else {
3551 last = b->pos + ctx->rest;
3552 }
3553
3554 state = ctx->frame_state;
3555
3556 if (state == sw_start) {
3557
3558 if (ctx->stream_id) {
3559 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3560 "upstream sent settings frame "
3561 "with non-zero stream id: %ui",
3562 ctx->stream_id);
3563 return NGX_ERROR;
3564 }
3565
3566 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
3567 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3568 "grpc settings ack");
3569
3570 if (ctx->rest != 0) {
3571 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3572 "upstream sent settings frame "
3573 "with ack flag and non-zero length: %uz",
3574 ctx->rest);
3575 return NGX_ERROR;
3576 }
3577
3578 ctx->state = ngx_http_grpc_st_start;
3579
3580 return NGX_OK;
3581 }
3582
3583 if (ctx->rest % 6 != 0) {
3584 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3585 "upstream sent settings frame "
3586 "with invalid length: %uz",
3587 ctx->rest);
3588 return NGX_ERROR;
3589 }
3590
3591 if (ctx->free == NULL && ctx->settings++ > 1000) {
3592 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3593 "upstream sent too many settings frames");
3594 return NGX_ERROR;
3595 }
3596 }
3597
3598 for (p = b->pos; p < last; p++) {
3599 ch = *p;
3600
3601 #if 0
3602 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3603 "grpc settings byte: %02Xd s:%d", ch, state);
3604 #endif
3605
3606 switch (state) {
3607
3608 case sw_start:
3609 case sw_id:
3610 ctx->setting_id = ch << 8;
3611 state = sw_id_2;
3612 break;
3613
3614 case sw_id_2:
3615 ctx->setting_id |= ch;
3616 state = sw_value;
3617 break;
3618
3619 case sw_value:
3620 ctx->setting_value = (ngx_uint_t) ch << 24;
3621 state = sw_value_2;
3622 break;
3623
3624 case sw_value_2:
3625 ctx->setting_value |= ch << 16;
3626 state = sw_value_3;
3627 break;
3628
3629 case sw_value_3:
3630 ctx->setting_value |= ch << 8;
3631 state = sw_value_4;
3632 break;
3633
3634 case sw_value_4:
3635 ctx->setting_value |= ch;
3636 state = sw_id;
3637
3638 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3639 "grpc setting: %ui %ui",
3640 ctx->setting_id, ctx->setting_value);
3641
3642 /*
3643 * The following settings are defined by the protocol:
3644 *
3645 * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
3646 * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
3647 * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
3648 *
3649 * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
3650 * a simple client.
3651 */
3652
3653 if (ctx->setting_id == 0x04) {
3654 /* SETTINGS_INITIAL_WINDOW_SIZE */
3655
3656 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
3657 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3658 "upstream sent settings frame "
3659 "with too large initial window size: %ui",
3660 ctx->setting_value);
3661 return NGX_ERROR;
3662 }
3663
3664 window_update = ctx->setting_value
3665 - ctx->connection->init_window;
3666 ctx->connection->init_window = ctx->setting_value;
3667
3668 if (ctx->send_window > 0
3669 && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
3670 - ctx->send_window)
3671 {
3672 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3673 "upstream sent settings frame "
3674 "with too large initial window size: %ui",
3675 ctx->setting_value);
3676 return NGX_ERROR;
3677 }
3678
3679 ctx->send_window += window_update;
3680 }
3681
3682 break;
3683 }
3684 }
3685
3686 ctx->rest -= p - b->pos;
3687 ctx->frame_state = state;
3688 b->pos = p;
3689
3690 if (ctx->rest > 0) {
3691 return NGX_AGAIN;
3692 }
3693
3694 ctx->state = ngx_http_grpc_st_start;
3695
3696 return ngx_http_grpc_send_settings_ack(r, ctx);
3697 }
3698
3699
3700 static ngx_int_t
ngx_http_grpc_parse_ping(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_buf_t * b)3701 ngx_http_grpc_parse_ping(ngx_http_request_t *r,
3702 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
3703 {
3704 u_char ch, *p, *last;
3705 enum {
3706 sw_start = 0,
3707 sw_data_2,
3708 sw_data_3,
3709 sw_data_4,
3710 sw_data_5,
3711 sw_data_6,
3712 sw_data_7,
3713 sw_data_8
3714 } state;
3715
3716 if (b->last - b->pos < (ssize_t) ctx->rest) {
3717 last = b->last;
3718
3719 } else {
3720 last = b->pos + ctx->rest;
3721 }
3722
3723 state = ctx->frame_state;
3724
3725 if (state == sw_start) {
3726
3727 if (ctx->stream_id) {
3728 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3729 "upstream sent ping frame "
3730 "with non-zero stream id: %ui",
3731 ctx->stream_id);
3732 return NGX_ERROR;
3733 }
3734
3735 if (ctx->rest != 8) {
3736 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3737 "upstream sent ping frame "
3738 "with invalid length: %uz",
3739 ctx->rest);
3740 return NGX_ERROR;
3741 }
3742
3743 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
3744 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3745 "upstream sent ping frame with ack flag");
3746 return NGX_ERROR;
3747 }
3748
3749 if (ctx->free == NULL && ctx->pings++ > 1000) {
3750 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3751 "upstream sent too many ping frames");
3752 return NGX_ERROR;
3753 }
3754 }
3755
3756 for (p = b->pos; p < last; p++) {
3757 ch = *p;
3758
3759 #if 0
3760 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3761 "grpc ping byte: %02Xd s:%d", ch, state);
3762 #endif
3763
3764 if (state < sw_data_8) {
3765 ctx->ping_data[state] = ch;
3766 state++;
3767
3768 } else {
3769 ctx->ping_data[7] = ch;
3770 state = sw_start;
3771
3772 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3773 "grpc ping");
3774 }
3775 }
3776
3777 ctx->rest -= p - b->pos;
3778 ctx->frame_state = state;
3779 b->pos = p;
3780
3781 if (ctx->rest > 0) {
3782 return NGX_AGAIN;
3783 }
3784
3785 ctx->state = ngx_http_grpc_st_start;
3786
3787 return ngx_http_grpc_send_ping_ack(r, ctx);
3788 }
3789
3790
3791 static ngx_int_t
ngx_http_grpc_send_settings_ack(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx)3792 ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
3793 {
3794 ngx_chain_t *cl, **ll;
3795 ngx_http_grpc_frame_t *f;
3796
3797 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3798 "grpc send settings ack");
3799
3800 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
3801 ll = &cl->next;
3802 }
3803
3804 cl = ngx_http_grpc_get_buf(r, ctx);
3805 if (cl == NULL) {
3806 return NGX_ERROR;
3807 }
3808
3809 f = (ngx_http_grpc_frame_t *) cl->buf->last;
3810 cl->buf->last += sizeof(ngx_http_grpc_frame_t);
3811
3812 f->length_0 = 0;
3813 f->length_1 = 0;
3814 f->length_2 = 0;
3815 f->type = NGX_HTTP_V2_SETTINGS_FRAME;
3816 f->flags = NGX_HTTP_V2_ACK_FLAG;
3817 f->stream_id_0 = 0;
3818 f->stream_id_1 = 0;
3819 f->stream_id_2 = 0;
3820 f->stream_id_3 = 0;
3821
3822 *ll = cl;
3823
3824 return NGX_OK;
3825 }
3826
3827
3828 static ngx_int_t
ngx_http_grpc_send_ping_ack(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx)3829 ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
3830 {
3831 ngx_chain_t *cl, **ll;
3832 ngx_http_grpc_frame_t *f;
3833
3834 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3835 "grpc send ping ack");
3836
3837 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
3838 ll = &cl->next;
3839 }
3840
3841 cl = ngx_http_grpc_get_buf(r, ctx);
3842 if (cl == NULL) {
3843 return NGX_ERROR;
3844 }
3845
3846 f = (ngx_http_grpc_frame_t *) cl->buf->last;
3847 cl->buf->last += sizeof(ngx_http_grpc_frame_t);
3848
3849 f->length_0 = 0;
3850 f->length_1 = 0;
3851 f->length_2 = 8;
3852 f->type = NGX_HTTP_V2_PING_FRAME;
3853 f->flags = NGX_HTTP_V2_ACK_FLAG;
3854 f->stream_id_0 = 0;
3855 f->stream_id_1 = 0;
3856 f->stream_id_2 = 0;
3857 f->stream_id_3 = 0;
3858
3859 cl->buf->last = ngx_copy(cl->buf->last, ctx->ping_data, 8);
3860
3861 *ll = cl;
3862
3863 return NGX_OK;
3864 }
3865
3866
3867 static ngx_int_t
ngx_http_grpc_send_window_update(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx)3868 ngx_http_grpc_send_window_update(ngx_http_request_t *r,
3869 ngx_http_grpc_ctx_t *ctx)
3870 {
3871 size_t n;
3872 ngx_chain_t *cl, **ll;
3873 ngx_http_grpc_frame_t *f;
3874
3875 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3876 "grpc send window update: %uz %uz",
3877 ctx->connection->recv_window, ctx->recv_window);
3878
3879 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
3880 ll = &cl->next;
3881 }
3882
3883 cl = ngx_http_grpc_get_buf(r, ctx);
3884 if (cl == NULL) {
3885 return NGX_ERROR;
3886 }
3887
3888 f = (ngx_http_grpc_frame_t *) cl->buf->last;
3889 cl->buf->last += sizeof(ngx_http_grpc_frame_t);
3890
3891 f->length_0 = 0;
3892 f->length_1 = 0;
3893 f->length_2 = 4;
3894 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
3895 f->flags = 0;
3896 f->stream_id_0 = 0;
3897 f->stream_id_1 = 0;
3898 f->stream_id_2 = 0;
3899 f->stream_id_3 = 0;
3900
3901 n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
3902 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;
3903
3904 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
3905 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
3906 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
3907 *cl->buf->last++ = (u_char) (n & 0xff);
3908
3909 f = (ngx_http_grpc_frame_t *) cl->buf->last;
3910 cl->buf->last += sizeof(ngx_http_grpc_frame_t);
3911
3912 f->length_0 = 0;
3913 f->length_1 = 0;
3914 f->length_2 = 4;
3915 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
3916 f->flags = 0;
3917 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
3918 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
3919 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
3920 f->stream_id_3 = (u_char) (ctx->id & 0xff);
3921
3922 n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
3923 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
3924
3925 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
3926 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
3927 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
3928 *cl->buf->last++ = (u_char) (n & 0xff);
3929
3930 *ll = cl;
3931
3932 return NGX_OK;
3933 }
3934
3935
3936 static ngx_chain_t *
ngx_http_grpc_get_buf(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx)3937 ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
3938 {
3939 u_char *start;
3940 ngx_buf_t *b;
3941 ngx_chain_t *cl;
3942
3943 cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
3944 if (cl == NULL) {
3945 return NULL;
3946 }
3947
3948 b = cl->buf;
3949 start = b->start;
3950
3951 if (start == NULL) {
3952
3953 /*
3954 * each buffer is large enough to hold two window update
3955 * frames in a row
3956 */
3957
3958 start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8);
3959 if (start == NULL) {
3960 return NULL;
3961 }
3962
3963 }
3964
3965 ngx_memzero(b, sizeof(ngx_buf_t));
3966
3967 b->start = start;
3968 b->pos = start;
3969 b->last = start;
3970 b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8;
3971
3972 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
3973 b->temporary = 1;
3974 b->flush = 1;
3975
3976 return cl;
3977 }
3978
3979
3980 static ngx_http_grpc_ctx_t *
ngx_http_grpc_get_ctx(ngx_http_request_t * r)3981 ngx_http_grpc_get_ctx(ngx_http_request_t *r)
3982 {
3983 ngx_http_grpc_ctx_t *ctx;
3984 ngx_http_upstream_t *u;
3985
3986 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
3987
3988 if (ctx->connection == NULL) {
3989 u = r->upstream;
3990
3991 if (ngx_http_grpc_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
3992 return NULL;
3993 }
3994 }
3995
3996 return ctx;
3997 }
3998
3999
4000 static ngx_int_t
ngx_http_grpc_get_connection_data(ngx_http_request_t * r,ngx_http_grpc_ctx_t * ctx,ngx_peer_connection_t * pc)4001 ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
4002 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc)
4003 {
4004 ngx_connection_t *c;
4005 ngx_pool_cleanup_t *cln;
4006
4007 c = pc->connection;
4008
4009 if (pc->cached) {
4010
4011 /*
4012 * for cached connections, connection data can be found
4013 * in the cleanup handler
4014 */
4015
4016 for (cln = c->pool->cleanup; cln; cln = cln->next) {
4017 if (cln->handler == ngx_http_grpc_cleanup) {
4018 ctx->connection = cln->data;
4019 break;
4020 }
4021 }
4022
4023 if (ctx->connection == NULL) {
4024 ngx_log_error(NGX_LOG_ERR, c->log, 0,
4025 "no connection data found for "
4026 "keepalive http2 connection");
4027 return NGX_ERROR;
4028 }
4029
4030 ctx->send_window = ctx->connection->init_window;
4031 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4032
4033 ctx->connection->last_stream_id += 2;
4034 ctx->id = ctx->connection->last_stream_id;
4035
4036 return NGX_OK;
4037 }
4038
4039 cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_grpc_conn_t));
4040 if (cln == NULL) {
4041 return NGX_ERROR;
4042 }
4043
4044 cln->handler = ngx_http_grpc_cleanup;
4045 ctx->connection = cln->data;
4046
4047 ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4048 ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4049 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4050
4051 ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4052 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4053
4054 ctx->id = 1;
4055 ctx->connection->last_stream_id = 1;
4056
4057 return NGX_OK;
4058 }
4059
4060
4061 static void
ngx_http_grpc_cleanup(void * data)4062 ngx_http_grpc_cleanup(void *data)
4063 {
4064 #if 0
4065 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
4066 "grpc cleanup");
4067 #endif
4068 return;
4069 }
4070
4071
4072 static void
ngx_http_grpc_abort_request(ngx_http_request_t * r)4073 ngx_http_grpc_abort_request(ngx_http_request_t *r)
4074 {
4075 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4076 "abort grpc request");
4077 return;
4078 }
4079
4080
4081 static void
ngx_http_grpc_finalize_request(ngx_http_request_t * r,ngx_int_t rc)4082 ngx_http_grpc_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
4083 {
4084 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4085 "finalize grpc request");
4086 return;
4087 }
4088
4089
4090 static ngx_int_t
ngx_http_grpc_internal_trailers_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)4091 ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r,
4092 ngx_http_variable_value_t *v, uintptr_t data)
4093 {
4094 ngx_table_elt_t *te;
4095
4096 te = r->headers_in.te;
4097
4098 if (te == NULL) {
4099 v->not_found = 1;
4100 return NGX_OK;
4101 }
4102
4103 if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len,
4104 (u_char *) "trailers", 8 - 1)
4105 == NULL)
4106 {
4107 v->not_found = 1;
4108 return NGX_OK;
4109 }
4110
4111 v->valid = 1;
4112 v->no_cacheable = 0;
4113 v->not_found = 0;
4114
4115 v->data = (u_char *) "trailers";
4116 v->len = sizeof("trailers") - 1;
4117
4118 return NGX_OK;
4119 }
4120
4121
4122 static ngx_int_t
ngx_http_grpc_add_variables(ngx_conf_t * cf)4123 ngx_http_grpc_add_variables(ngx_conf_t *cf)
4124 {
4125 ngx_http_variable_t *var, *v;
4126
4127 for (v = ngx_http_grpc_vars; v->name.len; v++) {
4128 var = ngx_http_add_variable(cf, &v->name, v->flags);
4129 if (var == NULL) {
4130 return NGX_ERROR;
4131 }
4132
4133 var->get_handler = v->get_handler;
4134 var->data = v->data;
4135 }
4136
4137 return NGX_OK;
4138 }
4139
4140
4141 static void *
ngx_http_grpc_create_loc_conf(ngx_conf_t * cf)4142 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
4143 {
4144 ngx_http_grpc_loc_conf_t *conf;
4145
4146 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_grpc_loc_conf_t));
4147 if (conf == NULL) {
4148 return NULL;
4149 }
4150
4151 /*
4152 * set by ngx_pcalloc():
4153 *
4154 * conf->upstream.ignore_headers = 0;
4155 * conf->upstream.next_upstream = 0;
4156 * conf->upstream.hide_headers_hash = { NULL, 0 };
4157 * conf->upstream.ssl_name = NULL;
4158 *
4159 * conf->headers_source = NULL;
4160 * conf->headers.lengths = NULL;
4161 * conf->headers.values = NULL;
4162 * conf->headers.hash = { NULL, 0 };
4163 * conf->host = { 0, NULL };
4164 * conf->host_set = 0;
4165 * conf->ssl = 0;
4166 * conf->ssl_protocols = 0;
4167 * conf->ssl_ciphers = { 0, NULL };
4168 * conf->ssl_trusted_certificate = { 0, NULL };
4169 * conf->ssl_crl = { 0, NULL };
4170 * conf->ssl_certificate = { 0, NULL };
4171 * conf->ssl_certificate_key = { 0, NULL };
4172 */
4173
4174 conf->upstream.local = NGX_CONF_UNSET_PTR;
4175 conf->upstream.socket_keepalive = NGX_CONF_UNSET;
4176 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
4177 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
4178 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
4179 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
4180 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
4181
4182 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
4183
4184 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
4185 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
4186
4187 conf->upstream.intercept_errors = NGX_CONF_UNSET;
4188
4189 #if (NGX_HTTP_SSL)
4190 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
4191 conf->upstream.ssl_server_name = NGX_CONF_UNSET;
4192 conf->upstream.ssl_verify = NGX_CONF_UNSET;
4193 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
4194 conf->ssl_passwords = NGX_CONF_UNSET_PTR;
4195 #endif
4196
4197 /* the hardcoded values */
4198 conf->upstream.cyclic_temp_file = 0;
4199 conf->upstream.buffering = 0;
4200 conf->upstream.ignore_client_abort = 0;
4201 conf->upstream.send_lowat = 0;
4202 conf->upstream.bufs.num = 0;
4203 conf->upstream.busy_buffers_size = 0;
4204 conf->upstream.max_temp_file_size = 0;
4205 conf->upstream.temp_file_write_size = 0;
4206 conf->upstream.pass_request_headers = 1;
4207 conf->upstream.pass_request_body = 1;
4208 conf->upstream.force_ranges = 0;
4209 conf->upstream.pass_trailers = 1;
4210 conf->upstream.preserve_output = 1;
4211
4212 ngx_str_set(&conf->upstream.module, "grpc");
4213
4214 return conf;
4215 }
4216
4217
4218 static char *
ngx_http_grpc_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)4219 ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
4220 {
4221 ngx_http_grpc_loc_conf_t *prev = parent;
4222 ngx_http_grpc_loc_conf_t *conf = child;
4223
4224 ngx_int_t rc;
4225 ngx_hash_init_t hash;
4226 ngx_http_core_loc_conf_t *clcf;
4227
4228 ngx_conf_merge_ptr_value(conf->upstream.local,
4229 prev->upstream.local, NULL);
4230
4231 ngx_conf_merge_value(conf->upstream.socket_keepalive,
4232 prev->upstream.socket_keepalive, 0);
4233
4234 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
4235 prev->upstream.next_upstream_tries, 0);
4236
4237 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
4238 prev->upstream.connect_timeout, 60000);
4239
4240 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
4241 prev->upstream.send_timeout, 60000);
4242
4243 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
4244 prev->upstream.read_timeout, 60000);
4245
4246 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
4247 prev->upstream.next_upstream_timeout, 0);
4248
4249 ngx_conf_merge_size_value(conf->upstream.buffer_size,
4250 prev->upstream.buffer_size,
4251 (size_t) ngx_pagesize);
4252
4253 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
4254 prev->upstream.ignore_headers,
4255 NGX_CONF_BITMASK_SET);
4256
4257 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
4258 prev->upstream.next_upstream,
4259 (NGX_CONF_BITMASK_SET
4260 |NGX_HTTP_UPSTREAM_FT_ERROR
4261 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
4262
4263 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
4264 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
4265 |NGX_HTTP_UPSTREAM_FT_OFF;
4266 }
4267
4268 ngx_conf_merge_value(conf->upstream.intercept_errors,
4269 prev->upstream.intercept_errors, 0);
4270
4271 #if (NGX_HTTP_SSL)
4272
4273 ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
4274 prev->upstream.ssl_session_reuse, 1);
4275
4276 ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
4277 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
4278 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
4279
4280 ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
4281 "DEFAULT");
4282
4283 if (conf->upstream.ssl_name == NULL) {
4284 conf->upstream.ssl_name = prev->upstream.ssl_name;
4285 }
4286
4287 ngx_conf_merge_value(conf->upstream.ssl_server_name,
4288 prev->upstream.ssl_server_name, 0);
4289 ngx_conf_merge_value(conf->upstream.ssl_verify,
4290 prev->upstream.ssl_verify, 0);
4291 ngx_conf_merge_uint_value(conf->ssl_verify_depth,
4292 prev->ssl_verify_depth, 1);
4293 ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
4294 prev->ssl_trusted_certificate, "");
4295 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
4296
4297 ngx_conf_merge_str_value(conf->ssl_certificate,
4298 prev->ssl_certificate, "");
4299 ngx_conf_merge_str_value(conf->ssl_certificate_key,
4300 prev->ssl_certificate_key, "");
4301 ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
4302
4303 if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) {
4304 return NGX_CONF_ERROR;
4305 }
4306
4307 #endif
4308
4309 hash.max_size = 512;
4310 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
4311 hash.name = "grpc_headers_hash";
4312
4313 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
4314 &prev->upstream, ngx_http_grpc_hide_headers, &hash)
4315 != NGX_OK)
4316 {
4317 return NGX_CONF_ERROR;
4318 }
4319
4320 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
4321
4322 if (clcf->noname && conf->upstream.upstream == NULL) {
4323 conf->upstream.upstream = prev->upstream.upstream;
4324 conf->host = prev->host;
4325 #if (NGX_HTTP_SSL)
4326 conf->upstream.ssl = prev->upstream.ssl;
4327 #endif
4328 }
4329
4330 if (clcf->lmt_excpt && clcf->handler == NULL && conf->upstream.upstream) {
4331 clcf->handler = ngx_http_grpc_handler;
4332 }
4333
4334 if (conf->headers_source == NULL) {
4335 conf->headers = prev->headers;
4336 conf->headers_source = prev->headers_source;
4337 conf->host_set = prev->host_set;
4338 }
4339
4340 rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers,
4341 ngx_http_grpc_headers);
4342 if (rc != NGX_OK) {
4343 return NGX_CONF_ERROR;
4344 }
4345
4346 /*
4347 * special handling to preserve conf->headers in the "http" section
4348 * to inherit it to all servers
4349 */
4350
4351 if (prev->headers.hash.buckets == NULL
4352 && conf->headers_source == prev->headers_source)
4353 {
4354 prev->headers = conf->headers;
4355 prev->host_set = conf->host_set;
4356 }
4357
4358 return NGX_CONF_OK;
4359 }
4360
4361
4362 static ngx_int_t
ngx_http_grpc_init_headers(ngx_conf_t * cf,ngx_http_grpc_loc_conf_t * conf,ngx_http_grpc_headers_t * headers,ngx_keyval_t * default_headers)4363 ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
4364 ngx_http_grpc_headers_t *headers, ngx_keyval_t *default_headers)
4365 {
4366 u_char *p;
4367 size_t size;
4368 uintptr_t *code;
4369 ngx_uint_t i;
4370 ngx_array_t headers_names, headers_merged;
4371 ngx_keyval_t *src, *s, *h;
4372 ngx_hash_key_t *hk;
4373 ngx_hash_init_t hash;
4374 ngx_http_script_compile_t sc;
4375 ngx_http_script_copy_code_t *copy;
4376
4377 if (headers->hash.buckets) {
4378 return NGX_OK;
4379 }
4380
4381 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
4382 != NGX_OK)
4383 {
4384 return NGX_ERROR;
4385 }
4386
4387 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
4388 != NGX_OK)
4389 {
4390 return NGX_ERROR;
4391 }
4392
4393 headers->lengths = ngx_array_create(cf->pool, 64, 1);
4394 if (headers->lengths == NULL) {
4395 return NGX_ERROR;
4396 }
4397
4398 headers->values = ngx_array_create(cf->pool, 512, 1);
4399 if (headers->values == NULL) {
4400 return NGX_ERROR;
4401 }
4402
4403 if (conf->headers_source) {
4404
4405 src = conf->headers_source->elts;
4406 for (i = 0; i < conf->headers_source->nelts; i++) {
4407
4408 if (src[i].key.len == 4
4409 && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0)
4410 {
4411 conf->host_set = 1;
4412 }
4413
4414 s = ngx_array_push(&headers_merged);
4415 if (s == NULL) {
4416 return NGX_ERROR;
4417 }
4418
4419 *s = src[i];
4420 }
4421 }
4422
4423 h = default_headers;
4424
4425 while (h->key.len) {
4426
4427 src = headers_merged.elts;
4428 for (i = 0; i < headers_merged.nelts; i++) {
4429 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
4430 goto next;
4431 }
4432 }
4433
4434 s = ngx_array_push(&headers_merged);
4435 if (s == NULL) {
4436 return NGX_ERROR;
4437 }
4438
4439 *s = *h;
4440
4441 next:
4442
4443 h++;
4444 }
4445
4446
4447 src = headers_merged.elts;
4448 for (i = 0; i < headers_merged.nelts; i++) {
4449
4450 hk = ngx_array_push(&headers_names);
4451 if (hk == NULL) {
4452 return NGX_ERROR;
4453 }
4454
4455 hk->key = src[i].key;
4456 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
4457 hk->value = (void *) 1;
4458
4459 if (src[i].value.len == 0) {
4460 continue;
4461 }
4462
4463 copy = ngx_array_push_n(headers->lengths,
4464 sizeof(ngx_http_script_copy_code_t));
4465 if (copy == NULL) {
4466 return NGX_ERROR;
4467 }
4468
4469 copy->code = (ngx_http_script_code_pt) (void *)
4470 ngx_http_script_copy_len_code;
4471 copy->len = src[i].key.len;
4472
4473 size = (sizeof(ngx_http_script_copy_code_t)
4474 + src[i].key.len + sizeof(uintptr_t) - 1)
4475 & ~(sizeof(uintptr_t) - 1);
4476
4477 copy = ngx_array_push_n(headers->values, size);
4478 if (copy == NULL) {
4479 return NGX_ERROR;
4480 }
4481
4482 copy->code = ngx_http_script_copy_code;
4483 copy->len = src[i].key.len;
4484
4485 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
4486 ngx_memcpy(p, src[i].key.data, src[i].key.len);
4487
4488 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4489
4490 sc.cf = cf;
4491 sc.source = &src[i].value;
4492 sc.flushes = &headers->flushes;
4493 sc.lengths = &headers->lengths;
4494 sc.values = &headers->values;
4495
4496 if (ngx_http_script_compile(&sc) != NGX_OK) {
4497 return NGX_ERROR;
4498 }
4499
4500 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
4501 if (code == NULL) {
4502 return NGX_ERROR;
4503 }
4504
4505 *code = (uintptr_t) NULL;
4506
4507 code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
4508 if (code == NULL) {
4509 return NGX_ERROR;
4510 }
4511
4512 *code = (uintptr_t) NULL;
4513 }
4514
4515 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
4516 if (code == NULL) {
4517 return NGX_ERROR;
4518 }
4519
4520 *code = (uintptr_t) NULL;
4521
4522
4523 hash.hash = &headers->hash;
4524 hash.key = ngx_hash_key_lc;
4525 hash.max_size = 512;
4526 hash.bucket_size = 64;
4527 hash.name = "grpc_headers_hash";
4528 hash.pool = cf->pool;
4529 hash.temp_pool = NULL;
4530
4531 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
4532 }
4533
4534
4535 static char *
ngx_http_grpc_pass(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4536 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4537 {
4538 ngx_http_grpc_loc_conf_t *glcf = conf;
4539
4540 size_t add;
4541 ngx_str_t *value, *url;
4542 ngx_url_t u;
4543 ngx_http_core_loc_conf_t *clcf;
4544
4545 if (glcf->upstream.upstream) {
4546 return "is duplicate";
4547 }
4548
4549 value = cf->args->elts;
4550 url = &value[1];
4551
4552 if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) {
4553 add = 7;
4554
4555 } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) {
4556
4557 #if (NGX_HTTP_SSL)
4558 glcf->ssl = 1;
4559
4560 add = 8;
4561 #else
4562 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4563 "grpcs protocol requires SSL support");
4564 return NGX_CONF_ERROR;
4565 #endif
4566
4567 } else {
4568 add = 0;
4569 }
4570
4571 ngx_memzero(&u, sizeof(ngx_url_t));
4572
4573 u.url.len = url->len - add;
4574 u.url.data = url->data + add;
4575 u.no_resolve = 1;
4576
4577 glcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
4578 if (glcf->upstream.upstream == NULL) {
4579 return NGX_CONF_ERROR;
4580 }
4581
4582 if (u.family != AF_UNIX) {
4583
4584 if (u.no_port) {
4585 glcf->host = u.host;
4586
4587 } else {
4588 glcf->host.len = u.host.len + 1 + u.port_text.len;
4589 glcf->host.data = u.host.data;
4590 }
4591
4592 } else {
4593 ngx_str_set(&glcf->host, "localhost");
4594 }
4595
4596 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
4597
4598 clcf->handler = ngx_http_grpc_handler;
4599
4600 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
4601 clcf->auto_redirect = 1;
4602 }
4603
4604 return NGX_CONF_OK;
4605 }
4606
4607
4608 #if (NGX_HTTP_SSL)
4609
4610 static char *
ngx_http_grpc_ssl_password_file(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4611 ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4612 {
4613 ngx_http_grpc_loc_conf_t *glcf = conf;
4614
4615 ngx_str_t *value;
4616
4617 if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
4618 return "is duplicate";
4619 }
4620
4621 value = cf->args->elts;
4622
4623 glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
4624
4625 if (glcf->ssl_passwords == NULL) {
4626 return NGX_CONF_ERROR;
4627 }
4628
4629 return NGX_CONF_OK;
4630 }
4631
4632
4633 static ngx_int_t
ngx_http_grpc_set_ssl(ngx_conf_t * cf,ngx_http_grpc_loc_conf_t * glcf)4634 ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf)
4635 {
4636 ngx_pool_cleanup_t *cln;
4637
4638 glcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
4639 if (glcf->upstream.ssl == NULL) {
4640 return NGX_ERROR;
4641 }
4642
4643 glcf->upstream.ssl->log = cf->log;
4644
4645 if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL)
4646 != NGX_OK)
4647 {
4648 return NGX_ERROR;
4649 }
4650
4651 cln = ngx_pool_cleanup_add(cf->pool, 0);
4652 if (cln == NULL) {
4653 ngx_ssl_cleanup_ctx(glcf->upstream.ssl);
4654 return NGX_ERROR;
4655 }
4656
4657 cln->handler = ngx_ssl_cleanup_ctx;
4658 cln->data = glcf->upstream.ssl;
4659
4660 if (glcf->ssl_certificate.len) {
4661
4662 if (glcf->ssl_certificate_key.len == 0) {
4663 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4664 "no \"grpc_ssl_certificate_key\" is defined "
4665 "for certificate \"%V\"", &glcf->ssl_certificate);
4666 return NGX_ERROR;
4667 }
4668
4669 if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate,
4670 &glcf->ssl_certificate_key, glcf->ssl_passwords)
4671 != NGX_OK)
4672 {
4673 return NGX_ERROR;
4674 }
4675 }
4676
4677 if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0)
4678 != NGX_OK)
4679 {
4680 return NGX_ERROR;
4681 }
4682
4683 if (glcf->upstream.ssl_verify) {
4684 if (glcf->ssl_trusted_certificate.len == 0) {
4685 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4686 "no grpc_ssl_trusted_certificate for grpc_ssl_verify");
4687 return NGX_ERROR;
4688 }
4689
4690 if (ngx_ssl_trusted_certificate(cf, glcf->upstream.ssl,
4691 &glcf->ssl_trusted_certificate,
4692 glcf->ssl_verify_depth)
4693 != NGX_OK)
4694 {
4695 return NGX_ERROR;
4696 }
4697
4698 if (ngx_ssl_crl(cf, glcf->upstream.ssl, &glcf->ssl_crl) != NGX_OK) {
4699 return NGX_ERROR;
4700 }
4701 }
4702
4703 if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl,
4704 glcf->upstream.ssl_session_reuse)
4705 != NGX_OK)
4706 {
4707 return NGX_ERROR;
4708 }
4709
4710 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
4711
4712 if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx,
4713 (u_char *) "\x02h2", 3)
4714 != 0)
4715 {
4716 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
4717 "SSL_CTX_set_alpn_protos() failed");
4718 return NGX_ERROR;
4719 }
4720
4721 #endif
4722
4723 return NGX_OK;
4724 }
4725
4726 #endif
4727