1
2 /*
3 * Copyright (C) Nginx, Inc.
4 * Copyright (C) Valentin V. Bartenev
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 #include <ngx_http_v2_module.h>
12
13
14 typedef struct {
15 ngx_str_t name;
16 ngx_uint_t offset;
17 ngx_uint_t hash;
18 ngx_http_header_t *hh;
19 } ngx_http_v2_parse_header_t;
20
21
22 /* errors */
23 #define NGX_HTTP_V2_NO_ERROR 0x0
24 #define NGX_HTTP_V2_PROTOCOL_ERROR 0x1
25 #define NGX_HTTP_V2_INTERNAL_ERROR 0x2
26 #define NGX_HTTP_V2_FLOW_CTRL_ERROR 0x3
27 #define NGX_HTTP_V2_SETTINGS_TIMEOUT 0x4
28 #define NGX_HTTP_V2_STREAM_CLOSED 0x5
29 #define NGX_HTTP_V2_SIZE_ERROR 0x6
30 #define NGX_HTTP_V2_REFUSED_STREAM 0x7
31 #define NGX_HTTP_V2_CANCEL 0x8
32 #define NGX_HTTP_V2_COMP_ERROR 0x9
33 #define NGX_HTTP_V2_CONNECT_ERROR 0xa
34 #define NGX_HTTP_V2_ENHANCE_YOUR_CALM 0xb
35 #define NGX_HTTP_V2_INADEQUATE_SECURITY 0xc
36 #define NGX_HTTP_V2_HTTP_1_1_REQUIRED 0xd
37
38 /* frame sizes */
39 #define NGX_HTTP_V2_SETTINGS_ACK_SIZE 0
40 #define NGX_HTTP_V2_RST_STREAM_SIZE 4
41 #define NGX_HTTP_V2_PRIORITY_SIZE 5
42 #define NGX_HTTP_V2_PING_SIZE 8
43 #define NGX_HTTP_V2_GOAWAY_SIZE 8
44 #define NGX_HTTP_V2_WINDOW_UPDATE_SIZE 4
45
46 #define NGX_HTTP_V2_SETTINGS_PARAM_SIZE 6
47
48 /* settings fields */
49 #define NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING 0x1
50 #define NGX_HTTP_V2_ENABLE_PUSH_SETTING 0x2
51 #define NGX_HTTP_V2_MAX_STREAMS_SETTING 0x3
52 #define NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING 0x4
53 #define NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING 0x5
54
55 #define NGX_HTTP_V2_FRAME_BUFFER_SIZE 24
56
57 #define NGX_HTTP_V2_ROOT (void *) -1
58
59
60 static void ngx_http_v2_read_handler(ngx_event_t *rev);
61 static void ngx_http_v2_write_handler(ngx_event_t *wev);
62 static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c);
63
64 static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c,
65 u_char *pos, u_char *end);
66 static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c,
67 u_char *pos, u_char *end);
68 static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c,
69 u_char *pos, u_char *end);
70 static u_char *ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c,
71 u_char *pos, u_char *end);
72 static u_char *ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c,
73 u_char *pos, u_char *end);
74 static u_char *ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c,
75 u_char *pos, u_char *end);
76 static u_char *ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c,
77 u_char *pos, u_char *end);
78 static u_char *ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c,
79 u_char *pos, u_char *end);
80 static u_char *ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c,
81 u_char *pos, u_char *end);
82 static u_char *ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c,
83 u_char *pos, u_char *end);
84 static u_char *ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c,
85 u_char *pos, u_char *end);
86 static u_char *ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c,
87 u_char *pos, u_char *end);
88 static u_char *ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c,
89 u_char *pos, u_char *end);
90 static u_char *ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c,
91 u_char *pos, u_char *end);
92 static u_char *ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c,
93 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
94 static u_char *ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c,
95 u_char *pos, u_char *end);
96 static u_char *ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c,
97 u_char *pos, u_char *end);
98 static u_char *ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c,
99 u_char *pos, u_char *end);
100 static u_char *ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c,
101 u_char *pos, u_char *end);
102 static u_char *ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c,
103 u_char *pos, u_char *end);
104 static u_char *ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c,
105 u_char *pos, u_char *end);
106 static u_char *ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c,
107 u_char *pos, u_char *end);
108 static u_char *ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c,
109 u_char *pos, u_char *end);
110 static u_char *ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c,
111 u_char *pos, u_char *end);
112 static u_char *ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c,
113 u_char *pos, u_char *end);
114 static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c,
115 u_char *pos, u_char *end);
116 static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c,
117 u_char *pos, u_char *end);
118 static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c,
119 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
120 static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c,
121 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
122 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
123 ngx_uint_t err);
124
125 static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c,
126 u_char **pos, u_char *end, ngx_uint_t prefix);
127
128 static ngx_http_v2_stream_t *ngx_http_v2_create_stream(
129 ngx_http_v2_connection_t *h2c, ngx_uint_t push);
130 static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id(
131 ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc);
132 static ngx_http_v2_node_t *ngx_http_v2_get_closed_node(
133 ngx_http_v2_connection_t *h2c);
134 #define ngx_http_v2_index_size(h2scf) (h2scf->streams_index_mask + 1)
135 #define ngx_http_v2_index(h2scf, sid) ((sid >> 1) & h2scf->streams_index_mask)
136
137 static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c);
138 static ngx_int_t ngx_http_v2_settings_frame_handler(
139 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame);
140 static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c,
141 ngx_uint_t sid, size_t window);
142 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c,
143 ngx_uint_t sid, ngx_uint_t status);
144 static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c,
145 ngx_uint_t status);
146
147 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame(
148 ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type,
149 u_char flags, ngx_uint_t sid);
150 static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
151 ngx_http_v2_out_frame_t *frame);
152
153 static ngx_int_t ngx_http_v2_validate_header(ngx_http_request_t *r,
154 ngx_http_v2_header_t *header);
155 static ngx_int_t ngx_http_v2_pseudo_header(ngx_http_request_t *r,
156 ngx_http_v2_header_t *header);
157 static ngx_int_t ngx_http_v2_parse_path(ngx_http_request_t *r,
158 ngx_str_t *value);
159 static ngx_int_t ngx_http_v2_parse_method(ngx_http_request_t *r,
160 ngx_str_t *value);
161 static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r,
162 ngx_str_t *value);
163 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
164 ngx_str_t *value);
165 static ngx_int_t ngx_http_v2_parse_header(ngx_http_request_t *r,
166 ngx_http_v2_parse_header_t *header, ngx_str_t *value);
167 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
168 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
169 ngx_http_v2_header_t *header);
170 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
171 static void ngx_http_v2_run_request(ngx_http_request_t *r);
172 static void ngx_http_v2_run_request_handler(ngx_event_t *ev);
173 static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
174 u_char *pos, size_t size, ngx_uint_t last);
175 static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r);
176 static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
177
178 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
179 ngx_http_v2_stream_t *stream, ngx_uint_t status);
180 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev);
181 static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev);
182 static void ngx_http_v2_idle_handler(ngx_event_t *rev);
183 static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
184 ngx_uint_t status);
185
186 static ngx_int_t ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c,
187 ssize_t delta);
188 static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
189 ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive);
190 static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node);
191
192 static void ngx_http_v2_pool_cleanup(void *data);
193
194
195 static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = {
196 ngx_http_v2_state_data, /* NGX_HTTP_V2_DATA_FRAME */
197 ngx_http_v2_state_headers, /* NGX_HTTP_V2_HEADERS_FRAME */
198 ngx_http_v2_state_priority, /* NGX_HTTP_V2_PRIORITY_FRAME */
199 ngx_http_v2_state_rst_stream, /* NGX_HTTP_V2_RST_STREAM_FRAME */
200 ngx_http_v2_state_settings, /* NGX_HTTP_V2_SETTINGS_FRAME */
201 ngx_http_v2_state_push_promise, /* NGX_HTTP_V2_PUSH_PROMISE_FRAME */
202 ngx_http_v2_state_ping, /* NGX_HTTP_V2_PING_FRAME */
203 ngx_http_v2_state_goaway, /* NGX_HTTP_V2_GOAWAY_FRAME */
204 ngx_http_v2_state_window_update, /* NGX_HTTP_V2_WINDOW_UPDATE_FRAME */
205 ngx_http_v2_state_continuation /* NGX_HTTP_V2_CONTINUATION_FRAME */
206 };
207
208 #define NGX_HTTP_V2_FRAME_STATES \
209 (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt))
210
211
212 static ngx_http_v2_parse_header_t ngx_http_v2_parse_headers[] = {
213 { ngx_string("host"),
214 offsetof(ngx_http_headers_in_t, host), 0, NULL },
215
216 { ngx_string("accept-encoding"),
217 offsetof(ngx_http_headers_in_t, accept_encoding), 0, NULL },
218
219 { ngx_string("accept-language"),
220 offsetof(ngx_http_headers_in_t, accept_language), 0, NULL },
221
222 { ngx_string("user-agent"),
223 offsetof(ngx_http_headers_in_t, user_agent), 0, NULL },
224
225 { ngx_null_string, 0, 0, NULL }
226 };
227
228
229 void
ngx_http_v2_init(ngx_event_t * rev)230 ngx_http_v2_init(ngx_event_t *rev)
231 {
232 ngx_connection_t *c;
233 ngx_pool_cleanup_t *cln;
234 ngx_http_connection_t *hc;
235 ngx_http_v2_srv_conf_t *h2scf;
236 ngx_http_v2_main_conf_t *h2mcf;
237 ngx_http_v2_connection_t *h2c;
238
239 c = rev->data;
240 hc = c->data;
241
242 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init http2 connection");
243
244 c->log->action = "processing HTTP/2 connection";
245
246 h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module);
247
248 if (h2mcf->recv_buffer == NULL) {
249 h2mcf->recv_buffer = ngx_palloc(ngx_cycle->pool,
250 h2mcf->recv_buffer_size);
251 if (h2mcf->recv_buffer == NULL) {
252 ngx_http_close_connection(c);
253 return;
254 }
255 }
256
257 h2c = ngx_pcalloc(c->pool, sizeof(ngx_http_v2_connection_t));
258 if (h2c == NULL) {
259 ngx_http_close_connection(c);
260 return;
261 }
262
263 h2c->connection = c;
264 h2c->http_connection = hc;
265
266 h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
267 h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
268
269 h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
270
271 h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
272
273 h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
274
275 h2c->concurrent_pushes = h2scf->concurrent_pushes;
276 h2c->priority_limit = h2scf->concurrent_streams;
277
278 h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
279 if (h2c->pool == NULL) {
280 ngx_http_close_connection(c);
281 return;
282 }
283
284 cln = ngx_pool_cleanup_add(c->pool, 0);
285 if (cln == NULL) {
286 ngx_http_close_connection(c);
287 return;
288 }
289
290 cln->handler = ngx_http_v2_pool_cleanup;
291 cln->data = h2c;
292
293 h2c->streams_index = ngx_pcalloc(c->pool, ngx_http_v2_index_size(h2scf)
294 * sizeof(ngx_http_v2_node_t *));
295 if (h2c->streams_index == NULL) {
296 ngx_http_close_connection(c);
297 return;
298 }
299
300 if (ngx_http_v2_send_settings(h2c) == NGX_ERROR) {
301 ngx_http_close_connection(c);
302 return;
303 }
304
305 if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
306 - NGX_HTTP_V2_DEFAULT_WINDOW)
307 == NGX_ERROR)
308 {
309 ngx_http_close_connection(c);
310 return;
311 }
312
313 h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol
314 : ngx_http_v2_state_preface;
315
316 ngx_queue_init(&h2c->waiting);
317 ngx_queue_init(&h2c->dependencies);
318 ngx_queue_init(&h2c->closed);
319
320 c->data = h2c;
321
322 rev->handler = ngx_http_v2_read_handler;
323 c->write->handler = ngx_http_v2_write_handler;
324
325 c->idle = 1;
326
327 ngx_http_v2_read_handler(rev);
328 }
329
330
331 static void
ngx_http_v2_read_handler(ngx_event_t * rev)332 ngx_http_v2_read_handler(ngx_event_t *rev)
333 {
334 u_char *p, *end;
335 size_t available;
336 ssize_t n;
337 ngx_connection_t *c;
338 ngx_http_v2_main_conf_t *h2mcf;
339 ngx_http_v2_connection_t *h2c;
340
341 c = rev->data;
342 h2c = c->data;
343
344 if (rev->timedout) {
345 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
346 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
347 return;
348 }
349
350 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
351
352 h2c->blocked = 1;
353
354 if (c->close) {
355 c->close = 0;
356
357 if (!h2c->goaway) {
358 h2c->goaway = 1;
359
360 if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR)
361 == NGX_ERROR)
362 {
363 ngx_http_v2_finalize_connection(h2c, 0);
364 return;
365 }
366
367 if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
368 ngx_http_v2_finalize_connection(h2c, 0);
369 return;
370 }
371 }
372
373 h2c->blocked = 0;
374
375 return;
376 }
377
378 h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
379 ngx_http_v2_module);
380
381 available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE;
382
383 do {
384 p = h2mcf->recv_buffer;
385
386 ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE);
387 end = p + h2c->state.buffer_used;
388
389 n = c->recv(c, end, available);
390
391 if (n == NGX_AGAIN) {
392 break;
393 }
394
395 if (n == 0
396 && (h2c->state.incomplete || h2c->processing || h2c->pushing))
397 {
398 ngx_log_error(NGX_LOG_INFO, c->log, 0,
399 "client prematurely closed connection");
400 }
401
402 if (n == 0 || n == NGX_ERROR) {
403 c->error = 1;
404 ngx_http_v2_finalize_connection(h2c, 0);
405 return;
406 }
407
408 end += n;
409
410 h2c->state.buffer_used = 0;
411 h2c->state.incomplete = 0;
412
413 do {
414 p = h2c->state.handler(h2c, p, end);
415
416 if (p == NULL) {
417 return;
418 }
419
420 } while (p != end);
421
422 } while (rev->ready);
423
424 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
425 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
426 return;
427 }
428
429 if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
430 ngx_http_v2_finalize_connection(h2c, 0);
431 return;
432 }
433
434 h2c->blocked = 0;
435
436 if (h2c->processing || h2c->pushing) {
437 if (rev->timer_set) {
438 ngx_del_timer(rev);
439 }
440
441 return;
442 }
443
444 ngx_http_v2_handle_connection(h2c);
445 }
446
447
448 static void
ngx_http_v2_write_handler(ngx_event_t * wev)449 ngx_http_v2_write_handler(ngx_event_t *wev)
450 {
451 ngx_int_t rc;
452 ngx_connection_t *c;
453 ngx_http_v2_connection_t *h2c;
454
455 c = wev->data;
456 h2c = c->data;
457
458 if (wev->timedout) {
459 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
460 "http2 write event timed out");
461 c->error = 1;
462 ngx_http_v2_finalize_connection(h2c, 0);
463 return;
464 }
465
466 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler");
467
468 if (h2c->last_out == NULL && !c->buffered) {
469
470 if (wev->timer_set) {
471 ngx_del_timer(wev);
472 }
473
474 ngx_http_v2_handle_connection(h2c);
475 return;
476 }
477
478 h2c->blocked = 1;
479
480 rc = ngx_http_v2_send_output_queue(h2c);
481
482 if (rc == NGX_ERROR) {
483 ngx_http_v2_finalize_connection(h2c, 0);
484 return;
485 }
486
487 h2c->blocked = 0;
488
489 if (rc == NGX_AGAIN) {
490 return;
491 }
492
493 ngx_http_v2_handle_connection(h2c);
494 }
495
496
497 ngx_int_t
ngx_http_v2_send_output_queue(ngx_http_v2_connection_t * h2c)498 ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c)
499 {
500 int tcp_nodelay;
501 ngx_chain_t *cl;
502 ngx_event_t *wev;
503 ngx_connection_t *c;
504 ngx_http_v2_out_frame_t *out, *frame, *fn;
505 ngx_http_core_loc_conf_t *clcf;
506
507 c = h2c->connection;
508
509 if (c->error) {
510 return NGX_ERROR;
511 }
512
513 wev = c->write;
514
515 if (!wev->ready) {
516 return NGX_AGAIN;
517 }
518
519 cl = NULL;
520 out = NULL;
521
522 for (frame = h2c->last_out; frame; frame = fn) {
523 frame->last->next = cl;
524 cl = frame->first;
525
526 fn = frame->next;
527 frame->next = out;
528 out = frame;
529
530 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
531 "http2 frame out: %p sid:%ui bl:%d len:%uz",
532 out, out->stream ? out->stream->node->id : 0,
533 out->blocked, out->length);
534 }
535
536 cl = c->send_chain(c, cl, 0);
537
538 if (cl == NGX_CHAIN_ERROR) {
539 goto error;
540 }
541
542 clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
543 ngx_http_core_module);
544
545 if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
546 goto error;
547 }
548
549 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
550 if (ngx_tcp_push(c->fd) == -1) {
551 ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");
552 goto error;
553 }
554
555 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
556 tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
557
558 } else {
559 tcp_nodelay = 1;
560 }
561
562 if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
563 goto error;
564 }
565
566 for ( /* void */ ; out; out = fn) {
567 fn = out->next;
568
569 if (out->handler(h2c, out) != NGX_OK) {
570 out->blocked = 1;
571 break;
572 }
573
574 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
575 "http2 frame sent: %p sid:%ui bl:%d len:%uz",
576 out, out->stream ? out->stream->node->id : 0,
577 out->blocked, out->length);
578 }
579
580 frame = NULL;
581
582 for ( /* void */ ; out; out = fn) {
583 fn = out->next;
584 out->next = frame;
585 frame = out;
586 }
587
588 h2c->last_out = frame;
589
590 if (!wev->ready) {
591 ngx_add_timer(wev, clcf->send_timeout);
592 return NGX_AGAIN;
593 }
594
595 if (wev->timer_set) {
596 ngx_del_timer(wev);
597 }
598
599 return NGX_OK;
600
601 error:
602
603 c->error = 1;
604
605 if (!h2c->blocked) {
606 ngx_post_event(wev, &ngx_posted_events);
607 }
608
609 return NGX_ERROR;
610 }
611
612
613 static void
ngx_http_v2_handle_connection(ngx_http_v2_connection_t * h2c)614 ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
615 {
616 ngx_int_t rc;
617 ngx_connection_t *c;
618 ngx_http_v2_srv_conf_t *h2scf;
619
620 if (h2c->last_out || h2c->processing || h2c->pushing) {
621 return;
622 }
623
624 c = h2c->connection;
625
626 if (c->error) {
627 ngx_http_close_connection(c);
628 return;
629 }
630
631 if (c->buffered) {
632 h2c->blocked = 1;
633
634 rc = ngx_http_v2_send_output_queue(h2c);
635
636 h2c->blocked = 0;
637
638 if (rc == NGX_ERROR) {
639 ngx_http_close_connection(c);
640 return;
641 }
642
643 if (rc == NGX_AGAIN) {
644 return;
645 }
646
647 /* rc == NGX_OK */
648 }
649
650 if (h2c->goaway) {
651 ngx_http_close_connection(c);
652 return;
653 }
654
655 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
656 ngx_http_v2_module);
657 if (h2c->state.incomplete) {
658 ngx_add_timer(c->read, h2scf->recv_timeout);
659 return;
660 }
661
662 ngx_destroy_pool(h2c->pool);
663
664 h2c->pool = NULL;
665 h2c->free_frames = NULL;
666 h2c->frames = 0;
667 h2c->free_fake_connections = NULL;
668
669 #if (NGX_HTTP_SSL)
670 if (c->ssl) {
671 ngx_ssl_free_buffer(c);
672 }
673 #endif
674
675 c->destroyed = 1;
676 ngx_reusable_connection(c, 1);
677
678 c->write->handler = ngx_http_empty_handler;
679 c->read->handler = ngx_http_v2_idle_handler;
680
681 if (c->write->timer_set) {
682 ngx_del_timer(c->write);
683 }
684
685 ngx_add_timer(c->read, h2scf->idle_timeout);
686 }
687
688
689 static u_char *
ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)690 ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos,
691 u_char *end)
692 {
693 ngx_log_t *log;
694
695 log = h2c->connection->log;
696 log->action = "reading PROXY protocol";
697
698 pos = ngx_proxy_protocol_read(h2c->connection, pos, end);
699
700 log->action = "processing HTTP/2 connection";
701
702 if (pos == NULL) {
703 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
704 }
705
706 return ngx_http_v2_state_preface(h2c, pos, end);
707 }
708
709
710 static u_char *
ngx_http_v2_state_preface(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)711 ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos,
712 u_char *end)
713 {
714 static const u_char preface[] = "PRI * HTTP/2.0\r\n";
715
716 if ((size_t) (end - pos) < sizeof(preface) - 1) {
717 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface);
718 }
719
720 if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
721 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
722 "invalid http2 connection preface \"%*s\"",
723 sizeof(preface) - 1, pos);
724
725 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
726 }
727
728 return ngx_http_v2_state_preface_end(h2c, pos + sizeof(preface) - 1, end);
729 }
730
731
732 static u_char *
ngx_http_v2_state_preface_end(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)733 ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos,
734 u_char *end)
735 {
736 static const u_char preface[] = "\r\nSM\r\n\r\n";
737
738 if ((size_t) (end - pos) < sizeof(preface) - 1) {
739 return ngx_http_v2_state_save(h2c, pos, end,
740 ngx_http_v2_state_preface_end);
741 }
742
743 if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
744 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
745 "invalid http2 connection preface \"%*s\"",
746 sizeof(preface) - 1, pos);
747
748 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
749 }
750
751 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
752 "http2 preface verified");
753
754 return ngx_http_v2_state_head(h2c, pos + sizeof(preface) - 1, end);
755 }
756
757
758 static u_char *
ngx_http_v2_state_head(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)759 ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
760 {
761 uint32_t head;
762 ngx_uint_t type;
763
764 if (end - pos < NGX_HTTP_V2_FRAME_HEADER_SIZE) {
765 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_head);
766 }
767
768 head = ngx_http_v2_parse_uint32(pos);
769
770 h2c->state.length = ngx_http_v2_parse_length(head);
771 h2c->state.flags = pos[4];
772
773 h2c->state.sid = ngx_http_v2_parse_sid(&pos[5]);
774
775 pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
776
777 type = ngx_http_v2_parse_type(head);
778
779 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
780 "http2 frame type:%ui f:%Xd l:%uz sid:%ui",
781 type, h2c->state.flags, h2c->state.length, h2c->state.sid);
782
783 if (type >= NGX_HTTP_V2_FRAME_STATES) {
784 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
785 "client sent frame with unknown type %ui", type);
786 return ngx_http_v2_state_skip(h2c, pos, end);
787 }
788
789 return ngx_http_v2_frame_states[type](h2c, pos, end);
790 }
791
792
793 static u_char *
ngx_http_v2_state_data(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)794 ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
795 {
796 size_t size;
797 ngx_http_v2_node_t *node;
798 ngx_http_v2_stream_t *stream;
799
800 size = h2c->state.length;
801
802 if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
803
804 if (h2c->state.length == 0) {
805 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
806 "client sent padded DATA frame "
807 "with incorrect length: 0");
808
809 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
810 }
811
812 if (end - pos == 0) {
813 return ngx_http_v2_state_save(h2c, pos, end,
814 ngx_http_v2_state_data);
815 }
816
817 h2c->state.padding = *pos++;
818
819 if (h2c->state.padding >= size) {
820 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
821 "client sent padded DATA frame "
822 "with incorrect length: %uz, padding: %uz",
823 size, h2c->state.padding);
824
825 return ngx_http_v2_connection_error(h2c,
826 NGX_HTTP_V2_PROTOCOL_ERROR);
827 }
828
829 h2c->state.length -= 1 + h2c->state.padding;
830 }
831
832 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
833 "http2 DATA frame");
834
835 if (size > h2c->recv_window) {
836 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
837 "client violated connection flow control: "
838 "received DATA frame length %uz, available window %uz",
839 size, h2c->recv_window);
840
841 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
842 }
843
844 h2c->recv_window -= size;
845
846 if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
847
848 if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
849 - h2c->recv_window)
850 == NGX_ERROR)
851 {
852 return ngx_http_v2_connection_error(h2c,
853 NGX_HTTP_V2_INTERNAL_ERROR);
854 }
855
856 h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
857 }
858
859 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
860
861 if (node == NULL || node->stream == NULL) {
862 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
863 "unknown http2 stream");
864
865 return ngx_http_v2_state_skip_padded(h2c, pos, end);
866 }
867
868 stream = node->stream;
869
870 if (size > stream->recv_window) {
871 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
872 "client violated flow control for stream %ui: "
873 "received DATA frame length %uz, available window %uz",
874 node->id, size, stream->recv_window);
875
876 if (ngx_http_v2_terminate_stream(h2c, stream,
877 NGX_HTTP_V2_FLOW_CTRL_ERROR)
878 == NGX_ERROR)
879 {
880 return ngx_http_v2_connection_error(h2c,
881 NGX_HTTP_V2_INTERNAL_ERROR);
882 }
883
884 return ngx_http_v2_state_skip_padded(h2c, pos, end);
885 }
886
887 stream->recv_window -= size;
888
889 if (stream->no_flow_control
890 && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
891 {
892 if (ngx_http_v2_send_window_update(h2c, node->id,
893 NGX_HTTP_V2_MAX_WINDOW
894 - stream->recv_window)
895 == NGX_ERROR)
896 {
897 return ngx_http_v2_connection_error(h2c,
898 NGX_HTTP_V2_INTERNAL_ERROR);
899 }
900
901 stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
902 }
903
904 if (stream->in_closed) {
905 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
906 "client sent DATA frame for half-closed stream %ui",
907 node->id);
908
909 if (ngx_http_v2_terminate_stream(h2c, stream,
910 NGX_HTTP_V2_STREAM_CLOSED)
911 == NGX_ERROR)
912 {
913 return ngx_http_v2_connection_error(h2c,
914 NGX_HTTP_V2_INTERNAL_ERROR);
915 }
916
917 return ngx_http_v2_state_skip_padded(h2c, pos, end);
918 }
919
920 h2c->state.stream = stream;
921
922 return ngx_http_v2_state_read_data(h2c, pos, end);
923 }
924
925
926 static u_char *
ngx_http_v2_state_read_data(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)927 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
928 u_char *end)
929 {
930 size_t size;
931 ngx_buf_t *buf;
932 ngx_int_t rc;
933 ngx_http_request_t *r;
934 ngx_http_v2_stream_t *stream;
935 ngx_http_v2_srv_conf_t *h2scf;
936
937 stream = h2c->state.stream;
938
939 if (stream == NULL) {
940 return ngx_http_v2_state_skip_padded(h2c, pos, end);
941 }
942
943 if (stream->skip_data) {
944 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
945 "skipping http2 DATA frame");
946
947 return ngx_http_v2_state_skip_padded(h2c, pos, end);
948 }
949
950 size = end - pos;
951
952 if (size >= h2c->state.length) {
953 size = h2c->state.length;
954 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
955 }
956
957 r = stream->request;
958
959 if (r->request_body) {
960 rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed);
961
962 if (rc != NGX_OK) {
963 stream->skip_data = 1;
964 ngx_http_finalize_request(r, rc);
965 }
966
967 } else if (size) {
968 buf = stream->preread;
969
970 if (buf == NULL) {
971 h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
972
973 buf = ngx_create_temp_buf(r->pool, h2scf->preread_size);
974 if (buf == NULL) {
975 return ngx_http_v2_connection_error(h2c,
976 NGX_HTTP_V2_INTERNAL_ERROR);
977 }
978
979 stream->preread = buf;
980 }
981
982 if (size > (size_t) (buf->end - buf->last)) {
983 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
984 "http2 preread buffer overflow");
985 return ngx_http_v2_connection_error(h2c,
986 NGX_HTTP_V2_INTERNAL_ERROR);
987 }
988
989 buf->last = ngx_cpymem(buf->last, pos, size);
990 }
991
992 pos += size;
993 h2c->state.length -= size;
994
995 if (h2c->state.length) {
996 return ngx_http_v2_state_save(h2c, pos, end,
997 ngx_http_v2_state_read_data);
998 }
999
1000 if (h2c->state.padding) {
1001 return ngx_http_v2_state_skip_padded(h2c, pos, end);
1002 }
1003
1004 return ngx_http_v2_state_complete(h2c, pos, end);
1005 }
1006
1007
1008 static u_char *
ngx_http_v2_state_headers(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1009 ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
1010 u_char *end)
1011 {
1012 size_t size;
1013 ngx_uint_t padded, priority, depend, dependency, excl, weight;
1014 ngx_uint_t status;
1015 ngx_http_v2_node_t *node;
1016 ngx_http_v2_stream_t *stream;
1017 ngx_http_v2_srv_conf_t *h2scf;
1018
1019 padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG;
1020 priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG;
1021
1022 size = 0;
1023
1024 if (padded) {
1025 size++;
1026 }
1027
1028 if (priority) {
1029 size += sizeof(uint32_t) + 1;
1030 }
1031
1032 if (h2c->state.length < size) {
1033 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1034 "client sent HEADERS frame with incorrect length %uz",
1035 h2c->state.length);
1036
1037 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1038 }
1039
1040 if (h2c->state.length == size) {
1041 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1042 "client sent HEADERS frame with empty header block");
1043
1044 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1045 }
1046
1047 if (h2c->goaway) {
1048 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1049 "skipping http2 HEADERS frame");
1050 return ngx_http_v2_state_skip(h2c, pos, end);
1051 }
1052
1053 if ((size_t) (end - pos) < size) {
1054 return ngx_http_v2_state_save(h2c, pos, end,
1055 ngx_http_v2_state_headers);
1056 }
1057
1058 h2c->state.length -= size;
1059
1060 if (padded) {
1061 h2c->state.padding = *pos++;
1062
1063 if (h2c->state.padding > h2c->state.length) {
1064 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1065 "client sent padded HEADERS frame "
1066 "with incorrect length: %uz, padding: %uz",
1067 h2c->state.length, h2c->state.padding);
1068
1069 return ngx_http_v2_connection_error(h2c,
1070 NGX_HTTP_V2_PROTOCOL_ERROR);
1071 }
1072
1073 h2c->state.length -= h2c->state.padding;
1074 }
1075
1076 depend = 0;
1077 excl = 0;
1078 weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
1079
1080 if (priority) {
1081 dependency = ngx_http_v2_parse_uint32(pos);
1082
1083 depend = dependency & 0x7fffffff;
1084 excl = dependency >> 31;
1085 weight = pos[4] + 1;
1086
1087 pos += sizeof(uint32_t) + 1;
1088 }
1089
1090 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1091 "http2 HEADERS frame sid:%ui "
1092 "depends on %ui excl:%ui weight:%ui",
1093 h2c->state.sid, depend, excl, weight);
1094
1095 if (h2c->state.sid % 2 == 0 || h2c->state.sid <= h2c->last_sid) {
1096 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1097 "client sent HEADERS frame with incorrect identifier "
1098 "%ui, the last was %ui", h2c->state.sid, h2c->last_sid);
1099
1100 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1101 }
1102
1103 h2c->last_sid = h2c->state.sid;
1104
1105 h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
1106 if (h2c->state.pool == NULL) {
1107 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1108 }
1109
1110 if (depend == h2c->state.sid) {
1111 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1112 "client sent HEADERS frame for stream %ui "
1113 "with incorrect dependency", h2c->state.sid);
1114
1115 status = NGX_HTTP_V2_PROTOCOL_ERROR;
1116 goto rst_stream;
1117 }
1118
1119 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1120 ngx_http_v2_module);
1121
1122 h2c->state.header_limit = h2scf->max_header_size;
1123
1124 if (h2c->processing >= h2scf->concurrent_streams) {
1125 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1126 "concurrent streams exceeded %ui", h2c->processing);
1127
1128 status = NGX_HTTP_V2_REFUSED_STREAM;
1129 goto rst_stream;
1130 }
1131
1132 if (!h2c->settings_ack
1133 && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
1134 && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
1135 {
1136 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1137 "client sent stream with data "
1138 "before settings were acknowledged");
1139
1140 status = NGX_HTTP_V2_REFUSED_STREAM;
1141 goto rst_stream;
1142 }
1143
1144 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
1145
1146 if (node == NULL) {
1147 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1148 }
1149
1150 if (node->parent) {
1151 ngx_queue_remove(&node->reuse);
1152 h2c->closed_nodes--;
1153 }
1154
1155 stream = ngx_http_v2_create_stream(h2c, 0);
1156 if (stream == NULL) {
1157 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1158 }
1159
1160 h2c->state.stream = stream;
1161
1162 stream->pool = h2c->state.pool;
1163 h2c->state.keep_pool = 1;
1164
1165 stream->request->request_length = h2c->state.length;
1166
1167 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
1168 stream->node = node;
1169
1170 node->stream = stream;
1171
1172 if (priority || node->parent == NULL) {
1173 node->weight = weight;
1174 ngx_http_v2_set_dependency(h2c, node, depend, excl);
1175 }
1176
1177 if (h2c->connection->requests >= h2scf->max_requests) {
1178 h2c->goaway = 1;
1179
1180 if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) {
1181 return ngx_http_v2_connection_error(h2c,
1182 NGX_HTTP_V2_INTERNAL_ERROR);
1183 }
1184 }
1185
1186 return ngx_http_v2_state_header_block(h2c, pos, end);
1187
1188 rst_stream:
1189
1190 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) {
1191 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1192 }
1193
1194 return ngx_http_v2_state_header_block(h2c, pos, end);
1195 }
1196
1197
1198 static u_char *
ngx_http_v2_state_header_block(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1199 ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos,
1200 u_char *end)
1201 {
1202 u_char ch;
1203 ngx_int_t value;
1204 ngx_uint_t indexed, size_update, prefix;
1205
1206 if (end - pos < 1) {
1207 return ngx_http_v2_state_headers_save(h2c, pos, end,
1208 ngx_http_v2_state_header_block);
1209 }
1210
1211 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1212 && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1213 {
1214 return ngx_http_v2_handle_continuation(h2c, pos, end,
1215 ngx_http_v2_state_header_block);
1216 }
1217
1218 size_update = 0;
1219 indexed = 0;
1220
1221 ch = *pos;
1222
1223 if (ch >= (1 << 7)) {
1224 /* indexed header field */
1225 indexed = 1;
1226 prefix = ngx_http_v2_prefix(7);
1227
1228 } else if (ch >= (1 << 6)) {
1229 /* literal header field with incremental indexing */
1230 h2c->state.index = 1;
1231 prefix = ngx_http_v2_prefix(6);
1232
1233 } else if (ch >= (1 << 5)) {
1234 /* dynamic table size update */
1235 size_update = 1;
1236 prefix = ngx_http_v2_prefix(5);
1237
1238 } else if (ch >= (1 << 4)) {
1239 /* literal header field never indexed */
1240 prefix = ngx_http_v2_prefix(4);
1241
1242 } else {
1243 /* literal header field without indexing */
1244 prefix = ngx_http_v2_prefix(4);
1245 }
1246
1247 value = ngx_http_v2_parse_int(h2c, &pos, end, prefix);
1248
1249 if (value < 0) {
1250 if (value == NGX_AGAIN) {
1251 return ngx_http_v2_state_headers_save(h2c, pos, end,
1252 ngx_http_v2_state_header_block);
1253 }
1254
1255 if (value == NGX_DECLINED) {
1256 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1257 "client sent header block with too long %s value",
1258 size_update ? "size update" : "header index");
1259
1260 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1261 }
1262
1263 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1264 "client sent header block with incorrect length");
1265
1266 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1267 }
1268
1269 if (indexed) {
1270 if (ngx_http_v2_get_indexed_header(h2c, value, 0) != NGX_OK) {
1271 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1272 }
1273
1274 return ngx_http_v2_state_process_header(h2c, pos, end);
1275 }
1276
1277 if (size_update) {
1278 if (ngx_http_v2_table_size(h2c, value) != NGX_OK) {
1279 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1280 }
1281
1282 return ngx_http_v2_state_header_complete(h2c, pos, end);
1283 }
1284
1285 if (value == 0) {
1286 h2c->state.parse_name = 1;
1287
1288 } else if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) {
1289 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1290 }
1291
1292 h2c->state.parse_value = 1;
1293
1294 return ngx_http_v2_state_field_len(h2c, pos, end);
1295 }
1296
1297
1298 static u_char *
ngx_http_v2_state_field_len(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1299 ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos,
1300 u_char *end)
1301 {
1302 size_t alloc;
1303 ngx_int_t len;
1304 ngx_uint_t huff;
1305 ngx_http_v2_srv_conf_t *h2scf;
1306
1307 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1308 && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1309 {
1310 return ngx_http_v2_handle_continuation(h2c, pos, end,
1311 ngx_http_v2_state_field_len);
1312 }
1313
1314 if (h2c->state.length < 1) {
1315 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1316 "client sent header block with incorrect length");
1317
1318 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1319 }
1320
1321 if (end - pos < 1) {
1322 return ngx_http_v2_state_headers_save(h2c, pos, end,
1323 ngx_http_v2_state_field_len);
1324 }
1325
1326 huff = *pos >> 7;
1327 len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7));
1328
1329 if (len < 0) {
1330 if (len == NGX_AGAIN) {
1331 return ngx_http_v2_state_headers_save(h2c, pos, end,
1332 ngx_http_v2_state_field_len);
1333 }
1334
1335 if (len == NGX_DECLINED) {
1336 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1337 "client sent header field with too long length value");
1338
1339 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1340 }
1341
1342 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1343 "client sent header block with incorrect length");
1344
1345 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1346 }
1347
1348 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1349 "http2 %s string, len:%i",
1350 huff ? "encoded" : "raw", len);
1351
1352 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1353 ngx_http_v2_module);
1354
1355 if ((size_t) len > h2scf->max_field_size) {
1356 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1357 "client exceeded http2_max_field_size limit");
1358
1359 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1360 }
1361
1362 h2c->state.field_rest = len;
1363
1364 if (h2c->state.stream == NULL && !h2c->state.index) {
1365 return ngx_http_v2_state_field_skip(h2c, pos, end);
1366 }
1367
1368 alloc = (huff ? len * 8 / 5 : len) + 1;
1369
1370 h2c->state.field_start = ngx_pnalloc(h2c->state.pool, alloc);
1371 if (h2c->state.field_start == NULL) {
1372 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1373 }
1374
1375 h2c->state.field_end = h2c->state.field_start;
1376
1377 if (huff) {
1378 return ngx_http_v2_state_field_huff(h2c, pos, end);
1379 }
1380
1381 return ngx_http_v2_state_field_raw(h2c, pos, end);
1382 }
1383
1384
1385 static u_char *
ngx_http_v2_state_field_huff(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1386 ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos,
1387 u_char *end)
1388 {
1389 size_t size;
1390
1391 size = end - pos;
1392
1393 if (size > h2c->state.field_rest) {
1394 size = h2c->state.field_rest;
1395 }
1396
1397 if (size > h2c->state.length) {
1398 size = h2c->state.length;
1399 }
1400
1401 h2c->state.length -= size;
1402 h2c->state.field_rest -= size;
1403
1404 if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size,
1405 &h2c->state.field_end,
1406 h2c->state.field_rest == 0,
1407 h2c->connection->log)
1408 != NGX_OK)
1409 {
1410 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1411 "client sent invalid encoded header field");
1412
1413 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1414 }
1415
1416 pos += size;
1417
1418 if (h2c->state.field_rest == 0) {
1419 *h2c->state.field_end = '\0';
1420 return ngx_http_v2_state_process_header(h2c, pos, end);
1421 }
1422
1423 if (h2c->state.length) {
1424 return ngx_http_v2_state_headers_save(h2c, pos, end,
1425 ngx_http_v2_state_field_huff);
1426 }
1427
1428 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1429 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1430 "client sent header field with incorrect length");
1431
1432 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1433 }
1434
1435 return ngx_http_v2_handle_continuation(h2c, pos, end,
1436 ngx_http_v2_state_field_huff);
1437 }
1438
1439
1440 static u_char *
ngx_http_v2_state_field_raw(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1441 ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos,
1442 u_char *end)
1443 {
1444 size_t size;
1445
1446 size = end - pos;
1447
1448 if (size > h2c->state.field_rest) {
1449 size = h2c->state.field_rest;
1450 }
1451
1452 if (size > h2c->state.length) {
1453 size = h2c->state.length;
1454 }
1455
1456 h2c->state.length -= size;
1457 h2c->state.field_rest -= size;
1458
1459 h2c->state.field_end = ngx_cpymem(h2c->state.field_end, pos, size);
1460
1461 pos += size;
1462
1463 if (h2c->state.field_rest == 0) {
1464 *h2c->state.field_end = '\0';
1465 return ngx_http_v2_state_process_header(h2c, pos, end);
1466 }
1467
1468 if (h2c->state.length) {
1469 return ngx_http_v2_state_headers_save(h2c, pos, end,
1470 ngx_http_v2_state_field_raw);
1471 }
1472
1473 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1474 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1475 "client sent header field with incorrect length");
1476
1477 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1478 }
1479
1480 return ngx_http_v2_handle_continuation(h2c, pos, end,
1481 ngx_http_v2_state_field_raw);
1482 }
1483
1484
1485 static u_char *
ngx_http_v2_state_field_skip(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1486 ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, u_char *pos,
1487 u_char *end)
1488 {
1489 size_t size;
1490
1491 size = end - pos;
1492
1493 if (size > h2c->state.field_rest) {
1494 size = h2c->state.field_rest;
1495 }
1496
1497 if (size > h2c->state.length) {
1498 size = h2c->state.length;
1499 }
1500
1501 h2c->state.length -= size;
1502 h2c->state.field_rest -= size;
1503
1504 pos += size;
1505
1506 if (h2c->state.field_rest == 0) {
1507 return ngx_http_v2_state_process_header(h2c, pos, end);
1508 }
1509
1510 if (h2c->state.length) {
1511 return ngx_http_v2_state_save(h2c, pos, end,
1512 ngx_http_v2_state_field_skip);
1513 }
1514
1515 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1516 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1517 "client sent header field with incorrect length");
1518
1519 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1520 }
1521
1522 return ngx_http_v2_handle_continuation(h2c, pos, end,
1523 ngx_http_v2_state_field_skip);
1524 }
1525
1526
1527 static u_char *
ngx_http_v2_state_process_header(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1528 ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
1529 u_char *end)
1530 {
1531 size_t len;
1532 ngx_int_t rc;
1533 ngx_table_elt_t *h;
1534 ngx_http_header_t *hh;
1535 ngx_http_request_t *r;
1536 ngx_http_v2_header_t *header;
1537 ngx_http_core_srv_conf_t *cscf;
1538 ngx_http_core_main_conf_t *cmcf;
1539
1540 static ngx_str_t cookie = ngx_string("cookie");
1541
1542 header = &h2c->state.header;
1543
1544 if (h2c->state.parse_name) {
1545 h2c->state.parse_name = 0;
1546
1547 header->name.len = h2c->state.field_end - h2c->state.field_start;
1548 header->name.data = h2c->state.field_start;
1549
1550 if (header->name.len == 0) {
1551 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1552 "client sent zero header name length");
1553
1554 return ngx_http_v2_connection_error(h2c,
1555 NGX_HTTP_V2_PROTOCOL_ERROR);
1556 }
1557
1558 return ngx_http_v2_state_field_len(h2c, pos, end);
1559 }
1560
1561 if (h2c->state.parse_value) {
1562 h2c->state.parse_value = 0;
1563
1564 header->value.len = h2c->state.field_end - h2c->state.field_start;
1565 header->value.data = h2c->state.field_start;
1566 }
1567
1568 len = header->name.len + header->value.len;
1569
1570 if (len > h2c->state.header_limit) {
1571 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1572 "client exceeded http2_max_header_size limit");
1573
1574 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1575 }
1576
1577 h2c->state.header_limit -= len;
1578
1579 if (h2c->state.index) {
1580 if (ngx_http_v2_add_header(h2c, header) != NGX_OK) {
1581 return ngx_http_v2_connection_error(h2c,
1582 NGX_HTTP_V2_INTERNAL_ERROR);
1583 }
1584
1585 h2c->state.index = 0;
1586 }
1587
1588 if (h2c->state.stream == NULL) {
1589 return ngx_http_v2_state_header_complete(h2c, pos, end);
1590 }
1591
1592 r = h2c->state.stream->request;
1593
1594 /* TODO Optimization: validate headers while parsing. */
1595 if (ngx_http_v2_validate_header(r, header) != NGX_OK) {
1596 if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream,
1597 NGX_HTTP_V2_PROTOCOL_ERROR)
1598 == NGX_ERROR)
1599 {
1600 return ngx_http_v2_connection_error(h2c,
1601 NGX_HTTP_V2_INTERNAL_ERROR);
1602 }
1603
1604 goto error;
1605 }
1606
1607 if (header->name.data[0] == ':') {
1608 rc = ngx_http_v2_pseudo_header(r, header);
1609
1610 if (rc == NGX_OK) {
1611 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1612 "http2 header: \":%V: %V\"",
1613 &header->name, &header->value);
1614
1615 return ngx_http_v2_state_header_complete(h2c, pos, end);
1616 }
1617
1618 if (rc == NGX_ABORT) {
1619 goto error;
1620 }
1621
1622 if (rc == NGX_DECLINED) {
1623 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1624 goto error;
1625 }
1626
1627 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1628 }
1629
1630 if (r->invalid_header) {
1631 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1632
1633 if (cscf->ignore_invalid_headers) {
1634 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1635 "client sent invalid header: \"%V\"", &header->name);
1636
1637 return ngx_http_v2_state_header_complete(h2c, pos, end);
1638 }
1639 }
1640
1641 if (header->name.len == cookie.len
1642 && ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0)
1643 {
1644 if (ngx_http_v2_cookie(r, header) != NGX_OK) {
1645 return ngx_http_v2_connection_error(h2c,
1646 NGX_HTTP_V2_INTERNAL_ERROR);
1647 }
1648
1649 } else {
1650 h = ngx_list_push(&r->headers_in.headers);
1651 if (h == NULL) {
1652 return ngx_http_v2_connection_error(h2c,
1653 NGX_HTTP_V2_INTERNAL_ERROR);
1654 }
1655
1656 h->key.len = header->name.len;
1657 h->key.data = header->name.data;
1658
1659 /*
1660 * TODO Optimization: precalculate hash
1661 * and handler for indexed headers.
1662 */
1663 h->hash = ngx_hash_key(h->key.data, h->key.len);
1664
1665 h->value.len = header->value.len;
1666 h->value.data = header->value.data;
1667
1668 h->lowcase_key = h->key.data;
1669
1670 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1671
1672 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1673 h->lowcase_key, h->key.len);
1674
1675 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1676 goto error;
1677 }
1678 }
1679
1680 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1681 "http2 header: \"%V: %V\"",
1682 &header->name, &header->value);
1683
1684 return ngx_http_v2_state_header_complete(h2c, pos, end);
1685
1686 error:
1687
1688 h2c->state.stream = NULL;
1689
1690 return ngx_http_v2_state_header_complete(h2c, pos, end);
1691 }
1692
1693
1694 static u_char *
ngx_http_v2_state_header_complete(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1695 ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
1696 u_char *end)
1697 {
1698 ngx_http_v2_stream_t *stream;
1699
1700 if (h2c->state.length) {
1701 h2c->state.handler = ngx_http_v2_state_header_block;
1702 return pos;
1703 }
1704
1705 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) {
1706 return ngx_http_v2_handle_continuation(h2c, pos, end,
1707 ngx_http_v2_state_header_complete);
1708 }
1709
1710 stream = h2c->state.stream;
1711
1712 if (stream) {
1713 ngx_http_v2_run_request(stream->request);
1714 }
1715
1716 if (!h2c->state.keep_pool) {
1717 ngx_destroy_pool(h2c->state.pool);
1718 }
1719
1720 h2c->state.pool = NULL;
1721 h2c->state.keep_pool = 0;
1722
1723 if (h2c->state.padding) {
1724 return ngx_http_v2_state_skip_padded(h2c, pos, end);
1725 }
1726
1727 return ngx_http_v2_state_complete(h2c, pos, end);
1728 }
1729
1730
1731 static u_char *
ngx_http_v2_handle_continuation(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end,ngx_http_v2_handler_pt handler)1732 ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
1733 u_char *end, ngx_http_v2_handler_pt handler)
1734 {
1735 u_char *p;
1736 size_t len, skip;
1737 uint32_t head;
1738
1739 len = h2c->state.length;
1740
1741 if (h2c->state.padding && (size_t) (end - pos) > len) {
1742 skip = ngx_min(h2c->state.padding, (end - pos) - len);
1743
1744 h2c->state.padding -= skip;
1745
1746 p = pos;
1747 pos += skip;
1748 ngx_memmove(pos, p, len);
1749 }
1750
1751 if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) {
1752 return ngx_http_v2_state_headers_save(h2c, pos, end, handler);
1753 }
1754
1755 p = pos + len;
1756
1757 head = ngx_http_v2_parse_uint32(p);
1758
1759 if (ngx_http_v2_parse_type(head) != NGX_HTTP_V2_CONTINUATION_FRAME) {
1760 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1761 "client sent inappropriate frame while CONTINUATION was expected");
1762
1763 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1764 }
1765
1766 h2c->state.flags |= p[4];
1767
1768 if (h2c->state.sid != ngx_http_v2_parse_sid(&p[5])) {
1769 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1770 "client sent CONTINUATION frame with incorrect identifier");
1771
1772 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1773 }
1774
1775 p = pos;
1776 pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
1777
1778 ngx_memcpy(pos, p, len);
1779
1780 len = ngx_http_v2_parse_length(head);
1781
1782 h2c->state.length += len;
1783
1784 if (h2c->state.stream) {
1785 h2c->state.stream->request->request_length += len;
1786 }
1787
1788 h2c->state.handler = handler;
1789 return pos;
1790 }
1791
1792
1793 static u_char *
ngx_http_v2_state_priority(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1794 ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
1795 u_char *end)
1796 {
1797 ngx_uint_t depend, dependency, excl, weight;
1798 ngx_http_v2_node_t *node;
1799
1800 if (h2c->state.length != NGX_HTTP_V2_PRIORITY_SIZE) {
1801 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1802 "client sent PRIORITY frame with incorrect length %uz",
1803 h2c->state.length);
1804
1805 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1806 }
1807
1808 if (--h2c->priority_limit == 0) {
1809 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1810 "client sent too many PRIORITY frames");
1811
1812 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1813 }
1814
1815 if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) {
1816 return ngx_http_v2_state_save(h2c, pos, end,
1817 ngx_http_v2_state_priority);
1818 }
1819
1820 dependency = ngx_http_v2_parse_uint32(pos);
1821
1822 depend = dependency & 0x7fffffff;
1823 excl = dependency >> 31;
1824 weight = pos[4] + 1;
1825
1826 pos += NGX_HTTP_V2_PRIORITY_SIZE;
1827
1828 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1829 "http2 PRIORITY frame sid:%ui "
1830 "depends on %ui excl:%ui weight:%ui",
1831 h2c->state.sid, depend, excl, weight);
1832
1833 if (h2c->state.sid == 0) {
1834 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1835 "client sent PRIORITY frame with incorrect identifier");
1836
1837 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1838 }
1839
1840 if (depend == h2c->state.sid) {
1841 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1842 "client sent PRIORITY frame for stream %ui "
1843 "with incorrect dependency", h2c->state.sid);
1844
1845 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
1846
1847 if (node && node->stream) {
1848 if (ngx_http_v2_terminate_stream(h2c, node->stream,
1849 NGX_HTTP_V2_PROTOCOL_ERROR)
1850 == NGX_ERROR)
1851 {
1852 return ngx_http_v2_connection_error(h2c,
1853 NGX_HTTP_V2_INTERNAL_ERROR);
1854 }
1855
1856 } else {
1857 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
1858 NGX_HTTP_V2_PROTOCOL_ERROR)
1859 == NGX_ERROR)
1860 {
1861 return ngx_http_v2_connection_error(h2c,
1862 NGX_HTTP_V2_INTERNAL_ERROR);
1863 }
1864 }
1865
1866 return ngx_http_v2_state_complete(h2c, pos, end);
1867 }
1868
1869 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
1870
1871 if (node == NULL) {
1872 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1873 }
1874
1875 node->weight = weight;
1876
1877 if (node->stream == NULL) {
1878 if (node->parent == NULL) {
1879 h2c->closed_nodes++;
1880
1881 } else {
1882 ngx_queue_remove(&node->reuse);
1883 }
1884
1885 ngx_queue_insert_tail(&h2c->closed, &node->reuse);
1886 }
1887
1888 ngx_http_v2_set_dependency(h2c, node, depend, excl);
1889
1890 return ngx_http_v2_state_complete(h2c, pos, end);
1891 }
1892
1893
1894 static u_char *
ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1895 ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos,
1896 u_char *end)
1897 {
1898 ngx_uint_t status;
1899 ngx_event_t *ev;
1900 ngx_connection_t *fc;
1901 ngx_http_v2_node_t *node;
1902 ngx_http_v2_stream_t *stream;
1903
1904 if (h2c->state.length != NGX_HTTP_V2_RST_STREAM_SIZE) {
1905 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1906 "client sent RST_STREAM frame with incorrect length %uz",
1907 h2c->state.length);
1908
1909 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1910 }
1911
1912 if (end - pos < NGX_HTTP_V2_RST_STREAM_SIZE) {
1913 return ngx_http_v2_state_save(h2c, pos, end,
1914 ngx_http_v2_state_rst_stream);
1915 }
1916
1917 status = ngx_http_v2_parse_uint32(pos);
1918
1919 pos += NGX_HTTP_V2_RST_STREAM_SIZE;
1920
1921 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1922 "http2 RST_STREAM frame, sid:%ui status:%ui",
1923 h2c->state.sid, status);
1924
1925 if (h2c->state.sid == 0) {
1926 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1927 "client sent RST_STREAM frame with incorrect identifier");
1928
1929 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1930 }
1931
1932 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
1933
1934 if (node == NULL || node->stream == NULL) {
1935 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1936 "unknown http2 stream");
1937
1938 return ngx_http_v2_state_complete(h2c, pos, end);
1939 }
1940
1941 stream = node->stream;
1942
1943 stream->in_closed = 1;
1944 stream->out_closed = 1;
1945
1946 fc = stream->request->connection;
1947 fc->error = 1;
1948
1949 switch (status) {
1950
1951 case NGX_HTTP_V2_CANCEL:
1952 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1953 "client canceled stream %ui", h2c->state.sid);
1954 break;
1955
1956 case NGX_HTTP_V2_REFUSED_STREAM:
1957 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1958 "client refused stream %ui", h2c->state.sid);
1959 break;
1960
1961 case NGX_HTTP_V2_INTERNAL_ERROR:
1962 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1963 "client terminated stream %ui due to internal error",
1964 h2c->state.sid);
1965 break;
1966
1967 default:
1968 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1969 "client terminated stream %ui with status %ui",
1970 h2c->state.sid, status);
1971 break;
1972 }
1973
1974 ev = fc->read;
1975 ev->handler(ev);
1976
1977 return ngx_http_v2_state_complete(h2c, pos, end);
1978 }
1979
1980
1981 static u_char *
ngx_http_v2_state_settings(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)1982 ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
1983 u_char *end)
1984 {
1985 if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) {
1986
1987 if (h2c->state.length != 0) {
1988 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1989 "client sent SETTINGS frame with the ACK flag "
1990 "and nonzero length");
1991
1992 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1993 }
1994
1995 h2c->settings_ack = 1;
1996
1997 return ngx_http_v2_state_complete(h2c, pos, end);
1998 }
1999
2000 if (h2c->state.length % NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
2001 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2002 "client sent SETTINGS frame with incorrect length %uz",
2003 h2c->state.length);
2004
2005 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2006 }
2007
2008 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2009 "http2 SETTINGS frame");
2010
2011 return ngx_http_v2_state_settings_params(h2c, pos, end);
2012 }
2013
2014
2015 static u_char *
ngx_http_v2_state_settings_params(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2016 ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
2017 u_char *end)
2018 {
2019 ssize_t window_delta;
2020 ngx_uint_t id, value;
2021 ngx_http_v2_srv_conf_t *h2scf;
2022 ngx_http_v2_out_frame_t *frame;
2023
2024 window_delta = 0;
2025
2026 while (h2c->state.length) {
2027 if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
2028 return ngx_http_v2_state_save(h2c, pos, end,
2029 ngx_http_v2_state_settings_params);
2030 }
2031
2032 h2c->state.length -= NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2033
2034 id = ngx_http_v2_parse_uint16(pos);
2035 value = ngx_http_v2_parse_uint32(&pos[2]);
2036
2037 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2038 "http2 setting %ui:%ui", id, value);
2039
2040 switch (id) {
2041
2042 case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING:
2043
2044 if (value > NGX_HTTP_V2_MAX_WINDOW) {
2045 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2046 "client sent SETTINGS frame with incorrect "
2047 "INITIAL_WINDOW_SIZE value %ui", value);
2048
2049 return ngx_http_v2_connection_error(h2c,
2050 NGX_HTTP_V2_FLOW_CTRL_ERROR);
2051 }
2052
2053 window_delta = value - h2c->init_window;
2054 break;
2055
2056 case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING:
2057
2058 if (value > NGX_HTTP_V2_MAX_FRAME_SIZE
2059 || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE)
2060 {
2061 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2062 "client sent SETTINGS frame with incorrect "
2063 "MAX_FRAME_SIZE value %ui", value);
2064
2065 return ngx_http_v2_connection_error(h2c,
2066 NGX_HTTP_V2_PROTOCOL_ERROR);
2067 }
2068
2069 h2c->frame_size = value;
2070 break;
2071
2072 case NGX_HTTP_V2_ENABLE_PUSH_SETTING:
2073
2074 if (value > 1) {
2075 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2076 "client sent SETTINGS frame with incorrect "
2077 "ENABLE_PUSH value %ui", value);
2078
2079 return ngx_http_v2_connection_error(h2c,
2080 NGX_HTTP_V2_PROTOCOL_ERROR);
2081 }
2082
2083 h2c->push_disabled = !value;
2084 break;
2085
2086 case NGX_HTTP_V2_MAX_STREAMS_SETTING:
2087 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2088 ngx_http_v2_module);
2089
2090 h2c->concurrent_pushes = ngx_min(value, h2scf->concurrent_pushes);
2091 break;
2092
2093 case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING:
2094
2095 h2c->table_update = 1;
2096 break;
2097
2098 default:
2099 break;
2100 }
2101
2102 pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2103 }
2104
2105 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE,
2106 NGX_HTTP_V2_SETTINGS_FRAME,
2107 NGX_HTTP_V2_ACK_FLAG, 0);
2108 if (frame == NULL) {
2109 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2110 }
2111
2112 ngx_http_v2_queue_ordered_frame(h2c, frame);
2113
2114 if (window_delta) {
2115 h2c->init_window += window_delta;
2116
2117 if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) {
2118 return ngx_http_v2_connection_error(h2c,
2119 NGX_HTTP_V2_INTERNAL_ERROR);
2120 }
2121 }
2122
2123 return ngx_http_v2_state_complete(h2c, pos, end);
2124 }
2125
2126
2127 static u_char *
ngx_http_v2_state_push_promise(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2128 ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, u_char *pos,
2129 u_char *end)
2130 {
2131 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2132 "client sent PUSH_PROMISE frame");
2133
2134 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2135 }
2136
2137
2138 static u_char *
ngx_http_v2_state_ping(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2139 ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2140 {
2141 ngx_buf_t *buf;
2142 ngx_http_v2_out_frame_t *frame;
2143
2144 if (h2c->state.length != NGX_HTTP_V2_PING_SIZE) {
2145 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2146 "client sent PING frame with incorrect length %uz",
2147 h2c->state.length);
2148
2149 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2150 }
2151
2152 if (end - pos < NGX_HTTP_V2_PING_SIZE) {
2153 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping);
2154 }
2155
2156 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2157 "http2 PING frame");
2158
2159 if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) {
2160 return ngx_http_v2_state_skip(h2c, pos, end);
2161 }
2162
2163 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_PING_SIZE,
2164 NGX_HTTP_V2_PING_FRAME,
2165 NGX_HTTP_V2_ACK_FLAG, 0);
2166 if (frame == NULL) {
2167 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2168 }
2169
2170 buf = frame->first->buf;
2171
2172 buf->last = ngx_cpymem(buf->last, pos, NGX_HTTP_V2_PING_SIZE);
2173
2174 ngx_http_v2_queue_blocked_frame(h2c, frame);
2175
2176 return ngx_http_v2_state_complete(h2c, pos + NGX_HTTP_V2_PING_SIZE, end);
2177 }
2178
2179
2180 static u_char *
ngx_http_v2_state_goaway(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2181 ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos,
2182 u_char *end)
2183 {
2184 #if (NGX_DEBUG)
2185 ngx_uint_t last_sid, error;
2186 #endif
2187
2188 if (h2c->state.length < NGX_HTTP_V2_GOAWAY_SIZE) {
2189 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2190 "client sent GOAWAY frame "
2191 "with incorrect length %uz", h2c->state.length);
2192
2193 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2194 }
2195
2196 if (end - pos < NGX_HTTP_V2_GOAWAY_SIZE) {
2197 return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway);
2198 }
2199
2200 #if (NGX_DEBUG)
2201 h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE;
2202
2203 last_sid = ngx_http_v2_parse_sid(pos);
2204 error = ngx_http_v2_parse_uint32(&pos[4]);
2205
2206 pos += NGX_HTTP_V2_GOAWAY_SIZE;
2207
2208 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2209 "http2 GOAWAY frame: last sid %ui, error %ui",
2210 last_sid, error);
2211 #endif
2212
2213 return ngx_http_v2_state_skip(h2c, pos, end);
2214 }
2215
2216
2217 static u_char *
ngx_http_v2_state_window_update(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2218 ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos,
2219 u_char *end)
2220 {
2221 size_t window;
2222 ngx_event_t *wev;
2223 ngx_queue_t *q;
2224 ngx_http_v2_node_t *node;
2225 ngx_http_v2_stream_t *stream;
2226
2227 if (h2c->state.length != NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2228 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2229 "client sent WINDOW_UPDATE frame "
2230 "with incorrect length %uz", h2c->state.length);
2231
2232 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2233 }
2234
2235 if (end - pos < NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2236 return ngx_http_v2_state_save(h2c, pos, end,
2237 ngx_http_v2_state_window_update);
2238 }
2239
2240 window = ngx_http_v2_parse_window(pos);
2241
2242 pos += NGX_HTTP_V2_WINDOW_UPDATE_SIZE;
2243
2244 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2245 "http2 WINDOW_UPDATE frame sid:%ui window:%uz",
2246 h2c->state.sid, window);
2247
2248 if (window == 0) {
2249 if (h2c->state.sid == 0) {
2250 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2251 "client sent WINDOW_UPDATE frame "
2252 "with incorrect window increment 0");
2253
2254 return ngx_http_v2_connection_error(h2c,
2255 NGX_HTTP_V2_PROTOCOL_ERROR);
2256 }
2257
2258 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2259 "client sent WINDOW_UPDATE frame for stream %ui "
2260 "with incorrect window increment 0", h2c->state.sid);
2261
2262 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2263
2264 if (node && node->stream) {
2265 if (ngx_http_v2_terminate_stream(h2c, node->stream,
2266 NGX_HTTP_V2_PROTOCOL_ERROR)
2267 == NGX_ERROR)
2268 {
2269 return ngx_http_v2_connection_error(h2c,
2270 NGX_HTTP_V2_INTERNAL_ERROR);
2271 }
2272
2273 } else {
2274 if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
2275 NGX_HTTP_V2_PROTOCOL_ERROR)
2276 == NGX_ERROR)
2277 {
2278 return ngx_http_v2_connection_error(h2c,
2279 NGX_HTTP_V2_INTERNAL_ERROR);
2280 }
2281 }
2282
2283 return ngx_http_v2_state_complete(h2c, pos, end);
2284 }
2285
2286 if (h2c->state.sid) {
2287 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2288
2289 if (node == NULL || node->stream == NULL) {
2290 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2291 "unknown http2 stream");
2292
2293 return ngx_http_v2_state_complete(h2c, pos, end);
2294 }
2295
2296 stream = node->stream;
2297
2298 if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) {
2299
2300 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2301 "client violated flow control for stream %ui: "
2302 "received WINDOW_UPDATE frame "
2303 "with window increment %uz "
2304 "not allowed for window %z",
2305 h2c->state.sid, window, stream->send_window);
2306
2307 if (ngx_http_v2_terminate_stream(h2c, stream,
2308 NGX_HTTP_V2_FLOW_CTRL_ERROR)
2309 == NGX_ERROR)
2310 {
2311 return ngx_http_v2_connection_error(h2c,
2312 NGX_HTTP_V2_INTERNAL_ERROR);
2313 }
2314
2315 return ngx_http_v2_state_complete(h2c, pos, end);
2316 }
2317
2318 stream->send_window += window;
2319
2320 if (stream->exhausted) {
2321 stream->exhausted = 0;
2322
2323 wev = stream->request->connection->write;
2324
2325 wev->active = 0;
2326 wev->ready = 1;
2327
2328 if (!wev->delayed) {
2329 wev->handler(wev);
2330 }
2331 }
2332
2333 return ngx_http_v2_state_complete(h2c, pos, end);
2334 }
2335
2336 if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) {
2337 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2338 "client violated connection flow control: "
2339 "received WINDOW_UPDATE frame "
2340 "with window increment %uz "
2341 "not allowed for window %uz",
2342 window, h2c->send_window);
2343
2344 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
2345 }
2346
2347 h2c->send_window += window;
2348
2349 while (!ngx_queue_empty(&h2c->waiting)) {
2350 q = ngx_queue_head(&h2c->waiting);
2351
2352 ngx_queue_remove(q);
2353
2354 stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue);
2355
2356 stream->waiting = 0;
2357
2358 wev = stream->request->connection->write;
2359
2360 wev->active = 0;
2361 wev->ready = 1;
2362
2363 if (!wev->delayed) {
2364 wev->handler(wev);
2365
2366 if (h2c->send_window == 0) {
2367 break;
2368 }
2369 }
2370 }
2371
2372 return ngx_http_v2_state_complete(h2c, pos, end);
2373 }
2374
2375
2376 static u_char *
ngx_http_v2_state_continuation(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2377 ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
2378 u_char *end)
2379 {
2380 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2381 "client sent unexpected CONTINUATION frame");
2382
2383 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2384 }
2385
2386
2387 static u_char *
ngx_http_v2_state_complete(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2388 ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
2389 u_char *end)
2390 {
2391 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2392 "http2 frame complete pos:%p end:%p", pos, end);
2393
2394 if (pos > end) {
2395 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2396 "receive buffer overrun");
2397
2398 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2399 }
2400
2401 h2c->state.stream = NULL;
2402 h2c->state.handler = ngx_http_v2_state_head;
2403
2404 return pos;
2405 }
2406
2407
2408 static u_char *
ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2409 ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos,
2410 u_char *end)
2411 {
2412 h2c->state.length += h2c->state.padding;
2413 h2c->state.padding = 0;
2414
2415 return ngx_http_v2_state_skip(h2c, pos, end);
2416 }
2417
2418
2419 static u_char *
ngx_http_v2_state_skip(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end)2420 ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2421 {
2422 size_t size;
2423
2424 size = end - pos;
2425
2426 if (size < h2c->state.length) {
2427 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2428 "http2 frame skip %uz of %uz", size, h2c->state.length);
2429
2430 h2c->state.length -= size;
2431 return ngx_http_v2_state_save(h2c, end, end, ngx_http_v2_state_skip);
2432 }
2433
2434 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2435 "http2 frame skip %uz", h2c->state.length);
2436
2437 return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end);
2438 }
2439
2440
2441 static u_char *
ngx_http_v2_state_save(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end,ngx_http_v2_handler_pt handler)2442 ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end,
2443 ngx_http_v2_handler_pt handler)
2444 {
2445 size_t size;
2446
2447 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2448 "http2 frame state save pos:%p end:%p handler:%p",
2449 pos, end, handler);
2450
2451 size = end - pos;
2452
2453 if (size > NGX_HTTP_V2_STATE_BUFFER_SIZE) {
2454 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2455 "state buffer overflow: %uz bytes required", size);
2456
2457 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2458 }
2459
2460 ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE);
2461
2462 h2c->state.buffer_used = size;
2463 h2c->state.handler = handler;
2464 h2c->state.incomplete = 1;
2465
2466 return end;
2467 }
2468
2469
2470 static u_char *
ngx_http_v2_state_headers_save(ngx_http_v2_connection_t * h2c,u_char * pos,u_char * end,ngx_http_v2_handler_pt handler)2471 ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos,
2472 u_char *end, ngx_http_v2_handler_pt handler)
2473 {
2474 ngx_event_t *rev;
2475 ngx_http_request_t *r;
2476 ngx_http_core_srv_conf_t *cscf;
2477
2478 if (h2c->state.stream) {
2479 r = h2c->state.stream->request;
2480 rev = r->connection->read;
2481
2482 if (!rev->timer_set) {
2483 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2484 ngx_add_timer(rev, cscf->client_header_timeout);
2485 }
2486 }
2487
2488 return ngx_http_v2_state_save(h2c, pos, end, handler);
2489 }
2490
2491
2492 static u_char *
ngx_http_v2_connection_error(ngx_http_v2_connection_t * h2c,ngx_uint_t err)2493 ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
2494 ngx_uint_t err)
2495 {
2496 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2497 "http2 state connection error");
2498
2499 if (err == NGX_HTTP_V2_INTERNAL_ERROR) {
2500 ngx_debug_point();
2501 }
2502
2503 ngx_http_v2_finalize_connection(h2c, err);
2504
2505 return NULL;
2506 }
2507
2508
2509 static ngx_int_t
ngx_http_v2_parse_int(ngx_http_v2_connection_t * h2c,u_char ** pos,u_char * end,ngx_uint_t prefix)2510 ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end,
2511 ngx_uint_t prefix)
2512 {
2513 u_char *start, *p;
2514 ngx_uint_t value, octet, shift;
2515
2516 start = *pos;
2517 p = start;
2518
2519 value = *p++ & prefix;
2520
2521 if (value != prefix) {
2522 if (h2c->state.length == 0) {
2523 return NGX_ERROR;
2524 }
2525
2526 h2c->state.length--;
2527
2528 *pos = p;
2529 return value;
2530 }
2531
2532 if (end - start > NGX_HTTP_V2_INT_OCTETS) {
2533 end = start + NGX_HTTP_V2_INT_OCTETS;
2534 }
2535
2536 for (shift = 0; p != end; shift += 7) {
2537 octet = *p++;
2538
2539 value += (octet & 0x7f) << shift;
2540
2541 if (octet < 128) {
2542 if ((size_t) (p - start) > h2c->state.length) {
2543 return NGX_ERROR;
2544 }
2545
2546 h2c->state.length -= p - start;
2547
2548 *pos = p;
2549 return value;
2550 }
2551 }
2552
2553 if ((size_t) (end - start) >= h2c->state.length) {
2554 return NGX_ERROR;
2555 }
2556
2557 if (end == start + NGX_HTTP_V2_INT_OCTETS) {
2558 return NGX_DECLINED;
2559 }
2560
2561 return NGX_AGAIN;
2562 }
2563
2564
2565 ngx_http_v2_stream_t *
ngx_http_v2_push_stream(ngx_http_v2_stream_t * parent,ngx_str_t * path)2566 ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path)
2567 {
2568 ngx_int_t rc;
2569 ngx_str_t value;
2570 ngx_pool_t *pool;
2571 ngx_uint_t index;
2572 ngx_table_elt_t **h;
2573 ngx_connection_t *fc;
2574 ngx_http_request_t *r;
2575 ngx_http_v2_node_t *node;
2576 ngx_http_v2_stream_t *stream;
2577 ngx_http_v2_srv_conf_t *h2scf;
2578 ngx_http_v2_connection_t *h2c;
2579 ngx_http_v2_parse_header_t *header;
2580
2581 h2c = parent->connection;
2582
2583 pool = ngx_create_pool(1024, h2c->connection->log);
2584 if (pool == NULL) {
2585 goto rst_stream;
2586 }
2587
2588 node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1);
2589
2590 if (node == NULL) {
2591 ngx_destroy_pool(pool);
2592 goto rst_stream;
2593 }
2594
2595 stream = ngx_http_v2_create_stream(h2c, 1);
2596 if (stream == NULL) {
2597
2598 if (node->parent == NULL) {
2599 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2600 ngx_http_v2_module);
2601
2602 index = ngx_http_v2_index(h2scf, h2c->last_push);
2603 h2c->streams_index[index] = node->index;
2604
2605 ngx_queue_insert_tail(&h2c->closed, &node->reuse);
2606 h2c->closed_nodes++;
2607 }
2608
2609 ngx_destroy_pool(pool);
2610 goto rst_stream;
2611 }
2612
2613 if (node->parent) {
2614 ngx_queue_remove(&node->reuse);
2615 h2c->closed_nodes--;
2616 }
2617
2618 stream->pool = pool;
2619
2620 r = stream->request;
2621 fc = r->connection;
2622
2623 stream->in_closed = 1;
2624 stream->node = node;
2625
2626 node->stream = stream;
2627
2628 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2629 "http2 push stream sid:%ui "
2630 "depends on %ui excl:0 weight:16",
2631 h2c->last_push, parent->node->id);
2632
2633 node->weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
2634 ngx_http_v2_set_dependency(h2c, node, parent->node->id, 0);
2635
2636 r->method_name = ngx_http_core_get_method;
2637 r->method = NGX_HTTP_GET;
2638
2639 r->schema.data = ngx_pstrdup(pool, &parent->request->schema);
2640 if (r->schema.data == NULL) {
2641 goto close;
2642 }
2643
2644 r->schema.len = parent->request->schema.len;
2645
2646 value.data = ngx_pstrdup(pool, path);
2647 if (value.data == NULL) {
2648 goto close;
2649 }
2650
2651 value.len = path->len;
2652
2653 rc = ngx_http_v2_parse_path(r, &value);
2654
2655 if (rc != NGX_OK) {
2656 goto error;
2657 }
2658
2659 for (header = ngx_http_v2_parse_headers; header->name.len; header++) {
2660 h = (ngx_table_elt_t **)
2661 ((char *) &parent->request->headers_in + header->offset);
2662
2663 if (*h == NULL) {
2664 continue;
2665 }
2666
2667 value.len = (*h)->value.len;
2668
2669 value.data = ngx_pnalloc(pool, value.len + 1);
2670 if (value.data == NULL) {
2671 goto close;
2672 }
2673
2674 ngx_memcpy(value.data, (*h)->value.data, value.len);
2675 value.data[value.len] = '\0';
2676
2677 rc = ngx_http_v2_parse_header(r, header, &value);
2678
2679 if (rc != NGX_OK) {
2680 goto error;
2681 }
2682 }
2683
2684 fc->write->handler = ngx_http_v2_run_request_handler;
2685 ngx_post_event(fc->write, &ngx_posted_events);
2686
2687 return stream;
2688
2689 error:
2690
2691 if (rc == NGX_ABORT) {
2692 /* header handler has already finalized request */
2693 ngx_http_run_posted_requests(fc);
2694 return NULL;
2695 }
2696
2697 if (rc == NGX_DECLINED) {
2698 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
2699 ngx_http_run_posted_requests(fc);
2700 return NULL;
2701 }
2702
2703 close:
2704
2705 ngx_http_v2_close_stream(stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
2706
2707 return NULL;
2708
2709 rst_stream:
2710
2711 if (ngx_http_v2_send_rst_stream(h2c, h2c->last_push,
2712 NGX_HTTP_INTERNAL_SERVER_ERROR)
2713 != NGX_OK)
2714 {
2715 h2c->connection->error = 1;
2716 }
2717
2718 return NULL;
2719 }
2720
2721
2722 static ngx_int_t
ngx_http_v2_send_settings(ngx_http_v2_connection_t * h2c)2723 ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c)
2724 {
2725 size_t len;
2726 ngx_buf_t *buf;
2727 ngx_chain_t *cl;
2728 ngx_http_v2_srv_conf_t *h2scf;
2729 ngx_http_v2_out_frame_t *frame;
2730
2731 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2732 "http2 send SETTINGS frame");
2733
2734 frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t));
2735 if (frame == NULL) {
2736 return NGX_ERROR;
2737 }
2738
2739 cl = ngx_alloc_chain_link(h2c->pool);
2740 if (cl == NULL) {
2741 return NGX_ERROR;
2742 }
2743
2744 len = NGX_HTTP_V2_SETTINGS_PARAM_SIZE * 3;
2745
2746 buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len);
2747 if (buf == NULL) {
2748 return NGX_ERROR;
2749 }
2750
2751 buf->last_buf = 1;
2752
2753 cl->buf = buf;
2754 cl->next = NULL;
2755
2756 frame->first = cl;
2757 frame->last = cl;
2758 frame->handler = ngx_http_v2_settings_frame_handler;
2759 frame->stream = NULL;
2760 #if (NGX_DEBUG)
2761 frame->length = len;
2762 #endif
2763 frame->blocked = 0;
2764
2765 buf->last = ngx_http_v2_write_len_and_type(buf->last, len,
2766 NGX_HTTP_V2_SETTINGS_FRAME);
2767
2768 *buf->last++ = NGX_HTTP_V2_NO_FLAG;
2769
2770 buf->last = ngx_http_v2_write_sid(buf->last, 0);
2771
2772 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2773 ngx_http_v2_module);
2774
2775 buf->last = ngx_http_v2_write_uint16(buf->last,
2776 NGX_HTTP_V2_MAX_STREAMS_SETTING);
2777 buf->last = ngx_http_v2_write_uint32(buf->last,
2778 h2scf->concurrent_streams);
2779
2780 buf->last = ngx_http_v2_write_uint16(buf->last,
2781 NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING);
2782 buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size);
2783
2784 buf->last = ngx_http_v2_write_uint16(buf->last,
2785 NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING);
2786 buf->last = ngx_http_v2_write_uint32(buf->last,
2787 NGX_HTTP_V2_MAX_FRAME_SIZE);
2788
2789 ngx_http_v2_queue_blocked_frame(h2c, frame);
2790
2791 return NGX_OK;
2792 }
2793
2794
2795 static ngx_int_t
ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)2796 ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c,
2797 ngx_http_v2_out_frame_t *frame)
2798 {
2799 ngx_buf_t *buf;
2800
2801 buf = frame->first->buf;
2802
2803 if (buf->pos != buf->last) {
2804 return NGX_AGAIN;
2805 }
2806
2807 ngx_free_chain(h2c->pool, frame->first);
2808
2809 return NGX_OK;
2810 }
2811
2812
2813 static ngx_int_t
ngx_http_v2_send_window_update(ngx_http_v2_connection_t * h2c,ngx_uint_t sid,size_t window)2814 ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2815 size_t window)
2816 {
2817 ngx_buf_t *buf;
2818 ngx_http_v2_out_frame_t *frame;
2819
2820 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2821 "http2 send WINDOW_UPDATE frame sid:%ui, window:%uz",
2822 sid, window);
2823
2824 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE,
2825 NGX_HTTP_V2_WINDOW_UPDATE_FRAME,
2826 NGX_HTTP_V2_NO_FLAG, sid);
2827 if (frame == NULL) {
2828 return NGX_ERROR;
2829 }
2830
2831 buf = frame->first->buf;
2832
2833 buf->last = ngx_http_v2_write_uint32(buf->last, window);
2834
2835 ngx_http_v2_queue_blocked_frame(h2c, frame);
2836
2837 return NGX_OK;
2838 }
2839
2840
2841 static ngx_int_t
ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t * h2c,ngx_uint_t sid,ngx_uint_t status)2842 ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2843 ngx_uint_t status)
2844 {
2845 ngx_buf_t *buf;
2846 ngx_http_v2_out_frame_t *frame;
2847
2848 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2849 "http2 send RST_STREAM frame sid:%ui, status:%ui",
2850 sid, status);
2851
2852 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE,
2853 NGX_HTTP_V2_RST_STREAM_FRAME,
2854 NGX_HTTP_V2_NO_FLAG, sid);
2855 if (frame == NULL) {
2856 return NGX_ERROR;
2857 }
2858
2859 buf = frame->first->buf;
2860
2861 buf->last = ngx_http_v2_write_uint32(buf->last, status);
2862
2863 ngx_http_v2_queue_blocked_frame(h2c, frame);
2864
2865 return NGX_OK;
2866 }
2867
2868
2869 static ngx_int_t
ngx_http_v2_send_goaway(ngx_http_v2_connection_t * h2c,ngx_uint_t status)2870 ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status)
2871 {
2872 ngx_buf_t *buf;
2873 ngx_http_v2_out_frame_t *frame;
2874
2875 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2876 "http2 send GOAWAY frame: last sid %ui, error %ui",
2877 h2c->last_sid, status);
2878
2879 frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE,
2880 NGX_HTTP_V2_GOAWAY_FRAME,
2881 NGX_HTTP_V2_NO_FLAG, 0);
2882 if (frame == NULL) {
2883 return NGX_ERROR;
2884 }
2885
2886 buf = frame->first->buf;
2887
2888 buf->last = ngx_http_v2_write_sid(buf->last, h2c->last_sid);
2889 buf->last = ngx_http_v2_write_uint32(buf->last, status);
2890
2891 ngx_http_v2_queue_blocked_frame(h2c, frame);
2892
2893 return NGX_OK;
2894 }
2895
2896
2897 static ngx_http_v2_out_frame_t *
ngx_http_v2_get_frame(ngx_http_v2_connection_t * h2c,size_t length,ngx_uint_t type,u_char flags,ngx_uint_t sid)2898 ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length,
2899 ngx_uint_t type, u_char flags, ngx_uint_t sid)
2900 {
2901 ngx_buf_t *buf;
2902 ngx_pool_t *pool;
2903 ngx_http_v2_out_frame_t *frame;
2904
2905 frame = h2c->free_frames;
2906
2907 if (frame) {
2908 h2c->free_frames = frame->next;
2909
2910 buf = frame->first->buf;
2911 buf->pos = buf->start;
2912
2913 frame->blocked = 0;
2914
2915 } else if (h2c->frames < 10000) {
2916 pool = h2c->pool ? h2c->pool : h2c->connection->pool;
2917
2918 frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t));
2919 if (frame == NULL) {
2920 return NULL;
2921 }
2922
2923 frame->first = ngx_alloc_chain_link(pool);
2924 if (frame->first == NULL) {
2925 return NULL;
2926 }
2927
2928 buf = ngx_create_temp_buf(pool, NGX_HTTP_V2_FRAME_BUFFER_SIZE);
2929 if (buf == NULL) {
2930 return NULL;
2931 }
2932
2933 buf->last_buf = 1;
2934
2935 frame->first->buf = buf;
2936 frame->last = frame->first;
2937
2938 frame->handler = ngx_http_v2_frame_handler;
2939
2940 h2c->frames++;
2941
2942 } else {
2943 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2944 "http2 flood detected");
2945
2946 h2c->connection->error = 1;
2947 return NULL;
2948 }
2949
2950 #if (NGX_DEBUG)
2951 if (length > NGX_HTTP_V2_FRAME_BUFFER_SIZE - NGX_HTTP_V2_FRAME_HEADER_SIZE)
2952 {
2953 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2954 "requested control frame is too large: %uz", length);
2955 return NULL;
2956 }
2957
2958 frame->length = length;
2959 #endif
2960
2961 buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
2962
2963 *buf->last++ = flags;
2964
2965 buf->last = ngx_http_v2_write_sid(buf->last, sid);
2966
2967 return frame;
2968 }
2969
2970
2971 static ngx_int_t
ngx_http_v2_frame_handler(ngx_http_v2_connection_t * h2c,ngx_http_v2_out_frame_t * frame)2972 ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
2973 ngx_http_v2_out_frame_t *frame)
2974 {
2975 ngx_buf_t *buf;
2976
2977 buf = frame->first->buf;
2978
2979 if (buf->pos != buf->last) {
2980 return NGX_AGAIN;
2981 }
2982
2983 frame->next = h2c->free_frames;
2984 h2c->free_frames = frame;
2985
2986 return NGX_OK;
2987 }
2988
2989
2990 static ngx_http_v2_stream_t *
ngx_http_v2_create_stream(ngx_http_v2_connection_t * h2c,ngx_uint_t push)2991 ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push)
2992 {
2993 ngx_log_t *log;
2994 ngx_event_t *rev, *wev;
2995 ngx_connection_t *fc;
2996 ngx_http_log_ctx_t *ctx;
2997 ngx_http_request_t *r;
2998 ngx_http_v2_stream_t *stream;
2999 ngx_http_v2_srv_conf_t *h2scf;
3000 ngx_http_core_srv_conf_t *cscf;
3001
3002 fc = h2c->free_fake_connections;
3003
3004 if (fc) {
3005 h2c->free_fake_connections = fc->data;
3006
3007 rev = fc->read;
3008 wev = fc->write;
3009 log = fc->log;
3010 ctx = log->data;
3011
3012 } else {
3013 fc = ngx_palloc(h2c->pool, sizeof(ngx_connection_t));
3014 if (fc == NULL) {
3015 return NULL;
3016 }
3017
3018 rev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
3019 if (rev == NULL) {
3020 return NULL;
3021 }
3022
3023 wev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
3024 if (wev == NULL) {
3025 return NULL;
3026 }
3027
3028 log = ngx_palloc(h2c->pool, sizeof(ngx_log_t));
3029 if (log == NULL) {
3030 return NULL;
3031 }
3032
3033 ctx = ngx_palloc(h2c->pool, sizeof(ngx_http_log_ctx_t));
3034 if (ctx == NULL) {
3035 return NULL;
3036 }
3037
3038 ctx->connection = fc;
3039 ctx->request = NULL;
3040 ctx->current_request = NULL;
3041 }
3042
3043 ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t));
3044
3045 log->data = ctx;
3046
3047 if (push) {
3048 log->action = "processing pushed request headers";
3049
3050 } else {
3051 log->action = "reading client request headers";
3052 }
3053
3054 ngx_memzero(rev, sizeof(ngx_event_t));
3055
3056 rev->data = fc;
3057 rev->ready = 1;
3058 rev->handler = ngx_http_v2_close_stream_handler;
3059 rev->log = log;
3060
3061 ngx_memcpy(wev, rev, sizeof(ngx_event_t));
3062
3063 wev->write = 1;
3064
3065 ngx_memcpy(fc, h2c->connection, sizeof(ngx_connection_t));
3066
3067 fc->data = h2c->http_connection;
3068 fc->read = rev;
3069 fc->write = wev;
3070 fc->sent = 0;
3071 fc->log = log;
3072 fc->buffered = 0;
3073 fc->sndlowat = 1;
3074 fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
3075
3076 r = ngx_http_create_request(fc);
3077 if (r == NULL) {
3078 return NULL;
3079 }
3080
3081 ngx_str_set(&r->http_protocol, "HTTP/2.0");
3082
3083 r->http_version = NGX_HTTP_VERSION_20;
3084 r->valid_location = 1;
3085
3086 fc->data = r;
3087 h2c->connection->requests++;
3088
3089 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3090
3091 r->header_in = ngx_create_temp_buf(r->pool,
3092 cscf->client_header_buffer_size);
3093 if (r->header_in == NULL) {
3094 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3095 return NULL;
3096 }
3097
3098 if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
3099 sizeof(ngx_table_elt_t))
3100 != NGX_OK)
3101 {
3102 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3103 return NULL;
3104 }
3105
3106 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
3107
3108 stream = ngx_pcalloc(r->pool, sizeof(ngx_http_v2_stream_t));
3109 if (stream == NULL) {
3110 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3111 return NULL;
3112 }
3113
3114 r->stream = stream;
3115
3116 stream->request = r;
3117 stream->connection = h2c;
3118
3119 h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3120
3121 stream->send_window = h2c->init_window;
3122 stream->recv_window = h2scf->preread_size;
3123
3124 if (push) {
3125 h2c->pushing++;
3126
3127 } else {
3128 h2c->processing++;
3129 }
3130
3131 h2c->priority_limit += h2scf->concurrent_streams;
3132
3133 return stream;
3134 }
3135
3136
3137 static ngx_http_v2_node_t *
ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t * h2c,ngx_uint_t sid,ngx_uint_t alloc)3138 ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
3139 ngx_uint_t alloc)
3140 {
3141 ngx_uint_t index;
3142 ngx_http_v2_node_t *node;
3143 ngx_http_v2_srv_conf_t *h2scf;
3144
3145 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3146 ngx_http_v2_module);
3147
3148 index = ngx_http_v2_index(h2scf, sid);
3149
3150 for (node = h2c->streams_index[index]; node; node = node->index) {
3151
3152 if (node->id == sid) {
3153 return node;
3154 }
3155 }
3156
3157 if (!alloc) {
3158 return NULL;
3159 }
3160
3161 if (h2c->closed_nodes < 32) {
3162 node = ngx_pcalloc(h2c->connection->pool, sizeof(ngx_http_v2_node_t));
3163 if (node == NULL) {
3164 return NULL;
3165 }
3166
3167 } else {
3168 node = ngx_http_v2_get_closed_node(h2c);
3169 }
3170
3171 node->id = sid;
3172
3173 ngx_queue_init(&node->children);
3174
3175 node->index = h2c->streams_index[index];
3176 h2c->streams_index[index] = node;
3177
3178 return node;
3179 }
3180
3181
3182 static ngx_http_v2_node_t *
ngx_http_v2_get_closed_node(ngx_http_v2_connection_t * h2c)3183 ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c)
3184 {
3185 ngx_uint_t weight;
3186 ngx_queue_t *q, *children;
3187 ngx_http_v2_node_t *node, **next, *n, *parent, *child;
3188 ngx_http_v2_srv_conf_t *h2scf;
3189
3190 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3191 ngx_http_v2_module);
3192
3193 h2c->closed_nodes--;
3194
3195 q = ngx_queue_head(&h2c->closed);
3196
3197 ngx_queue_remove(q);
3198
3199 node = ngx_queue_data(q, ngx_http_v2_node_t, reuse);
3200
3201 next = &h2c->streams_index[ngx_http_v2_index(h2scf, node->id)];
3202
3203 for ( ;; ) {
3204 n = *next;
3205
3206 if (n == node) {
3207 *next = n->index;
3208 break;
3209 }
3210
3211 next = &n->index;
3212 }
3213
3214 ngx_queue_remove(&node->queue);
3215
3216 weight = 0;
3217
3218 for (q = ngx_queue_head(&node->children);
3219 q != ngx_queue_sentinel(&node->children);
3220 q = ngx_queue_next(q))
3221 {
3222 child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3223 weight += child->weight;
3224 }
3225
3226 parent = node->parent;
3227
3228 for (q = ngx_queue_head(&node->children);
3229 q != ngx_queue_sentinel(&node->children);
3230 q = ngx_queue_next(q))
3231 {
3232 child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3233 child->parent = parent;
3234 child->weight = node->weight * child->weight / weight;
3235
3236 if (child->weight == 0) {
3237 child->weight = 1;
3238 }
3239 }
3240
3241 if (parent == NGX_HTTP_V2_ROOT) {
3242 node->rank = 0;
3243 node->rel_weight = 1.0;
3244
3245 children = &h2c->dependencies;
3246
3247 } else {
3248 node->rank = parent->rank;
3249 node->rel_weight = parent->rel_weight;
3250
3251 children = &parent->children;
3252 }
3253
3254 ngx_http_v2_node_children_update(node);
3255 ngx_queue_add(children, &node->children);
3256
3257 ngx_memzero(node, sizeof(ngx_http_v2_node_t));
3258
3259 return node;
3260 }
3261
3262
3263 static ngx_int_t
ngx_http_v2_validate_header(ngx_http_request_t * r,ngx_http_v2_header_t * header)3264 ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3265 {
3266 u_char ch;
3267 ngx_uint_t i;
3268 ngx_http_core_srv_conf_t *cscf;
3269
3270 r->invalid_header = 0;
3271
3272 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3273
3274 for (i = (header->name.data[0] == ':'); i != header->name.len; i++) {
3275 ch = header->name.data[i];
3276
3277 if ((ch >= 'a' && ch <= 'z')
3278 || (ch == '-')
3279 || (ch >= '0' && ch <= '9')
3280 || (ch == '_' && cscf->underscores_in_headers))
3281 {
3282 continue;
3283 }
3284
3285 if (ch == '\0' || ch == LF || ch == CR || ch == ':'
3286 || (ch >= 'A' && ch <= 'Z'))
3287 {
3288 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3289 "client sent invalid header name: \"%V\"",
3290 &header->name);
3291
3292 return NGX_ERROR;
3293 }
3294
3295 r->invalid_header = 1;
3296 }
3297
3298 for (i = 0; i != header->value.len; i++) {
3299 ch = header->value.data[i];
3300
3301 if (ch == '\0' || ch == LF || ch == CR) {
3302 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3303 "client sent header \"%V\" with "
3304 "invalid value: \"%V\"",
3305 &header->name, &header->value);
3306
3307 return NGX_ERROR;
3308 }
3309 }
3310
3311 return NGX_OK;
3312 }
3313
3314
3315 static ngx_int_t
ngx_http_v2_pseudo_header(ngx_http_request_t * r,ngx_http_v2_header_t * header)3316 ngx_http_v2_pseudo_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3317 {
3318 header->name.len--;
3319 header->name.data++;
3320
3321 switch (header->name.len) {
3322 case 4:
3323 if (ngx_memcmp(header->name.data, "path", sizeof("path") - 1)
3324 == 0)
3325 {
3326 return ngx_http_v2_parse_path(r, &header->value);
3327 }
3328
3329 break;
3330
3331 case 6:
3332 if (ngx_memcmp(header->name.data, "method", sizeof("method") - 1)
3333 == 0)
3334 {
3335 return ngx_http_v2_parse_method(r, &header->value);
3336 }
3337
3338 if (ngx_memcmp(header->name.data, "scheme", sizeof("scheme") - 1)
3339 == 0)
3340 {
3341 return ngx_http_v2_parse_scheme(r, &header->value);
3342 }
3343
3344 break;
3345
3346 case 9:
3347 if (ngx_memcmp(header->name.data, "authority", sizeof("authority") - 1)
3348 == 0)
3349 {
3350 return ngx_http_v2_parse_authority(r, &header->value);
3351 }
3352
3353 break;
3354 }
3355
3356 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3357 "client sent unknown pseudo-header \":%V\"",
3358 &header->name);
3359
3360 return NGX_DECLINED;
3361 }
3362
3363
3364 static ngx_int_t
ngx_http_v2_parse_path(ngx_http_request_t * r,ngx_str_t * value)3365 ngx_http_v2_parse_path(ngx_http_request_t *r, ngx_str_t *value)
3366 {
3367 if (r->unparsed_uri.len) {
3368 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3369 "client sent duplicate :path header");
3370
3371 return NGX_DECLINED;
3372 }
3373
3374 if (value->len == 0) {
3375 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3376 "client sent empty :path header");
3377
3378 return NGX_DECLINED;
3379 }
3380
3381 r->uri_start = value->data;
3382 r->uri_end = value->data + value->len;
3383
3384 if (ngx_http_parse_uri(r) != NGX_OK) {
3385 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3386 "client sent invalid :path header: \"%V\"", value);
3387
3388 return NGX_DECLINED;
3389 }
3390
3391 if (ngx_http_process_request_uri(r) != NGX_OK) {
3392 /*
3393 * request has been finalized already
3394 * in ngx_http_process_request_uri()
3395 */
3396 return NGX_ABORT;
3397 }
3398
3399 return NGX_OK;
3400 }
3401
3402
3403 static ngx_int_t
ngx_http_v2_parse_method(ngx_http_request_t * r,ngx_str_t * value)3404 ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value)
3405 {
3406 size_t k, len;
3407 ngx_uint_t n;
3408 const u_char *p, *m;
3409
3410 /*
3411 * This array takes less than 256 sequential bytes,
3412 * and if typical CPU cache line size is 64 bytes,
3413 * it is prefetched for 4 load operations.
3414 */
3415 static const struct {
3416 u_char len;
3417 const u_char method[11];
3418 uint32_t value;
3419 } tests[] = {
3420 { 3, "GET", NGX_HTTP_GET },
3421 { 4, "POST", NGX_HTTP_POST },
3422 { 4, "HEAD", NGX_HTTP_HEAD },
3423 { 7, "OPTIONS", NGX_HTTP_OPTIONS },
3424 { 8, "PROPFIND", NGX_HTTP_PROPFIND },
3425 { 3, "PUT", NGX_HTTP_PUT },
3426 { 5, "MKCOL", NGX_HTTP_MKCOL },
3427 { 6, "DELETE", NGX_HTTP_DELETE },
3428 { 4, "COPY", NGX_HTTP_COPY },
3429 { 4, "MOVE", NGX_HTTP_MOVE },
3430 { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
3431 { 4, "LOCK", NGX_HTTP_LOCK },
3432 { 6, "UNLOCK", NGX_HTTP_UNLOCK },
3433 { 5, "PATCH", NGX_HTTP_PATCH },
3434 { 5, "TRACE", NGX_HTTP_TRACE }
3435 }, *test;
3436
3437 if (r->method_name.len) {
3438 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3439 "client sent duplicate :method header");
3440
3441 return NGX_DECLINED;
3442 }
3443
3444 if (value->len == 0) {
3445 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3446 "client sent empty :method header");
3447
3448 return NGX_DECLINED;
3449 }
3450
3451 r->method_name.len = value->len;
3452 r->method_name.data = value->data;
3453
3454 len = r->method_name.len;
3455 n = sizeof(tests) / sizeof(tests[0]);
3456 test = tests;
3457
3458 do {
3459 if (len == test->len) {
3460 p = r->method_name.data;
3461 m = test->method;
3462 k = len;
3463
3464 do {
3465 if (*p++ != *m++) {
3466 goto next;
3467 }
3468 } while (--k);
3469
3470 r->method = test->value;
3471 return NGX_OK;
3472 }
3473
3474 next:
3475 test++;
3476
3477 } while (--n);
3478
3479 p = r->method_name.data;
3480
3481 do {
3482 if ((*p < 'A' || *p > 'Z') && *p != '_' && *p != '-') {
3483 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3484 "client sent invalid method: \"%V\"",
3485 &r->method_name);
3486
3487 return NGX_DECLINED;
3488 }
3489
3490 p++;
3491
3492 } while (--len);
3493
3494 return NGX_OK;
3495 }
3496
3497
3498 static ngx_int_t
ngx_http_v2_parse_scheme(ngx_http_request_t * r,ngx_str_t * value)3499 ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value)
3500 {
3501 u_char c, ch;
3502 ngx_uint_t i;
3503
3504 if (r->schema.len) {
3505 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3506 "client sent duplicate :scheme header");
3507
3508 return NGX_DECLINED;
3509 }
3510
3511 if (value->len == 0) {
3512 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3513 "client sent empty :scheme header");
3514
3515 return NGX_DECLINED;
3516 }
3517
3518 for (i = 0; i < value->len; i++) {
3519 ch = value->data[i];
3520
3521 c = (u_char) (ch | 0x20);
3522 if (c >= 'a' && c <= 'z') {
3523 continue;
3524 }
3525
3526 if (((ch >= '0' && ch <= '9') || ch == '+' || ch == '-' || ch == '.')
3527 && i > 0)
3528 {
3529 continue;
3530 }
3531
3532 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3533 "client sent invalid :scheme header: \"%V\"", value);
3534
3535 return NGX_DECLINED;
3536 }
3537
3538 r->schema = *value;
3539
3540 return NGX_OK;
3541 }
3542
3543
3544 static ngx_int_t
ngx_http_v2_parse_authority(ngx_http_request_t * r,ngx_str_t * value)3545 ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value)
3546 {
3547 return ngx_http_v2_parse_header(r, &ngx_http_v2_parse_headers[0], value);
3548 }
3549
3550
3551 static ngx_int_t
ngx_http_v2_parse_header(ngx_http_request_t * r,ngx_http_v2_parse_header_t * header,ngx_str_t * value)3552 ngx_http_v2_parse_header(ngx_http_request_t *r,
3553 ngx_http_v2_parse_header_t *header, ngx_str_t *value)
3554 {
3555 ngx_table_elt_t *h;
3556 ngx_http_core_main_conf_t *cmcf;
3557
3558 h = ngx_list_push(&r->headers_in.headers);
3559 if (h == NULL) {
3560 return NGX_ERROR;
3561 }
3562
3563 h->key.len = header->name.len;
3564 h->key.data = header->name.data;
3565 h->lowcase_key = header->name.data;
3566
3567 if (header->hh == NULL) {
3568 header->hash = ngx_hash_key(header->name.data, header->name.len);
3569
3570 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3571
3572 header->hh = ngx_hash_find(&cmcf->headers_in_hash, header->hash,
3573 h->lowcase_key, h->key.len);
3574 if (header->hh == NULL) {
3575 return NGX_ERROR;
3576 }
3577 }
3578
3579 h->hash = header->hash;
3580
3581 h->value.len = value->len;
3582 h->value.data = value->data;
3583
3584 if (header->hh->handler(r, h, header->hh->offset) != NGX_OK) {
3585 /* header handler has already finalized request */
3586 return NGX_ABORT;
3587 }
3588
3589 return NGX_OK;
3590 }
3591
3592
3593 static ngx_int_t
ngx_http_v2_construct_request_line(ngx_http_request_t * r)3594 ngx_http_v2_construct_request_line(ngx_http_request_t *r)
3595 {
3596 u_char *p;
3597
3598 static const u_char ending[] = " HTTP/2.0";
3599
3600 if (r->method_name.len == 0
3601 || r->schema.len == 0
3602 || r->unparsed_uri.len == 0)
3603 {
3604 if (r->method_name.len == 0) {
3605 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3606 "client sent no :method header");
3607
3608 } else if (r->schema.len == 0) {
3609 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3610 "client sent no :scheme header");
3611
3612 } else {
3613 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3614 "client sent no :path header");
3615 }
3616
3617 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3618 return NGX_ERROR;
3619 }
3620
3621 r->request_line.len = r->method_name.len + 1
3622 + r->unparsed_uri.len
3623 + sizeof(ending) - 1;
3624
3625 p = ngx_pnalloc(r->pool, r->request_line.len + 1);
3626 if (p == NULL) {
3627 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3628 return NGX_ERROR;
3629 }
3630
3631 r->request_line.data = p;
3632
3633 p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
3634
3635 *p++ = ' ';
3636
3637 p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
3638
3639 ngx_memcpy(p, ending, sizeof(ending));
3640
3641 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3642 "http2 request line: \"%V\"", &r->request_line);
3643
3644 return NGX_OK;
3645 }
3646
3647
3648 static ngx_int_t
ngx_http_v2_cookie(ngx_http_request_t * r,ngx_http_v2_header_t * header)3649 ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3650 {
3651 ngx_str_t *val;
3652 ngx_array_t *cookies;
3653
3654 cookies = r->stream->cookies;
3655
3656 if (cookies == NULL) {
3657 cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t));
3658 if (cookies == NULL) {
3659 return NGX_ERROR;
3660 }
3661
3662 r->stream->cookies = cookies;
3663 }
3664
3665 val = ngx_array_push(cookies);
3666 if (val == NULL) {
3667 return NGX_ERROR;
3668 }
3669
3670 val->len = header->value.len;
3671 val->data = header->value.data;
3672
3673 return NGX_OK;
3674 }
3675
3676
3677 static ngx_int_t
ngx_http_v2_construct_cookie_header(ngx_http_request_t * r)3678 ngx_http_v2_construct_cookie_header(ngx_http_request_t *r)
3679 {
3680 u_char *buf, *p, *end;
3681 size_t len;
3682 ngx_str_t *vals;
3683 ngx_uint_t i;
3684 ngx_array_t *cookies;
3685 ngx_table_elt_t *h;
3686 ngx_http_header_t *hh;
3687 ngx_http_core_main_conf_t *cmcf;
3688
3689 static ngx_str_t cookie = ngx_string("cookie");
3690
3691 cookies = r->stream->cookies;
3692
3693 if (cookies == NULL) {
3694 return NGX_OK;
3695 }
3696
3697 vals = cookies->elts;
3698
3699 i = 0;
3700 len = 0;
3701
3702 do {
3703 len += vals[i].len + 2;
3704 } while (++i != cookies->nelts);
3705
3706 len -= 2;
3707
3708 buf = ngx_pnalloc(r->pool, len + 1);
3709 if (buf == NULL) {
3710 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3711 return NGX_ERROR;
3712 }
3713
3714 p = buf;
3715 end = buf + len;
3716
3717 for (i = 0; /* void */ ; i++) {
3718
3719 p = ngx_cpymem(p, vals[i].data, vals[i].len);
3720
3721 if (p == end) {
3722 *p = '\0';
3723 break;
3724 }
3725
3726 *p++ = ';'; *p++ = ' ';
3727 }
3728
3729 h = ngx_list_push(&r->headers_in.headers);
3730 if (h == NULL) {
3731 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3732 return NGX_ERROR;
3733 }
3734
3735 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
3736 ngx_hash('c', 'o'), 'o'), 'k'), 'i'), 'e');
3737
3738 h->key.len = cookie.len;
3739 h->key.data = cookie.data;
3740
3741 h->value.len = len;
3742 h->value.data = buf;
3743
3744 h->lowcase_key = cookie.data;
3745
3746 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3747
3748 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
3749 h->lowcase_key, h->key.len);
3750
3751 if (hh == NULL) {
3752 ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3753 return NGX_ERROR;
3754 }
3755
3756 if (hh->handler(r, h, hh->offset) != NGX_OK) {
3757 /*
3758 * request has been finalized already
3759 * in ngx_http_process_multi_header_lines()
3760 */
3761 return NGX_ERROR;
3762 }
3763
3764 return NGX_OK;
3765 }
3766
3767
3768 static void
ngx_http_v2_run_request(ngx_http_request_t * r)3769 ngx_http_v2_run_request(ngx_http_request_t *r)
3770 {
3771 ngx_connection_t *fc;
3772
3773 fc = r->connection;
3774
3775 if (ngx_http_v2_construct_request_line(r) != NGX_OK) {
3776 goto failed;
3777 }
3778
3779 if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) {
3780 goto failed;
3781 }
3782
3783 r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
3784
3785 if (ngx_http_process_request_header(r) != NGX_OK) {
3786 goto failed;
3787 }
3788
3789 if (r->headers_in.content_length_n > 0 && r->stream->in_closed) {
3790 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3791 "client prematurely closed stream");
3792
3793 r->stream->skip_data = 1;
3794
3795 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3796 goto failed;
3797 }
3798
3799 if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) {
3800 r->headers_in.chunked = 1;
3801 }
3802
3803 ngx_http_process_request(r);
3804
3805 failed:
3806
3807 ngx_http_run_posted_requests(fc);
3808 }
3809
3810
3811 static void
ngx_http_v2_run_request_handler(ngx_event_t * ev)3812 ngx_http_v2_run_request_handler(ngx_event_t *ev)
3813 {
3814 ngx_connection_t *fc;
3815 ngx_http_request_t *r;
3816
3817 fc = ev->data;
3818 r = fc->data;
3819
3820 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
3821 "http2 run request handler");
3822
3823 ngx_http_v2_run_request(r);
3824 }
3825
3826
3827 ngx_int_t
ngx_http_v2_read_request_body(ngx_http_request_t * r)3828 ngx_http_v2_read_request_body(ngx_http_request_t *r)
3829 {
3830 off_t len;
3831 size_t size;
3832 ngx_buf_t *buf;
3833 ngx_int_t rc;
3834 ngx_http_v2_stream_t *stream;
3835 ngx_http_v2_srv_conf_t *h2scf;
3836 ngx_http_request_body_t *rb;
3837 ngx_http_core_loc_conf_t *clcf;
3838 ngx_http_v2_connection_t *h2c;
3839
3840 stream = r->stream;
3841 rb = r->request_body;
3842
3843 if (stream->skip_data) {
3844 r->request_body_no_buffering = 0;
3845 rb->post_handler(r);
3846 return NGX_OK;
3847 }
3848
3849 h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3850 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3851
3852 len = r->headers_in.content_length_n;
3853
3854 if (r->request_body_no_buffering && !stream->in_closed) {
3855
3856 if (len < 0 || len > (off_t) clcf->client_body_buffer_size) {
3857 len = clcf->client_body_buffer_size;
3858 }
3859
3860 /*
3861 * We need a room to store data up to the stream's initial window size,
3862 * at least until this window will be exhausted.
3863 */
3864
3865 if (len < (off_t) h2scf->preread_size) {
3866 len = h2scf->preread_size;
3867 }
3868
3869 if (len > NGX_HTTP_V2_MAX_WINDOW) {
3870 len = NGX_HTTP_V2_MAX_WINDOW;
3871 }
3872
3873 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3874
3875 } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size
3876 && !r->request_body_in_file_only)
3877 {
3878 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3879
3880 } else {
3881 rb->buf = ngx_calloc_buf(r->pool);
3882
3883 if (rb->buf != NULL) {
3884 rb->buf->sync = 1;
3885 }
3886 }
3887
3888 if (rb->buf == NULL) {
3889 stream->skip_data = 1;
3890 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3891 }
3892
3893 rb->rest = 1;
3894
3895 buf = stream->preread;
3896
3897 if (stream->in_closed) {
3898 r->request_body_no_buffering = 0;
3899
3900 if (buf) {
3901 rc = ngx_http_v2_process_request_body(r, buf->pos,
3902 buf->last - buf->pos, 1);
3903 ngx_pfree(r->pool, buf->start);
3904 return rc;
3905 }
3906
3907 return ngx_http_v2_process_request_body(r, NULL, 0, 1);
3908 }
3909
3910 if (buf) {
3911 rc = ngx_http_v2_process_request_body(r, buf->pos,
3912 buf->last - buf->pos, 0);
3913
3914 ngx_pfree(r->pool, buf->start);
3915
3916 if (rc != NGX_OK) {
3917 stream->skip_data = 1;
3918 return rc;
3919 }
3920 }
3921
3922 if (r->request_body_no_buffering) {
3923 size = (size_t) len - h2scf->preread_size;
3924
3925 } else {
3926 stream->no_flow_control = 1;
3927 size = NGX_HTTP_V2_MAX_WINDOW - stream->recv_window;
3928 }
3929
3930 if (size) {
3931 if (ngx_http_v2_send_window_update(stream->connection,
3932 stream->node->id, size)
3933 == NGX_ERROR)
3934 {
3935 stream->skip_data = 1;
3936 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3937 }
3938
3939 h2c = stream->connection;
3940
3941 if (!h2c->blocked) {
3942 if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
3943 stream->skip_data = 1;
3944 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3945 }
3946 }
3947
3948 stream->recv_window += size;
3949 }
3950
3951 if (!buf) {
3952 ngx_add_timer(r->connection->read, clcf->client_body_timeout);
3953 }
3954
3955 r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
3956 r->write_event_handler = ngx_http_request_empty_handler;
3957
3958 return NGX_AGAIN;
3959 }
3960
3961
3962 static ngx_int_t
ngx_http_v2_process_request_body(ngx_http_request_t * r,u_char * pos,size_t size,ngx_uint_t last)3963 ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos,
3964 size_t size, ngx_uint_t last)
3965 {
3966 ngx_buf_t *buf;
3967 ngx_int_t rc;
3968 ngx_connection_t *fc;
3969 ngx_http_request_body_t *rb;
3970 ngx_http_core_loc_conf_t *clcf;
3971
3972 fc = r->connection;
3973 rb = r->request_body;
3974 buf = rb->buf;
3975
3976 if (size) {
3977 if (buf->sync) {
3978 buf->pos = buf->start = pos;
3979 buf->last = buf->end = pos + size;
3980
3981 r->request_body_in_file_only = 1;
3982
3983 } else {
3984 if (size > (size_t) (buf->end - buf->last)) {
3985 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
3986 "client intended to send body data "
3987 "larger than declared");
3988
3989 return NGX_HTTP_BAD_REQUEST;
3990 }
3991
3992 buf->last = ngx_cpymem(buf->last, pos, size);
3993 }
3994 }
3995
3996 if (last) {
3997 rb->rest = 0;
3998
3999 if (fc->read->timer_set) {
4000 ngx_del_timer(fc->read);
4001 }
4002
4003 if (r->request_body_no_buffering) {
4004 ngx_post_event(fc->read, &ngx_posted_events);
4005 return NGX_OK;
4006 }
4007
4008 rc = ngx_http_v2_filter_request_body(r);
4009
4010 if (rc != NGX_OK) {
4011 return rc;
4012 }
4013
4014 if (buf->sync) {
4015 /* prevent reusing this buffer in the upstream module */
4016 rb->buf = NULL;
4017 }
4018
4019 if (r->headers_in.chunked) {
4020 r->headers_in.content_length_n = rb->received;
4021 }
4022
4023 r->read_event_handler = ngx_http_block_reading;
4024 rb->post_handler(r);
4025
4026 return NGX_OK;
4027 }
4028
4029 if (size == 0) {
4030 return NGX_OK;
4031 }
4032
4033 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4034 ngx_add_timer(fc->read, clcf->client_body_timeout);
4035
4036 if (r->request_body_no_buffering) {
4037 ngx_post_event(fc->read, &ngx_posted_events);
4038 return NGX_OK;
4039 }
4040
4041 if (buf->sync) {
4042 return ngx_http_v2_filter_request_body(r);
4043 }
4044
4045 return NGX_OK;
4046 }
4047
4048
4049 static ngx_int_t
ngx_http_v2_filter_request_body(ngx_http_request_t * r)4050 ngx_http_v2_filter_request_body(ngx_http_request_t *r)
4051 {
4052 ngx_buf_t *b, *buf;
4053 ngx_int_t rc;
4054 ngx_chain_t *cl;
4055 ngx_http_request_body_t *rb;
4056 ngx_http_core_loc_conf_t *clcf;
4057
4058 rb = r->request_body;
4059 buf = rb->buf;
4060
4061 if (buf->pos == buf->last && rb->rest) {
4062 cl = NULL;
4063 goto update;
4064 }
4065
4066 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
4067 if (cl == NULL) {
4068 return NGX_HTTP_INTERNAL_SERVER_ERROR;
4069 }
4070
4071 b = cl->buf;
4072
4073 ngx_memzero(b, sizeof(ngx_buf_t));
4074
4075 if (buf->pos != buf->last) {
4076 r->request_length += buf->last - buf->pos;
4077 rb->received += buf->last - buf->pos;
4078
4079 if (r->headers_in.content_length_n != -1) {
4080 if (rb->received > r->headers_in.content_length_n) {
4081 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4082 "client intended to send body data "
4083 "larger than declared");
4084
4085 return NGX_HTTP_BAD_REQUEST;
4086 }
4087
4088 } else {
4089 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4090
4091 if (clcf->client_max_body_size
4092 && rb->received > clcf->client_max_body_size)
4093 {
4094 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4095 "client intended to send too large chunked body: "
4096 "%O bytes", rb->received);
4097
4098 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
4099 }
4100 }
4101
4102 b->temporary = 1;
4103 b->pos = buf->pos;
4104 b->last = buf->last;
4105 b->start = b->pos;
4106 b->end = b->last;
4107
4108 buf->pos = buf->last;
4109 }
4110
4111 if (!rb->rest) {
4112 if (r->headers_in.content_length_n != -1
4113 && r->headers_in.content_length_n != rb->received)
4114 {
4115 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4116 "client prematurely closed stream: "
4117 "only %O out of %O bytes of request body received",
4118 rb->received, r->headers_in.content_length_n);
4119
4120 return NGX_HTTP_BAD_REQUEST;
4121 }
4122
4123 b->last_buf = 1;
4124 }
4125
4126 b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body;
4127 b->flush = r->request_body_no_buffering;
4128
4129 update:
4130
4131 rc = ngx_http_top_request_body_filter(r, cl);
4132
4133 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl,
4134 (ngx_buf_tag_t) &ngx_http_v2_filter_request_body);
4135
4136 return rc;
4137 }
4138
4139
4140 static void
ngx_http_v2_read_client_request_body_handler(ngx_http_request_t * r)4141 ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r)
4142 {
4143 ngx_connection_t *fc;
4144
4145 fc = r->connection;
4146
4147 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4148 "http2 read client request body handler");
4149
4150 if (fc->read->timedout) {
4151 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4152
4153 fc->timedout = 1;
4154 r->stream->skip_data = 1;
4155
4156 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
4157 return;
4158 }
4159
4160 if (fc->error) {
4161 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
4162 "client prematurely closed stream");
4163
4164 r->stream->skip_data = 1;
4165
4166 ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
4167 return;
4168 }
4169 }
4170
4171
4172 ngx_int_t
ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t * r)4173 ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r)
4174 {
4175 size_t window;
4176 ngx_buf_t *buf;
4177 ngx_int_t rc;
4178 ngx_connection_t *fc;
4179 ngx_http_v2_stream_t *stream;
4180 ngx_http_v2_connection_t *h2c;
4181 ngx_http_core_loc_conf_t *clcf;
4182
4183 stream = r->stream;
4184 fc = r->connection;
4185
4186 if (fc->read->timedout) {
4187 if (stream->recv_window) {
4188 stream->skip_data = 1;
4189 fc->timedout = 1;
4190
4191 return NGX_HTTP_REQUEST_TIME_OUT;
4192 }
4193
4194 fc->read->timedout = 0;
4195 }
4196
4197 if (fc->error) {
4198 stream->skip_data = 1;
4199 return NGX_HTTP_BAD_REQUEST;
4200 }
4201
4202 rc = ngx_http_v2_filter_request_body(r);
4203
4204 if (rc != NGX_OK) {
4205 stream->skip_data = 1;
4206 return rc;
4207 }
4208
4209 if (!r->request_body->rest) {
4210 return NGX_OK;
4211 }
4212
4213 if (r->request_body->busy != NULL) {
4214 return NGX_AGAIN;
4215 }
4216
4217 buf = r->request_body->buf;
4218
4219 buf->pos = buf->start;
4220 buf->last = buf->start;
4221
4222 window = buf->end - buf->start;
4223 h2c = stream->connection;
4224
4225 if (h2c->state.stream == stream) {
4226 window -= h2c->state.length;
4227 }
4228
4229 if (window <= stream->recv_window) {
4230 if (window < stream->recv_window) {
4231 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
4232 "http2 negative window update");
4233 stream->skip_data = 1;
4234 return NGX_HTTP_INTERNAL_SERVER_ERROR;
4235 }
4236
4237 return NGX_AGAIN;
4238 }
4239
4240 if (ngx_http_v2_send_window_update(h2c, stream->node->id,
4241 window - stream->recv_window)
4242 == NGX_ERROR)
4243 {
4244 stream->skip_data = 1;
4245 return NGX_HTTP_INTERNAL_SERVER_ERROR;
4246 }
4247
4248 if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4249 stream->skip_data = 1;
4250 return NGX_HTTP_INTERNAL_SERVER_ERROR;
4251 }
4252
4253 if (stream->recv_window == 0) {
4254 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4255 ngx_add_timer(fc->read, clcf->client_body_timeout);
4256 }
4257
4258 stream->recv_window = window;
4259
4260 return NGX_AGAIN;
4261 }
4262
4263
4264 static ngx_int_t
ngx_http_v2_terminate_stream(ngx_http_v2_connection_t * h2c,ngx_http_v2_stream_t * stream,ngx_uint_t status)4265 ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
4266 ngx_http_v2_stream_t *stream, ngx_uint_t status)
4267 {
4268 ngx_event_t *rev;
4269 ngx_connection_t *fc;
4270
4271 if (stream->rst_sent) {
4272 return NGX_OK;
4273 }
4274
4275 if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status)
4276 == NGX_ERROR)
4277 {
4278 return NGX_ERROR;
4279 }
4280
4281 stream->rst_sent = 1;
4282 stream->skip_data = 1;
4283
4284 fc = stream->request->connection;
4285 fc->error = 1;
4286
4287 rev = fc->read;
4288 rev->handler(rev);
4289
4290 return NGX_OK;
4291 }
4292
4293
4294 void
ngx_http_v2_close_stream(ngx_http_v2_stream_t * stream,ngx_int_t rc)4295 ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
4296 {
4297 ngx_pool_t *pool;
4298 ngx_uint_t push;
4299 ngx_event_t *ev;
4300 ngx_connection_t *fc;
4301 ngx_http_v2_node_t *node;
4302 ngx_http_v2_connection_t *h2c;
4303
4304 h2c = stream->connection;
4305 node = stream->node;
4306
4307 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4308 "http2 close stream %ui, queued %ui, "
4309 "processing %ui, pushing %ui",
4310 node->id, stream->queued, h2c->processing, h2c->pushing);
4311
4312 fc = stream->request->connection;
4313
4314 if (stream->queued) {
4315 fc->write->handler = ngx_http_v2_close_stream_handler;
4316 fc->read->handler = ngx_http_empty_handler;
4317 return;
4318 }
4319
4320 if (!stream->rst_sent && !h2c->connection->error) {
4321
4322 if (!stream->out_closed) {
4323 if (ngx_http_v2_send_rst_stream(h2c, node->id,
4324 fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
4325 : NGX_HTTP_V2_INTERNAL_ERROR)
4326 != NGX_OK)
4327 {
4328 h2c->connection->error = 1;
4329 }
4330
4331 } else if (!stream->in_closed) {
4332 #if 0
4333 if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
4334 != NGX_OK)
4335 {
4336 h2c->connection->error = 1;
4337 }
4338 #else
4339 /*
4340 * At the time of writing at least the latest versions of Chrome
4341 * do not properly handle RST_STREAM with NO_ERROR status.
4342 *
4343 * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182
4344 *
4345 * As a workaround, the stream window is maximized before closing
4346 * the stream. This allows a client to send up to 2 GB of data
4347 * before getting blocked on flow control.
4348 */
4349
4350 if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW
4351 && ngx_http_v2_send_window_update(h2c, node->id,
4352 NGX_HTTP_V2_MAX_WINDOW
4353 - stream->recv_window)
4354 != NGX_OK)
4355 {
4356 h2c->connection->error = 1;
4357 }
4358 #endif
4359 }
4360 }
4361
4362 if (h2c->state.stream == stream) {
4363 h2c->state.stream = NULL;
4364 }
4365
4366 push = stream->node->id % 2 == 0;
4367
4368 node->stream = NULL;
4369
4370 ngx_queue_insert_tail(&h2c->closed, &node->reuse);
4371 h2c->closed_nodes++;
4372
4373 /*
4374 * This pool keeps decoded request headers which can be used by log phase
4375 * handlers in ngx_http_free_request().
4376 *
4377 * The pointer is stored into local variable because the stream object
4378 * will be destroyed after a call to ngx_http_free_request().
4379 */
4380 pool = stream->pool;
4381
4382 h2c->frames -= stream->frames;
4383
4384 ngx_http_free_request(stream->request, rc);
4385
4386 if (pool != h2c->state.pool) {
4387 ngx_destroy_pool(pool);
4388
4389 } else {
4390 /* pool will be destroyed when the complete header is parsed */
4391 h2c->state.keep_pool = 0;
4392 }
4393
4394 ev = fc->read;
4395
4396 if (ev->timer_set) {
4397 ngx_del_timer(ev);
4398 }
4399
4400 if (ev->posted) {
4401 ngx_delete_posted_event(ev);
4402 }
4403
4404 ev = fc->write;
4405
4406 if (ev->timer_set) {
4407 ngx_del_timer(ev);
4408 }
4409
4410 if (ev->posted) {
4411 ngx_delete_posted_event(ev);
4412 }
4413
4414 fc->data = h2c->free_fake_connections;
4415 h2c->free_fake_connections = fc;
4416
4417 if (push) {
4418 h2c->pushing--;
4419
4420 } else {
4421 h2c->processing--;
4422 }
4423
4424 if (h2c->processing || h2c->pushing || h2c->blocked) {
4425 return;
4426 }
4427
4428 ev = h2c->connection->read;
4429
4430 ev->handler = ngx_http_v2_handle_connection_handler;
4431 ngx_post_event(ev, &ngx_posted_events);
4432 }
4433
4434
4435 static void
ngx_http_v2_close_stream_handler(ngx_event_t * ev)4436 ngx_http_v2_close_stream_handler(ngx_event_t *ev)
4437 {
4438 ngx_connection_t *fc;
4439 ngx_http_request_t *r;
4440
4441 fc = ev->data;
4442 r = fc->data;
4443
4444 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4445 "http2 close stream handler");
4446
4447 if (ev->timedout) {
4448 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4449
4450 fc->timedout = 1;
4451
4452 ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT);
4453 return;
4454 }
4455
4456 ngx_http_v2_close_stream(r->stream, 0);
4457 }
4458
4459
4460 static void
ngx_http_v2_handle_connection_handler(ngx_event_t * rev)4461 ngx_http_v2_handle_connection_handler(ngx_event_t *rev)
4462 {
4463 ngx_connection_t *c;
4464 ngx_http_v2_connection_t *h2c;
4465
4466 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
4467 "http2 handle connection handler");
4468
4469 c = rev->data;
4470 h2c = c->data;
4471
4472 if (c->error) {
4473 ngx_http_v2_finalize_connection(h2c, 0);
4474 return;
4475 }
4476
4477 rev->handler = ngx_http_v2_read_handler;
4478
4479 if (rev->ready) {
4480 ngx_http_v2_read_handler(rev);
4481 return;
4482 }
4483
4484 if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4485 ngx_http_v2_finalize_connection(h2c, 0);
4486 return;
4487 }
4488
4489 ngx_http_v2_handle_connection(c->data);
4490 }
4491
4492
4493 static void
ngx_http_v2_idle_handler(ngx_event_t * rev)4494 ngx_http_v2_idle_handler(ngx_event_t *rev)
4495 {
4496 ngx_connection_t *c;
4497 ngx_http_v2_srv_conf_t *h2scf;
4498 ngx_http_v2_connection_t *h2c;
4499
4500 c = rev->data;
4501 h2c = c->data;
4502
4503 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 idle handler");
4504
4505 if (rev->timedout || c->close) {
4506 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
4507 return;
4508 }
4509
4510 #if (NGX_HAVE_KQUEUE) || (NGX_HAVE_FSTACK)
4511
4512 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
4513 if (rev->pending_eof) {
4514 c->log->handler = NULL;
4515 ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
4516 "kevent() reported that client %V closed "
4517 "idle connection", &c->addr_text);
4518 #if (NGX_HTTP_SSL)
4519 if (c->ssl) {
4520 c->ssl->no_send_shutdown = 1;
4521 }
4522 #endif
4523 ngx_http_close_connection(c);
4524 return;
4525 }
4526 }
4527
4528 #endif
4529
4530 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4531 ngx_http_v2_module);
4532
4533 if (h2c->idle++ > 10 * h2scf->max_requests) {
4534 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
4535 "http2 flood detected");
4536 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
4537 return;
4538 }
4539
4540 c->destroyed = 0;
4541 ngx_reusable_connection(c, 0);
4542
4543 h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
4544 if (h2c->pool == NULL) {
4545 ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
4546 return;
4547 }
4548
4549 c->write->handler = ngx_http_v2_write_handler;
4550
4551 rev->handler = ngx_http_v2_read_handler;
4552 ngx_http_v2_read_handler(rev);
4553 }
4554
4555
4556 static void
ngx_http_v2_finalize_connection(ngx_http_v2_connection_t * h2c,ngx_uint_t status)4557 ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
4558 ngx_uint_t status)
4559 {
4560 ngx_uint_t i, size;
4561 ngx_event_t *ev;
4562 ngx_connection_t *c, *fc;
4563 ngx_http_request_t *r;
4564 ngx_http_v2_node_t *node;
4565 ngx_http_v2_stream_t *stream;
4566 ngx_http_v2_srv_conf_t *h2scf;
4567
4568 c = h2c->connection;
4569
4570 h2c->blocked = 1;
4571
4572 if (!c->error && !h2c->goaway) {
4573 if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
4574 (void) ngx_http_v2_send_output_queue(h2c);
4575 }
4576 }
4577
4578 c->error = 1;
4579
4580 if (!h2c->processing && !h2c->pushing) {
4581 ngx_http_close_connection(c);
4582 return;
4583 }
4584
4585 c->read->handler = ngx_http_empty_handler;
4586 c->write->handler = ngx_http_empty_handler;
4587
4588 h2c->last_out = NULL;
4589
4590 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4591 ngx_http_v2_module);
4592
4593 size = ngx_http_v2_index_size(h2scf);
4594
4595 for (i = 0; i < size; i++) {
4596
4597 for (node = h2c->streams_index[i]; node; node = node->index) {
4598 stream = node->stream;
4599
4600 if (stream == NULL) {
4601 continue;
4602 }
4603
4604 stream->waiting = 0;
4605
4606 r = stream->request;
4607 fc = r->connection;
4608
4609 fc->error = 1;
4610
4611 if (stream->queued) {
4612 stream->queued = 0;
4613
4614 ev = fc->write;
4615 ev->active = 0;
4616 ev->ready = 1;
4617
4618 } else {
4619 ev = fc->read;
4620 }
4621
4622 ev->eof = 1;
4623 ev->handler(ev);
4624 }
4625 }
4626
4627 h2c->blocked = 0;
4628
4629 if (h2c->processing || h2c->pushing) {
4630 return;
4631 }
4632
4633 ngx_http_close_connection(c);
4634 }
4635
4636
4637 static ngx_int_t
ngx_http_v2_adjust_windows(ngx_http_v2_connection_t * h2c,ssize_t delta)4638 ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta)
4639 {
4640 ngx_uint_t i, size;
4641 ngx_event_t *wev;
4642 ngx_http_v2_node_t *node;
4643 ngx_http_v2_stream_t *stream;
4644 ngx_http_v2_srv_conf_t *h2scf;
4645
4646 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4647 ngx_http_v2_module);
4648
4649 size = ngx_http_v2_index_size(h2scf);
4650
4651 for (i = 0; i < size; i++) {
4652
4653 for (node = h2c->streams_index[i]; node; node = node->index) {
4654 stream = node->stream;
4655
4656 if (stream == NULL) {
4657 continue;
4658 }
4659
4660 if (delta > 0
4661 && stream->send_window
4662 > (ssize_t) (NGX_HTTP_V2_MAX_WINDOW - delta))
4663 {
4664 if (ngx_http_v2_terminate_stream(h2c, stream,
4665 NGX_HTTP_V2_FLOW_CTRL_ERROR)
4666 == NGX_ERROR)
4667 {
4668 return NGX_ERROR;
4669 }
4670
4671 continue;
4672 }
4673
4674 stream->send_window += delta;
4675
4676 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4677 "http2:%ui adjusted window: %z",
4678 node->id, stream->send_window);
4679
4680 if (stream->send_window > 0 && stream->exhausted) {
4681 stream->exhausted = 0;
4682
4683 wev = stream->request->connection->write;
4684
4685 wev->active = 0;
4686 wev->ready = 1;
4687
4688 if (!wev->delayed) {
4689 wev->handler(wev);
4690 }
4691 }
4692 }
4693 }
4694
4695 return NGX_OK;
4696 }
4697
4698
4699 static void
ngx_http_v2_set_dependency(ngx_http_v2_connection_t * h2c,ngx_http_v2_node_t * node,ngx_uint_t depend,ngx_uint_t exclusive)4700 ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
4701 ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive)
4702 {
4703 ngx_queue_t *children, *q;
4704 ngx_http_v2_node_t *parent, *child, *next;
4705
4706 parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL;
4707
4708 if (parent == NULL) {
4709 parent = NGX_HTTP_V2_ROOT;
4710
4711 if (depend != 0) {
4712 exclusive = 0;
4713 }
4714
4715 node->rank = 1;
4716 node->rel_weight = (1.0 / 256) * node->weight;
4717
4718 children = &h2c->dependencies;
4719
4720 } else {
4721 if (node->parent != NULL) {
4722
4723 for (next = parent->parent;
4724 next != NGX_HTTP_V2_ROOT && next->rank >= node->rank;
4725 next = next->parent)
4726 {
4727 if (next != node) {
4728 continue;
4729 }
4730
4731 ngx_queue_remove(&parent->queue);
4732 ngx_queue_insert_after(&node->queue, &parent->queue);
4733
4734 parent->parent = node->parent;
4735
4736 if (node->parent == NGX_HTTP_V2_ROOT) {
4737 parent->rank = 1;
4738 parent->rel_weight = (1.0 / 256) * parent->weight;
4739
4740 } else {
4741 parent->rank = node->parent->rank + 1;
4742 parent->rel_weight = (node->parent->rel_weight / 256)
4743 * parent->weight;
4744 }
4745
4746 if (!exclusive) {
4747 ngx_http_v2_node_children_update(parent);
4748 }
4749
4750 break;
4751 }
4752 }
4753
4754 node->rank = parent->rank + 1;
4755 node->rel_weight = (parent->rel_weight / 256) * node->weight;
4756
4757 if (parent->stream == NULL) {
4758 ngx_queue_remove(&parent->reuse);
4759 ngx_queue_insert_tail(&h2c->closed, &parent->reuse);
4760 }
4761
4762 children = &parent->children;
4763 }
4764
4765 if (exclusive) {
4766 for (q = ngx_queue_head(children);
4767 q != ngx_queue_sentinel(children);
4768 q = ngx_queue_next(q))
4769 {
4770 child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4771 child->parent = node;
4772 }
4773
4774 ngx_queue_add(&node->children, children);
4775 ngx_queue_init(children);
4776 }
4777
4778 if (node->parent != NULL) {
4779 ngx_queue_remove(&node->queue);
4780 }
4781
4782 ngx_queue_insert_tail(children, &node->queue);
4783
4784 node->parent = parent;
4785
4786 ngx_http_v2_node_children_update(node);
4787 }
4788
4789
4790 static void
ngx_http_v2_node_children_update(ngx_http_v2_node_t * node)4791 ngx_http_v2_node_children_update(ngx_http_v2_node_t *node)
4792 {
4793 ngx_queue_t *q;
4794 ngx_http_v2_node_t *child;
4795
4796 for (q = ngx_queue_head(&node->children);
4797 q != ngx_queue_sentinel(&node->children);
4798 q = ngx_queue_next(q))
4799 {
4800 child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4801
4802 child->rank = node->rank + 1;
4803 child->rel_weight = (node->rel_weight / 256) * child->weight;
4804
4805 ngx_http_v2_node_children_update(child);
4806 }
4807 }
4808
4809
4810 static void
ngx_http_v2_pool_cleanup(void * data)4811 ngx_http_v2_pool_cleanup(void *data)
4812 {
4813 ngx_http_v2_connection_t *h2c = data;
4814
4815 if (h2c->state.pool) {
4816 ngx_destroy_pool(h2c->state.pool);
4817 }
4818
4819 if (h2c->pool) {
4820 ngx_destroy_pool(h2c->pool);
4821 }
4822 }
4823