Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Nginx, Inc.
0004  * Copyright (C) Valentin V. Bartenev
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 #include <ngx_http_v2_module.h>
0012 
0013 
0014 typedef struct {
0015     ngx_str_t           name;
0016     ngx_uint_t          offset;
0017     ngx_uint_t          hash;
0018     ngx_http_header_t  *hh;
0019 } ngx_http_v2_parse_header_t;
0020 
0021 
0022 /* errors */
0023 #define NGX_HTTP_V2_NO_ERROR                     0x0
0024 #define NGX_HTTP_V2_PROTOCOL_ERROR               0x1
0025 #define NGX_HTTP_V2_INTERNAL_ERROR               0x2
0026 #define NGX_HTTP_V2_FLOW_CTRL_ERROR              0x3
0027 #define NGX_HTTP_V2_SETTINGS_TIMEOUT             0x4
0028 #define NGX_HTTP_V2_STREAM_CLOSED                0x5
0029 #define NGX_HTTP_V2_SIZE_ERROR                   0x6
0030 #define NGX_HTTP_V2_REFUSED_STREAM               0x7
0031 #define NGX_HTTP_V2_CANCEL                       0x8
0032 #define NGX_HTTP_V2_COMP_ERROR                   0x9
0033 #define NGX_HTTP_V2_CONNECT_ERROR                0xa
0034 #define NGX_HTTP_V2_ENHANCE_YOUR_CALM            0xb
0035 #define NGX_HTTP_V2_INADEQUATE_SECURITY          0xc
0036 #define NGX_HTTP_V2_HTTP_1_1_REQUIRED            0xd
0037 
0038 /* frame sizes */
0039 #define NGX_HTTP_V2_SETTINGS_ACK_SIZE            0
0040 #define NGX_HTTP_V2_RST_STREAM_SIZE              4
0041 #define NGX_HTTP_V2_PRIORITY_SIZE                5
0042 #define NGX_HTTP_V2_PING_SIZE                    8
0043 #define NGX_HTTP_V2_GOAWAY_SIZE                  8
0044 #define NGX_HTTP_V2_WINDOW_UPDATE_SIZE           4
0045 
0046 #define NGX_HTTP_V2_SETTINGS_PARAM_SIZE          6
0047 
0048 /* settings fields */
0049 #define NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING    0x1
0050 #define NGX_HTTP_V2_ENABLE_PUSH_SETTING          0x2
0051 #define NGX_HTTP_V2_MAX_STREAMS_SETTING          0x3
0052 #define NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING     0x4
0053 #define NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING       0x5
0054 
0055 #define NGX_HTTP_V2_FRAME_BUFFER_SIZE            24
0056 
0057 #define NGX_HTTP_V2_ROOT                         (void *) -1
0058 
0059 
0060 static void ngx_http_v2_read_handler(ngx_event_t *rev);
0061 static void ngx_http_v2_write_handler(ngx_event_t *wev);
0062 static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c);
0063 
0064 static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c,
0065     u_char *pos, u_char *end);
0066 static u_char *ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c,
0067     u_char *pos, u_char *end);
0068 static u_char *ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c,
0069     u_char *pos, u_char *end);
0070 static u_char *ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c,
0071     u_char *pos, u_char *end);
0072 static u_char *ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c,
0073     u_char *pos, u_char *end);
0074 static u_char *ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c,
0075     u_char *pos, u_char *end);
0076 static u_char *ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c,
0077     u_char *pos, u_char *end);
0078 static u_char *ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c,
0079     u_char *pos, u_char *end);
0080 static u_char *ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c,
0081     u_char *pos, u_char *end);
0082 static u_char *ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c,
0083     u_char *pos, u_char *end);
0084 static u_char *ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c,
0085     u_char *pos, u_char *end);
0086 static u_char *ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c,
0087     u_char *pos, u_char *end);
0088 static u_char *ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c,
0089     u_char *pos, u_char *end);
0090 static u_char *ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c,
0091     u_char *pos, u_char *end);
0092 static u_char *ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c,
0093     u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
0094 static u_char *ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c,
0095     u_char *pos, u_char *end);
0096 static u_char *ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c,
0097     u_char *pos, u_char *end);
0098 static u_char *ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c,
0099     u_char *pos, u_char *end);
0100 static u_char *ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c,
0101     u_char *pos, u_char *end);
0102 static u_char *ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c,
0103     u_char *pos, u_char *end);
0104 static u_char *ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c,
0105     u_char *pos, u_char *end);
0106 static u_char *ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c,
0107     u_char *pos, u_char *end);
0108 static u_char *ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c,
0109     u_char *pos, u_char *end);
0110 static u_char *ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c,
0111     u_char *pos, u_char *end);
0112 static u_char *ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c,
0113     u_char *pos, u_char *end);
0114 static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c,
0115     u_char *pos, u_char *end);
0116 static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c,
0117     u_char *pos, u_char *end);
0118 static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c,
0119     u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
0120 static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c,
0121     u_char *pos, u_char *end, ngx_http_v2_handler_pt handler);
0122 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
0123     ngx_uint_t err);
0124 
0125 static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c,
0126     u_char **pos, u_char *end, ngx_uint_t prefix);
0127 
0128 static ngx_http_v2_stream_t *ngx_http_v2_create_stream(
0129     ngx_http_v2_connection_t *h2c, ngx_uint_t push);
0130 static ngx_http_v2_node_t *ngx_http_v2_get_node_by_id(
0131     ngx_http_v2_connection_t *h2c, ngx_uint_t sid, ngx_uint_t alloc);
0132 static ngx_http_v2_node_t *ngx_http_v2_get_closed_node(
0133     ngx_http_v2_connection_t *h2c);
0134 #define ngx_http_v2_index_size(h2scf)  (h2scf->streams_index_mask + 1)
0135 #define ngx_http_v2_index(h2scf, sid)  ((sid >> 1) & h2scf->streams_index_mask)
0136 
0137 static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c);
0138 static ngx_int_t ngx_http_v2_settings_frame_handler(
0139     ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame);
0140 static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c,
0141     ngx_uint_t sid, size_t window);
0142 static ngx_int_t ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c,
0143     ngx_uint_t sid, ngx_uint_t status);
0144 static ngx_int_t ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c,
0145     ngx_uint_t status);
0146 
0147 static ngx_http_v2_out_frame_t *ngx_http_v2_get_frame(
0148     ngx_http_v2_connection_t *h2c, size_t length, ngx_uint_t type,
0149     u_char flags, ngx_uint_t sid);
0150 static ngx_int_t ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
0151     ngx_http_v2_out_frame_t *frame);
0152 
0153 static ngx_int_t ngx_http_v2_validate_header(ngx_http_request_t *r,
0154     ngx_http_v2_header_t *header);
0155 static ngx_int_t ngx_http_v2_pseudo_header(ngx_http_request_t *r,
0156     ngx_http_v2_header_t *header);
0157 static ngx_int_t ngx_http_v2_parse_path(ngx_http_request_t *r,
0158     ngx_str_t *value);
0159 static ngx_int_t ngx_http_v2_parse_method(ngx_http_request_t *r,
0160     ngx_str_t *value);
0161 static ngx_int_t ngx_http_v2_parse_scheme(ngx_http_request_t *r,
0162     ngx_str_t *value);
0163 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
0164     ngx_str_t *value);
0165 static ngx_int_t ngx_http_v2_parse_header(ngx_http_request_t *r,
0166     ngx_http_v2_parse_header_t *header, ngx_str_t *value);
0167 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
0168 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
0169     ngx_http_v2_header_t *header);
0170 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
0171 static void ngx_http_v2_run_request(ngx_http_request_t *r);
0172 static void ngx_http_v2_run_request_handler(ngx_event_t *ev);
0173 static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
0174     u_char *pos, size_t size, ngx_uint_t last);
0175 static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r);
0176 static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
0177 
0178 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
0179     ngx_http_v2_stream_t *stream, ngx_uint_t status);
0180 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev);
0181 static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev);
0182 static void ngx_http_v2_idle_handler(ngx_event_t *rev);
0183 static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
0184     ngx_uint_t status);
0185 
0186 static ngx_int_t ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c,
0187     ssize_t delta);
0188 static void ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
0189     ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive);
0190 static void ngx_http_v2_node_children_update(ngx_http_v2_node_t *node);
0191 
0192 static void ngx_http_v2_pool_cleanup(void *data);
0193 
0194 
0195 static ngx_http_v2_handler_pt ngx_http_v2_frame_states[] = {
0196     ngx_http_v2_state_data,               /* NGX_HTTP_V2_DATA_FRAME */
0197     ngx_http_v2_state_headers,            /* NGX_HTTP_V2_HEADERS_FRAME */
0198     ngx_http_v2_state_priority,           /* NGX_HTTP_V2_PRIORITY_FRAME */
0199     ngx_http_v2_state_rst_stream,         /* NGX_HTTP_V2_RST_STREAM_FRAME */
0200     ngx_http_v2_state_settings,           /* NGX_HTTP_V2_SETTINGS_FRAME */
0201     ngx_http_v2_state_push_promise,       /* NGX_HTTP_V2_PUSH_PROMISE_FRAME */
0202     ngx_http_v2_state_ping,               /* NGX_HTTP_V2_PING_FRAME */
0203     ngx_http_v2_state_goaway,             /* NGX_HTTP_V2_GOAWAY_FRAME */
0204     ngx_http_v2_state_window_update,      /* NGX_HTTP_V2_WINDOW_UPDATE_FRAME */
0205     ngx_http_v2_state_continuation        /* NGX_HTTP_V2_CONTINUATION_FRAME */
0206 };
0207 
0208 #define NGX_HTTP_V2_FRAME_STATES                                              \
0209     (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt))
0210 
0211 
0212 static ngx_http_v2_parse_header_t  ngx_http_v2_parse_headers[] = {
0213     { ngx_string("host"),
0214       offsetof(ngx_http_headers_in_t, host), 0, NULL },
0215 
0216     { ngx_string("accept-encoding"),
0217       offsetof(ngx_http_headers_in_t, accept_encoding), 0, NULL },
0218 
0219     { ngx_string("accept-language"),
0220       offsetof(ngx_http_headers_in_t, accept_language), 0, NULL },
0221 
0222     { ngx_string("user-agent"),
0223       offsetof(ngx_http_headers_in_t, user_agent), 0, NULL },
0224 
0225     { ngx_null_string, 0, 0, NULL }
0226 };
0227 
0228 
0229 void
0230 ngx_http_v2_init(ngx_event_t *rev)
0231 {
0232     ngx_connection_t          *c;
0233     ngx_pool_cleanup_t        *cln;
0234     ngx_http_connection_t     *hc;
0235     ngx_http_v2_srv_conf_t    *h2scf;
0236     ngx_http_v2_main_conf_t   *h2mcf;
0237     ngx_http_v2_connection_t  *h2c;
0238 
0239     c = rev->data;
0240     hc = c->data;
0241 
0242     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init http2 connection");
0243 
0244     c->log->action = "processing HTTP/2 connection";
0245 
0246     h2mcf = ngx_http_get_module_main_conf(hc->conf_ctx, ngx_http_v2_module);
0247 
0248     if (h2mcf->recv_buffer == NULL) {
0249         h2mcf->recv_buffer = ngx_palloc(ngx_cycle->pool,
0250                                         h2mcf->recv_buffer_size);
0251         if (h2mcf->recv_buffer == NULL) {
0252             ngx_http_close_connection(c);
0253             return;
0254         }
0255     }
0256 
0257     h2c = ngx_pcalloc(c->pool, sizeof(ngx_http_v2_connection_t));
0258     if (h2c == NULL) {
0259         ngx_http_close_connection(c);
0260         return;
0261     }
0262 
0263     h2c->connection = c;
0264     h2c->http_connection = hc;
0265 
0266     h2c->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
0267     h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
0268 
0269     h2c->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
0270 
0271     h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
0272 
0273     h2c->table_update = 1;
0274 
0275     h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
0276 
0277     h2c->concurrent_pushes = h2scf->concurrent_pushes;
0278 
0279     h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
0280     if (h2c->pool == NULL) {
0281         ngx_http_close_connection(c);
0282         return;
0283     }
0284 
0285     cln = ngx_pool_cleanup_add(c->pool, 0);
0286     if (cln == NULL) {
0287         ngx_http_close_connection(c);
0288         return;
0289     }
0290 
0291     cln->handler = ngx_http_v2_pool_cleanup;
0292     cln->data = h2c;
0293 
0294     h2c->streams_index = ngx_pcalloc(c->pool, ngx_http_v2_index_size(h2scf)
0295                                               * sizeof(ngx_http_v2_node_t *));
0296     if (h2c->streams_index == NULL) {
0297         ngx_http_close_connection(c);
0298         return;
0299     }
0300 
0301     if (ngx_http_v2_send_settings(h2c) == NGX_ERROR) {
0302         ngx_http_close_connection(c);
0303         return;
0304     }
0305 
0306     if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
0307                                                - NGX_HTTP_V2_DEFAULT_WINDOW)
0308         == NGX_ERROR)
0309     {
0310         ngx_http_close_connection(c);
0311         return;
0312     }
0313 
0314     h2c->state.handler = hc->proxy_protocol ? ngx_http_v2_state_proxy_protocol
0315                                             : ngx_http_v2_state_preface;
0316 
0317     ngx_queue_init(&h2c->waiting);
0318     ngx_queue_init(&h2c->dependencies);
0319     ngx_queue_init(&h2c->closed);
0320 
0321     c->data = h2c;
0322 
0323     rev->handler = ngx_http_v2_read_handler;
0324     c->write->handler = ngx_http_v2_write_handler;
0325 
0326     c->idle = 1;
0327 
0328     ngx_http_v2_read_handler(rev);
0329 }
0330 
0331 
0332 static void
0333 ngx_http_v2_read_handler(ngx_event_t *rev)
0334 {
0335     u_char                    *p, *end;
0336     size_t                     available;
0337     ssize_t                    n;
0338     ngx_connection_t          *c;
0339     ngx_http_v2_main_conf_t   *h2mcf;
0340     ngx_http_v2_connection_t  *h2c;
0341 
0342     c = rev->data;
0343     h2c = c->data;
0344 
0345     if (rev->timedout) {
0346         ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
0347         ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
0348         return;
0349     }
0350 
0351     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 read handler");
0352 
0353     h2c->blocked = 1;
0354 
0355     if (c->close) {
0356         c->close = 0;
0357 
0358         if (!h2c->goaway) {
0359             h2c->goaway = 1;
0360 
0361             if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR)
0362                 == NGX_ERROR)
0363             {
0364                 ngx_http_v2_finalize_connection(h2c, 0);
0365                 return;
0366             }
0367 
0368             if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
0369                 ngx_http_v2_finalize_connection(h2c, 0);
0370                 return;
0371             }
0372         }
0373 
0374         h2c->blocked = 0;
0375 
0376         return;
0377     }
0378 
0379     h2mcf = ngx_http_get_module_main_conf(h2c->http_connection->conf_ctx,
0380                                           ngx_http_v2_module);
0381 
0382     available = h2mcf->recv_buffer_size - 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE;
0383 
0384     do {
0385         p = h2mcf->recv_buffer;
0386 
0387         ngx_memcpy(p, h2c->state.buffer, NGX_HTTP_V2_STATE_BUFFER_SIZE);
0388         end = p + h2c->state.buffer_used;
0389 
0390         n = c->recv(c, end, available);
0391 
0392         if (n == NGX_AGAIN) {
0393             break;
0394         }
0395 
0396         if (n == 0
0397             && (h2c->state.incomplete || h2c->processing || h2c->pushing))
0398         {
0399             ngx_log_error(NGX_LOG_INFO, c->log, 0,
0400                           "client prematurely closed connection");
0401         }
0402 
0403         if (n == 0 || n == NGX_ERROR) {
0404             c->error = 1;
0405             ngx_http_v2_finalize_connection(h2c, 0);
0406             return;
0407         }
0408 
0409         end += n;
0410 
0411         h2c->state.buffer_used = 0;
0412         h2c->state.incomplete = 0;
0413 
0414         do {
0415             p = h2c->state.handler(h2c, p, end);
0416 
0417             if (p == NULL) {
0418                 return;
0419             }
0420 
0421         } while (p != end);
0422 
0423     } while (rev->ready);
0424 
0425     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
0426         ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
0427         return;
0428     }
0429 
0430     if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
0431         ngx_http_v2_finalize_connection(h2c, 0);
0432         return;
0433     }
0434 
0435     h2c->blocked = 0;
0436 
0437     if (h2c->processing || h2c->pushing) {
0438         if (rev->timer_set) {
0439             ngx_del_timer(rev);
0440         }
0441 
0442         return;
0443     }
0444 
0445     ngx_http_v2_handle_connection(h2c);
0446 }
0447 
0448 
0449 static void
0450 ngx_http_v2_write_handler(ngx_event_t *wev)
0451 {
0452     ngx_int_t                  rc;
0453     ngx_connection_t          *c;
0454     ngx_http_v2_connection_t  *h2c;
0455 
0456     c = wev->data;
0457     h2c = c->data;
0458 
0459     if (wev->timedout) {
0460         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
0461                        "http2 write event timed out");
0462         c->error = 1;
0463         ngx_http_v2_finalize_connection(h2c, 0);
0464         return;
0465     }
0466 
0467     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 write handler");
0468 
0469     if (h2c->last_out == NULL && !c->buffered) {
0470 
0471         if (wev->timer_set) {
0472             ngx_del_timer(wev);
0473         }
0474 
0475         ngx_http_v2_handle_connection(h2c);
0476         return;
0477     }
0478 
0479     h2c->blocked = 1;
0480 
0481     rc = ngx_http_v2_send_output_queue(h2c);
0482 
0483     if (rc == NGX_ERROR) {
0484         ngx_http_v2_finalize_connection(h2c, 0);
0485         return;
0486     }
0487 
0488     h2c->blocked = 0;
0489 
0490     if (rc == NGX_AGAIN) {
0491         return;
0492     }
0493 
0494     ngx_http_v2_handle_connection(h2c);
0495 }
0496 
0497 
0498 ngx_int_t
0499 ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c)
0500 {
0501     int                        tcp_nodelay;
0502     ngx_chain_t               *cl;
0503     ngx_event_t               *wev;
0504     ngx_connection_t          *c;
0505     ngx_http_v2_out_frame_t   *out, *frame, *fn;
0506     ngx_http_core_loc_conf_t  *clcf;
0507 
0508     c = h2c->connection;
0509 
0510     if (c->error) {
0511         return NGX_ERROR;
0512     }
0513 
0514     wev = c->write;
0515 
0516     if (!wev->ready) {
0517         return NGX_AGAIN;
0518     }
0519 
0520     cl = NULL;
0521     out = NULL;
0522 
0523     for (frame = h2c->last_out; frame; frame = fn) {
0524         frame->last->next = cl;
0525         cl = frame->first;
0526 
0527         fn = frame->next;
0528         frame->next = out;
0529         out = frame;
0530 
0531         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
0532                        "http2 frame out: %p sid:%ui bl:%d len:%uz",
0533                        out, out->stream ? out->stream->node->id : 0,
0534                        out->blocked, out->length);
0535     }
0536 
0537     cl = c->send_chain(c, cl, 0);
0538 
0539     if (cl == NGX_CHAIN_ERROR) {
0540         goto error;
0541     }
0542 
0543     clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
0544                                         ngx_http_core_module);
0545 
0546     if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
0547         goto error;
0548     }
0549 
0550     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
0551         if (ngx_tcp_push(c->fd) == -1) {
0552             ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed");
0553             goto error;
0554         }
0555 
0556         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
0557         tcp_nodelay = ngx_tcp_nodelay_and_tcp_nopush ? 1 : 0;
0558 
0559     } else {
0560         tcp_nodelay = 1;
0561     }
0562 
0563     if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
0564         goto error;
0565     }
0566 
0567     for ( /* void */ ; out; out = fn) {
0568         fn = out->next;
0569 
0570         if (out->handler(h2c, out) != NGX_OK) {
0571             out->blocked = 1;
0572             break;
0573         }
0574 
0575         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, c->log, 0,
0576                        "http2 frame sent: %p sid:%ui bl:%d len:%uz",
0577                        out, out->stream ? out->stream->node->id : 0,
0578                        out->blocked, out->length);
0579     }
0580 
0581     frame = NULL;
0582 
0583     for ( /* void */ ; out; out = fn) {
0584         fn = out->next;
0585         out->next = frame;
0586         frame = out;
0587     }
0588 
0589     h2c->last_out = frame;
0590 
0591     if (!wev->ready) {
0592         ngx_add_timer(wev, clcf->send_timeout);
0593         return NGX_AGAIN;
0594     }
0595 
0596     if (wev->timer_set) {
0597         ngx_del_timer(wev);
0598     }
0599 
0600     return NGX_OK;
0601 
0602 error:
0603 
0604     c->error = 1;
0605 
0606     if (!h2c->blocked) {
0607         ngx_post_event(wev, &ngx_posted_events);
0608     }
0609 
0610     return NGX_ERROR;
0611 }
0612 
0613 
0614 static void
0615 ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
0616 {
0617     ngx_int_t                rc;
0618     ngx_connection_t        *c;
0619     ngx_http_v2_srv_conf_t  *h2scf;
0620 
0621     if (h2c->last_out || h2c->processing || h2c->pushing) {
0622         return;
0623     }
0624 
0625     c = h2c->connection;
0626 
0627     if (c->error) {
0628         ngx_http_close_connection(c);
0629         return;
0630     }
0631 
0632     if (c->buffered) {
0633         h2c->blocked = 1;
0634 
0635         rc = ngx_http_v2_send_output_queue(h2c);
0636 
0637         h2c->blocked = 0;
0638 
0639         if (rc == NGX_ERROR) {
0640             ngx_http_close_connection(c);
0641             return;
0642         }
0643 
0644         if (rc == NGX_AGAIN) {
0645             return;
0646         }
0647 
0648         /* rc == NGX_OK */
0649     }
0650 
0651     if (h2c->goaway) {
0652         ngx_http_close_connection(c);
0653         return;
0654     }
0655 
0656     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
0657                                          ngx_http_v2_module);
0658     if (h2c->state.incomplete) {
0659         ngx_add_timer(c->read, h2scf->recv_timeout);
0660         return;
0661     }
0662 
0663     ngx_destroy_pool(h2c->pool);
0664 
0665     h2c->pool = NULL;
0666     h2c->free_frames = NULL;
0667     h2c->free_fake_connections = NULL;
0668 
0669 #if (NGX_HTTP_SSL)
0670     if (c->ssl) {
0671         ngx_ssl_free_buffer(c);
0672     }
0673 #endif
0674 
0675     c->destroyed = 1;
0676     ngx_reusable_connection(c, 1);
0677 
0678     c->write->handler = ngx_http_empty_handler;
0679     c->read->handler = ngx_http_v2_idle_handler;
0680 
0681     if (c->write->timer_set) {
0682         ngx_del_timer(c->write);
0683     }
0684 
0685     ngx_add_timer(c->read, h2scf->idle_timeout);
0686 }
0687 
0688 
0689 static u_char *
0690 ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos,
0691     u_char *end)
0692 {
0693     ngx_log_t  *log;
0694 
0695     log = h2c->connection->log;
0696     log->action = "reading PROXY protocol";
0697 
0698     pos = ngx_proxy_protocol_read(h2c->connection, pos, end);
0699 
0700     log->action = "processing HTTP/2 connection";
0701 
0702     if (pos == NULL) {
0703         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
0704     }
0705 
0706     return ngx_http_v2_state_preface(h2c, pos, end);
0707 }
0708 
0709 
0710 static u_char *
0711 ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos,
0712     u_char *end)
0713 {
0714     static const u_char preface[] = "PRI * HTTP/2.0\r\n";
0715 
0716     if ((size_t) (end - pos) < sizeof(preface) - 1) {
0717         return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_preface);
0718     }
0719 
0720     if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
0721         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0722                        "invalid http2 connection preface \"%*s\"",
0723                        sizeof(preface) - 1, pos);
0724 
0725         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
0726     }
0727 
0728     return ngx_http_v2_state_preface_end(h2c, pos + sizeof(preface) - 1, end);
0729 }
0730 
0731 
0732 static u_char *
0733 ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos,
0734     u_char *end)
0735 {
0736     static const u_char preface[] = "\r\nSM\r\n\r\n";
0737 
0738     if ((size_t) (end - pos) < sizeof(preface) - 1) {
0739         return ngx_http_v2_state_save(h2c, pos, end,
0740                                       ngx_http_v2_state_preface_end);
0741     }
0742 
0743     if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
0744         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0745                        "invalid http2 connection preface \"%*s\"",
0746                        sizeof(preface) - 1, pos);
0747 
0748         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
0749     }
0750 
0751     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0752                    "http2 preface verified");
0753 
0754     return ngx_http_v2_state_head(h2c, pos + sizeof(preface) - 1, end);
0755 }
0756 
0757 
0758 static u_char *
0759 ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
0760 {
0761     uint32_t    head;
0762     ngx_uint_t  type;
0763 
0764     if (end - pos < NGX_HTTP_V2_FRAME_HEADER_SIZE) {
0765         return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_head);
0766     }
0767 
0768     head = ngx_http_v2_parse_uint32(pos);
0769 
0770     h2c->state.length = ngx_http_v2_parse_length(head);
0771     h2c->state.flags = pos[4];
0772 
0773     h2c->state.sid = ngx_http_v2_parse_sid(&pos[5]);
0774 
0775     pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
0776 
0777     type = ngx_http_v2_parse_type(head);
0778 
0779     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0780                    "http2 frame type:%ui f:%Xd l:%uz sid:%ui",
0781                    type, h2c->state.flags, h2c->state.length, h2c->state.sid);
0782 
0783     if (type >= NGX_HTTP_V2_FRAME_STATES) {
0784         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0785                       "client sent frame with unknown type %ui", type);
0786         return ngx_http_v2_state_skip(h2c, pos, end);
0787     }
0788 
0789     return ngx_http_v2_frame_states[type](h2c, pos, end);
0790 }
0791 
0792 
0793 static u_char *
0794 ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
0795 {
0796     size_t                 size;
0797     ngx_http_v2_node_t    *node;
0798     ngx_http_v2_stream_t  *stream;
0799 
0800     size = h2c->state.length;
0801 
0802     if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
0803 
0804         if (h2c->state.length == 0) {
0805             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0806                           "client sent padded DATA frame "
0807                           "with incorrect length: 0");
0808 
0809             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
0810         }
0811 
0812         if (end - pos == 0) {
0813             return ngx_http_v2_state_save(h2c, pos, end,
0814                                           ngx_http_v2_state_data);
0815         }
0816 
0817         h2c->state.padding = *pos++;
0818 
0819         if (h2c->state.padding >= size) {
0820             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0821                           "client sent padded DATA frame "
0822                           "with incorrect length: %uz, padding: %uz",
0823                           size, h2c->state.padding);
0824 
0825             return ngx_http_v2_connection_error(h2c,
0826                                                 NGX_HTTP_V2_PROTOCOL_ERROR);
0827         }
0828 
0829         h2c->state.length -= 1 + h2c->state.padding;
0830     }
0831 
0832     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0833                    "http2 DATA frame");
0834 
0835     if (size > h2c->recv_window) {
0836         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0837                       "client violated connection flow control: "
0838                       "received DATA frame length %uz, available window %uz",
0839                       size, h2c->recv_window);
0840 
0841         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
0842     }
0843 
0844     h2c->recv_window -= size;
0845 
0846     if (h2c->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
0847 
0848         if (ngx_http_v2_send_window_update(h2c, 0, NGX_HTTP_V2_MAX_WINDOW
0849                                                    - h2c->recv_window)
0850             == NGX_ERROR)
0851         {
0852             return ngx_http_v2_connection_error(h2c,
0853                                                 NGX_HTTP_V2_INTERNAL_ERROR);
0854         }
0855 
0856         h2c->recv_window = NGX_HTTP_V2_MAX_WINDOW;
0857     }
0858 
0859     node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
0860 
0861     if (node == NULL || node->stream == NULL) {
0862         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0863                        "unknown http2 stream");
0864 
0865         return ngx_http_v2_state_skip_padded(h2c, pos, end);
0866     }
0867 
0868     stream = node->stream;
0869 
0870     if (size > stream->recv_window) {
0871         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0872                       "client violated flow control for stream %ui: "
0873                       "received DATA frame length %uz, available window %uz",
0874                       node->id, size, stream->recv_window);
0875 
0876         if (ngx_http_v2_terminate_stream(h2c, stream,
0877                                          NGX_HTTP_V2_FLOW_CTRL_ERROR)
0878             == NGX_ERROR)
0879         {
0880             return ngx_http_v2_connection_error(h2c,
0881                                                 NGX_HTTP_V2_INTERNAL_ERROR);
0882         }
0883 
0884         return ngx_http_v2_state_skip_padded(h2c, pos, end);
0885     }
0886 
0887     stream->recv_window -= size;
0888 
0889     if (stream->no_flow_control
0890         && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
0891     {
0892         if (ngx_http_v2_send_window_update(h2c, node->id,
0893                                            NGX_HTTP_V2_MAX_WINDOW
0894                                            - stream->recv_window)
0895             == NGX_ERROR)
0896         {
0897             return ngx_http_v2_connection_error(h2c,
0898                                                 NGX_HTTP_V2_INTERNAL_ERROR);
0899         }
0900 
0901         stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
0902     }
0903 
0904     if (stream->in_closed) {
0905         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
0906                       "client sent DATA frame for half-closed stream %ui",
0907                       node->id);
0908 
0909         if (ngx_http_v2_terminate_stream(h2c, stream,
0910                                          NGX_HTTP_V2_STREAM_CLOSED)
0911             == NGX_ERROR)
0912         {
0913             return ngx_http_v2_connection_error(h2c,
0914                                                 NGX_HTTP_V2_INTERNAL_ERROR);
0915         }
0916 
0917         return ngx_http_v2_state_skip_padded(h2c, pos, end);
0918     }
0919 
0920     h2c->state.stream = stream;
0921 
0922     return ngx_http_v2_state_read_data(h2c, pos, end);
0923 }
0924 
0925 
0926 static u_char *
0927 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
0928     u_char *end)
0929 {
0930     size_t                   size;
0931     ngx_buf_t               *buf;
0932     ngx_int_t                rc;
0933     ngx_http_request_t      *r;
0934     ngx_http_v2_stream_t    *stream;
0935     ngx_http_v2_srv_conf_t  *h2scf;
0936 
0937     stream = h2c->state.stream;
0938 
0939     if (stream == NULL) {
0940         return ngx_http_v2_state_skip_padded(h2c, pos, end);
0941     }
0942 
0943     if (stream->skip_data) {
0944         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
0945                        "skipping http2 DATA frame");
0946 
0947         return ngx_http_v2_state_skip_padded(h2c, pos, end);
0948     }
0949 
0950     size = end - pos;
0951 
0952     if (size >= h2c->state.length) {
0953         size = h2c->state.length;
0954         stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
0955     }
0956 
0957     r = stream->request;
0958 
0959     if (r->request_body) {
0960         rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed);
0961 
0962         if (rc != NGX_OK) {
0963             stream->skip_data = 1;
0964             ngx_http_finalize_request(r, rc);
0965         }
0966 
0967     } else if (size) {
0968         buf = stream->preread;
0969 
0970         if (buf == NULL) {
0971             h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
0972 
0973             buf = ngx_create_temp_buf(r->pool, h2scf->preread_size);
0974             if (buf == NULL) {
0975                 return ngx_http_v2_connection_error(h2c,
0976                                                     NGX_HTTP_V2_INTERNAL_ERROR);
0977             }
0978 
0979             stream->preread = buf;
0980         }
0981 
0982         if (size > (size_t) (buf->end - buf->last)) {
0983             ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
0984                           "http2 preread buffer overflow");
0985             return ngx_http_v2_connection_error(h2c,
0986                                                 NGX_HTTP_V2_INTERNAL_ERROR);
0987         }
0988 
0989         buf->last = ngx_cpymem(buf->last, pos, size);
0990     }
0991 
0992     pos += size;
0993     h2c->state.length -= size;
0994 
0995     if (h2c->state.length) {
0996         return ngx_http_v2_state_save(h2c, pos, end,
0997                                       ngx_http_v2_state_read_data);
0998     }
0999 
1000     if (h2c->state.padding) {
1001         return ngx_http_v2_state_skip_padded(h2c, pos, end);
1002     }
1003 
1004     return ngx_http_v2_state_complete(h2c, pos, end);
1005 }
1006 
1007 
1008 static u_char *
1009 ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
1010     u_char *end)
1011 {
1012     size_t                   size;
1013     ngx_uint_t               padded, priority, depend, dependency, excl, weight;
1014     ngx_uint_t               status;
1015     ngx_http_v2_node_t      *node;
1016     ngx_http_v2_stream_t    *stream;
1017     ngx_http_v2_srv_conf_t  *h2scf;
1018 
1019     padded = h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG;
1020     priority = h2c->state.flags & NGX_HTTP_V2_PRIORITY_FLAG;
1021 
1022     size = 0;
1023 
1024     if (padded) {
1025         size++;
1026     }
1027 
1028     if (priority) {
1029         size += sizeof(uint32_t) + 1;
1030     }
1031 
1032     if (h2c->state.length < size) {
1033         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1034                       "client sent HEADERS frame with incorrect length %uz",
1035                       h2c->state.length);
1036 
1037         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1038     }
1039 
1040     if (h2c->state.length == size) {
1041         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1042                       "client sent HEADERS frame with empty header block");
1043 
1044         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1045     }
1046 
1047     if (h2c->goaway) {
1048         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1049                        "skipping http2 HEADERS frame");
1050         return ngx_http_v2_state_skip(h2c, pos, end);
1051     }
1052 
1053     if ((size_t) (end - pos) < size) {
1054         return ngx_http_v2_state_save(h2c, pos, end,
1055                                       ngx_http_v2_state_headers);
1056     }
1057 
1058     h2c->state.length -= size;
1059 
1060     if (padded) {
1061         h2c->state.padding = *pos++;
1062 
1063         if (h2c->state.padding > h2c->state.length) {
1064             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1065                           "client sent padded HEADERS frame "
1066                           "with incorrect length: %uz, padding: %uz",
1067                           h2c->state.length, h2c->state.padding);
1068 
1069             return ngx_http_v2_connection_error(h2c,
1070                                                 NGX_HTTP_V2_PROTOCOL_ERROR);
1071         }
1072 
1073         h2c->state.length -= h2c->state.padding;
1074     }
1075 
1076     depend = 0;
1077     excl = 0;
1078     weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
1079 
1080     if (priority) {
1081         dependency = ngx_http_v2_parse_uint32(pos);
1082 
1083         depend = dependency & 0x7fffffff;
1084         excl = dependency >> 31;
1085         weight = pos[4] + 1;
1086 
1087         pos += sizeof(uint32_t) + 1;
1088     }
1089 
1090     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1091                    "http2 HEADERS frame sid:%ui "
1092                    "depends on %ui excl:%ui weight:%ui",
1093                    h2c->state.sid, depend, excl, weight);
1094 
1095     if (h2c->state.sid % 2 == 0 || h2c->state.sid <= h2c->last_sid) {
1096         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1097                       "client sent HEADERS frame with incorrect identifier "
1098                       "%ui, the last was %ui", h2c->state.sid, h2c->last_sid);
1099 
1100         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1101     }
1102 
1103     h2c->last_sid = h2c->state.sid;
1104 
1105     h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
1106     if (h2c->state.pool == NULL) {
1107         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1108     }
1109 
1110     if (depend == h2c->state.sid) {
1111         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1112                       "client sent HEADERS frame for stream %ui "
1113                       "with incorrect dependency", h2c->state.sid);
1114 
1115         status = NGX_HTTP_V2_PROTOCOL_ERROR;
1116         goto rst_stream;
1117     }
1118 
1119     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1120                                          ngx_http_v2_module);
1121 
1122     h2c->state.header_limit = h2scf->max_header_size;
1123 
1124     if (h2c->processing >= h2scf->concurrent_streams) {
1125         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1126                       "concurrent streams exceeded %ui", h2c->processing);
1127 
1128         status = NGX_HTTP_V2_REFUSED_STREAM;
1129         goto rst_stream;
1130     }
1131 
1132     if (!h2c->settings_ack
1133         && !(h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG)
1134         && h2scf->preread_size < NGX_HTTP_V2_DEFAULT_WINDOW)
1135     {
1136         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1137                       "client sent stream with data "
1138                       "before settings were acknowledged");
1139 
1140         status = NGX_HTTP_V2_REFUSED_STREAM;
1141         goto rst_stream;
1142     }
1143 
1144     node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
1145 
1146     if (node == NULL) {
1147         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1148     }
1149 
1150     if (node->parent) {
1151         ngx_queue_remove(&node->reuse);
1152         h2c->closed_nodes--;
1153     }
1154 
1155     stream = ngx_http_v2_create_stream(h2c, 0);
1156     if (stream == NULL) {
1157         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1158     }
1159 
1160     h2c->state.stream = stream;
1161 
1162     stream->pool = h2c->state.pool;
1163     h2c->state.keep_pool = 1;
1164 
1165     stream->request->request_length = h2c->state.length;
1166 
1167     stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
1168     stream->node = node;
1169 
1170     node->stream = stream;
1171 
1172     if (priority || node->parent == NULL) {
1173         node->weight = weight;
1174         ngx_http_v2_set_dependency(h2c, node, depend, excl);
1175     }
1176 
1177     if (h2c->connection->requests >= h2scf->max_requests) {
1178         h2c->goaway = 1;
1179 
1180         if (ngx_http_v2_send_goaway(h2c, NGX_HTTP_V2_NO_ERROR) == NGX_ERROR) {
1181             return ngx_http_v2_connection_error(h2c,
1182                                                 NGX_HTTP_V2_INTERNAL_ERROR);
1183         }
1184     }
1185 
1186     return ngx_http_v2_state_header_block(h2c, pos, end);
1187 
1188 rst_stream:
1189 
1190     if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid, status) != NGX_OK) {
1191         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1192     }
1193 
1194     return ngx_http_v2_state_header_block(h2c, pos, end);
1195 }
1196 
1197 
1198 static u_char *
1199 ngx_http_v2_state_header_block(ngx_http_v2_connection_t *h2c, u_char *pos,
1200     u_char *end)
1201 {
1202     u_char      ch;
1203     ngx_int_t   value;
1204     ngx_uint_t  indexed, size_update, prefix;
1205 
1206     if (end - pos < 1) {
1207         return ngx_http_v2_state_headers_save(h2c, pos, end,
1208                                               ngx_http_v2_state_header_block);
1209     }
1210 
1211     if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1212         && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1213     {
1214         return ngx_http_v2_handle_continuation(h2c, pos, end,
1215                                                ngx_http_v2_state_header_block);
1216     }
1217 
1218     size_update = 0;
1219     indexed = 0;
1220 
1221     ch = *pos;
1222 
1223     if (ch >= (1 << 7)) {
1224         /* indexed header field */
1225         indexed = 1;
1226         prefix = ngx_http_v2_prefix(7);
1227 
1228     } else if (ch >= (1 << 6)) {
1229         /* literal header field with incremental indexing */
1230         h2c->state.index = 1;
1231         prefix = ngx_http_v2_prefix(6);
1232 
1233     } else if (ch >= (1 << 5)) {
1234         /* dynamic table size update */
1235         size_update = 1;
1236         prefix = ngx_http_v2_prefix(5);
1237 
1238     } else if (ch >= (1 << 4)) {
1239         /* literal header field never indexed */
1240         prefix = ngx_http_v2_prefix(4);
1241 
1242     } else {
1243         /* literal header field without indexing */
1244         prefix = ngx_http_v2_prefix(4);
1245     }
1246 
1247     value = ngx_http_v2_parse_int(h2c, &pos, end, prefix);
1248 
1249     if (value < 0) {
1250         if (value == NGX_AGAIN) {
1251             return ngx_http_v2_state_headers_save(h2c, pos, end,
1252                                                ngx_http_v2_state_header_block);
1253         }
1254 
1255         if (value == NGX_DECLINED) {
1256             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1257                           "client sent header block with too long %s value",
1258                           size_update ? "size update" : "header index");
1259 
1260             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1261         }
1262 
1263         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1264                       "client sent header block with incorrect length");
1265 
1266         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1267     }
1268 
1269     if (indexed) {
1270         if (ngx_http_v2_get_indexed_header(h2c, value, 0) != NGX_OK) {
1271             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1272         }
1273 
1274         return ngx_http_v2_state_process_header(h2c, pos, end);
1275     }
1276 
1277     if (size_update) {
1278         if (ngx_http_v2_table_size(h2c, value) != NGX_OK) {
1279             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1280         }
1281 
1282         return ngx_http_v2_state_header_complete(h2c, pos, end);
1283     }
1284 
1285     if (value == 0) {
1286         h2c->state.parse_name = 1;
1287 
1288     } else if (ngx_http_v2_get_indexed_header(h2c, value, 1) != NGX_OK) {
1289         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1290     }
1291 
1292     h2c->state.parse_value = 1;
1293 
1294     return ngx_http_v2_state_field_len(h2c, pos, end);
1295 }
1296 
1297 
1298 static u_char *
1299 ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos,
1300     u_char *end)
1301 {
1302     size_t                   alloc;
1303     ngx_int_t                len;
1304     ngx_uint_t               huff;
1305     ngx_http_v2_srv_conf_t  *h2scf;
1306 
1307     if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)
1308         && h2c->state.length < NGX_HTTP_V2_INT_OCTETS)
1309     {
1310         return ngx_http_v2_handle_continuation(h2c, pos, end,
1311                                                ngx_http_v2_state_field_len);
1312     }
1313 
1314     if (h2c->state.length < 1) {
1315         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1316                       "client sent header block with incorrect length");
1317 
1318         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1319     }
1320 
1321     if (end - pos < 1) {
1322         return ngx_http_v2_state_headers_save(h2c, pos, end,
1323                                               ngx_http_v2_state_field_len);
1324     }
1325 
1326     huff = *pos >> 7;
1327     len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7));
1328 
1329     if (len < 0) {
1330         if (len == NGX_AGAIN) {
1331             return ngx_http_v2_state_headers_save(h2c, pos, end,
1332                                                   ngx_http_v2_state_field_len);
1333         }
1334 
1335         if (len == NGX_DECLINED) {
1336             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1337                         "client sent header field with too long length value");
1338 
1339             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1340         }
1341 
1342         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1343                       "client sent header block with incorrect length");
1344 
1345         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1346     }
1347 
1348     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1349                    "http2 %s string, len:%i",
1350                    huff ? "encoded" : "raw", len);
1351 
1352     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
1353                                          ngx_http_v2_module);
1354 
1355     if ((size_t) len > h2scf->max_field_size) {
1356         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1357                       "client exceeded http2_max_field_size limit");
1358 
1359         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1360     }
1361 
1362     h2c->state.field_rest = len;
1363 
1364     if (h2c->state.stream == NULL && !h2c->state.index) {
1365         return ngx_http_v2_state_field_skip(h2c, pos, end);
1366     }
1367 
1368     alloc = (huff ? len * 8 / 5 : len) + 1;
1369 
1370     h2c->state.field_start = ngx_pnalloc(h2c->state.pool, alloc);
1371     if (h2c->state.field_start == NULL) {
1372         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1373     }
1374 
1375     h2c->state.field_end = h2c->state.field_start;
1376 
1377     if (huff) {
1378         return ngx_http_v2_state_field_huff(h2c, pos, end);
1379     }
1380 
1381     return ngx_http_v2_state_field_raw(h2c, pos, end);
1382 }
1383 
1384 
1385 static u_char *
1386 ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos,
1387     u_char *end)
1388 {
1389     size_t  size;
1390 
1391     size = end - pos;
1392 
1393     if (size > h2c->state.field_rest) {
1394         size = h2c->state.field_rest;
1395     }
1396 
1397     if (size > h2c->state.length) {
1398         size = h2c->state.length;
1399     }
1400 
1401     h2c->state.length -= size;
1402     h2c->state.field_rest -= size;
1403 
1404     if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size,
1405                                 &h2c->state.field_end,
1406                                 h2c->state.field_rest == 0,
1407                                 h2c->connection->log)
1408         != NGX_OK)
1409     {
1410         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1411                       "client sent invalid encoded header field");
1412 
1413         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_COMP_ERROR);
1414     }
1415 
1416     pos += size;
1417 
1418     if (h2c->state.field_rest == 0) {
1419         *h2c->state.field_end = '\0';
1420         return ngx_http_v2_state_process_header(h2c, pos, end);
1421     }
1422 
1423     if (h2c->state.length) {
1424         return ngx_http_v2_state_headers_save(h2c, pos, end,
1425                                               ngx_http_v2_state_field_huff);
1426     }
1427 
1428     if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1429         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1430                       "client sent header field with incorrect length");
1431 
1432         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1433     }
1434 
1435     return ngx_http_v2_handle_continuation(h2c, pos, end,
1436                                            ngx_http_v2_state_field_huff);
1437 }
1438 
1439 
1440 static u_char *
1441 ngx_http_v2_state_field_raw(ngx_http_v2_connection_t *h2c, u_char *pos,
1442     u_char *end)
1443 {
1444     size_t  size;
1445 
1446     size = end - pos;
1447 
1448     if (size > h2c->state.field_rest) {
1449         size = h2c->state.field_rest;
1450     }
1451 
1452     if (size > h2c->state.length) {
1453         size = h2c->state.length;
1454     }
1455 
1456     h2c->state.length -= size;
1457     h2c->state.field_rest -= size;
1458 
1459     h2c->state.field_end = ngx_cpymem(h2c->state.field_end, pos, size);
1460 
1461     pos += size;
1462 
1463     if (h2c->state.field_rest == 0) {
1464         *h2c->state.field_end = '\0';
1465         return ngx_http_v2_state_process_header(h2c, pos, end);
1466     }
1467 
1468     if (h2c->state.length) {
1469         return ngx_http_v2_state_headers_save(h2c, pos, end,
1470                                               ngx_http_v2_state_field_raw);
1471     }
1472 
1473     if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1474         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1475                       "client sent header field with incorrect length");
1476 
1477         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1478     }
1479 
1480     return ngx_http_v2_handle_continuation(h2c, pos, end,
1481                                            ngx_http_v2_state_field_raw);
1482 }
1483 
1484 
1485 static u_char *
1486 ngx_http_v2_state_field_skip(ngx_http_v2_connection_t *h2c, u_char *pos,
1487     u_char *end)
1488 {
1489     size_t  size;
1490 
1491     size = end - pos;
1492 
1493     if (size > h2c->state.field_rest) {
1494         size = h2c->state.field_rest;
1495     }
1496 
1497     if (size > h2c->state.length) {
1498         size = h2c->state.length;
1499     }
1500 
1501     h2c->state.length -= size;
1502     h2c->state.field_rest -= size;
1503 
1504     pos += size;
1505 
1506     if (h2c->state.field_rest == 0) {
1507         return ngx_http_v2_state_process_header(h2c, pos, end);
1508     }
1509 
1510     if (h2c->state.length) {
1511         return ngx_http_v2_state_save(h2c, pos, end,
1512                                       ngx_http_v2_state_field_skip);
1513     }
1514 
1515     if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
1516         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1517                       "client sent header field with incorrect length");
1518 
1519         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1520     }
1521 
1522     return ngx_http_v2_handle_continuation(h2c, pos, end,
1523                                            ngx_http_v2_state_field_skip);
1524 }
1525 
1526 
1527 static u_char *
1528 ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
1529     u_char *end)
1530 {
1531     size_t                      len;
1532     ngx_int_t                   rc;
1533     ngx_table_elt_t            *h;
1534     ngx_http_header_t          *hh;
1535     ngx_http_request_t         *r;
1536     ngx_http_v2_header_t       *header;
1537     ngx_http_core_srv_conf_t   *cscf;
1538     ngx_http_core_main_conf_t  *cmcf;
1539 
1540     static ngx_str_t cookie = ngx_string("cookie");
1541 
1542     header = &h2c->state.header;
1543 
1544     if (h2c->state.parse_name) {
1545         h2c->state.parse_name = 0;
1546 
1547         header->name.len = h2c->state.field_end - h2c->state.field_start;
1548         header->name.data = h2c->state.field_start;
1549 
1550         return ngx_http_v2_state_field_len(h2c, pos, end);
1551     }
1552 
1553     if (h2c->state.parse_value) {
1554         h2c->state.parse_value = 0;
1555 
1556         header->value.len = h2c->state.field_end - h2c->state.field_start;
1557         header->value.data = h2c->state.field_start;
1558     }
1559 
1560     len = header->name.len + header->value.len;
1561 
1562     if (len > h2c->state.header_limit) {
1563         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1564                       "client exceeded http2_max_header_size limit");
1565 
1566         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
1567     }
1568 
1569     h2c->state.header_limit -= len;
1570 
1571     if (h2c->state.index) {
1572         if (ngx_http_v2_add_header(h2c, header) != NGX_OK) {
1573             return ngx_http_v2_connection_error(h2c,
1574                                                 NGX_HTTP_V2_INTERNAL_ERROR);
1575         }
1576 
1577         h2c->state.index = 0;
1578     }
1579 
1580     if (h2c->state.stream == NULL) {
1581         return ngx_http_v2_state_header_complete(h2c, pos, end);
1582     }
1583 
1584     r = h2c->state.stream->request;
1585 
1586     /* TODO Optimization: validate headers while parsing. */
1587     if (ngx_http_v2_validate_header(r, header) != NGX_OK) {
1588         if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream,
1589                                          NGX_HTTP_V2_PROTOCOL_ERROR)
1590             == NGX_ERROR)
1591         {
1592             return ngx_http_v2_connection_error(h2c,
1593                                                 NGX_HTTP_V2_INTERNAL_ERROR);
1594         }
1595 
1596         goto error;
1597     }
1598 
1599     if (header->name.data[0] == ':') {
1600         rc = ngx_http_v2_pseudo_header(r, header);
1601 
1602         if (rc == NGX_OK) {
1603             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1604                            "http2 header: \":%V: %V\"",
1605                            &header->name, &header->value);
1606 
1607             return ngx_http_v2_state_header_complete(h2c, pos, end);
1608         }
1609 
1610         if (rc == NGX_ABORT) {
1611             goto error;
1612         }
1613 
1614         if (rc == NGX_DECLINED) {
1615             ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
1616             goto error;
1617         }
1618 
1619         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1620     }
1621 
1622     if (r->invalid_header) {
1623         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1624 
1625         if (cscf->ignore_invalid_headers) {
1626             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
1627                           "client sent invalid header: \"%V\"", &header->name);
1628 
1629             return ngx_http_v2_state_header_complete(h2c, pos, end);
1630         }
1631     }
1632 
1633     if (header->name.len == cookie.len
1634         && ngx_memcmp(header->name.data, cookie.data, cookie.len) == 0)
1635     {
1636         if (ngx_http_v2_cookie(r, header) != NGX_OK) {
1637             return ngx_http_v2_connection_error(h2c,
1638                                                 NGX_HTTP_V2_INTERNAL_ERROR);
1639         }
1640 
1641     } else {
1642         h = ngx_list_push(&r->headers_in.headers);
1643         if (h == NULL) {
1644             return ngx_http_v2_connection_error(h2c,
1645                                                 NGX_HTTP_V2_INTERNAL_ERROR);
1646         }
1647 
1648         h->key.len = header->name.len;
1649         h->key.data = header->name.data;
1650 
1651         /*
1652          * TODO Optimization: precalculate hash
1653          * and handler for indexed headers.
1654          */
1655         h->hash = ngx_hash_key(h->key.data, h->key.len);
1656 
1657         h->value.len = header->value.len;
1658         h->value.data = header->value.data;
1659 
1660         h->lowcase_key = h->key.data;
1661 
1662         cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1663 
1664         hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1665                            h->lowcase_key, h->key.len);
1666 
1667         if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1668             goto error;
1669         }
1670     }
1671 
1672     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1673                    "http2 header: \"%V: %V\"",
1674                    &header->name, &header->value);
1675 
1676     return ngx_http_v2_state_header_complete(h2c, pos, end);
1677 
1678 error:
1679 
1680     h2c->state.stream = NULL;
1681 
1682     return ngx_http_v2_state_header_complete(h2c, pos, end);
1683 }
1684 
1685 
1686 static u_char *
1687 ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
1688     u_char *end)
1689 {
1690     ngx_http_v2_stream_t  *stream;
1691 
1692     if (h2c->state.length) {
1693         h2c->state.handler = ngx_http_v2_state_header_block;
1694         return pos;
1695     }
1696 
1697     if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) {
1698         return ngx_http_v2_handle_continuation(h2c, pos, end,
1699                                              ngx_http_v2_state_header_complete);
1700     }
1701 
1702     stream = h2c->state.stream;
1703 
1704     if (stream) {
1705         ngx_http_v2_run_request(stream->request);
1706     }
1707 
1708     if (!h2c->state.keep_pool) {
1709         ngx_destroy_pool(h2c->state.pool);
1710     }
1711 
1712     h2c->state.pool = NULL;
1713     h2c->state.keep_pool = 0;
1714 
1715     if (h2c->state.padding) {
1716         return ngx_http_v2_state_skip_padded(h2c, pos, end);
1717     }
1718 
1719     return ngx_http_v2_state_complete(h2c, pos, end);
1720 }
1721 
1722 
1723 static u_char *
1724 ngx_http_v2_handle_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
1725     u_char *end, ngx_http_v2_handler_pt handler)
1726 {
1727     u_char    *p;
1728     size_t     len, skip;
1729     uint32_t   head;
1730 
1731     len = h2c->state.length;
1732 
1733     if (h2c->state.padding && (size_t) (end - pos) > len) {
1734         skip = ngx_min(h2c->state.padding, (end - pos) - len);
1735 
1736         h2c->state.padding -= skip;
1737 
1738         p = pos;
1739         pos += skip;
1740         ngx_memmove(pos, p, len);
1741     }
1742 
1743     if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) {
1744         return ngx_http_v2_state_headers_save(h2c, pos, end, handler);
1745     }
1746 
1747     p = pos + len;
1748 
1749     head = ngx_http_v2_parse_uint32(p);
1750 
1751     if (ngx_http_v2_parse_type(head) != NGX_HTTP_V2_CONTINUATION_FRAME) {
1752         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1753              "client sent inappropriate frame while CONTINUATION was expected");
1754 
1755         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1756     }
1757 
1758     h2c->state.flags |= p[4];
1759 
1760     if (h2c->state.sid != ngx_http_v2_parse_sid(&p[5])) {
1761         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1762                     "client sent CONTINUATION frame with incorrect identifier");
1763 
1764         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1765     }
1766 
1767     p = pos;
1768     pos += NGX_HTTP_V2_FRAME_HEADER_SIZE;
1769 
1770     ngx_memcpy(pos, p, len);
1771 
1772     len = ngx_http_v2_parse_length(head);
1773 
1774     h2c->state.length += len;
1775 
1776     if (h2c->state.stream) {
1777         h2c->state.stream->request->request_length += len;
1778     }
1779 
1780     h2c->state.handler = handler;
1781     return pos;
1782 }
1783 
1784 
1785 static u_char *
1786 ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
1787     u_char *end)
1788 {
1789     ngx_uint_t           depend, dependency, excl, weight;
1790     ngx_http_v2_node_t  *node;
1791 
1792     if (h2c->state.length != NGX_HTTP_V2_PRIORITY_SIZE) {
1793         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1794                       "client sent PRIORITY frame with incorrect length %uz",
1795                       h2c->state.length);
1796 
1797         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1798     }
1799 
1800     if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) {
1801         return ngx_http_v2_state_save(h2c, pos, end,
1802                                       ngx_http_v2_state_priority);
1803     }
1804 
1805     dependency = ngx_http_v2_parse_uint32(pos);
1806 
1807     depend = dependency & 0x7fffffff;
1808     excl = dependency >> 31;
1809     weight = pos[4] + 1;
1810 
1811     pos += NGX_HTTP_V2_PRIORITY_SIZE;
1812 
1813     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1814                    "http2 PRIORITY frame sid:%ui "
1815                    "depends on %ui excl:%ui weight:%ui",
1816                    h2c->state.sid, depend, excl, weight);
1817 
1818     if (h2c->state.sid == 0) {
1819         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1820                       "client sent PRIORITY frame with incorrect identifier");
1821 
1822         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1823     }
1824 
1825     if (depend == h2c->state.sid) {
1826         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1827                       "client sent PRIORITY frame for stream %ui "
1828                       "with incorrect dependency", h2c->state.sid);
1829 
1830         node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
1831 
1832         if (node && node->stream) {
1833             if (ngx_http_v2_terminate_stream(h2c, node->stream,
1834                                              NGX_HTTP_V2_PROTOCOL_ERROR)
1835                 == NGX_ERROR)
1836             {
1837                 return ngx_http_v2_connection_error(h2c,
1838                                                     NGX_HTTP_V2_INTERNAL_ERROR);
1839             }
1840 
1841         } else {
1842             if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
1843                                             NGX_HTTP_V2_PROTOCOL_ERROR)
1844                 == NGX_ERROR)
1845             {
1846                 return ngx_http_v2_connection_error(h2c,
1847                                                     NGX_HTTP_V2_INTERNAL_ERROR);
1848             }
1849         }
1850 
1851         return ngx_http_v2_state_complete(h2c, pos, end);
1852     }
1853 
1854     node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
1855 
1856     if (node == NULL) {
1857         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
1858     }
1859 
1860     node->weight = weight;
1861 
1862     if (node->stream == NULL) {
1863         if (node->parent == NULL) {
1864             h2c->closed_nodes++;
1865 
1866         } else {
1867             ngx_queue_remove(&node->reuse);
1868         }
1869 
1870         ngx_queue_insert_tail(&h2c->closed, &node->reuse);
1871     }
1872 
1873     ngx_http_v2_set_dependency(h2c, node, depend, excl);
1874 
1875     return ngx_http_v2_state_complete(h2c, pos, end);
1876 }
1877 
1878 
1879 static u_char *
1880 ngx_http_v2_state_rst_stream(ngx_http_v2_connection_t *h2c, u_char *pos,
1881     u_char *end)
1882 {
1883     ngx_uint_t             status;
1884     ngx_event_t           *ev;
1885     ngx_connection_t      *fc;
1886     ngx_http_v2_node_t    *node;
1887     ngx_http_v2_stream_t  *stream;
1888 
1889     if (h2c->state.length != NGX_HTTP_V2_RST_STREAM_SIZE) {
1890         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1891                       "client sent RST_STREAM frame with incorrect length %uz",
1892                       h2c->state.length);
1893 
1894         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1895     }
1896 
1897     if (end - pos < NGX_HTTP_V2_RST_STREAM_SIZE) {
1898         return ngx_http_v2_state_save(h2c, pos, end,
1899                                       ngx_http_v2_state_rst_stream);
1900     }
1901 
1902     status = ngx_http_v2_parse_uint32(pos);
1903 
1904     pos += NGX_HTTP_V2_RST_STREAM_SIZE;
1905 
1906     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1907                    "http2 RST_STREAM frame, sid:%ui status:%ui",
1908                    h2c->state.sid, status);
1909 
1910     if (h2c->state.sid == 0) {
1911         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1912                       "client sent RST_STREAM frame with incorrect identifier");
1913 
1914         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
1915     }
1916 
1917     node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
1918 
1919     if (node == NULL || node->stream == NULL) {
1920         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1921                        "unknown http2 stream");
1922 
1923         return ngx_http_v2_state_complete(h2c, pos, end);
1924     }
1925 
1926     stream = node->stream;
1927 
1928     stream->in_closed = 1;
1929     stream->out_closed = 1;
1930 
1931     fc = stream->request->connection;
1932     fc->error = 1;
1933 
1934     switch (status) {
1935 
1936     case NGX_HTTP_V2_CANCEL:
1937         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1938                       "client canceled stream %ui", h2c->state.sid);
1939         break;
1940 
1941     case NGX_HTTP_V2_REFUSED_STREAM:
1942         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1943                       "client refused stream %ui", h2c->state.sid);
1944         break;
1945 
1946     case NGX_HTTP_V2_INTERNAL_ERROR:
1947         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1948                       "client terminated stream %ui due to internal error",
1949                       h2c->state.sid);
1950         break;
1951 
1952     default:
1953         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
1954                       "client terminated stream %ui with status %ui",
1955                       h2c->state.sid, status);
1956         break;
1957     }
1958 
1959     ev = fc->read;
1960     ev->handler(ev);
1961 
1962     return ngx_http_v2_state_complete(h2c, pos, end);
1963 }
1964 
1965 
1966 static u_char *
1967 ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
1968     u_char *end)
1969 {
1970     if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) {
1971 
1972         if (h2c->state.length != 0) {
1973             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1974                           "client sent SETTINGS frame with the ACK flag "
1975                           "and nonzero length");
1976 
1977             return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1978         }
1979 
1980         h2c->settings_ack = 1;
1981 
1982         return ngx_http_v2_state_complete(h2c, pos, end);
1983     }
1984 
1985     if (h2c->state.length % NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
1986         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
1987                       "client sent SETTINGS frame with incorrect length %uz",
1988                       h2c->state.length);
1989 
1990         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
1991     }
1992 
1993     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1994                    "http2 SETTINGS frame");
1995 
1996     return ngx_http_v2_state_settings_params(h2c, pos, end);
1997 }
1998 
1999 
2000 static u_char *
2001 ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
2002     u_char *end)
2003 {
2004     ssize_t                   window_delta;
2005     ngx_uint_t                id, value;
2006     ngx_http_v2_srv_conf_t   *h2scf;
2007     ngx_http_v2_out_frame_t  *frame;
2008 
2009     window_delta = 0;
2010 
2011     while (h2c->state.length) {
2012         if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) {
2013             return ngx_http_v2_state_save(h2c, pos, end,
2014                                           ngx_http_v2_state_settings_params);
2015         }
2016 
2017         h2c->state.length -= NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2018 
2019         id = ngx_http_v2_parse_uint16(pos);
2020         value = ngx_http_v2_parse_uint32(&pos[2]);
2021 
2022         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2023                        "http2 setting %ui:%ui", id, value);
2024 
2025         switch (id) {
2026 
2027         case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING:
2028 
2029             if (value > NGX_HTTP_V2_MAX_WINDOW) {
2030                 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2031                               "client sent SETTINGS frame with incorrect "
2032                               "INITIAL_WINDOW_SIZE value %ui", value);
2033 
2034                 return ngx_http_v2_connection_error(h2c,
2035                                                   NGX_HTTP_V2_FLOW_CTRL_ERROR);
2036             }
2037 
2038             window_delta = value - h2c->init_window;
2039             break;
2040 
2041         case NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING:
2042 
2043             if (value > NGX_HTTP_V2_MAX_FRAME_SIZE
2044                 || value < NGX_HTTP_V2_DEFAULT_FRAME_SIZE)
2045             {
2046                 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2047                               "client sent SETTINGS frame with incorrect "
2048                               "MAX_FRAME_SIZE value %ui", value);
2049 
2050                 return ngx_http_v2_connection_error(h2c,
2051                                                     NGX_HTTP_V2_PROTOCOL_ERROR);
2052             }
2053 
2054             h2c->frame_size = value;
2055             break;
2056 
2057         case NGX_HTTP_V2_ENABLE_PUSH_SETTING:
2058 
2059             if (value > 1) {
2060                 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2061                               "client sent SETTINGS frame with incorrect "
2062                               "ENABLE_PUSH value %ui", value);
2063 
2064                 return ngx_http_v2_connection_error(h2c,
2065                                                     NGX_HTTP_V2_PROTOCOL_ERROR);
2066             }
2067 
2068             h2c->push_disabled = !value;
2069             break;
2070 
2071         case NGX_HTTP_V2_MAX_STREAMS_SETTING:
2072             h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2073                                                  ngx_http_v2_module);
2074 
2075             h2c->concurrent_pushes = ngx_min(value, h2scf->concurrent_pushes);
2076             break;
2077 
2078         default:
2079             break;
2080         }
2081 
2082         pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE;
2083     }
2084 
2085     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE,
2086                                   NGX_HTTP_V2_SETTINGS_FRAME,
2087                                   NGX_HTTP_V2_ACK_FLAG, 0);
2088     if (frame == NULL) {
2089         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2090     }
2091 
2092     ngx_http_v2_queue_ordered_frame(h2c, frame);
2093 
2094     if (window_delta) {
2095         h2c->init_window += window_delta;
2096 
2097         if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) {
2098             return ngx_http_v2_connection_error(h2c,
2099                                                 NGX_HTTP_V2_INTERNAL_ERROR);
2100         }
2101     }
2102 
2103     return ngx_http_v2_state_complete(h2c, pos, end);
2104 }
2105 
2106 
2107 static u_char *
2108 ngx_http_v2_state_push_promise(ngx_http_v2_connection_t *h2c, u_char *pos,
2109     u_char *end)
2110 {
2111     ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2112                   "client sent PUSH_PROMISE frame");
2113 
2114     return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2115 }
2116 
2117 
2118 static u_char *
2119 ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2120 {
2121     ngx_buf_t                *buf;
2122     ngx_http_v2_out_frame_t  *frame;
2123 
2124     if (h2c->state.length != NGX_HTTP_V2_PING_SIZE) {
2125         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2126                       "client sent PING frame with incorrect length %uz",
2127                       h2c->state.length);
2128 
2129         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2130     }
2131 
2132     if (end - pos < NGX_HTTP_V2_PING_SIZE) {
2133         return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping);
2134     }
2135 
2136     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2137                    "http2 PING frame");
2138 
2139     if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) {
2140         return ngx_http_v2_state_skip(h2c, pos, end);
2141     }
2142 
2143     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_PING_SIZE,
2144                                   NGX_HTTP_V2_PING_FRAME,
2145                                   NGX_HTTP_V2_ACK_FLAG, 0);
2146     if (frame == NULL) {
2147         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2148     }
2149 
2150     buf = frame->first->buf;
2151 
2152     buf->last = ngx_cpymem(buf->last, pos, NGX_HTTP_V2_PING_SIZE);
2153 
2154     ngx_http_v2_queue_blocked_frame(h2c, frame);
2155 
2156     return ngx_http_v2_state_complete(h2c, pos + NGX_HTTP_V2_PING_SIZE, end);
2157 }
2158 
2159 
2160 static u_char *
2161 ngx_http_v2_state_goaway(ngx_http_v2_connection_t *h2c, u_char *pos,
2162     u_char *end)
2163 {
2164 #if (NGX_DEBUG)
2165     ngx_uint_t  last_sid, error;
2166 #endif
2167 
2168     if (h2c->state.length < NGX_HTTP_V2_GOAWAY_SIZE) {
2169         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2170                       "client sent GOAWAY frame "
2171                       "with incorrect length %uz", h2c->state.length);
2172 
2173         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2174     }
2175 
2176     if (end - pos < NGX_HTTP_V2_GOAWAY_SIZE) {
2177         return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway);
2178     }
2179 
2180 #if (NGX_DEBUG)
2181     h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE;
2182 
2183     last_sid = ngx_http_v2_parse_sid(pos);
2184     error = ngx_http_v2_parse_uint32(&pos[4]);
2185 
2186     pos += NGX_HTTP_V2_GOAWAY_SIZE;
2187 
2188     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2189                    "http2 GOAWAY frame: last sid %ui, error %ui",
2190                    last_sid, error);
2191 #endif
2192 
2193     return ngx_http_v2_state_skip(h2c, pos, end);
2194 }
2195 
2196 
2197 static u_char *
2198 ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos,
2199     u_char *end)
2200 {
2201     size_t                 window;
2202     ngx_event_t           *wev;
2203     ngx_queue_t           *q;
2204     ngx_http_v2_node_t    *node;
2205     ngx_http_v2_stream_t  *stream;
2206 
2207     if (h2c->state.length != NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2208         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2209                       "client sent WINDOW_UPDATE frame "
2210                       "with incorrect length %uz", h2c->state.length);
2211 
2212         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
2213     }
2214 
2215     if (end - pos < NGX_HTTP_V2_WINDOW_UPDATE_SIZE) {
2216         return ngx_http_v2_state_save(h2c, pos, end,
2217                                       ngx_http_v2_state_window_update);
2218     }
2219 
2220     window = ngx_http_v2_parse_window(pos);
2221 
2222     pos += NGX_HTTP_V2_WINDOW_UPDATE_SIZE;
2223 
2224     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2225                    "http2 WINDOW_UPDATE frame sid:%ui window:%uz",
2226                    h2c->state.sid, window);
2227 
2228     if (window == 0) {
2229         if (h2c->state.sid == 0) {
2230             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2231                           "client sent WINDOW_UPDATE frame "
2232                           "with incorrect window increment 0");
2233 
2234             return ngx_http_v2_connection_error(h2c,
2235                                                 NGX_HTTP_V2_PROTOCOL_ERROR);
2236         }
2237 
2238         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2239                       "client sent WINDOW_UPDATE frame for stream %ui "
2240                       "with incorrect window increment 0", h2c->state.sid);
2241 
2242         node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2243 
2244         if (node && node->stream) {
2245             if (ngx_http_v2_terminate_stream(h2c, node->stream,
2246                                              NGX_HTTP_V2_PROTOCOL_ERROR)
2247                 == NGX_ERROR)
2248             {
2249                 return ngx_http_v2_connection_error(h2c,
2250                                                     NGX_HTTP_V2_INTERNAL_ERROR);
2251             }
2252 
2253         } else {
2254             if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
2255                                             NGX_HTTP_V2_PROTOCOL_ERROR)
2256                 == NGX_ERROR)
2257             {
2258                 return ngx_http_v2_connection_error(h2c,
2259                                                     NGX_HTTP_V2_INTERNAL_ERROR);
2260             }
2261         }
2262 
2263         return ngx_http_v2_state_complete(h2c, pos, end);
2264     }
2265 
2266     if (h2c->state.sid) {
2267         node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
2268 
2269         if (node == NULL || node->stream == NULL) {
2270             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2271                            "unknown http2 stream");
2272 
2273             return ngx_http_v2_state_complete(h2c, pos, end);
2274         }
2275 
2276         stream = node->stream;
2277 
2278         if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) {
2279 
2280             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2281                           "client violated flow control for stream %ui: "
2282                           "received WINDOW_UPDATE frame "
2283                           "with window increment %uz "
2284                           "not allowed for window %z",
2285                           h2c->state.sid, window, stream->send_window);
2286 
2287             if (ngx_http_v2_terminate_stream(h2c, stream,
2288                                              NGX_HTTP_V2_FLOW_CTRL_ERROR)
2289                 == NGX_ERROR)
2290             {
2291                 return ngx_http_v2_connection_error(h2c,
2292                                                     NGX_HTTP_V2_INTERNAL_ERROR);
2293             }
2294 
2295             return ngx_http_v2_state_complete(h2c, pos, end);
2296         }
2297 
2298         stream->send_window += window;
2299 
2300         if (stream->exhausted) {
2301             stream->exhausted = 0;
2302 
2303             wev = stream->request->connection->write;
2304 
2305             wev->active = 0;
2306             wev->ready = 1;
2307 
2308             if (!wev->delayed) {
2309                 wev->handler(wev);
2310             }
2311         }
2312 
2313         return ngx_http_v2_state_complete(h2c, pos, end);
2314     }
2315 
2316     if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) {
2317         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2318                       "client violated connection flow control: "
2319                       "received WINDOW_UPDATE frame "
2320                       "with window increment %uz "
2321                       "not allowed for window %uz",
2322                       window, h2c->send_window);
2323 
2324         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_FLOW_CTRL_ERROR);
2325     }
2326 
2327     h2c->send_window += window;
2328 
2329     while (!ngx_queue_empty(&h2c->waiting)) {
2330         q = ngx_queue_head(&h2c->waiting);
2331 
2332         ngx_queue_remove(q);
2333 
2334         stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue);
2335 
2336         stream->waiting = 0;
2337 
2338         wev = stream->request->connection->write;
2339 
2340         wev->active = 0;
2341         wev->ready = 1;
2342 
2343         if (!wev->delayed) {
2344             wev->handler(wev);
2345 
2346             if (h2c->send_window == 0) {
2347                 break;
2348             }
2349         }
2350     }
2351 
2352     return ngx_http_v2_state_complete(h2c, pos, end);
2353 }
2354 
2355 
2356 static u_char *
2357 ngx_http_v2_state_continuation(ngx_http_v2_connection_t *h2c, u_char *pos,
2358     u_char *end)
2359 {
2360     ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
2361                   "client sent unexpected CONTINUATION frame");
2362 
2363     return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
2364 }
2365 
2366 
2367 static u_char *
2368 ngx_http_v2_state_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
2369     u_char *end)
2370 {
2371     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2372                    "http2 frame complete pos:%p end:%p", pos, end);
2373 
2374     if (pos > end) {
2375         ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2376                       "receive buffer overrun");
2377 
2378         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2379     }
2380 
2381     h2c->state.stream = NULL;
2382     h2c->state.handler = ngx_http_v2_state_head;
2383 
2384     return pos;
2385 }
2386 
2387 
2388 static u_char *
2389 ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, u_char *pos,
2390     u_char *end)
2391 {
2392     h2c->state.length += h2c->state.padding;
2393     h2c->state.padding = 0;
2394 
2395     return ngx_http_v2_state_skip(h2c, pos, end);
2396 }
2397 
2398 
2399 static u_char *
2400 ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
2401 {
2402     size_t  size;
2403 
2404     size = end - pos;
2405 
2406     if (size < h2c->state.length) {
2407         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2408                        "http2 frame skip %uz of %uz", size, h2c->state.length);
2409 
2410         h2c->state.length -= size;
2411         return ngx_http_v2_state_save(h2c, end, end, ngx_http_v2_state_skip);
2412     }
2413 
2414     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2415                    "http2 frame skip %uz", h2c->state.length);
2416 
2417     return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end);
2418 }
2419 
2420 
2421 static u_char *
2422 ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end,
2423     ngx_http_v2_handler_pt handler)
2424 {
2425     size_t  size;
2426 
2427     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2428                    "http2 frame state save pos:%p end:%p handler:%p",
2429                    pos, end, handler);
2430 
2431     size = end - pos;
2432 
2433     if (size > NGX_HTTP_V2_STATE_BUFFER_SIZE) {
2434         ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2435                       "state buffer overflow: %uz bytes required", size);
2436 
2437         return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
2438     }
2439 
2440     ngx_memcpy(h2c->state.buffer, pos, NGX_HTTP_V2_STATE_BUFFER_SIZE);
2441 
2442     h2c->state.buffer_used = size;
2443     h2c->state.handler = handler;
2444     h2c->state.incomplete = 1;
2445 
2446     return end;
2447 }
2448 
2449 
2450 static u_char *
2451 ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos,
2452     u_char *end, ngx_http_v2_handler_pt handler)
2453 {
2454     ngx_event_t               *rev;
2455     ngx_http_request_t        *r;
2456     ngx_http_core_srv_conf_t  *cscf;
2457 
2458     if (h2c->state.stream) {
2459         r = h2c->state.stream->request;
2460         rev = r->connection->read;
2461 
2462         if (!rev->timer_set) {
2463             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
2464             ngx_add_timer(rev, cscf->client_header_timeout);
2465         }
2466     }
2467 
2468     return ngx_http_v2_state_save(h2c, pos, end, handler);
2469 }
2470 
2471 
2472 static u_char *
2473 ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
2474     ngx_uint_t err)
2475 {
2476     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2477                    "http2 state connection error");
2478 
2479     if (err == NGX_HTTP_V2_INTERNAL_ERROR) {
2480         ngx_debug_point();
2481     }
2482 
2483     ngx_http_v2_finalize_connection(h2c, err);
2484 
2485     return NULL;
2486 }
2487 
2488 
2489 static ngx_int_t
2490 ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end,
2491     ngx_uint_t prefix)
2492 {
2493     u_char      *start, *p;
2494     ngx_uint_t   value, octet, shift;
2495 
2496     start = *pos;
2497     p = start;
2498 
2499     value = *p++ & prefix;
2500 
2501     if (value != prefix) {
2502         if (h2c->state.length == 0) {
2503             return NGX_ERROR;
2504         }
2505 
2506         h2c->state.length--;
2507 
2508         *pos = p;
2509         return value;
2510     }
2511 
2512     if (end - start > NGX_HTTP_V2_INT_OCTETS) {
2513         end = start + NGX_HTTP_V2_INT_OCTETS;
2514     }
2515 
2516     for (shift = 0; p != end; shift += 7) {
2517         octet = *p++;
2518 
2519         value += (octet & 0x7f) << shift;
2520 
2521         if (octet < 128) {
2522             if ((size_t) (p - start) > h2c->state.length) {
2523                 return NGX_ERROR;
2524             }
2525 
2526             h2c->state.length -= p - start;
2527 
2528             *pos = p;
2529             return value;
2530         }
2531     }
2532 
2533     if ((size_t) (end - start) >= h2c->state.length) {
2534         return NGX_ERROR;
2535     }
2536 
2537     if (end == start + NGX_HTTP_V2_INT_OCTETS) {
2538         return NGX_DECLINED;
2539     }
2540 
2541     return NGX_AGAIN;
2542 }
2543 
2544 
2545 ngx_http_v2_stream_t *
2546 ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path)
2547 {
2548     ngx_int_t                     rc;
2549     ngx_str_t                     value;
2550     ngx_pool_t                   *pool;
2551     ngx_uint_t                    index;
2552     ngx_table_elt_t             **h;
2553     ngx_connection_t             *fc;
2554     ngx_http_request_t           *r;
2555     ngx_http_v2_node_t           *node;
2556     ngx_http_v2_stream_t         *stream;
2557     ngx_http_v2_srv_conf_t       *h2scf;
2558     ngx_http_v2_connection_t     *h2c;
2559     ngx_http_v2_parse_header_t   *header;
2560 
2561     h2c = parent->connection;
2562 
2563     pool = ngx_create_pool(1024, h2c->connection->log);
2564     if (pool == NULL) {
2565         goto rst_stream;
2566     }
2567 
2568     node = ngx_http_v2_get_node_by_id(h2c, h2c->last_push, 1);
2569 
2570     if (node == NULL) {
2571         ngx_destroy_pool(pool);
2572         goto rst_stream;
2573     }
2574 
2575     stream = ngx_http_v2_create_stream(h2c, 1);
2576     if (stream == NULL) {
2577 
2578         if (node->parent == NULL) {
2579             h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2580                                                  ngx_http_v2_module);
2581 
2582             index = ngx_http_v2_index(h2scf, h2c->last_push);
2583             h2c->streams_index[index] = node->index;
2584 
2585             ngx_queue_insert_tail(&h2c->closed, &node->reuse);
2586             h2c->closed_nodes++;
2587         }
2588 
2589         ngx_destroy_pool(pool);
2590         goto rst_stream;
2591     }
2592 
2593     if (node->parent) {
2594         ngx_queue_remove(&node->reuse);
2595         h2c->closed_nodes--;
2596     }
2597 
2598     stream->pool = pool;
2599 
2600     r = stream->request;
2601     fc = r->connection;
2602 
2603     stream->in_closed = 1;
2604     stream->node = node;
2605 
2606     node->stream = stream;
2607 
2608     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2609                    "http2 push stream sid:%ui "
2610                    "depends on %ui excl:0 weight:16",
2611                    h2c->last_push, parent->node->id);
2612 
2613     node->weight = NGX_HTTP_V2_DEFAULT_WEIGHT;
2614     ngx_http_v2_set_dependency(h2c, node, parent->node->id, 0);
2615 
2616     r->method_name = ngx_http_core_get_method;
2617     r->method = NGX_HTTP_GET;
2618 
2619     r->schema_start = (u_char *) "https";
2620 
2621 #if (NGX_HTTP_SSL)
2622     if (fc->ssl) {
2623         r->schema_end = r->schema_start + 5;
2624 
2625     } else
2626 #endif
2627     {
2628         r->schema_end = r->schema_start + 4;
2629     }
2630 
2631     value.data = ngx_pstrdup(pool, path);
2632     if (value.data == NULL) {
2633         goto close;
2634     }
2635 
2636     value.len = path->len;
2637 
2638     rc = ngx_http_v2_parse_path(r, &value);
2639 
2640     if (rc != NGX_OK) {
2641         goto error;
2642     }
2643 
2644     for (header = ngx_http_v2_parse_headers; header->name.len; header++) {
2645         h = (ngx_table_elt_t **)
2646                 ((char *) &parent->request->headers_in + header->offset);
2647 
2648         if (*h == NULL) {
2649             continue;
2650         }
2651 
2652         value.len = (*h)->value.len;
2653 
2654         value.data = ngx_pnalloc(pool, value.len + 1);
2655         if (value.data == NULL) {
2656             goto close;
2657         }
2658 
2659         ngx_memcpy(value.data, (*h)->value.data, value.len);
2660         value.data[value.len] = '\0';
2661 
2662         rc = ngx_http_v2_parse_header(r, header, &value);
2663 
2664         if (rc != NGX_OK) {
2665             goto error;
2666         }
2667     }
2668 
2669     fc->write->handler = ngx_http_v2_run_request_handler;
2670     ngx_post_event(fc->write, &ngx_posted_events);
2671 
2672     return stream;
2673 
2674 error:
2675 
2676     if (rc == NGX_ABORT) {
2677         /* header handler has already finalized request */
2678         return NULL;
2679     }
2680 
2681     if (rc == NGX_DECLINED) {
2682         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
2683         return NULL;
2684     }
2685 
2686 close:
2687 
2688     ngx_http_v2_close_stream(stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
2689 
2690     return NULL;
2691 
2692 rst_stream:
2693 
2694     if (ngx_http_v2_send_rst_stream(h2c, h2c->last_push,
2695                                     NGX_HTTP_INTERNAL_SERVER_ERROR)
2696         != NGX_OK)
2697     {
2698         h2c->connection->error = 1;
2699     }
2700 
2701     return NULL;
2702 }
2703 
2704 
2705 static ngx_int_t
2706 ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c)
2707 {
2708     size_t                    len;
2709     ngx_buf_t                *buf;
2710     ngx_chain_t              *cl;
2711     ngx_http_v2_srv_conf_t   *h2scf;
2712     ngx_http_v2_out_frame_t  *frame;
2713 
2714     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2715                    "http2 send SETTINGS frame");
2716 
2717     frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t));
2718     if (frame == NULL) {
2719         return NGX_ERROR;
2720     }
2721 
2722     cl = ngx_alloc_chain_link(h2c->pool);
2723     if (cl == NULL) {
2724         return NGX_ERROR;
2725     }
2726 
2727     len = NGX_HTTP_V2_SETTINGS_PARAM_SIZE * 3;
2728 
2729     buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len);
2730     if (buf == NULL) {
2731         return NGX_ERROR;
2732     }
2733 
2734     buf->last_buf = 1;
2735 
2736     cl->buf = buf;
2737     cl->next = NULL;
2738 
2739     frame->first = cl;
2740     frame->last = cl;
2741     frame->handler = ngx_http_v2_settings_frame_handler;
2742     frame->stream = NULL;
2743 #if (NGX_DEBUG)
2744     frame->length = len;
2745 #endif
2746     frame->blocked = 0;
2747 
2748     buf->last = ngx_http_v2_write_len_and_type(buf->last, len,
2749                                                NGX_HTTP_V2_SETTINGS_FRAME);
2750 
2751     *buf->last++ = NGX_HTTP_V2_NO_FLAG;
2752 
2753     buf->last = ngx_http_v2_write_sid(buf->last, 0);
2754 
2755     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
2756                                          ngx_http_v2_module);
2757 
2758     buf->last = ngx_http_v2_write_uint16(buf->last,
2759                                          NGX_HTTP_V2_MAX_STREAMS_SETTING);
2760     buf->last = ngx_http_v2_write_uint32(buf->last,
2761                                          h2scf->concurrent_streams);
2762 
2763     buf->last = ngx_http_v2_write_uint16(buf->last,
2764                                          NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING);
2765     buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size);
2766 
2767     buf->last = ngx_http_v2_write_uint16(buf->last,
2768                                          NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING);
2769     buf->last = ngx_http_v2_write_uint32(buf->last,
2770                                          NGX_HTTP_V2_MAX_FRAME_SIZE);
2771 
2772     ngx_http_v2_queue_blocked_frame(h2c, frame);
2773 
2774     return NGX_OK;
2775 }
2776 
2777 
2778 static ngx_int_t
2779 ngx_http_v2_settings_frame_handler(ngx_http_v2_connection_t *h2c,
2780     ngx_http_v2_out_frame_t *frame)
2781 {
2782     ngx_buf_t  *buf;
2783 
2784     buf = frame->first->buf;
2785 
2786     if (buf->pos != buf->last) {
2787         return NGX_AGAIN;
2788     }
2789 
2790     ngx_free_chain(h2c->pool, frame->first);
2791 
2792     return NGX_OK;
2793 }
2794 
2795 
2796 static ngx_int_t
2797 ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2798     size_t window)
2799 {
2800     ngx_buf_t                *buf;
2801     ngx_http_v2_out_frame_t  *frame;
2802 
2803     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2804                    "http2 send WINDOW_UPDATE frame sid:%ui, window:%uz",
2805                    sid, window);
2806 
2807     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_WINDOW_UPDATE_SIZE,
2808                                   NGX_HTTP_V2_WINDOW_UPDATE_FRAME,
2809                                   NGX_HTTP_V2_NO_FLAG, sid);
2810     if (frame == NULL) {
2811         return NGX_ERROR;
2812     }
2813 
2814     buf = frame->first->buf;
2815 
2816     buf->last = ngx_http_v2_write_uint32(buf->last, window);
2817 
2818     ngx_http_v2_queue_blocked_frame(h2c, frame);
2819 
2820     return NGX_OK;
2821 }
2822 
2823 
2824 static ngx_int_t
2825 ngx_http_v2_send_rst_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
2826     ngx_uint_t status)
2827 {
2828     ngx_buf_t                *buf;
2829     ngx_http_v2_out_frame_t  *frame;
2830 
2831     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2832                    "http2 send RST_STREAM frame sid:%ui, status:%ui",
2833                    sid, status);
2834 
2835     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_RST_STREAM_SIZE,
2836                                   NGX_HTTP_V2_RST_STREAM_FRAME,
2837                                   NGX_HTTP_V2_NO_FLAG, sid);
2838     if (frame == NULL) {
2839         return NGX_ERROR;
2840     }
2841 
2842     buf = frame->first->buf;
2843 
2844     buf->last = ngx_http_v2_write_uint32(buf->last, status);
2845 
2846     ngx_http_v2_queue_blocked_frame(h2c, frame);
2847 
2848     return NGX_OK;
2849 }
2850 
2851 
2852 static ngx_int_t
2853 ngx_http_v2_send_goaway(ngx_http_v2_connection_t *h2c, ngx_uint_t status)
2854 {
2855     ngx_buf_t                *buf;
2856     ngx_http_v2_out_frame_t  *frame;
2857 
2858     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
2859                    "http2 send GOAWAY frame: last sid %ui, error %ui",
2860                    h2c->last_sid, status);
2861 
2862     frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_GOAWAY_SIZE,
2863                                   NGX_HTTP_V2_GOAWAY_FRAME,
2864                                   NGX_HTTP_V2_NO_FLAG, 0);
2865     if (frame == NULL) {
2866         return NGX_ERROR;
2867     }
2868 
2869     buf = frame->first->buf;
2870 
2871     buf->last = ngx_http_v2_write_sid(buf->last, h2c->last_sid);
2872     buf->last = ngx_http_v2_write_uint32(buf->last, status);
2873 
2874     ngx_http_v2_queue_blocked_frame(h2c, frame);
2875 
2876     return NGX_OK;
2877 }
2878 
2879 
2880 static ngx_http_v2_out_frame_t *
2881 ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length,
2882     ngx_uint_t type, u_char flags, ngx_uint_t sid)
2883 {
2884     ngx_buf_t                *buf;
2885     ngx_pool_t               *pool;
2886     ngx_http_v2_out_frame_t  *frame;
2887 
2888     frame = h2c->free_frames;
2889 
2890     if (frame) {
2891         h2c->free_frames = frame->next;
2892 
2893         buf = frame->first->buf;
2894         buf->pos = buf->start;
2895 
2896         frame->blocked = 0;
2897 
2898     } else {
2899         pool = h2c->pool ? h2c->pool : h2c->connection->pool;
2900 
2901         frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t));
2902         if (frame == NULL) {
2903             return NULL;
2904         }
2905 
2906         frame->first = ngx_alloc_chain_link(pool);
2907         if (frame->first == NULL) {
2908             return NULL;
2909         }
2910 
2911         buf = ngx_create_temp_buf(pool, NGX_HTTP_V2_FRAME_BUFFER_SIZE);
2912         if (buf == NULL) {
2913             return NULL;
2914         }
2915 
2916         buf->last_buf = 1;
2917 
2918         frame->first->buf = buf;
2919         frame->last = frame->first;
2920 
2921         frame->handler = ngx_http_v2_frame_handler;
2922     }
2923 
2924 #if (NGX_DEBUG)
2925     if (length > NGX_HTTP_V2_FRAME_BUFFER_SIZE - NGX_HTTP_V2_FRAME_HEADER_SIZE)
2926     {
2927         ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0,
2928                       "requested control frame is too large: %uz", length);
2929         return NULL;
2930     }
2931 
2932     frame->length = length;
2933 #endif
2934 
2935     buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
2936 
2937     *buf->last++ = flags;
2938 
2939     buf->last = ngx_http_v2_write_sid(buf->last, sid);
2940 
2941     return frame;
2942 }
2943 
2944 
2945 static ngx_int_t
2946 ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
2947     ngx_http_v2_out_frame_t *frame)
2948 {
2949     ngx_buf_t  *buf;
2950 
2951     buf = frame->first->buf;
2952 
2953     if (buf->pos != buf->last) {
2954         return NGX_AGAIN;
2955     }
2956 
2957     frame->next = h2c->free_frames;
2958     h2c->free_frames = frame;
2959 
2960     return NGX_OK;
2961 }
2962 
2963 
2964 static ngx_http_v2_stream_t *
2965 ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push)
2966 {
2967     ngx_log_t                 *log;
2968     ngx_event_t               *rev, *wev;
2969     ngx_connection_t          *fc;
2970     ngx_http_log_ctx_t        *ctx;
2971     ngx_http_request_t        *r;
2972     ngx_http_v2_stream_t      *stream;
2973     ngx_http_v2_srv_conf_t    *h2scf;
2974     ngx_http_core_srv_conf_t  *cscf;
2975 
2976     fc = h2c->free_fake_connections;
2977 
2978     if (fc) {
2979         h2c->free_fake_connections = fc->data;
2980 
2981         rev = fc->read;
2982         wev = fc->write;
2983         log = fc->log;
2984         ctx = log->data;
2985 
2986     } else {
2987         fc = ngx_palloc(h2c->pool, sizeof(ngx_connection_t));
2988         if (fc == NULL) {
2989             return NULL;
2990         }
2991 
2992         rev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
2993         if (rev == NULL) {
2994             return NULL;
2995         }
2996 
2997         wev = ngx_palloc(h2c->pool, sizeof(ngx_event_t));
2998         if (wev == NULL) {
2999             return NULL;
3000         }
3001 
3002         log = ngx_palloc(h2c->pool, sizeof(ngx_log_t));
3003         if (log == NULL) {
3004             return NULL;
3005         }
3006 
3007         ctx = ngx_palloc(h2c->pool, sizeof(ngx_http_log_ctx_t));
3008         if (ctx == NULL) {
3009             return NULL;
3010         }
3011 
3012         ctx->connection = fc;
3013         ctx->request = NULL;
3014         ctx->current_request = NULL;
3015     }
3016 
3017     ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t));
3018 
3019     log->data = ctx;
3020 
3021     if (push) {
3022         log->action = "processing pushed request headers";
3023 
3024     } else {
3025         log->action = "reading client request headers";
3026     }
3027 
3028     ngx_memzero(rev, sizeof(ngx_event_t));
3029 
3030     rev->data = fc;
3031     rev->ready = 1;
3032     rev->handler = ngx_http_v2_close_stream_handler;
3033     rev->log = log;
3034 
3035     ngx_memcpy(wev, rev, sizeof(ngx_event_t));
3036 
3037     wev->write = 1;
3038 
3039     ngx_memcpy(fc, h2c->connection, sizeof(ngx_connection_t));
3040 
3041     fc->data = h2c->http_connection;
3042     fc->read = rev;
3043     fc->write = wev;
3044     fc->sent = 0;
3045     fc->log = log;
3046     fc->buffered = 0;
3047     fc->sndlowat = 1;
3048     fc->tcp_nodelay = NGX_TCP_NODELAY_DISABLED;
3049 
3050     r = ngx_http_create_request(fc);
3051     if (r == NULL) {
3052         return NULL;
3053     }
3054 
3055     ngx_str_set(&r->http_protocol, "HTTP/2.0");
3056 
3057     r->http_version = NGX_HTTP_VERSION_20;
3058     r->valid_location = 1;
3059 
3060     fc->data = r;
3061     h2c->connection->requests++;
3062 
3063     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3064 
3065     r->header_in = ngx_create_temp_buf(r->pool,
3066                                        cscf->client_header_buffer_size);
3067     if (r->header_in == NULL) {
3068         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3069         return NULL;
3070     }
3071 
3072     if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
3073                       sizeof(ngx_table_elt_t))
3074         != NGX_OK)
3075     {
3076         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3077         return NULL;
3078     }
3079 
3080     r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
3081 
3082     stream = ngx_pcalloc(r->pool, sizeof(ngx_http_v2_stream_t));
3083     if (stream == NULL) {
3084         ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
3085         return NULL;
3086     }
3087 
3088     r->stream = stream;
3089 
3090     stream->request = r;
3091     stream->connection = h2c;
3092 
3093     h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3094 
3095     stream->send_window = h2c->init_window;
3096     stream->recv_window = h2scf->preread_size;
3097 
3098     if (push) {
3099         h2c->pushing++;
3100 
3101     } else {
3102         h2c->processing++;
3103     }
3104 
3105     return stream;
3106 }
3107 
3108 
3109 static ngx_http_v2_node_t *
3110 ngx_http_v2_get_node_by_id(ngx_http_v2_connection_t *h2c, ngx_uint_t sid,
3111     ngx_uint_t alloc)
3112 {
3113     ngx_uint_t               index;
3114     ngx_http_v2_node_t      *node;
3115     ngx_http_v2_srv_conf_t  *h2scf;
3116 
3117     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3118                                          ngx_http_v2_module);
3119 
3120     index = ngx_http_v2_index(h2scf, sid);
3121 
3122     for (node = h2c->streams_index[index]; node; node = node->index) {
3123 
3124         if (node->id == sid) {
3125             return node;
3126         }
3127     }
3128 
3129     if (!alloc) {
3130         return NULL;
3131     }
3132 
3133     if (h2c->closed_nodes < 32) {
3134         node = ngx_pcalloc(h2c->connection->pool, sizeof(ngx_http_v2_node_t));
3135         if (node == NULL) {
3136             return NULL;
3137         }
3138 
3139     } else {
3140         node = ngx_http_v2_get_closed_node(h2c);
3141     }
3142 
3143     node->id = sid;
3144 
3145     ngx_queue_init(&node->children);
3146 
3147     node->index = h2c->streams_index[index];
3148     h2c->streams_index[index] = node;
3149 
3150     return node;
3151 }
3152 
3153 
3154 static ngx_http_v2_node_t *
3155 ngx_http_v2_get_closed_node(ngx_http_v2_connection_t *h2c)
3156 {
3157     ngx_uint_t               weight;
3158     ngx_queue_t             *q, *children;
3159     ngx_http_v2_node_t      *node, **next, *n, *parent, *child;
3160     ngx_http_v2_srv_conf_t  *h2scf;
3161 
3162     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
3163                                          ngx_http_v2_module);
3164 
3165     h2c->closed_nodes--;
3166 
3167     q = ngx_queue_head(&h2c->closed);
3168 
3169     ngx_queue_remove(q);
3170 
3171     node = ngx_queue_data(q, ngx_http_v2_node_t, reuse);
3172 
3173     next = &h2c->streams_index[ngx_http_v2_index(h2scf, node->id)];
3174 
3175     for ( ;; ) {
3176         n = *next;
3177 
3178         if (n == node) {
3179             *next = n->index;
3180             break;
3181         }
3182 
3183         next = &n->index;
3184     }
3185 
3186     ngx_queue_remove(&node->queue);
3187 
3188     weight = 0;
3189 
3190     for (q = ngx_queue_head(&node->children);
3191          q != ngx_queue_sentinel(&node->children);
3192          q = ngx_queue_next(q))
3193     {
3194         child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3195         weight += child->weight;
3196     }
3197 
3198     parent = node->parent;
3199 
3200     for (q = ngx_queue_head(&node->children);
3201          q != ngx_queue_sentinel(&node->children);
3202          q = ngx_queue_next(q))
3203     {
3204         child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
3205         child->parent = parent;
3206         child->weight = node->weight * child->weight / weight;
3207 
3208         if (child->weight == 0) {
3209             child->weight = 1;
3210         }
3211     }
3212 
3213     if (parent == NGX_HTTP_V2_ROOT) {
3214         node->rank = 0;
3215         node->rel_weight = 1.0;
3216 
3217         children = &h2c->dependencies;
3218 
3219     } else {
3220         node->rank = parent->rank;
3221         node->rel_weight = parent->rel_weight;
3222 
3223         children = &parent->children;
3224     }
3225 
3226     ngx_http_v2_node_children_update(node);
3227     ngx_queue_add(children, &node->children);
3228 
3229     ngx_memzero(node, sizeof(ngx_http_v2_node_t));
3230 
3231     return node;
3232 }
3233 
3234 
3235 static ngx_int_t
3236 ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3237 {
3238     u_char                     ch;
3239     ngx_uint_t                 i;
3240     ngx_http_core_srv_conf_t  *cscf;
3241 
3242     if (header->name.len == 0) {
3243         return NGX_ERROR;
3244     }
3245 
3246     r->invalid_header = 0;
3247 
3248     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
3249 
3250     for (i = (header->name.data[0] == ':'); i != header->name.len; i++) {
3251         ch = header->name.data[i];
3252 
3253         if ((ch >= 'a' && ch <= 'z')
3254             || (ch == '-')
3255             || (ch >= '0' && ch <= '9')
3256             || (ch == '_' && cscf->underscores_in_headers))
3257         {
3258             continue;
3259         }
3260 
3261         if (ch == '\0' || ch == LF || ch == CR || ch == ':'
3262             || (ch >= 'A' && ch <= 'Z'))
3263         {
3264             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3265                           "client sent invalid header name: \"%V\"",
3266                           &header->name);
3267 
3268             return NGX_ERROR;
3269         }
3270 
3271         r->invalid_header = 1;
3272     }
3273 
3274     for (i = 0; i != header->value.len; i++) {
3275         ch = header->value.data[i];
3276 
3277         if (ch == '\0' || ch == LF || ch == CR) {
3278             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3279                           "client sent header \"%V\" with "
3280                           "invalid value: \"%V\"",
3281                           &header->name, &header->value);
3282 
3283             return NGX_ERROR;
3284         }
3285     }
3286 
3287     return NGX_OK;
3288 }
3289 
3290 
3291 static ngx_int_t
3292 ngx_http_v2_pseudo_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3293 {
3294     header->name.len--;
3295     header->name.data++;
3296 
3297     switch (header->name.len) {
3298     case 4:
3299         if (ngx_memcmp(header->name.data, "path", sizeof("path") - 1)
3300             == 0)
3301         {
3302             return ngx_http_v2_parse_path(r, &header->value);
3303         }
3304 
3305         break;
3306 
3307     case 6:
3308         if (ngx_memcmp(header->name.data, "method", sizeof("method") - 1)
3309             == 0)
3310         {
3311             return ngx_http_v2_parse_method(r, &header->value);
3312         }
3313 
3314         if (ngx_memcmp(header->name.data, "scheme", sizeof("scheme") - 1)
3315             == 0)
3316         {
3317             return ngx_http_v2_parse_scheme(r, &header->value);
3318         }
3319 
3320         break;
3321 
3322     case 9:
3323         if (ngx_memcmp(header->name.data, "authority", sizeof("authority") - 1)
3324             == 0)
3325         {
3326             return ngx_http_v2_parse_authority(r, &header->value);
3327         }
3328 
3329         break;
3330     }
3331 
3332     ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3333                   "client sent unknown pseudo-header \":%V\"",
3334                   &header->name);
3335 
3336     return NGX_DECLINED;
3337 }
3338 
3339 
3340 static ngx_int_t
3341 ngx_http_v2_parse_path(ngx_http_request_t *r, ngx_str_t *value)
3342 {
3343     if (r->unparsed_uri.len) {
3344         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3345                       "client sent duplicate :path header");
3346 
3347         return NGX_DECLINED;
3348     }
3349 
3350     if (value->len == 0) {
3351         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3352                       "client sent empty :path header");
3353 
3354         return NGX_DECLINED;
3355     }
3356 
3357     r->uri_start = value->data;
3358     r->uri_end = value->data + value->len;
3359 
3360     if (ngx_http_parse_uri(r) != NGX_OK) {
3361         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3362                       "client sent invalid :path header: \"%V\"", value);
3363 
3364         return NGX_DECLINED;
3365     }
3366 
3367     if (ngx_http_process_request_uri(r) != NGX_OK) {
3368         /*
3369          * request has been finalized already
3370          * in ngx_http_process_request_uri()
3371          */
3372         return NGX_ABORT;
3373     }
3374 
3375     return NGX_OK;
3376 }
3377 
3378 
3379 static ngx_int_t
3380 ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value)
3381 {
3382     size_t         k, len;
3383     ngx_uint_t     n;
3384     const u_char  *p, *m;
3385 
3386     /*
3387      * This array takes less than 256 sequential bytes,
3388      * and if typical CPU cache line size is 64 bytes,
3389      * it is prefetched for 4 load operations.
3390      */
3391     static const struct {
3392         u_char            len;
3393         const u_char      method[11];
3394         uint32_t          value;
3395     } tests[] = {
3396         { 3, "GET",       NGX_HTTP_GET },
3397         { 4, "POST",      NGX_HTTP_POST },
3398         { 4, "HEAD",      NGX_HTTP_HEAD },
3399         { 7, "OPTIONS",   NGX_HTTP_OPTIONS },
3400         { 8, "PROPFIND",  NGX_HTTP_PROPFIND },
3401         { 3, "PUT",       NGX_HTTP_PUT },
3402         { 5, "MKCOL",     NGX_HTTP_MKCOL },
3403         { 6, "DELETE",    NGX_HTTP_DELETE },
3404         { 4, "COPY",      NGX_HTTP_COPY },
3405         { 4, "MOVE",      NGX_HTTP_MOVE },
3406         { 9, "PROPPATCH", NGX_HTTP_PROPPATCH },
3407         { 4, "LOCK",      NGX_HTTP_LOCK },
3408         { 6, "UNLOCK",    NGX_HTTP_UNLOCK },
3409         { 5, "PATCH",     NGX_HTTP_PATCH },
3410         { 5, "TRACE",     NGX_HTTP_TRACE }
3411     }, *test;
3412 
3413     if (r->method_name.len) {
3414         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3415                       "client sent duplicate :method header");
3416 
3417         return NGX_DECLINED;
3418     }
3419 
3420     if (value->len == 0) {
3421         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3422                       "client sent empty :method header");
3423 
3424         return NGX_DECLINED;
3425     }
3426 
3427     r->method_name.len = value->len;
3428     r->method_name.data = value->data;
3429 
3430     len = r->method_name.len;
3431     n = sizeof(tests) / sizeof(tests[0]);
3432     test = tests;
3433 
3434     do {
3435         if (len == test->len) {
3436             p = r->method_name.data;
3437             m = test->method;
3438             k = len;
3439 
3440             do {
3441                 if (*p++ != *m++) {
3442                     goto next;
3443                 }
3444             } while (--k);
3445 
3446             r->method = test->value;
3447             return NGX_OK;
3448         }
3449 
3450     next:
3451         test++;
3452 
3453     } while (--n);
3454 
3455     p = r->method_name.data;
3456 
3457     do {
3458         if ((*p < 'A' || *p > 'Z') && *p != '_' && *p != '-') {
3459             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3460                           "client sent invalid method: \"%V\"",
3461                           &r->method_name);
3462 
3463             return NGX_DECLINED;
3464         }
3465 
3466         p++;
3467 
3468     } while (--len);
3469 
3470     return NGX_OK;
3471 }
3472 
3473 
3474 static ngx_int_t
3475 ngx_http_v2_parse_scheme(ngx_http_request_t *r, ngx_str_t *value)
3476 {
3477     if (r->schema_start) {
3478         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3479                       "client sent duplicate :scheme header");
3480 
3481         return NGX_DECLINED;
3482     }
3483 
3484     if (value->len == 0) {
3485         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3486                       "client sent empty :scheme header");
3487 
3488         return NGX_DECLINED;
3489     }
3490 
3491     r->schema_start = value->data;
3492     r->schema_end = value->data + value->len;
3493 
3494     return NGX_OK;
3495 }
3496 
3497 
3498 static ngx_int_t
3499 ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value)
3500 {
3501     return ngx_http_v2_parse_header(r, &ngx_http_v2_parse_headers[0], value);
3502 }
3503 
3504 
3505 static ngx_int_t
3506 ngx_http_v2_parse_header(ngx_http_request_t *r,
3507     ngx_http_v2_parse_header_t *header, ngx_str_t *value)
3508 {
3509     ngx_table_elt_t            *h;
3510     ngx_http_core_main_conf_t  *cmcf;
3511 
3512     h = ngx_list_push(&r->headers_in.headers);
3513     if (h == NULL) {
3514         return NGX_ERROR;
3515     }
3516 
3517     h->key.len = header->name.len;
3518     h->key.data = header->name.data;
3519     h->lowcase_key = header->name.data;
3520 
3521     if (header->hh == NULL) {
3522         header->hash = ngx_hash_key(header->name.data, header->name.len);
3523 
3524         cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3525 
3526         header->hh = ngx_hash_find(&cmcf->headers_in_hash, header->hash,
3527                                    h->lowcase_key, h->key.len);
3528         if (header->hh == NULL) {
3529             return NGX_ERROR;
3530         }
3531     }
3532 
3533     h->hash = header->hash;
3534 
3535     h->value.len = value->len;
3536     h->value.data = value->data;
3537 
3538     if (header->hh->handler(r, h, header->hh->offset) != NGX_OK) {
3539         /* header handler has already finalized request */
3540         return NGX_ABORT;
3541     }
3542 
3543     return NGX_OK;
3544 }
3545 
3546 
3547 static ngx_int_t
3548 ngx_http_v2_construct_request_line(ngx_http_request_t *r)
3549 {
3550     u_char  *p;
3551 
3552     static const u_char ending[] = " HTTP/2.0";
3553 
3554     if (r->method_name.len == 0
3555         || r->schema_start == NULL
3556         || r->unparsed_uri.len == 0)
3557     {
3558         if (r->method_name.len == 0) {
3559             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3560                           "client sent no :method header");
3561 
3562         } else if (r->schema_start == NULL) {
3563             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3564                           "client sent no :scheme header");
3565 
3566         } else {
3567             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3568                           "client sent no :path header");
3569         }
3570 
3571         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3572         return NGX_ERROR;
3573     }
3574 
3575     r->request_line.len = r->method_name.len + 1
3576                           + r->unparsed_uri.len
3577                           + sizeof(ending) - 1;
3578 
3579     p = ngx_pnalloc(r->pool, r->request_line.len + 1);
3580     if (p == NULL) {
3581         ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3582         return NGX_ERROR;
3583     }
3584 
3585     r->request_line.data = p;
3586 
3587     p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
3588 
3589     *p++ = ' ';
3590 
3591     p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
3592 
3593     ngx_memcpy(p, ending, sizeof(ending));
3594 
3595     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3596                    "http2 request line: \"%V\"", &r->request_line);
3597 
3598     return NGX_OK;
3599 }
3600 
3601 
3602 static ngx_int_t
3603 ngx_http_v2_cookie(ngx_http_request_t *r, ngx_http_v2_header_t *header)
3604 {
3605     ngx_str_t    *val;
3606     ngx_array_t  *cookies;
3607 
3608     cookies = r->stream->cookies;
3609 
3610     if (cookies == NULL) {
3611         cookies = ngx_array_create(r->pool, 2, sizeof(ngx_str_t));
3612         if (cookies == NULL) {
3613             return NGX_ERROR;
3614         }
3615 
3616         r->stream->cookies = cookies;
3617     }
3618 
3619     val = ngx_array_push(cookies);
3620     if (val == NULL) {
3621         return NGX_ERROR;
3622     }
3623 
3624     val->len = header->value.len;
3625     val->data = header->value.data;
3626 
3627     return NGX_OK;
3628 }
3629 
3630 
3631 static ngx_int_t
3632 ngx_http_v2_construct_cookie_header(ngx_http_request_t *r)
3633 {
3634     u_char                     *buf, *p, *end;
3635     size_t                      len;
3636     ngx_str_t                  *vals;
3637     ngx_uint_t                  i;
3638     ngx_array_t                *cookies;
3639     ngx_table_elt_t            *h;
3640     ngx_http_header_t          *hh;
3641     ngx_http_core_main_conf_t  *cmcf;
3642 
3643     static ngx_str_t cookie = ngx_string("cookie");
3644 
3645     cookies = r->stream->cookies;
3646 
3647     if (cookies == NULL) {
3648         return NGX_OK;
3649     }
3650 
3651     vals = cookies->elts;
3652 
3653     i = 0;
3654     len = 0;
3655 
3656     do {
3657         len += vals[i].len + 2;
3658     } while (++i != cookies->nelts);
3659 
3660     len -= 2;
3661 
3662     buf = ngx_pnalloc(r->pool, len + 1);
3663     if (buf == NULL) {
3664         ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3665         return NGX_ERROR;
3666     }
3667 
3668     p = buf;
3669     end = buf + len;
3670 
3671     for (i = 0; /* void */ ; i++) {
3672 
3673         p = ngx_cpymem(p, vals[i].data, vals[i].len);
3674 
3675         if (p == end) {
3676             *p = '\0';
3677             break;
3678         }
3679 
3680         *p++ = ';'; *p++ = ' ';
3681     }
3682 
3683     h = ngx_list_push(&r->headers_in.headers);
3684     if (h == NULL) {
3685         ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3686         return NGX_ERROR;
3687     }
3688 
3689     h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
3690                                     ngx_hash('c', 'o'), 'o'), 'k'), 'i'), 'e');
3691 
3692     h->key.len = cookie.len;
3693     h->key.data = cookie.data;
3694 
3695     h->value.len = len;
3696     h->value.data = buf;
3697 
3698     h->lowcase_key = cookie.data;
3699 
3700     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
3701 
3702     hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
3703                        h->lowcase_key, h->key.len);
3704 
3705     if (hh == NULL) {
3706         ngx_http_v2_close_stream(r->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
3707         return NGX_ERROR;
3708     }
3709 
3710     if (hh->handler(r, h, hh->offset) != NGX_OK) {
3711         /*
3712          * request has been finalized already
3713          * in ngx_http_process_multi_header_lines()
3714          */
3715         return NGX_ERROR;
3716     }
3717 
3718     return NGX_OK;
3719 }
3720 
3721 
3722 static void
3723 ngx_http_v2_run_request(ngx_http_request_t *r)
3724 {
3725     if (ngx_http_v2_construct_request_line(r) != NGX_OK) {
3726         return;
3727     }
3728 
3729     if (ngx_http_v2_construct_cookie_header(r) != NGX_OK) {
3730         return;
3731     }
3732 
3733     r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
3734 
3735     if (ngx_http_process_request_header(r) != NGX_OK) {
3736         return;
3737     }
3738 
3739     if (r->headers_in.content_length_n > 0 && r->stream->in_closed) {
3740         ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3741                       "client prematurely closed stream");
3742 
3743         r->stream->skip_data = 1;
3744 
3745         ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3746         return;
3747     }
3748 
3749     if (r->headers_in.content_length_n == -1 && !r->stream->in_closed) {
3750         r->headers_in.chunked = 1;
3751     }
3752 
3753     ngx_http_process_request(r);
3754 }
3755 
3756 
3757 static void
3758 ngx_http_v2_run_request_handler(ngx_event_t *ev)
3759 {
3760     ngx_connection_t    *fc;
3761     ngx_http_request_t  *r;
3762 
3763     fc = ev->data;
3764     r = fc->data;
3765 
3766     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
3767                    "http2 run request handler");
3768 
3769     ngx_http_v2_run_request(r);
3770 }
3771 
3772 
3773 ngx_int_t
3774 ngx_http_v2_read_request_body(ngx_http_request_t *r)
3775 {
3776     off_t                      len;
3777     size_t                     size;
3778     ngx_buf_t                 *buf;
3779     ngx_int_t                  rc;
3780     ngx_http_v2_stream_t      *stream;
3781     ngx_http_v2_srv_conf_t    *h2scf;
3782     ngx_http_request_body_t   *rb;
3783     ngx_http_core_loc_conf_t  *clcf;
3784     ngx_http_v2_connection_t  *h2c;
3785 
3786     stream = r->stream;
3787     rb = r->request_body;
3788 
3789     if (stream->skip_data) {
3790         r->request_body_no_buffering = 0;
3791         rb->post_handler(r);
3792         return NGX_OK;
3793     }
3794 
3795     h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module);
3796     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3797 
3798     len = r->headers_in.content_length_n;
3799 
3800     if (r->request_body_no_buffering && !stream->in_closed) {
3801 
3802         if (len < 0 || len > (off_t) clcf->client_body_buffer_size) {
3803             len = clcf->client_body_buffer_size;
3804         }
3805 
3806         /*
3807          * We need a room to store data up to the stream's initial window size,
3808          * at least until this window will be exhausted.
3809          */
3810 
3811         if (len < (off_t) h2scf->preread_size) {
3812             len = h2scf->preread_size;
3813         }
3814 
3815         if (len > NGX_HTTP_V2_MAX_WINDOW) {
3816             len = NGX_HTTP_V2_MAX_WINDOW;
3817         }
3818 
3819         rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3820 
3821     } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size
3822                && !r->request_body_in_file_only)
3823     {
3824         rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3825 
3826     } else {
3827         rb->buf = ngx_calloc_buf(r->pool);
3828 
3829         if (rb->buf != NULL) {
3830             rb->buf->sync = 1;
3831         }
3832     }
3833 
3834     if (rb->buf == NULL) {
3835         stream->skip_data = 1;
3836         return NGX_HTTP_INTERNAL_SERVER_ERROR;
3837     }
3838 
3839     rb->rest = 1;
3840 
3841     buf = stream->preread;
3842 
3843     if (stream->in_closed) {
3844         r->request_body_no_buffering = 0;
3845 
3846         if (buf) {
3847             rc = ngx_http_v2_process_request_body(r, buf->pos,
3848                                                   buf->last - buf->pos, 1);
3849             ngx_pfree(r->pool, buf->start);
3850             return rc;
3851         }
3852 
3853         return ngx_http_v2_process_request_body(r, NULL, 0, 1);
3854     }
3855 
3856     if (buf) {
3857         rc = ngx_http_v2_process_request_body(r, buf->pos,
3858                                               buf->last - buf->pos, 0);
3859 
3860         ngx_pfree(r->pool, buf->start);
3861 
3862         if (rc != NGX_OK) {
3863             stream->skip_data = 1;
3864             return rc;
3865         }
3866     }
3867 
3868     if (r->request_body_no_buffering) {
3869         size = (size_t) len - h2scf->preread_size;
3870 
3871     } else {
3872         stream->no_flow_control = 1;
3873         size = NGX_HTTP_V2_MAX_WINDOW - stream->recv_window;
3874     }
3875 
3876     if (size) {
3877         if (ngx_http_v2_send_window_update(stream->connection,
3878                                            stream->node->id, size)
3879             == NGX_ERROR)
3880         {
3881             stream->skip_data = 1;
3882             return NGX_HTTP_INTERNAL_SERVER_ERROR;
3883         }
3884 
3885         h2c = stream->connection;
3886 
3887         if (!h2c->blocked) {
3888             if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
3889                 stream->skip_data = 1;
3890                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3891             }
3892         }
3893 
3894         stream->recv_window += size;
3895     }
3896 
3897     if (!buf) {
3898         ngx_add_timer(r->connection->read, clcf->client_body_timeout);
3899     }
3900 
3901     r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
3902     r->write_event_handler = ngx_http_request_empty_handler;
3903 
3904     return NGX_AGAIN;
3905 }
3906 
3907 
3908 static ngx_int_t
3909 ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos,
3910     size_t size, ngx_uint_t last)
3911 {
3912     ngx_buf_t                 *buf;
3913     ngx_int_t                  rc;
3914     ngx_connection_t          *fc;
3915     ngx_http_request_body_t   *rb;
3916     ngx_http_core_loc_conf_t  *clcf;
3917 
3918     fc = r->connection;
3919     rb = r->request_body;
3920     buf = rb->buf;
3921 
3922     if (size) {
3923         if (buf->sync) {
3924             buf->pos = buf->start = pos;
3925             buf->last = buf->end = pos + size;
3926 
3927             r->request_body_in_file_only = 1;
3928 
3929         } else {
3930             if (size > (size_t) (buf->end - buf->last)) {
3931                 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
3932                               "client intended to send body data "
3933                               "larger than declared");
3934 
3935                 return NGX_HTTP_BAD_REQUEST;
3936             }
3937 
3938             buf->last = ngx_cpymem(buf->last, pos, size);
3939         }
3940     }
3941 
3942     if (last) {
3943         rb->rest = 0;
3944 
3945         if (fc->read->timer_set) {
3946             ngx_del_timer(fc->read);
3947         }
3948 
3949         if (r->request_body_no_buffering) {
3950             ngx_post_event(fc->read, &ngx_posted_events);
3951             return NGX_OK;
3952         }
3953 
3954         rc = ngx_http_v2_filter_request_body(r);
3955 
3956         if (rc != NGX_OK) {
3957             return rc;
3958         }
3959 
3960         if (buf->sync) {
3961             /* prevent reusing this buffer in the upstream module */
3962             rb->buf = NULL;
3963         }
3964 
3965         if (r->headers_in.chunked) {
3966             r->headers_in.content_length_n = rb->received;
3967         }
3968 
3969         r->read_event_handler = ngx_http_block_reading;
3970         rb->post_handler(r);
3971 
3972         return NGX_OK;
3973     }
3974 
3975     if (size == 0) {
3976         return NGX_OK;
3977     }
3978 
3979     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3980     ngx_add_timer(fc->read, clcf->client_body_timeout);
3981 
3982     if (r->request_body_no_buffering) {
3983         ngx_post_event(fc->read, &ngx_posted_events);
3984         return NGX_OK;
3985     }
3986 
3987     if (buf->sync) {
3988         return ngx_http_v2_filter_request_body(r);
3989     }
3990 
3991     return NGX_OK;
3992 }
3993 
3994 
3995 static ngx_int_t
3996 ngx_http_v2_filter_request_body(ngx_http_request_t *r)
3997 {
3998     ngx_buf_t                 *b, *buf;
3999     ngx_int_t                  rc;
4000     ngx_chain_t               *cl;
4001     ngx_http_request_body_t   *rb;
4002     ngx_http_core_loc_conf_t  *clcf;
4003 
4004     rb = r->request_body;
4005     buf = rb->buf;
4006 
4007     if (buf->pos == buf->last && rb->rest) {
4008         cl = NULL;
4009         goto update;
4010     }
4011 
4012     cl = ngx_chain_get_free_buf(r->pool, &rb->free);
4013     if (cl == NULL) {
4014         return NGX_HTTP_INTERNAL_SERVER_ERROR;
4015     }
4016 
4017     b = cl->buf;
4018 
4019     ngx_memzero(b, sizeof(ngx_buf_t));
4020 
4021     if (buf->pos != buf->last) {
4022         r->request_length += buf->last - buf->pos;
4023         rb->received += buf->last - buf->pos;
4024 
4025         if (r->headers_in.content_length_n != -1) {
4026             if (rb->received > r->headers_in.content_length_n) {
4027                 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4028                               "client intended to send body data "
4029                               "larger than declared");
4030 
4031                 return NGX_HTTP_BAD_REQUEST;
4032             }
4033 
4034         } else {
4035             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4036 
4037             if (clcf->client_max_body_size
4038                 && rb->received > clcf->client_max_body_size)
4039             {
4040                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4041                               "client intended to send too large chunked body: "
4042                               "%O bytes", rb->received);
4043 
4044                 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
4045             }
4046         }
4047 
4048         b->temporary = 1;
4049         b->pos = buf->pos;
4050         b->last = buf->last;
4051         b->start = b->pos;
4052         b->end = b->last;
4053 
4054         buf->pos = buf->last;
4055     }
4056 
4057     if (!rb->rest) {
4058         if (r->headers_in.content_length_n != -1
4059             && r->headers_in.content_length_n != rb->received)
4060         {
4061             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
4062                           "client prematurely closed stream: "
4063                           "only %O out of %O bytes of request body received",
4064                           rb->received, r->headers_in.content_length_n);
4065 
4066             return NGX_HTTP_BAD_REQUEST;
4067         }
4068 
4069         b->last_buf = 1;
4070     }
4071 
4072     b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body;
4073     b->flush = r->request_body_no_buffering;
4074 
4075 update:
4076 
4077     rc = ngx_http_top_request_body_filter(r, cl);
4078 
4079     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl,
4080                             (ngx_buf_tag_t) &ngx_http_v2_filter_request_body);
4081 
4082     return rc;
4083 }
4084 
4085 
4086 static void
4087 ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r)
4088 {
4089     ngx_connection_t  *fc;
4090 
4091     fc = r->connection;
4092 
4093     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4094                    "http2 read client request body handler");
4095 
4096     if (fc->read->timedout) {
4097         ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4098 
4099         fc->timedout = 1;
4100         r->stream->skip_data = 1;
4101 
4102         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
4103         return;
4104     }
4105 
4106     if (fc->error) {
4107         ngx_log_error(NGX_LOG_INFO, fc->log, 0,
4108                       "client prematurely closed stream");
4109 
4110         r->stream->skip_data = 1;
4111 
4112         ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
4113         return;
4114     }
4115 }
4116 
4117 
4118 ngx_int_t
4119 ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r)
4120 {
4121     size_t                     window;
4122     ngx_buf_t                 *buf;
4123     ngx_int_t                  rc;
4124     ngx_connection_t          *fc;
4125     ngx_http_v2_stream_t      *stream;
4126     ngx_http_v2_connection_t  *h2c;
4127     ngx_http_core_loc_conf_t  *clcf;
4128 
4129     stream = r->stream;
4130     fc = r->connection;
4131 
4132     if (fc->read->timedout) {
4133         if (stream->recv_window) {
4134             stream->skip_data = 1;
4135             fc->timedout = 1;
4136 
4137             return NGX_HTTP_REQUEST_TIME_OUT;
4138         }
4139 
4140         fc->read->timedout = 0;
4141     }
4142 
4143     if (fc->error) {
4144         stream->skip_data = 1;
4145         return NGX_HTTP_BAD_REQUEST;
4146     }
4147 
4148     rc = ngx_http_v2_filter_request_body(r);
4149 
4150     if (rc != NGX_OK) {
4151         stream->skip_data = 1;
4152         return rc;
4153     }
4154 
4155     if (!r->request_body->rest) {
4156         return NGX_OK;
4157     }
4158 
4159     if (r->request_body->busy != NULL) {
4160         return NGX_AGAIN;
4161     }
4162 
4163     buf = r->request_body->buf;
4164 
4165     buf->pos = buf->start;
4166     buf->last = buf->start;
4167 
4168     window = buf->end - buf->start;
4169     h2c = stream->connection;
4170 
4171     if (h2c->state.stream == stream) {
4172         window -= h2c->state.length;
4173     }
4174 
4175     if (window <= stream->recv_window) {
4176         if (window < stream->recv_window) {
4177             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
4178                           "http2 negative window update");
4179             stream->skip_data = 1;
4180             return NGX_HTTP_INTERNAL_SERVER_ERROR;
4181         }
4182 
4183         return NGX_AGAIN;
4184     }
4185 
4186     if (ngx_http_v2_send_window_update(h2c, stream->node->id,
4187                                        window - stream->recv_window)
4188         == NGX_ERROR)
4189     {
4190         stream->skip_data = 1;
4191         return NGX_HTTP_INTERNAL_SERVER_ERROR;
4192     }
4193 
4194     if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4195         stream->skip_data = 1;
4196         return NGX_HTTP_INTERNAL_SERVER_ERROR;
4197     }
4198 
4199     if (stream->recv_window == 0) {
4200         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
4201         ngx_add_timer(fc->read, clcf->client_body_timeout);
4202     }
4203 
4204     stream->recv_window = window;
4205 
4206     return NGX_AGAIN;
4207 }
4208 
4209 
4210 static ngx_int_t
4211 ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
4212     ngx_http_v2_stream_t *stream, ngx_uint_t status)
4213 {
4214     ngx_event_t       *rev;
4215     ngx_connection_t  *fc;
4216 
4217     if (stream->rst_sent) {
4218         return NGX_OK;
4219     }
4220 
4221     if (ngx_http_v2_send_rst_stream(h2c, stream->node->id, status)
4222         == NGX_ERROR)
4223     {
4224         return NGX_ERROR;
4225     }
4226 
4227     stream->rst_sent = 1;
4228     stream->skip_data = 1;
4229 
4230     fc = stream->request->connection;
4231     fc->error = 1;
4232 
4233     rev = fc->read;
4234     rev->handler(rev);
4235 
4236     return NGX_OK;
4237 }
4238 
4239 
4240 void
4241 ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
4242 {
4243     ngx_pool_t                *pool;
4244     ngx_uint_t                 push;
4245     ngx_event_t               *ev;
4246     ngx_connection_t          *fc;
4247     ngx_http_v2_node_t        *node;
4248     ngx_http_v2_connection_t  *h2c;
4249 
4250     h2c = stream->connection;
4251     node = stream->node;
4252 
4253     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4254                    "http2 close stream %ui, queued %ui, "
4255                    "processing %ui, pushing %ui",
4256                    node->id, stream->queued, h2c->processing, h2c->pushing);
4257 
4258     fc = stream->request->connection;
4259 
4260     if (stream->queued) {
4261         fc->write->handler = ngx_http_v2_close_stream_handler;
4262         fc->read->handler = ngx_http_empty_handler;
4263         return;
4264     }
4265 
4266     if (!stream->rst_sent && !h2c->connection->error) {
4267 
4268         if (!stream->out_closed) {
4269             if (ngx_http_v2_send_rst_stream(h2c, node->id,
4270                                       fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR
4271                                                    : NGX_HTTP_V2_INTERNAL_ERROR)
4272                 != NGX_OK)
4273             {
4274                 h2c->connection->error = 1;
4275             }
4276 
4277         } else if (!stream->in_closed) {
4278 #if 0
4279             if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
4280                 != NGX_OK)
4281             {
4282                 h2c->connection->error = 1;
4283             }
4284 #else
4285             /*
4286              * At the time of writing at least the latest versions of Chrome
4287              * do not properly handle RST_STREAM with NO_ERROR status.
4288              *
4289              * See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182
4290              *
4291              * As a workaround, the stream window is maximized before closing
4292              * the stream.  This allows a client to send up to 2 GB of data
4293              * before getting blocked on flow control.
4294              */
4295 
4296             if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW
4297                 && ngx_http_v2_send_window_update(h2c, node->id,
4298                                                   NGX_HTTP_V2_MAX_WINDOW
4299                                                   - stream->recv_window)
4300                    != NGX_OK)
4301             {
4302                 h2c->connection->error = 1;
4303             }
4304 #endif
4305         }
4306     }
4307 
4308     if (h2c->state.stream == stream) {
4309         h2c->state.stream = NULL;
4310     }
4311 
4312     push = stream->node->id % 2 == 0;
4313 
4314     node->stream = NULL;
4315 
4316     ngx_queue_insert_tail(&h2c->closed, &node->reuse);
4317     h2c->closed_nodes++;
4318 
4319     /*
4320      * This pool keeps decoded request headers which can be used by log phase
4321      * handlers in ngx_http_free_request().
4322      *
4323      * The pointer is stored into local variable because the stream object
4324      * will be destroyed after a call to ngx_http_free_request().
4325      */
4326     pool = stream->pool;
4327 
4328     ngx_http_free_request(stream->request, rc);
4329 
4330     if (pool != h2c->state.pool) {
4331         ngx_destroy_pool(pool);
4332 
4333     } else {
4334         /* pool will be destroyed when the complete header is parsed */
4335         h2c->state.keep_pool = 0;
4336     }
4337 
4338     ev = fc->read;
4339 
4340     if (ev->timer_set) {
4341         ngx_del_timer(ev);
4342     }
4343 
4344     if (ev->posted) {
4345         ngx_delete_posted_event(ev);
4346     }
4347 
4348     ev = fc->write;
4349 
4350     if (ev->timer_set) {
4351         ngx_del_timer(ev);
4352     }
4353 
4354     if (ev->posted) {
4355         ngx_delete_posted_event(ev);
4356     }
4357 
4358     fc->data = h2c->free_fake_connections;
4359     h2c->free_fake_connections = fc;
4360 
4361     if (push) {
4362         h2c->pushing--;
4363 
4364     } else {
4365         h2c->processing--;
4366     }
4367 
4368     if (h2c->processing || h2c->pushing || h2c->blocked) {
4369         return;
4370     }
4371 
4372     ev = h2c->connection->read;
4373 
4374     ev->handler = ngx_http_v2_handle_connection_handler;
4375     ngx_post_event(ev, &ngx_posted_events);
4376 }
4377 
4378 
4379 static void
4380 ngx_http_v2_close_stream_handler(ngx_event_t *ev)
4381 {
4382     ngx_connection_t    *fc;
4383     ngx_http_request_t  *r;
4384 
4385     fc = ev->data;
4386     r = fc->data;
4387 
4388     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
4389                    "http2 close stream handler");
4390 
4391     if (ev->timedout) {
4392         ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
4393 
4394         fc->timedout = 1;
4395 
4396         ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT);
4397         return;
4398     }
4399 
4400     ngx_http_v2_close_stream(r->stream, 0);
4401 }
4402 
4403 
4404 static void
4405 ngx_http_v2_handle_connection_handler(ngx_event_t *rev)
4406 {
4407     ngx_connection_t          *c;
4408     ngx_http_v2_connection_t  *h2c;
4409 
4410     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
4411                    "http2 handle connection handler");
4412 
4413     c = rev->data;
4414     h2c = c->data;
4415 
4416     if (c->error) {
4417         ngx_http_v2_finalize_connection(h2c, 0);
4418         return;
4419     }
4420 
4421     rev->handler = ngx_http_v2_read_handler;
4422 
4423     if (rev->ready) {
4424         ngx_http_v2_read_handler(rev);
4425         return;
4426     }
4427 
4428     if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) {
4429         ngx_http_v2_finalize_connection(h2c, 0);
4430         return;
4431     }
4432 
4433     ngx_http_v2_handle_connection(c->data);
4434 }
4435 
4436 
4437 static void
4438 ngx_http_v2_idle_handler(ngx_event_t *rev)
4439 {
4440     ngx_connection_t          *c;
4441     ngx_http_v2_srv_conf_t    *h2scf;
4442     ngx_http_v2_connection_t  *h2c;
4443 
4444     c = rev->data;
4445     h2c = c->data;
4446 
4447     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 idle handler");
4448 
4449     if (rev->timedout || c->close) {
4450         ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
4451         return;
4452     }
4453 
4454 #if (NGX_HAVE_KQUEUE)
4455 
4456     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
4457         if (rev->pending_eof) {
4458             c->log->handler = NULL;
4459             ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
4460                           "kevent() reported that client %V closed "
4461                           "idle connection", &c->addr_text);
4462 #if (NGX_HTTP_SSL)
4463             if (c->ssl) {
4464                 c->ssl->no_send_shutdown = 1;
4465             }
4466 #endif
4467             ngx_http_close_connection(c);
4468             return;
4469         }
4470     }
4471 
4472 #endif
4473 
4474     c->destroyed = 0;
4475     ngx_reusable_connection(c, 0);
4476 
4477     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4478                                          ngx_http_v2_module);
4479 
4480     h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
4481     if (h2c->pool == NULL) {
4482         ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
4483         return;
4484     }
4485 
4486     c->write->handler = ngx_http_v2_write_handler;
4487 
4488     rev->handler = ngx_http_v2_read_handler;
4489     ngx_http_v2_read_handler(rev);
4490 }
4491 
4492 
4493 static void
4494 ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
4495     ngx_uint_t status)
4496 {
4497     ngx_uint_t               i, size;
4498     ngx_event_t             *ev;
4499     ngx_connection_t        *c, *fc;
4500     ngx_http_request_t      *r;
4501     ngx_http_v2_node_t      *node;
4502     ngx_http_v2_stream_t    *stream;
4503     ngx_http_v2_srv_conf_t  *h2scf;
4504 
4505     c = h2c->connection;
4506 
4507     h2c->blocked = 1;
4508 
4509     if (!c->error && !h2c->goaway) {
4510         if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
4511             (void) ngx_http_v2_send_output_queue(h2c);
4512         }
4513     }
4514 
4515     c->error = 1;
4516 
4517     if (!h2c->processing && !h2c->pushing) {
4518         ngx_http_close_connection(c);
4519         return;
4520     }
4521 
4522     c->read->handler = ngx_http_empty_handler;
4523     c->write->handler = ngx_http_empty_handler;
4524 
4525     h2c->last_out = NULL;
4526 
4527     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4528                                          ngx_http_v2_module);
4529 
4530     size = ngx_http_v2_index_size(h2scf);
4531 
4532     for (i = 0; i < size; i++) {
4533 
4534         for (node = h2c->streams_index[i]; node; node = node->index) {
4535             stream = node->stream;
4536 
4537             if (stream == NULL) {
4538                 continue;
4539             }
4540 
4541             stream->waiting = 0;
4542 
4543             r = stream->request;
4544             fc = r->connection;
4545 
4546             fc->error = 1;
4547 
4548             if (stream->queued) {
4549                 stream->queued = 0;
4550 
4551                 ev = fc->write;
4552                 ev->active = 0;
4553                 ev->ready = 1;
4554 
4555             } else {
4556                 ev = fc->read;
4557             }
4558 
4559             ev->eof = 1;
4560             ev->handler(ev);
4561         }
4562     }
4563 
4564     h2c->blocked = 0;
4565 
4566     if (h2c->processing || h2c->pushing) {
4567         return;
4568     }
4569 
4570     ngx_http_close_connection(c);
4571 }
4572 
4573 
4574 static ngx_int_t
4575 ngx_http_v2_adjust_windows(ngx_http_v2_connection_t *h2c, ssize_t delta)
4576 {
4577     ngx_uint_t               i, size;
4578     ngx_event_t             *wev;
4579     ngx_http_v2_node_t      *node;
4580     ngx_http_v2_stream_t    *stream;
4581     ngx_http_v2_srv_conf_t  *h2scf;
4582 
4583     h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
4584                                          ngx_http_v2_module);
4585 
4586     size = ngx_http_v2_index_size(h2scf);
4587 
4588     for (i = 0; i < size; i++) {
4589 
4590         for (node = h2c->streams_index[i]; node; node = node->index) {
4591             stream = node->stream;
4592 
4593             if (stream == NULL) {
4594                 continue;
4595             }
4596 
4597             if (delta > 0
4598                 && stream->send_window
4599                       > (ssize_t) (NGX_HTTP_V2_MAX_WINDOW - delta))
4600             {
4601                 if (ngx_http_v2_terminate_stream(h2c, stream,
4602                                                  NGX_HTTP_V2_FLOW_CTRL_ERROR)
4603                     == NGX_ERROR)
4604                 {
4605                     return NGX_ERROR;
4606                 }
4607 
4608                 continue;
4609             }
4610 
4611             stream->send_window += delta;
4612 
4613             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
4614                            "http2:%ui adjusted window: %z",
4615                            node->id, stream->send_window);
4616 
4617             if (stream->send_window > 0 && stream->exhausted) {
4618                 stream->exhausted = 0;
4619 
4620                 wev = stream->request->connection->write;
4621 
4622                 wev->active = 0;
4623                 wev->ready = 1;
4624 
4625                 if (!wev->delayed) {
4626                     wev->handler(wev);
4627                 }
4628             }
4629         }
4630     }
4631 
4632     return NGX_OK;
4633 }
4634 
4635 
4636 static void
4637 ngx_http_v2_set_dependency(ngx_http_v2_connection_t *h2c,
4638     ngx_http_v2_node_t *node, ngx_uint_t depend, ngx_uint_t exclusive)
4639 {
4640     ngx_queue_t         *children, *q;
4641     ngx_http_v2_node_t  *parent, *child, *next;
4642 
4643     parent = depend ? ngx_http_v2_get_node_by_id(h2c, depend, 0) : NULL;
4644 
4645     if (parent == NULL) {
4646         parent = NGX_HTTP_V2_ROOT;
4647 
4648         if (depend != 0) {
4649             exclusive = 0;
4650         }
4651 
4652         node->rank = 1;
4653         node->rel_weight = (1.0 / 256) * node->weight;
4654 
4655         children = &h2c->dependencies;
4656 
4657     } else {
4658         if (node->parent != NULL) {
4659 
4660             for (next = parent->parent;
4661                  next != NGX_HTTP_V2_ROOT && next->rank >= node->rank;
4662                  next = next->parent)
4663             {
4664                 if (next != node) {
4665                     continue;
4666                 }
4667 
4668                 ngx_queue_remove(&parent->queue);
4669                 ngx_queue_insert_after(&node->queue, &parent->queue);
4670 
4671                 parent->parent = node->parent;
4672 
4673                 if (node->parent == NGX_HTTP_V2_ROOT) {
4674                     parent->rank = 1;
4675                     parent->rel_weight = (1.0 / 256) * parent->weight;
4676 
4677                 } else {
4678                     parent->rank = node->parent->rank + 1;
4679                     parent->rel_weight = (node->parent->rel_weight / 256)
4680                                          * parent->weight;
4681                 }
4682 
4683                 if (!exclusive) {
4684                     ngx_http_v2_node_children_update(parent);
4685                 }
4686 
4687                 break;
4688             }
4689         }
4690 
4691         node->rank = parent->rank + 1;
4692         node->rel_weight = (parent->rel_weight / 256) * node->weight;
4693 
4694         if (parent->stream == NULL) {
4695             ngx_queue_remove(&parent->reuse);
4696             ngx_queue_insert_tail(&h2c->closed, &parent->reuse);
4697         }
4698 
4699         children = &parent->children;
4700     }
4701 
4702     if (exclusive) {
4703         for (q = ngx_queue_head(children);
4704              q != ngx_queue_sentinel(children);
4705              q = ngx_queue_next(q))
4706         {
4707             child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4708             child->parent = node;
4709         }
4710 
4711         ngx_queue_add(&node->children, children);
4712         ngx_queue_init(children);
4713     }
4714 
4715     if (node->parent != NULL) {
4716         ngx_queue_remove(&node->queue);
4717     }
4718 
4719     ngx_queue_insert_tail(children, &node->queue);
4720 
4721     node->parent = parent;
4722 
4723     ngx_http_v2_node_children_update(node);
4724 }
4725 
4726 
4727 static void
4728 ngx_http_v2_node_children_update(ngx_http_v2_node_t *node)
4729 {
4730     ngx_queue_t         *q;
4731     ngx_http_v2_node_t  *child;
4732 
4733     for (q = ngx_queue_head(&node->children);
4734          q != ngx_queue_sentinel(&node->children);
4735          q = ngx_queue_next(q))
4736     {
4737         child = ngx_queue_data(q, ngx_http_v2_node_t, queue);
4738 
4739         child->rank = node->rank + 1;
4740         child->rel_weight = (node->rel_weight / 256) * child->weight;
4741 
4742         ngx_http_v2_node_children_update(child);
4743     }
4744 }
4745 
4746 
4747 static void
4748 ngx_http_v2_pool_cleanup(void *data)
4749 {
4750     ngx_http_v2_connection_t  *h2c = data;
4751 
4752     if (h2c->state.pool) {
4753         ngx_destroy_pool(h2c->state.pool);
4754     }
4755 
4756     if (h2c->pool) {
4757         ngx_destroy_pool(h2c->pool);
4758     }
4759 }