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