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