comparison src/http/v2/ngx_http_v2.c @ 6246:257b51c37c5a

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