Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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