Back to home page

Nginx displayed by LXR

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

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