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 <nginx.h>
0012 #include <ngx_http_v2_module.h>
0013 
0014 
0015 /*
0016  * This returns precise number of octets for values in range 0..253
0017  * and estimate number for the rest, but not smaller than required.
0018  */
0019 
0020 #define ngx_http_v2_integer_octets(v)  (1 + (v) / 127)
0021 
0022 #define ngx_http_v2_literal_size(h)                                           \
0023     (ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1)
0024 
0025 #define ngx_http_v2_indexed(i)      (128 + (i))
0026 #define ngx_http_v2_inc_indexed(i)  (64 + (i))
0027 
0028 #define ngx_http_v2_write_name(dst, src, len, tmp)                            \
0029     ngx_http_v2_string_encode(dst, src, len, tmp, 1)
0030 #define ngx_http_v2_write_value(dst, src, len, tmp)                           \
0031     ngx_http_v2_string_encode(dst, src, len, tmp, 0)
0032 
0033 #define NGX_HTTP_V2_ENCODE_RAW            0
0034 #define NGX_HTTP_V2_ENCODE_HUFF           0x80
0035 
0036 #define NGX_HTTP_V2_STATUS_INDEX          8
0037 #define NGX_HTTP_V2_STATUS_200_INDEX      8
0038 #define NGX_HTTP_V2_STATUS_204_INDEX      9
0039 #define NGX_HTTP_V2_STATUS_206_INDEX      10
0040 #define NGX_HTTP_V2_STATUS_304_INDEX      11
0041 #define NGX_HTTP_V2_STATUS_400_INDEX      12
0042 #define NGX_HTTP_V2_STATUS_404_INDEX      13
0043 #define NGX_HTTP_V2_STATUS_500_INDEX      14
0044 
0045 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX  28
0046 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX    31
0047 #define NGX_HTTP_V2_DATE_INDEX            33
0048 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX   44
0049 #define NGX_HTTP_V2_LOCATION_INDEX        46
0050 #define NGX_HTTP_V2_SERVER_INDEX          54
0051 #define NGX_HTTP_V2_VARY_INDEX            59
0052 
0053 
0054 static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
0055     u_char *tmp, ngx_uint_t lower);
0056 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
0057     ngx_uint_t value);
0058 static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame(
0059     ngx_http_request_t *r, u_char *pos, u_char *end);
0060 
0061 static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc,
0062     ngx_chain_t *in, off_t limit);
0063 
0064 static ngx_chain_t *ngx_http_v2_filter_get_shadow(
0065     ngx_http_v2_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size);
0066 static ngx_http_v2_out_frame_t *ngx_http_v2_filter_get_data_frame(
0067     ngx_http_v2_stream_t *stream, size_t len, ngx_chain_t *first,
0068     ngx_chain_t *last);
0069 
0070 static ngx_inline ngx_int_t ngx_http_v2_flow_control(
0071     ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream);
0072 static void ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c,
0073     ngx_http_v2_stream_t *stream);
0074 
0075 static ngx_inline ngx_int_t ngx_http_v2_filter_send(
0076     ngx_connection_t *fc, ngx_http_v2_stream_t *stream);
0077 
0078 static ngx_int_t ngx_http_v2_headers_frame_handler(
0079     ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame);
0080 static ngx_int_t ngx_http_v2_data_frame_handler(
0081     ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame);
0082 static ngx_inline void ngx_http_v2_handle_frame(
0083     ngx_http_v2_stream_t *stream, ngx_http_v2_out_frame_t *frame);
0084 static ngx_inline void ngx_http_v2_handle_stream(
0085     ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream);
0086 
0087 static void ngx_http_v2_filter_cleanup(void *data);
0088 
0089 static ngx_int_t ngx_http_v2_filter_init(ngx_conf_t *cf);
0090 
0091 
0092 static ngx_http_module_t  ngx_http_v2_filter_module_ctx = {
0093     NULL,                                  /* preconfiguration */
0094     ngx_http_v2_filter_init,               /* postconfiguration */
0095 
0096     NULL,                                  /* create main configuration */
0097     NULL,                                  /* init main configuration */
0098 
0099     NULL,                                  /* create server configuration */
0100     NULL,                                  /* merge server configuration */
0101 
0102     NULL,                                  /* create location configuration */
0103     NULL                                   /* merge location configuration */
0104 };
0105 
0106 
0107 ngx_module_t  ngx_http_v2_filter_module = {
0108     NGX_MODULE_V1,
0109     &ngx_http_v2_filter_module_ctx,        /* module context */
0110     NULL,                                  /* module directives */
0111     NGX_HTTP_MODULE,                       /* module type */
0112     NULL,                                  /* init master */
0113     NULL,                                  /* init module */
0114     NULL,                                  /* init process */
0115     NULL,                                  /* init thread */
0116     NULL,                                  /* exit thread */
0117     NULL,                                  /* exit process */
0118     NULL,                                  /* exit master */
0119     NGX_MODULE_V1_PADDING
0120 };
0121 
0122 
0123 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
0124 
0125 
0126 static ngx_int_t
0127 ngx_http_v2_header_filter(ngx_http_request_t *r)
0128 {
0129     u_char                     status, *pos, *start, *p, *tmp;
0130     size_t                     len, tmp_len;
0131     ngx_str_t                  host, location;
0132     ngx_uint_t                 i, port;
0133     ngx_list_part_t           *part;
0134     ngx_table_elt_t           *header;
0135     ngx_connection_t          *fc;
0136     ngx_http_cleanup_t        *cln;
0137     ngx_http_v2_out_frame_t   *frame;
0138     ngx_http_core_loc_conf_t  *clcf;
0139     ngx_http_core_srv_conf_t  *cscf;
0140     u_char                     addr[NGX_SOCKADDR_STRLEN];
0141 
0142     static const u_char nginx[5] = "\x84\xaa\x63\x55\xe7";
0143 #if (NGX_HTTP_GZIP)
0144     static const u_char accept_encoding[12] =
0145         "\x8b\x84\x84\x2d\x69\x5b\x05\x44\x3c\x86\xaa\x6f";
0146 #endif
0147 
0148     static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER);
0149     static u_char nginx_ver[ngx_http_v2_literal_size(NGINX_VER)];
0150 
0151     static size_t nginx_ver_build_len =
0152                                   ngx_http_v2_literal_size(NGINX_VER_BUILD);
0153     static u_char nginx_ver_build[ngx_http_v2_literal_size(NGINX_VER_BUILD)];
0154 
0155     if (!r->stream) {
0156         return ngx_http_next_header_filter(r);
0157     }
0158 
0159     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0160                    "http2 header filter");
0161 
0162     if (r->header_sent) {
0163         return NGX_OK;
0164     }
0165 
0166     r->header_sent = 1;
0167 
0168     if (r != r->main) {
0169         return NGX_OK;
0170     }
0171 
0172     fc = r->connection;
0173 
0174     if (fc->error) {
0175         return NGX_ERROR;
0176     }
0177 
0178     if (r->method == NGX_HTTP_HEAD) {
0179         r->header_only = 1;
0180     }
0181 
0182     switch (r->headers_out.status) {
0183 
0184     case NGX_HTTP_OK:
0185         status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_200_INDEX);
0186         break;
0187 
0188     case NGX_HTTP_NO_CONTENT:
0189         r->header_only = 1;
0190 
0191         ngx_str_null(&r->headers_out.content_type);
0192 
0193         r->headers_out.content_length = NULL;
0194         r->headers_out.content_length_n = -1;
0195 
0196         r->headers_out.last_modified_time = -1;
0197         r->headers_out.last_modified = NULL;
0198 
0199         status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_204_INDEX);
0200         break;
0201 
0202     case NGX_HTTP_PARTIAL_CONTENT:
0203         status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_206_INDEX);
0204         break;
0205 
0206     case NGX_HTTP_NOT_MODIFIED:
0207         r->header_only = 1;
0208         status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_304_INDEX);
0209         break;
0210 
0211     default:
0212         r->headers_out.last_modified_time = -1;
0213         r->headers_out.last_modified = NULL;
0214 
0215         switch (r->headers_out.status) {
0216 
0217         case NGX_HTTP_BAD_REQUEST:
0218             status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_400_INDEX);
0219             break;
0220 
0221         case NGX_HTTP_NOT_FOUND:
0222             status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_404_INDEX);
0223             break;
0224 
0225         case NGX_HTTP_INTERNAL_SERVER_ERROR:
0226             status = ngx_http_v2_indexed(NGX_HTTP_V2_STATUS_500_INDEX);
0227             break;
0228 
0229         default:
0230             status = 0;
0231         }
0232     }
0233 
0234     len = status ? 1 : 1 + ngx_http_v2_literal_size("418");
0235 
0236     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0237 
0238     if (r->headers_out.server == NULL) {
0239 
0240         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
0241             len += 1 + nginx_ver_len;
0242 
0243         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
0244             len += 1 + nginx_ver_build_len;
0245 
0246         } else {
0247             len += 1 + sizeof(nginx);
0248         }
0249     }
0250 
0251     if (r->headers_out.date == NULL) {
0252         len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT");
0253     }
0254 
0255     if (r->headers_out.content_type.len) {
0256         len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_out.content_type.len;
0257 
0258         if (r->headers_out.content_type_len == r->headers_out.content_type.len
0259             && r->headers_out.charset.len)
0260         {
0261             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
0262         }
0263     }
0264 
0265     if (r->headers_out.content_length == NULL
0266         && r->headers_out.content_length_n >= 0)
0267     {
0268         len += 1 + ngx_http_v2_integer_octets(NGX_OFF_T_LEN) + NGX_OFF_T_LEN;
0269     }
0270 
0271     if (r->headers_out.last_modified == NULL
0272         && r->headers_out.last_modified_time != -1)
0273     {
0274         len += 1 + ngx_http_v2_literal_size("Wed, 31 Dec 1986 18:00:00 GMT");
0275     }
0276 
0277     if (r->headers_out.location && r->headers_out.location->value.len) {
0278 
0279         if (r->headers_out.location->value.data[0] == '/'
0280             && clcf->absolute_redirect)
0281         {
0282             if (clcf->server_name_in_redirect) {
0283                 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
0284                 host = cscf->server_name;
0285 
0286             } else if (r->headers_in.server.len) {
0287                 host = r->headers_in.server;
0288 
0289             } else {
0290                 host.len = NGX_SOCKADDR_STRLEN;
0291                 host.data = addr;
0292 
0293                 if (ngx_connection_local_sockaddr(fc, &host, 0) != NGX_OK) {
0294                     return NGX_ERROR;
0295                 }
0296             }
0297 
0298             port = ngx_inet_get_port(fc->local_sockaddr);
0299 
0300             location.len = sizeof("https://") - 1 + host.len
0301                            + r->headers_out.location->value.len;
0302 
0303             if (clcf->port_in_redirect) {
0304 
0305 #if (NGX_HTTP_SSL)
0306                 if (fc->ssl)
0307                     port = (port == 443) ? 0 : port;
0308                 else
0309 #endif
0310                     port = (port == 80) ? 0 : port;
0311 
0312             } else {
0313                 port = 0;
0314             }
0315 
0316             if (port) {
0317                 location.len += sizeof(":65535") - 1;
0318             }
0319 
0320             location.data = ngx_pnalloc(r->pool, location.len);
0321             if (location.data == NULL) {
0322                 return NGX_ERROR;
0323             }
0324 
0325             p = ngx_cpymem(location.data, "http", sizeof("http") - 1);
0326 
0327 #if (NGX_HTTP_SSL)
0328             if (fc->ssl) {
0329                 *p++ = 's';
0330             }
0331 #endif
0332 
0333             *p++ = ':'; *p++ = '/'; *p++ = '/';
0334             p = ngx_cpymem(p, host.data, host.len);
0335 
0336             if (port) {
0337                 p = ngx_sprintf(p, ":%ui", port);
0338             }
0339 
0340             p = ngx_cpymem(p, r->headers_out.location->value.data,
0341                               r->headers_out.location->value.len);
0342 
0343             /* update r->headers_out.location->value for possible logging */
0344 
0345             r->headers_out.location->value.len = p - location.data;
0346             r->headers_out.location->value.data = location.data;
0347             ngx_str_set(&r->headers_out.location->key, "Location");
0348         }
0349 
0350         r->headers_out.location->hash = 0;
0351 
0352         len += 1 + NGX_HTTP_V2_INT_OCTETS + r->headers_out.location->value.len;
0353     }
0354 
0355     tmp_len = len;
0356 
0357 #if (NGX_HTTP_GZIP)
0358     if (r->gzip_vary) {
0359         if (clcf->gzip_vary) {
0360             len += 1 + sizeof(accept_encoding);
0361 
0362         } else {
0363             r->gzip_vary = 0;
0364         }
0365     }
0366 #endif
0367 
0368     part = &r->headers_out.headers.part;
0369     header = part->elts;
0370 
0371     for (i = 0; /* void */; i++) {
0372 
0373         if (i >= part->nelts) {
0374             if (part->next == NULL) {
0375                 break;
0376             }
0377 
0378             part = part->next;
0379             header = part->elts;
0380             i = 0;
0381         }
0382 
0383         if (header[i].hash == 0) {
0384             continue;
0385         }
0386 
0387         if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
0388             ngx_log_error(NGX_LOG_CRIT, fc->log, 0,
0389                           "too long response header name: \"%V\"",
0390                           &header[i].key);
0391             return NGX_ERROR;
0392         }
0393 
0394         if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
0395             ngx_log_error(NGX_LOG_CRIT, fc->log, 0,
0396                           "too long response header value: \"%V: %V\"",
0397                           &header[i].key, &header[i].value);
0398             return NGX_ERROR;
0399         }
0400 
0401         len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
0402                  + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;
0403 
0404         if (header[i].key.len > tmp_len) {
0405             tmp_len = header[i].key.len;
0406         }
0407 
0408         if (header[i].value.len > tmp_len) {
0409             tmp_len = header[i].value.len;
0410         }
0411     }
0412 
0413     tmp = ngx_palloc(r->pool, tmp_len);
0414     pos = ngx_pnalloc(r->pool, len);
0415 
0416     if (pos == NULL || tmp == NULL) {
0417         return NGX_ERROR;
0418     }
0419 
0420     start = pos;
0421 
0422     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0423                    "http2 output header: \":status: %03ui\"",
0424                    r->headers_out.status);
0425 
0426     if (status) {
0427         *pos++ = status;
0428 
0429     } else {
0430         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX);
0431         *pos++ = NGX_HTTP_V2_ENCODE_RAW | 3;
0432         pos = ngx_sprintf(pos, "%03ui", r->headers_out.status);
0433     }
0434 
0435     if (r->headers_out.server == NULL) {
0436 
0437         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
0438             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0439                            "http2 output header: \"server: %s\"",
0440                            NGINX_VER);
0441 
0442         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
0443             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0444                            "http2 output header: \"server: %s\"",
0445                            NGINX_VER_BUILD);
0446 
0447         } else {
0448             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0449                            "http2 output header: \"server: nginx\"");
0450         }
0451 
0452         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX);
0453 
0454         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
0455             if (nginx_ver[0] == '\0') {
0456                 p = ngx_http_v2_write_value(nginx_ver, (u_char *) NGINX_VER,
0457                                             sizeof(NGINX_VER) - 1, tmp);
0458                 nginx_ver_len = p - nginx_ver;
0459             }
0460 
0461             pos = ngx_cpymem(pos, nginx_ver, nginx_ver_len);
0462 
0463         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
0464             if (nginx_ver_build[0] == '\0') {
0465                 p = ngx_http_v2_write_value(nginx_ver_build,
0466                                             (u_char *) NGINX_VER_BUILD,
0467                                             sizeof(NGINX_VER_BUILD) - 1, tmp);
0468                 nginx_ver_build_len = p - nginx_ver_build;
0469             }
0470 
0471             pos = ngx_cpymem(pos, nginx_ver_build, nginx_ver_build_len);
0472 
0473         } else {
0474             pos = ngx_cpymem(pos, nginx, sizeof(nginx));
0475         }
0476     }
0477 
0478     if (r->headers_out.date == NULL) {
0479         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0480                        "http2 output header: \"date: %V\"",
0481                        &ngx_cached_http_time);
0482 
0483         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX);
0484         pos = ngx_http_v2_write_value(pos, ngx_cached_http_time.data,
0485                                       ngx_cached_http_time.len, tmp);
0486     }
0487 
0488     if (r->headers_out.content_type.len) {
0489         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX);
0490 
0491         if (r->headers_out.content_type_len == r->headers_out.content_type.len
0492             && r->headers_out.charset.len)
0493         {
0494             len = r->headers_out.content_type.len + sizeof("; charset=") - 1
0495                   + r->headers_out.charset.len;
0496 
0497             p = ngx_pnalloc(r->pool, len);
0498             if (p == NULL) {
0499                 return NGX_ERROR;
0500             }
0501 
0502             p = ngx_cpymem(p, r->headers_out.content_type.data,
0503                            r->headers_out.content_type.len);
0504 
0505             p = ngx_cpymem(p, "; charset=", sizeof("; charset=") - 1);
0506 
0507             p = ngx_cpymem(p, r->headers_out.charset.data,
0508                            r->headers_out.charset.len);
0509 
0510             /* updated r->headers_out.content_type is also needed for logging */
0511 
0512             r->headers_out.content_type.len = len;
0513             r->headers_out.content_type.data = p - len;
0514         }
0515 
0516         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0517                        "http2 output header: \"content-type: %V\"",
0518                        &r->headers_out.content_type);
0519 
0520         pos = ngx_http_v2_write_value(pos, r->headers_out.content_type.data,
0521                                       r->headers_out.content_type.len, tmp);
0522     }
0523 
0524     if (r->headers_out.content_length == NULL
0525         && r->headers_out.content_length_n >= 0)
0526     {
0527         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0528                        "http2 output header: \"content-length: %O\"",
0529                        r->headers_out.content_length_n);
0530 
0531         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX);
0532 
0533         p = pos;
0534         pos = ngx_sprintf(pos + 1, "%O", r->headers_out.content_length_n);
0535         *p = NGX_HTTP_V2_ENCODE_RAW | (u_char) (pos - p - 1);
0536     }
0537 
0538     if (r->headers_out.last_modified == NULL
0539         && r->headers_out.last_modified_time != -1)
0540     {
0541         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX);
0542 
0543         ngx_http_time(pos, r->headers_out.last_modified_time);
0544         len = sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1;
0545 
0546         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0547                        "http2 output header: \"last-modified: %*s\"",
0548                        len, pos);
0549 
0550         /*
0551          * Date will always be encoded using huffman in the temporary buffer,
0552          * so it's safe here to use src and dst pointing to the same address.
0553          */
0554         pos = ngx_http_v2_write_value(pos, pos, len, tmp);
0555     }
0556 
0557     if (r->headers_out.location && r->headers_out.location->value.len) {
0558         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0559                        "http2 output header: \"location: %V\"",
0560                        &r->headers_out.location->value);
0561 
0562         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX);
0563         pos = ngx_http_v2_write_value(pos, r->headers_out.location->value.data,
0564                                       r->headers_out.location->value.len, tmp);
0565     }
0566 
0567 #if (NGX_HTTP_GZIP)
0568     if (r->gzip_vary) {
0569         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0570                        "http2 output header: \"vary: Accept-Encoding\"");
0571 
0572         *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX);
0573         pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding));
0574     }
0575 #endif
0576 
0577     part = &r->headers_out.headers.part;
0578     header = part->elts;
0579 
0580     for (i = 0; /* void */; i++) {
0581 
0582         if (i >= part->nelts) {
0583             if (part->next == NULL) {
0584                 break;
0585             }
0586 
0587             part = part->next;
0588             header = part->elts;
0589             i = 0;
0590         }
0591 
0592         if (header[i].hash == 0) {
0593             continue;
0594         }
0595 
0596 #if (NGX_DEBUG)
0597         if (fc->log->log_level & NGX_LOG_DEBUG_HTTP) {
0598             ngx_strlow(tmp, header[i].key.data, header[i].key.len);
0599 
0600             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, fc->log, 0,
0601                            "http2 output header: \"%*s: %V\"",
0602                            header[i].key.len, tmp, &header[i].value);
0603         }
0604 #endif
0605 
0606         *pos++ = 0;
0607 
0608         pos = ngx_http_v2_write_name(pos, header[i].key.data,
0609                                      header[i].key.len, tmp);
0610 
0611         pos = ngx_http_v2_write_value(pos, header[i].value.data,
0612                                       header[i].value.len, tmp);
0613     }
0614 
0615     frame = ngx_http_v2_create_headers_frame(r, start, pos);
0616     if (frame == NULL) {
0617         return NGX_ERROR;
0618     }
0619 
0620     ngx_http_v2_queue_blocked_frame(r->stream->connection, frame);
0621 
0622     cln = ngx_http_cleanup_add(r, 0);
0623     if (cln == NULL) {
0624         return NGX_ERROR;
0625     }
0626 
0627     cln->handler = ngx_http_v2_filter_cleanup;
0628     cln->data = r->stream;
0629 
0630     r->stream->queued = 1;
0631 
0632     fc->send_chain = ngx_http_v2_send_chain;
0633     fc->need_last_buf = 1;
0634 
0635     return ngx_http_v2_filter_send(fc, r->stream);
0636 }
0637 
0638 
0639 static u_char *
0640 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
0641     ngx_uint_t lower)
0642 {
0643     size_t  hlen;
0644 
0645     hlen = ngx_http_v2_huff_encode(src, len, tmp, lower);
0646 
0647     if (hlen > 0) {
0648         *dst = NGX_HTTP_V2_ENCODE_HUFF;
0649         dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), hlen);
0650         return ngx_cpymem(dst, tmp, hlen);
0651     }
0652 
0653     *dst = NGX_HTTP_V2_ENCODE_RAW;
0654     dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), len);
0655 
0656     if (lower) {
0657         ngx_strlow(dst, src, len);
0658         return dst + len;
0659     }
0660 
0661     return ngx_cpymem(dst, src, len);
0662 }
0663 
0664 
0665 static u_char *
0666 ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value)
0667 {
0668     if (value < prefix) {
0669         *pos++ |= value;
0670         return pos;
0671     }
0672 
0673     *pos++ |= prefix;
0674     value -= prefix;
0675 
0676     while (value >= 128) {
0677         *pos++ = value % 128 + 128;
0678         value /= 128;
0679     }
0680 
0681     *pos++ = (u_char) value;
0682 
0683     return pos;
0684 }
0685 
0686 
0687 static ngx_http_v2_out_frame_t *
0688 ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos,
0689     u_char *end)
0690 {
0691     u_char                    type, flags;
0692     size_t                    rest, frame_size;
0693     ngx_buf_t                *b;
0694     ngx_chain_t              *cl, **ll;
0695     ngx_http_v2_stream_t     *stream;
0696     ngx_http_v2_out_frame_t  *frame;
0697 
0698     stream = r->stream;
0699     rest = end - pos;
0700 
0701     frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t));
0702     if (frame == NULL) {
0703         return NULL;
0704     }
0705 
0706     frame->handler = ngx_http_v2_headers_frame_handler;
0707     frame->stream = stream;
0708     frame->length = rest;
0709     frame->blocked = 1;
0710     frame->fin = r->header_only;
0711 
0712     ll = &frame->first;
0713 
0714     type = NGX_HTTP_V2_HEADERS_FRAME;
0715     flags = r->header_only ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG;
0716     frame_size = stream->connection->frame_size;
0717 
0718     for ( ;; ) {
0719         if (rest <= frame_size) {
0720             frame_size = rest;
0721             flags |= NGX_HTTP_V2_END_HEADERS_FLAG;
0722         }
0723 
0724         b = ngx_create_temp_buf(r->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE);
0725         if (b == NULL) {
0726             return NULL;
0727         }
0728 
0729         b->last = ngx_http_v2_write_len_and_type(b->last, frame_size, type);
0730         *b->last++ = flags;
0731         b->last = ngx_http_v2_write_sid(b->last, stream->node->id);
0732 
0733         b->tag = (ngx_buf_tag_t) &ngx_http_v2_module;
0734 
0735         cl = ngx_alloc_chain_link(r->pool);
0736         if (cl == NULL) {
0737             return NULL;
0738         }
0739 
0740         cl->buf = b;
0741 
0742         *ll = cl;
0743         ll = &cl->next;
0744 
0745         b = ngx_calloc_buf(r->pool);
0746         if (b == NULL) {
0747             return NULL;
0748         }
0749 
0750         b->pos = pos;
0751 
0752         pos += frame_size;
0753 
0754         b->last = pos;
0755         b->start = b->pos;
0756         b->end = b->last;
0757         b->temporary = 1;
0758 
0759         cl = ngx_alloc_chain_link(r->pool);
0760         if (cl == NULL) {
0761             return NULL;
0762         }
0763 
0764         cl->buf = b;
0765 
0766         *ll = cl;
0767         ll = &cl->next;
0768 
0769         rest -= frame_size;
0770 
0771         if (rest) {
0772             frame->length += NGX_HTTP_V2_FRAME_HEADER_SIZE;
0773 
0774             type = NGX_HTTP_V2_CONTINUATION_FRAME;
0775             flags = NGX_HTTP_V2_NO_FLAG;
0776             continue;
0777         }
0778 
0779         b->last_buf = r->header_only;
0780         cl->next = NULL;
0781         frame->last = cl;
0782 
0783         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0784                        "http2:%ui create HEADERS frame %p: len:%uz",
0785                        stream->node->id, frame, frame->length);
0786 
0787         return frame;
0788     }
0789 }
0790 
0791 
0792 static ngx_chain_t *
0793 ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
0794 {
0795     off_t                      size, offset;
0796     size_t                     rest, frame_size;
0797     ngx_chain_t               *cl, *out, **ln;
0798     ngx_http_request_t        *r;
0799     ngx_http_v2_stream_t      *stream;
0800     ngx_http_v2_loc_conf_t    *h2lcf;
0801     ngx_http_v2_out_frame_t   *frame;
0802     ngx_http_v2_connection_t  *h2c;
0803 
0804     r = fc->data;
0805     stream = r->stream;
0806 
0807 #if (NGX_SUPPRESS_WARN)
0808     size = 0;
0809 #endif
0810 
0811     while (in) {
0812         size = ngx_buf_size(in->buf);
0813 
0814         if (size || in->buf->last_buf) {
0815             break;
0816         }
0817 
0818         in = in->next;
0819     }
0820 
0821     if (in == NULL) {
0822 
0823         if (stream->queued) {
0824             fc->write->active = 1;
0825             fc->write->ready = 0;
0826 
0827         } else {
0828             fc->buffered &= ~NGX_HTTP_V2_BUFFERED;
0829         }
0830 
0831         return NULL;
0832     }
0833 
0834     h2c = stream->connection;
0835 
0836     if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) {
0837         fc->write->active = 1;
0838         fc->write->ready = 0;
0839         return in;
0840     }
0841 
0842     if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) {
0843         cl = ngx_alloc_chain_link(r->pool);
0844         if (cl == NULL) {
0845             return NGX_CHAIN_ERROR;
0846         }
0847 
0848         cl->buf = in->buf;
0849         in->buf = cl->buf->shadow;
0850 
0851         offset = ngx_buf_in_memory(in->buf)
0852                  ? (cl->buf->pos - in->buf->pos)
0853                  : (cl->buf->file_pos - in->buf->file_pos);
0854 
0855         cl->next = stream->free_bufs;
0856         stream->free_bufs = cl;
0857 
0858     } else {
0859         offset = 0;
0860     }
0861 
0862     if (limit == 0 || limit > (off_t) h2c->send_window) {
0863         limit = h2c->send_window;
0864     }
0865 
0866     if (limit > stream->send_window) {
0867         limit = (stream->send_window > 0) ? stream->send_window : 0;
0868     }
0869 
0870     h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module);
0871 
0872     frame_size = (h2lcf->chunk_size < h2c->frame_size)
0873                  ? h2lcf->chunk_size : h2c->frame_size;
0874 
0875 #if (NGX_SUPPRESS_WARN)
0876     cl = NULL;
0877 #endif
0878 
0879     for ( ;; ) {
0880         if ((off_t) frame_size > limit) {
0881             frame_size = (size_t) limit;
0882         }
0883 
0884         ln = &out;
0885         rest = frame_size;
0886 
0887         while ((off_t) rest >= size) {
0888 
0889             if (offset) {
0890                 cl = ngx_http_v2_filter_get_shadow(stream, in->buf,
0891                                                    offset, size);
0892                 if (cl == NULL) {
0893                     return NGX_CHAIN_ERROR;
0894                 }
0895 
0896                 offset = 0;
0897 
0898             } else {
0899                 cl = ngx_alloc_chain_link(r->pool);
0900                 if (cl == NULL) {
0901                     return NGX_CHAIN_ERROR;
0902                 }
0903 
0904                 cl->buf = in->buf;
0905             }
0906 
0907             *ln = cl;
0908             ln = &cl->next;
0909 
0910             rest -= (size_t) size;
0911             in = in->next;
0912 
0913             if (in == NULL) {
0914                 frame_size -= rest;
0915                 rest = 0;
0916                 break;
0917             }
0918 
0919             size = ngx_buf_size(in->buf);
0920         }
0921 
0922         if (rest) {
0923             cl = ngx_http_v2_filter_get_shadow(stream, in->buf, offset, rest);
0924             if (cl == NULL) {
0925                 return NGX_CHAIN_ERROR;
0926             }
0927 
0928             cl->buf->flush = 0;
0929             cl->buf->last_buf = 0;
0930 
0931             *ln = cl;
0932 
0933             offset += rest;
0934             size -= rest;
0935         }
0936 
0937         frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl);
0938         if (frame == NULL) {
0939             return NGX_CHAIN_ERROR;
0940         }
0941 
0942         ngx_http_v2_queue_frame(h2c, frame);
0943 
0944         h2c->send_window -= frame_size;
0945 
0946         stream->send_window -= frame_size;
0947         stream->queued++;
0948 
0949         if (in == NULL) {
0950             break;
0951         }
0952 
0953         limit -= frame_size;
0954 
0955         if (limit == 0) {
0956             break;
0957         }
0958     }
0959 
0960     if (offset) {
0961         cl = ngx_http_v2_filter_get_shadow(stream, in->buf, offset, size);
0962         if (cl == NULL) {
0963             return NGX_CHAIN_ERROR;
0964         }
0965 
0966         in->buf = cl->buf;
0967         ngx_free_chain(r->pool, cl);
0968     }
0969 
0970     if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) {
0971         return NGX_CHAIN_ERROR;
0972     }
0973 
0974     if (in && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) {
0975         fc->write->active = 1;
0976         fc->write->ready = 0;
0977     }
0978 
0979     return in;
0980 }
0981 
0982 
0983 static ngx_chain_t *
0984 ngx_http_v2_filter_get_shadow(ngx_http_v2_stream_t *stream, ngx_buf_t *buf,
0985     off_t offset, off_t size)
0986 {
0987     ngx_buf_t    *chunk;
0988     ngx_chain_t  *cl;
0989 
0990     cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs);
0991     if (cl == NULL) {
0992         return NULL;
0993     }
0994 
0995     chunk = cl->buf;
0996 
0997     ngx_memcpy(chunk, buf, sizeof(ngx_buf_t));
0998 
0999     chunk->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow;
1000     chunk->shadow = buf;
1001 
1002     if (ngx_buf_in_memory(chunk)) {
1003         chunk->pos += offset;
1004         chunk->last = chunk->pos + size;
1005     }
1006 
1007     if (chunk->in_file) {
1008         chunk->file_pos += offset;
1009         chunk->file_last = chunk->file_pos + size;
1010     }
1011 
1012     return cl;
1013 }
1014 
1015 
1016 static ngx_http_v2_out_frame_t *
1017 ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream,
1018     size_t len, ngx_chain_t *first, ngx_chain_t *last)
1019 {
1020     u_char                    flags;
1021     ngx_buf_t                *buf;
1022     ngx_chain_t              *cl;
1023     ngx_http_v2_out_frame_t  *frame;
1024 
1025     frame = stream->free_frames;
1026 
1027     if (frame) {
1028         stream->free_frames = frame->next;
1029 
1030     } else {
1031         frame = ngx_palloc(stream->request->pool,
1032                            sizeof(ngx_http_v2_out_frame_t));
1033         if (frame == NULL) {
1034             return NULL;
1035         }
1036     }
1037 
1038     flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0;
1039 
1040     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, stream->request->connection->log, 0,
1041                    "http2:%ui create DATA frame %p: len:%uz flags:%ui",
1042                    stream->node->id, frame, len, (ngx_uint_t) flags);
1043 
1044     cl = ngx_chain_get_free_buf(stream->request->pool,
1045                                 &stream->free_frame_headers);
1046     if (cl == NULL) {
1047         return NULL;
1048     }
1049 
1050     buf = cl->buf;
1051 
1052     if (buf->start == NULL) {
1053         buf->start = ngx_palloc(stream->request->pool,
1054                                 NGX_HTTP_V2_FRAME_HEADER_SIZE);
1055         if (buf->start == NULL) {
1056             return NULL;
1057         }
1058 
1059         buf->end = buf->start + NGX_HTTP_V2_FRAME_HEADER_SIZE;
1060         buf->last = buf->end;
1061 
1062         buf->tag = (ngx_buf_tag_t) &ngx_http_v2_module;
1063         buf->memory = 1;
1064     }
1065 
1066     buf->pos = buf->start;
1067     buf->last = buf->pos;
1068 
1069     buf->last = ngx_http_v2_write_len_and_type(buf->last, len,
1070                                                NGX_HTTP_V2_DATA_FRAME);
1071     *buf->last++ = flags;
1072 
1073     buf->last = ngx_http_v2_write_sid(buf->last, stream->node->id);
1074 
1075     cl->next = first;
1076     first = cl;
1077 
1078     last->buf->flush = 1;
1079 
1080     frame->first = first;
1081     frame->last = last;
1082     frame->handler = ngx_http_v2_data_frame_handler;
1083     frame->stream = stream;
1084     frame->length = len;
1085     frame->blocked = 0;
1086     frame->fin = last->buf->last_buf;
1087 
1088     return frame;
1089 }
1090 
1091 
1092 static ngx_inline ngx_int_t
1093 ngx_http_v2_filter_send(ngx_connection_t *fc, ngx_http_v2_stream_t *stream)
1094 {
1095     stream->blocked = 1;
1096 
1097     if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) {
1098         fc->error = 1;
1099         return NGX_ERROR;
1100     }
1101 
1102     stream->blocked = 0;
1103 
1104     if (stream->queued) {
1105         fc->buffered |= NGX_HTTP_V2_BUFFERED;
1106         fc->write->active = 1;
1107         fc->write->ready = 0;
1108         return NGX_AGAIN;
1109     }
1110 
1111     fc->buffered &= ~NGX_HTTP_V2_BUFFERED;
1112 
1113     return NGX_OK;
1114 }
1115 
1116 
1117 static ngx_inline ngx_int_t
1118 ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c,
1119     ngx_http_v2_stream_t *stream)
1120 {
1121     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1122                    "http2:%ui available windows: conn:%uz stream:%z",
1123                    stream->node->id, h2c->send_window, stream->send_window);
1124 
1125     if (stream->send_window <= 0) {
1126         stream->exhausted = 1;
1127         return NGX_DECLINED;
1128     }
1129 
1130     if (h2c->send_window == 0) {
1131         ngx_http_v2_waiting_queue(h2c, stream);
1132         return NGX_DECLINED;
1133     }
1134 
1135     return NGX_OK;
1136 }
1137 
1138 
1139 static void
1140 ngx_http_v2_waiting_queue(ngx_http_v2_connection_t *h2c,
1141     ngx_http_v2_stream_t *stream)
1142 {
1143     ngx_queue_t           *q;
1144     ngx_http_v2_stream_t  *s;
1145 
1146     if (stream->waiting) {
1147         return;
1148     }
1149 
1150     stream->waiting = 1;
1151 
1152     for (q = ngx_queue_last(&h2c->waiting);
1153          q != ngx_queue_sentinel(&h2c->waiting);
1154          q = ngx_queue_prev(q))
1155     {
1156         s = ngx_queue_data(q, ngx_http_v2_stream_t, queue);
1157 
1158         if (s->node->rank < stream->node->rank
1159             || (s->node->rank == stream->node->rank
1160                 && s->node->rel_weight >= stream->node->rel_weight))
1161         {
1162             break;
1163         }
1164     }
1165 
1166     ngx_queue_insert_after(q, &stream->queue);
1167 }
1168 
1169 
1170 
1171 static ngx_int_t
1172 ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c,
1173     ngx_http_v2_out_frame_t *frame)
1174 {
1175     ngx_chain_t           *cl, *ln;
1176     ngx_http_v2_stream_t  *stream;
1177 
1178     stream = frame->stream;
1179     cl = frame->first;
1180 
1181     for ( ;; ) {
1182         if (cl->buf->pos != cl->buf->last) {
1183             frame->first = cl;
1184 
1185             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1186                            "http2:%ui HEADERS frame %p was sent partially",
1187                            stream->node->id, frame);
1188 
1189             return NGX_AGAIN;
1190         }
1191 
1192         ln = cl->next;
1193 
1194         if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) {
1195             cl->next = stream->free_frame_headers;
1196             stream->free_frame_headers = cl;
1197 
1198         } else {
1199             cl->next = stream->free_bufs;
1200             stream->free_bufs = cl;
1201         }
1202 
1203         if (cl == frame->last) {
1204             break;
1205         }
1206 
1207         cl = ln;
1208     }
1209 
1210     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1211                    "http2:%ui HEADERS frame %p was sent",
1212                    stream->node->id, frame);
1213 
1214     stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
1215                                     + frame->length;
1216 
1217     ngx_http_v2_handle_frame(stream, frame);
1218 
1219     ngx_http_v2_handle_stream(h2c, stream);
1220 
1221     return NGX_OK;
1222 }
1223 
1224 
1225 static ngx_int_t
1226 ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c,
1227     ngx_http_v2_out_frame_t *frame)
1228 {
1229     ngx_buf_t             *buf;
1230     ngx_chain_t           *cl, *ln;
1231     ngx_http_v2_stream_t  *stream;
1232 
1233     stream = frame->stream;
1234     cl = frame->first;
1235 
1236     if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) {
1237 
1238         if (cl->buf->pos != cl->buf->last) {
1239             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1240                            "http2:%ui DATA frame %p was sent partially",
1241                            stream->node->id, frame);
1242 
1243             return NGX_AGAIN;
1244         }
1245 
1246         ln = cl->next;
1247 
1248         cl->next = stream->free_frame_headers;
1249         stream->free_frame_headers = cl;
1250 
1251         if (cl == frame->last) {
1252             goto done;
1253         }
1254 
1255         cl = ln;
1256     }
1257 
1258     for ( ;; ) {
1259         if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) {
1260             buf = cl->buf->shadow;
1261 
1262             if (ngx_buf_in_memory(buf)) {
1263                 buf->pos = cl->buf->pos;
1264             }
1265 
1266             if (buf->in_file) {
1267                 buf->file_pos = cl->buf->file_pos;
1268             }
1269         }
1270 
1271         if (ngx_buf_size(cl->buf) != 0) {
1272 
1273             if (cl != frame->first) {
1274                 frame->first = cl;
1275                 ngx_http_v2_handle_stream(h2c, stream);
1276             }
1277 
1278             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1279                            "http2:%ui DATA frame %p was sent partially",
1280                            stream->node->id, frame);
1281 
1282             return NGX_AGAIN;
1283         }
1284 
1285         ln = cl->next;
1286 
1287         if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) {
1288             cl->next = stream->free_bufs;
1289             stream->free_bufs = cl;
1290 
1291         } else {
1292             ngx_free_chain(stream->request->pool, cl);
1293         }
1294 
1295         if (cl == frame->last) {
1296             goto done;
1297         }
1298 
1299         cl = ln;
1300     }
1301 
1302 done:
1303 
1304     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
1305                    "http2:%ui DATA frame %p was sent",
1306                    stream->node->id, frame);
1307 
1308     stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE;
1309 
1310     ngx_http_v2_handle_frame(stream, frame);
1311 
1312     ngx_http_v2_handle_stream(h2c, stream);
1313 
1314     return NGX_OK;
1315 }
1316 
1317 
1318 static ngx_inline void
1319 ngx_http_v2_handle_frame(ngx_http_v2_stream_t *stream,
1320     ngx_http_v2_out_frame_t *frame)
1321 {
1322     ngx_http_request_t  *r;
1323 
1324     r = stream->request;
1325 
1326     r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
1327 
1328     if (frame->fin) {
1329         stream->out_closed = 1;
1330     }
1331 
1332     frame->next = stream->free_frames;
1333     stream->free_frames = frame;
1334 
1335     stream->queued--;
1336 }
1337 
1338 
1339 static ngx_inline void
1340 ngx_http_v2_handle_stream(ngx_http_v2_connection_t *h2c,
1341     ngx_http_v2_stream_t *stream)
1342 {
1343     ngx_event_t       *wev;
1344     ngx_connection_t  *fc;
1345 
1346     if (stream->waiting || stream->blocked) {
1347         return;
1348     }
1349 
1350     fc = stream->request->connection;
1351 
1352     if (!fc->error && stream->exhausted) {
1353         return;
1354     }
1355 
1356     wev = fc->write;
1357 
1358     wev->active = 0;
1359     wev->ready = 1;
1360 
1361     if (!fc->error && wev->delayed) {
1362         return;
1363     }
1364 
1365     ngx_post_event(wev, &ngx_posted_events);
1366 }
1367 
1368 
1369 static void
1370 ngx_http_v2_filter_cleanup(void *data)
1371 {
1372     ngx_http_v2_stream_t *stream = data;
1373 
1374     size_t                     window;
1375     ngx_event_t               *wev;
1376     ngx_queue_t               *q;
1377     ngx_http_v2_out_frame_t   *frame, **fn;
1378     ngx_http_v2_connection_t  *h2c;
1379 
1380     if (stream->waiting) {
1381         stream->waiting = 0;
1382         ngx_queue_remove(&stream->queue);
1383     }
1384 
1385     if (stream->queued == 0) {
1386         return;
1387     }
1388 
1389     window = 0;
1390     h2c = stream->connection;
1391     fn = &h2c->last_out;
1392 
1393     for ( ;; ) {
1394         frame = *fn;
1395 
1396         if (frame == NULL) {
1397             break;
1398         }
1399 
1400         if (frame->stream == stream && !frame->blocked) {
1401             *fn = frame->next;
1402 
1403             window += frame->length;
1404 
1405             if (--stream->queued == 0) {
1406                 break;
1407             }
1408 
1409             continue;
1410         }
1411 
1412         fn = &frame->next;
1413     }
1414 
1415     if (h2c->send_window == 0 && window) {
1416 
1417         while (!ngx_queue_empty(&h2c->waiting)) {
1418             q = ngx_queue_head(&h2c->waiting);
1419 
1420             ngx_queue_remove(q);
1421 
1422             stream = ngx_queue_data(q, ngx_http_v2_stream_t, queue);
1423 
1424             stream->waiting = 0;
1425 
1426             wev = stream->request->connection->write;
1427 
1428             wev->active = 0;
1429             wev->ready = 1;
1430 
1431             if (!wev->delayed) {
1432                 ngx_post_event(wev, &ngx_posted_events);
1433             }
1434         }
1435     }
1436 
1437     h2c->send_window += window;
1438 }
1439 
1440 
1441 static ngx_int_t
1442 ngx_http_v2_filter_init(ngx_conf_t *cf)
1443 {
1444     ngx_http_next_header_filter = ngx_http_top_header_filter;
1445     ngx_http_top_header_filter = ngx_http_v2_header_filter;
1446 
1447     return NGX_OK;
1448 }