src/http/modules/ngx_http_proxy_v2_module.c - nginx

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Maxim Dounin
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>
  8. #include <ngx_http_proxy_module.h>


  9. typedef enum {
  10.     ngx_http_proxy_v2_st_start = 0,
  11.     ngx_http_proxy_v2_st_length_2,
  12.     ngx_http_proxy_v2_st_length_3,
  13.     ngx_http_proxy_v2_st_type,
  14.     ngx_http_proxy_v2_st_flags,
  15.     ngx_http_proxy_v2_st_stream_id,
  16.     ngx_http_proxy_v2_st_stream_id_2,
  17.     ngx_http_proxy_v2_st_stream_id_3,
  18.     ngx_http_proxy_v2_st_stream_id_4,
  19.     ngx_http_proxy_v2_st_payload,
  20.     ngx_http_proxy_v2_st_padding
  21. } ngx_http_proxy_v2_state_e;


  22. typedef struct {
  23.     size_t                         init_window;
  24.     size_t                         send_window;
  25.     size_t                         recv_window;
  26.     ngx_uint_t                     last_stream_id;
  27. } ngx_http_proxy_v2_conn_t;


  28. typedef struct {
  29.     ngx_http_proxy_ctx_t           ctx;

  30.     ngx_http_proxy_v2_state_e      state;
  31.     ngx_uint_t                     frame_state;
  32.     ngx_uint_t                     fragment_state;

  33.     ngx_chain_t                   *in;
  34.     ngx_chain_t                   *out;
  35.     ngx_chain_t                   *free;
  36.     ngx_chain_t                   *busy;

  37.     ngx_http_proxy_v2_conn_t      *connection;

  38.     ngx_uint_t                     id;

  39.     ngx_uint_t                     pings;
  40.     ngx_uint_t                     settings;

  41.     off_t                          length;

  42.     ssize_t                        send_window;
  43.     size_t                         recv_window;

  44.     size_t                         rest;
  45.     ngx_uint_t                     stream_id;
  46.     u_char                         type;
  47.     u_char                         flags;
  48.     u_char                         padding;

  49.     ngx_uint_t                     error;
  50.     ngx_uint_t                     window_update;

  51.     ngx_uint_t                     setting_id;
  52.     ngx_uint_t                     setting_value;

  53.     u_char                         ping_data[8];

  54.     ngx_uint_t                     index;
  55.     ngx_str_t                      name;
  56.     ngx_str_t                      value;

  57.     u_char                        *field_end;
  58.     size_t                         field_length;
  59.     size_t                         field_rest;
  60.     u_char                         field_state;

  61.     unsigned                       literal:1;
  62.     unsigned                       field_huffman:1;

  63.     unsigned                       header_sent:1;
  64.     unsigned                       output_closed:1;
  65.     unsigned                       output_blocked:1;
  66.     unsigned                       parsing_headers:1;
  67.     unsigned                       end_stream:1;
  68.     unsigned                       done:1;
  69.     unsigned                       status:1;
  70.     unsigned                       rst:1;
  71.     unsigned                       goaway:1;
  72. } ngx_http_proxy_v2_ctx_t;


  73. typedef struct {
  74.     u_char                        length_0;
  75.     u_char                        length_1;
  76.     u_char                        length_2;
  77.     u_char                        type;
  78.     u_char                        flags;
  79.     u_char                        stream_id_0;
  80.     u_char                        stream_id_1;
  81.     u_char                        stream_id_2;
  82.     u_char                        stream_id_3;
  83. } ngx_http_proxy_v2_frame_t;


  84. static ngx_int_t ngx_http_proxy_v2_create_request(ngx_http_request_t *r);
  85. static ngx_int_t ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r);
  86. static ngx_int_t ngx_http_proxy_v2_body_output_filter(void *data,
  87.     ngx_chain_t *in);
  88. static ngx_int_t ngx_http_proxy_v2_process_header(ngx_http_request_t *r);
  89. static ngx_int_t ngx_http_proxy_v2_filter_init(void *data);
  90. static ngx_int_t ngx_http_proxy_v2_non_buffered_filter(void *data,
  91.     ssize_t bytes);
  92. static ngx_int_t ngx_http_proxy_v2_body_filter(ngx_event_pipe_t *p,
  93.     ngx_buf_t *buf);
  94. static ngx_int_t ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
  95.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  96. static ngx_int_t ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx,
  97.     ngx_buf_t *b);
  98. static ngx_int_t ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
  99.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);

  100. static ngx_int_t ngx_http_proxy_v2_parse_frame(ngx_http_request_t *r,
  101.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  102. static ngx_int_t ngx_http_proxy_v2_parse_header(ngx_http_request_t *r,
  103.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  104. static ngx_int_t ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
  105.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  106. static ngx_int_t ngx_http_proxy_v2_validate_header_name(ngx_http_request_t *r,
  107.     ngx_str_t *s);
  108. static ngx_int_t ngx_http_proxy_v2_validate_header_value(ngx_http_request_t *r,
  109.     ngx_str_t *s);
  110. static ngx_int_t ngx_http_proxy_v2_parse_rst_stream(ngx_http_request_t *r,
  111.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  112. static ngx_int_t ngx_http_proxy_v2_parse_goaway(ngx_http_request_t *r,
  113.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  114. static ngx_int_t ngx_http_proxy_v2_parse_window_update(ngx_http_request_t *r,
  115.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  116. static ngx_int_t ngx_http_proxy_v2_parse_settings(ngx_http_request_t *r,
  117.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);
  118. static ngx_int_t ngx_http_proxy_v2_parse_ping(ngx_http_request_t *r,
  119.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b);

  120. static ngx_int_t ngx_http_proxy_v2_send_settings_ack(ngx_http_request_t *r,
  121.     ngx_http_proxy_v2_ctx_t *ctx);
  122. static ngx_int_t ngx_http_proxy_v2_send_ping_ack(ngx_http_request_t *r,
  123.     ngx_http_proxy_v2_ctx_t *ctx);
  124. static ngx_int_t ngx_http_proxy_v2_send_window_update(ngx_http_request_t *r,
  125.     ngx_http_proxy_v2_ctx_t *ctx);

  126. static ngx_chain_t *ngx_http_proxy_v2_get_buf(ngx_http_request_t *r,
  127.     ngx_http_proxy_v2_ctx_t *ctx);
  128. static ngx_http_proxy_v2_ctx_t *
  129.     ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r);
  130. static ngx_int_t ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
  131.     ngx_http_proxy_v2_ctx_t *ctx, ngx_peer_connection_t *pc);
  132. static void ngx_http_proxy_v2_cleanup(void *data);

  133. static void ngx_http_proxy_v2_abort_request(ngx_http_request_t *r);
  134. static void ngx_http_proxy_v2_finalize_request(ngx_http_request_t *r,
  135.     ngx_int_t rc);


  136. static ngx_http_module_t  ngx_http_proxy_v2_module_ctx = {
  137.     NULL,                                  /* preconfiguration */
  138.     NULL,                                  /* postconfiguration */

  139.     NULL,                                  /* create main configuration */
  140.     NULL,                                  /* init main configuration */

  141.     NULL,                                  /* create server configuration */
  142.     NULL,                                  /* merge server configuration */

  143.     NULL,                                  /* create location configuration */
  144.     NULL                                   /* merge location configuration */
  145. };


  146. ngx_module_t  ngx_http_proxy_v2_module = {
  147.     NGX_MODULE_V1,
  148.     &ngx_http_proxy_v2_module_ctx,         /* module context */
  149.     NULL,                                  /* module directives */
  150.     NGX_HTTP_MODULE,                       /* module type */
  151.     NULL,                                  /* init master */
  152.     NULL,                                  /* init module */
  153.     NULL,                                  /* init process */
  154.     NULL,                                  /* init thread */
  155.     NULL,                                  /* exit thread */
  156.     NULL,                                  /* exit process */
  157.     NULL,                                  /* exit master */
  158.     NGX_MODULE_V1_PADDING
  159. };


  160. static u_char  ngx_http_proxy_v2_connection_start[] =
  161.     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"         /* connection preface */

  162.     "\x00\x00\x12\x04\x00\x00\x00\x00\x00"     /* settings frame */
  163.     "\x00\x01\x00\x00\x00\x00"                 /* header table size */
  164.     "\x00\x02\x00\x00\x00\x00"                 /* disable push */
  165.     "\x00\x04\x7f\xff\xff\xff"                 /* initial window */

  166.     "\x00\x00\x04\x08\x00\x00\x00\x00\x00"     /* window update frame */
  167.     "\x7f\xff\x00\x00";


  168. ngx_int_t
  169. ngx_http_proxy_v2_handler(ngx_http_request_t *r)
  170. {
  171.     ngx_int_t                    rc;
  172.     ngx_http_upstream_t         *u;
  173.     ngx_http_proxy_v2_ctx_t     *ctx;
  174.     ngx_http_proxy_loc_conf_t   *plcf;
  175. #if (NGX_HTTP_CACHE)
  176.     ngx_http_proxy_main_conf_t  *pmcf;
  177. #endif

  178.     if (ngx_http_upstream_create(r) != NGX_OK) {
  179.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  180.     }

  181.     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_v2_ctx_t));
  182.     if (ctx == NULL) {
  183.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  184.     }

  185.     ngx_http_set_ctx(r, ctx, ngx_http_proxy_v2_module);

  186.     ngx_http_set_ctx(r, &ctx->ctx, ngx_http_proxy_module);

  187.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  188.     plcf->upstream.preserve_output = 1;

  189.     u = r->upstream;

  190.     if (plcf->proxy_lengths == NULL) {
  191.         ctx->ctx.vars = plcf->vars;
  192.         u->schema = plcf->vars.schema;
  193. #if (NGX_HTTP_SSL)
  194.         u->ssl = plcf->ssl;
  195. #endif

  196.     } else {
  197.         if (ngx_http_proxy_eval(r, &ctx->ctx, plcf) != NGX_OK) {
  198.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  199.         }
  200.     }

  201. #if (NGX_HTTP_SSL)
  202.     ngx_str_set(&u->ssl_alpn_protocol, NGX_HTTP_V2_ALPN_PROTO);
  203. #endif

  204.     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_module;

  205.     u->conf = &plcf->upstream;

  206. #if (NGX_HTTP_CACHE)
  207.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);

  208.     u->caches = &pmcf->caches;
  209.     u->create_key = ngx_http_proxy_create_key;
  210. #endif

  211.     u->create_request = ngx_http_proxy_v2_create_request;
  212.     u->reinit_request = ngx_http_proxy_v2_reinit_request;
  213.     u->process_header = ngx_http_proxy_v2_process_header;
  214.     u->abort_request = ngx_http_proxy_v2_abort_request;
  215.     u->finalize_request = ngx_http_proxy_v2_finalize_request;

  216.     if (plcf->redirects) {
  217.         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
  218.     }

  219.     if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) {
  220.         u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
  221.     }

  222.     u->buffering = plcf->upstream.buffering;

  223.     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
  224.     if (u->pipe == NULL) {
  225.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  226.     }

  227.     u->pipe->input_filter = ngx_http_proxy_v2_body_filter;
  228.     u->pipe->input_ctx = r;

  229.     u->input_filter_init = ngx_http_proxy_v2_filter_init;
  230.     u->input_filter = ngx_http_proxy_v2_non_buffered_filter;
  231.     u->input_filter_ctx = r;

  232.     u->accel = 1;

  233.     if (!plcf->upstream.request_buffering
  234.         && plcf->body_values == NULL && plcf->upstream.pass_request_body)
  235.     {
  236.         r->request_body_no_buffering = 1;
  237.     }

  238.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  239.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  240.         return rc;
  241.     }

  242.     return NGX_DONE;
  243. }


  244. static ngx_int_t
  245. ngx_http_proxy_v2_create_request(ngx_http_request_t *r)
  246. {
  247.     u_char                       *p, *tmp, *key_tmp, *val_tmp, *headers_frame;
  248.     size_t                        len, tmp_len, key_len, val_len, uri_len,
  249.                                   loc_len, body_len;
  250.     uintptr_t                     escape;
  251.     ngx_buf_t                    *b;
  252.     ngx_str_t                     method, *host;
  253.     ngx_uint_t                    i, next, unparsed_uri;
  254.     ngx_chain_t                  *cl, *body;
  255.     ngx_list_part_t              *part;
  256.     ngx_table_elt_t              *header;
  257.     ngx_http_upstream_t          *u;
  258.     ngx_http_proxy_v2_ctx_t      *ctx;
  259.     ngx_http_script_code_pt       code;
  260.     ngx_http_script_engine_t      e, le;
  261.     ngx_http_proxy_headers_t     *headers;
  262.     ngx_http_proxy_v2_frame_t    *f;
  263.     ngx_http_proxy_loc_conf_t    *plcf;
  264.     ngx_http_script_len_code_pt   lcode;

  265.     u = r->upstream;

  266.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  267. #if (NGX_HTTP_CACHE)
  268.     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
  269. #else
  270.     headers = &plcf->headers;
  271. #endif

  272.     if (u->method.len) {
  273.         /* HEAD was changed to GET to cache response */
  274.         method = u->method;

  275.     } else if (plcf->method) {
  276.         if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
  277.             return NGX_ERROR;
  278.         }

  279.     } else {
  280.         method = r->method_name;
  281.     }

  282.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  283.     if (method.len == 4
  284.         && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
  285.     {
  286.         ctx->ctx.head = 1;
  287.     }

  288.     len = sizeof(ngx_http_proxy_v2_connection_start) - 1
  289.           + sizeof(ngx_http_proxy_v2_frame_t);             /* headers frame */

  290.     /* :method header */

  291.     if ((method.len == 3 && ngx_strncmp(method.data, "GET", 3) == 0)
  292.         || (method.len == 4 && ngx_strncmp(method.data, "POST", 4) == 0))
  293.     {
  294.         len += 1;
  295.         tmp_len = 0;

  296.     } else {
  297.         len += 1 + NGX_HTTP_V2_INT_OCTETS + method.len;
  298.         tmp_len = method.len;
  299.     }

  300.     /* :scheme header */

  301.     len += 1;

  302.     /* :path header */

  303.     escape = 0;
  304.     loc_len = 0;
  305.     unparsed_uri = 0;

  306.     if (plcf->proxy_lengths && ctx->ctx.vars.uri.len) {
  307.         uri_len = ctx->ctx.vars.uri.len;

  308.     } else if (ctx->ctx.vars.uri.len == 0 && r->valid_unparsed_uri) {
  309.         unparsed_uri = 1;
  310.         uri_len = r->unparsed_uri.len;

  311.     } else {
  312.         loc_len = (r->valid_location && ctx->ctx.vars.uri.len)
  313.                   ? ngx_min(plcf->location.len, r->uri.len) : 0;

  314.         if (r->quoted_uri || r->internal) {
  315.             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  316.                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
  317.         }

  318.         uri_len = ctx->ctx.vars.uri.len + r->uri.len - loc_len + escape
  319.                   + sizeof("?") - 1 + r->args.len;
  320.     }

  321.     if (uri_len == 0) {
  322.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  323.                       "zero length URI to proxy");
  324.         return NGX_ERROR;
  325.     }

  326.     len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;

  327.     if (tmp_len < uri_len) {
  328.         tmp_len = uri_len;
  329.     }

  330.     /* :authority header */

  331.     host = &ctx->ctx.vars.host_header;

  332.     if (!plcf->host_set) {
  333.         len += 1 + NGX_HTTP_V2_INT_OCTETS + host->len;

  334.         if (tmp_len < host->len) {
  335.             tmp_len = host->len;
  336.         }
  337.     }

  338.     /* other headers */

  339.     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  340.     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
  341.     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);

  342.     body_len = 0;

  343.     if (plcf->body_lengths) {
  344.         le.ip = plcf->body_lengths->elts;
  345.         le.request = r;
  346.         le.flushed = 1;

  347.         while (*(uintptr_t *) le.ip) {
  348.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  349.             body_len += lcode(&le);
  350.         }

  351.         ctx->ctx.internal_body_length = body_len;

  352.     } else if (r->headers_in.chunked && r->reading_body) {
  353.         ctx->ctx.internal_body_length = -1;

  354.     } else {
  355.         ctx->ctx.internal_body_length = r->headers_in.content_length_n;
  356.     }

  357.     le.ip = headers->lengths->elts;
  358.     le.request = r;
  359.     le.flushed = 1;

  360.     while (*(uintptr_t *) le.ip) {

  361.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  362.         key_len = lcode(&le);

  363.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  364.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  365.         }
  366.         le.ip += sizeof(uintptr_t);

  367.         if (val_len == 0) {
  368.             continue;
  369.         }

  370.         len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
  371.                  + NGX_HTTP_V2_INT_OCTETS + val_len;

  372.         if (tmp_len < key_len) {
  373.             tmp_len = key_len;
  374.         }

  375.         if (tmp_len < val_len) {
  376.             tmp_len = val_len;
  377.         }
  378.     }

  379.     if (plcf->upstream.pass_request_headers) {
  380.         part = &r->headers_in.headers.part;
  381.         header = part->elts;

  382.         for (i = 0; /* void */; i++) {

  383.             if (i >= part->nelts) {
  384.                 if (part->next == NULL) {
  385.                     break;
  386.                 }

  387.                 part = part->next;
  388.                 header = part->elts;
  389.                 i = 0;
  390.             }

  391.             if (ngx_hash_find(&headers->hash, header[i].hash,
  392.                               header[i].lowcase_key, header[i].key.len))
  393.             {
  394.                 continue;
  395.             }

  396.             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
  397.                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;

  398.             if (tmp_len < header[i].key.len) {
  399.                 tmp_len = header[i].key.len;
  400.             }

  401.             if (tmp_len < header[i].value.len) {
  402.                 tmp_len = header[i].value.len;
  403.             }
  404.         }
  405.     }

  406.     /* continuation frames */

  407.     len += sizeof(ngx_http_proxy_v2_frame_t)
  408.            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);


  409.     b = ngx_create_temp_buf(r->pool, len);
  410.     if (b == NULL) {
  411.         return NGX_ERROR;
  412.     }

  413.     cl = ngx_alloc_chain_link(r->pool);
  414.     if (cl == NULL) {
  415.         return NGX_ERROR;
  416.     }

  417.     cl->buf = b;
  418.     cl->next = NULL;

  419.     tmp = ngx_palloc(r->pool, tmp_len * 3);
  420.     if (tmp == NULL) {
  421.         return NGX_ERROR;
  422.     }

  423.     key_tmp = tmp + tmp_len;
  424.     val_tmp = tmp + 2 * tmp_len;

  425.     /* connection preface */

  426.     b->last = ngx_copy(b->last, ngx_http_proxy_v2_connection_start,
  427.                        sizeof(ngx_http_proxy_v2_connection_start) - 1);

  428.     /* headers frame */

  429.     headers_frame = b->last;

  430.     f = (ngx_http_proxy_v2_frame_t *) b->last;
  431.     b->last += sizeof(ngx_http_proxy_v2_frame_t);

  432.     f->length_0 = 0;
  433.     f->length_1 = 0;
  434.     f->length_2 = 0;
  435.     f->type = NGX_HTTP_V2_HEADERS_FRAME;
  436.     f->flags = 0;
  437.     f->stream_id_0 = 0;
  438.     f->stream_id_1 = 0;
  439.     f->stream_id_2 = 0;
  440.     f->stream_id_3 = 1;

  441.     if (method.len == 3 && ngx_strncmp(method.data, "GET", 3) == 0) {
  442.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);

  443.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  444.                        "http proxy header: \":method: GET\"");

  445.     } else if (method.len == 4 && ngx_strncmp(method.data, "POST", 4) == 0) {
  446.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);

  447.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  448.                        "http proxy header: \":method: POST\"");

  449.     } else {
  450.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
  451.         b->last = ngx_http_v2_write_value(b->last, method.data,
  452.                                           method.len, tmp);

  453.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  454.                        "http proxy header: \":method: %V\"", &method);
  455.     }

  456. #if (NGX_HTTP_SSL)
  457.     if (u->ssl) {
  458.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);

  459.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  460.                        "http proxy header: \":scheme: https\"");
  461.     } else
  462. #endif
  463.     {
  464.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);

  465.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  466.                        "http proxy header: \":scheme: http\"");
  467.     }

  468.     if (plcf->proxy_lengths && ctx->ctx.vars.uri.len) {

  469.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  470.         b->last = ngx_http_v2_write_value(b->last, ctx->ctx.vars.uri.data,
  471.                                           ctx->ctx.vars.uri.len, tmp);

  472.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  473.                        "http proxy header: \":path: %V\"", &ctx->ctx.vars.uri);

  474.     } else if (unparsed_uri) {

  475.         if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') {
  476.             *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);

  477.         } else {
  478.             *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  479.             b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
  480.                                               r->unparsed_uri.len, tmp);
  481.         }

  482.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  483.                        "http proxy header: \":path: %V\"", &r->unparsed_uri);

  484.     } else {
  485.         p = val_tmp;

  486.         if (r->valid_location) {
  487.             p = ngx_copy(p, ctx->ctx.vars.uri.data, ctx->ctx.vars.uri.len);
  488.         }

  489.         if (escape) {
  490.             ngx_escape_uri(p, r->uri.data + loc_len,
  491.                            r->uri.len - loc_len, NGX_ESCAPE_URI);
  492.             p += r->uri.len - loc_len + escape;

  493.         } else {
  494.             p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
  495.         }

  496.         if (r->args.len > 0) {
  497.             *p++ = '?';
  498.             p = ngx_copy(p, r->args.data, r->args.len);
  499.         }

  500.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  501.         b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp);

  502.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  503.                        "http proxy header: \":path: %*s\"", p - val_tmp,
  504.                        val_tmp);
  505.     }

  506.     if (!plcf->host_set) {
  507.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
  508.         b->last = ngx_http_v2_write_value(b->last, host->data, host->len, tmp);

  509.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  510.                        "http proxy header: \":authority: %V\"", host);
  511.     }

  512.     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));

  513.     e.ip = headers->values->elts;
  514.     e.request = r;
  515.     e.flushed = 1;

  516.     le.ip = headers->lengths->elts;

  517.     while (*(uintptr_t *) le.ip) {

  518.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  519.         key_len = lcode(&le);

  520.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  521.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  522.         }
  523.         le.ip += sizeof(uintptr_t);

  524.         if (val_len == 0) {
  525.             e.skip = 1;

  526.             while (*(uintptr_t *) e.ip) {
  527.                 code = *(ngx_http_script_code_pt *) e.ip;
  528.                 code((ngx_http_script_engine_t *) &e);
  529.             }
  530.             e.ip += sizeof(uintptr_t);

  531.             e.skip = 0;

  532.             continue;
  533.         }

  534.         *b->last++ = 0;

  535.         e.pos = key_tmp;

  536.         code = *(ngx_http_script_code_pt *) e.ip;
  537.         code((ngx_http_script_engine_t *) &e);

  538.         b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp);

  539.         e.pos = val_tmp;

  540.         while (*(uintptr_t *) e.ip) {
  541.             code = *(ngx_http_script_code_pt *) e.ip;
  542.             code((ngx_http_script_engine_t *) &e);
  543.         }
  544.         e.ip += sizeof(uintptr_t);

  545.         b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp);

  546. #if (NGX_DEBUG)
  547.         if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
  548.             ngx_strlow(key_tmp, key_tmp, key_len);

  549.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  550.                            "http proxy header: \"%*s: %*s\"",
  551.                            key_len, key_tmp, val_len, val_tmp);
  552.         }
  553. #endif
  554.     }

  555.     if (plcf->upstream.pass_request_headers) {
  556.         part = &r->headers_in.headers.part;
  557.         header = part->elts;

  558.         for (i = 0; /* void */; i++) {

  559.             if (i >= part->nelts) {
  560.                 if (part->next == NULL) {
  561.                     break;
  562.                 }

  563.                 part = part->next;
  564.                 header = part->elts;
  565.                 i = 0;
  566.             }

  567.             if (ngx_hash_find(&headers->hash, header[i].hash,
  568.                               header[i].lowcase_key, header[i].key.len))
  569.             {
  570.                 continue;
  571.             }

  572.             *b->last++ = 0;

  573.             b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
  574.                                              header[i].key.len, tmp);

  575.             b->last = ngx_http_v2_write_value(b->last, header[i].value.data,
  576.                                               header[i].value.len, tmp);

  577. #if (NGX_DEBUG)
  578.             if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
  579.                 ngx_strlow(tmp, header[i].key.data, header[i].key.len);

  580.                 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  581.                                "http proxy header: \"%*s: %V\"",
  582.                                header[i].key.len, tmp, &header[i].value);
  583.             }
  584. #endif
  585.         }
  586.     }

  587.     /* update headers frame length */

  588.     len = b->last - headers_frame - sizeof(ngx_http_proxy_v2_frame_t);

  589.     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  590.         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  591.         next = 1;

  592.     } else {
  593.         next = 0;
  594.     }

  595.     f = (ngx_http_proxy_v2_frame_t *) headers_frame;

  596.     f->length_0 = (u_char) ((len >> 16) & 0xff);
  597.     f->length_1 = (u_char) ((len >> 8) & 0xff);
  598.     f->length_2 = (u_char) (len & 0xff);

  599.     /* create additional continuation frames */

  600.     p = headers_frame;

  601.     while (next) {
  602.         p += sizeof(ngx_http_proxy_v2_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  603.         len = b->last - p;

  604.         ngx_memmove(p + sizeof(ngx_http_proxy_v2_frame_t), p, len);
  605.         b->last += sizeof(ngx_http_proxy_v2_frame_t);

  606.         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  607.             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  608.             next = 1;

  609.         } else {
  610.             next = 0;
  611.         }

  612.         f = (ngx_http_proxy_v2_frame_t *) p;

  613.         f->length_0 = (u_char) ((len >> 16) & 0xff);
  614.         f->length_1 = (u_char) ((len >> 8) & 0xff);
  615.         f->length_2 = (u_char) (len & 0xff);
  616.         f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
  617.         f->flags = 0;
  618.         f->stream_id_0 = 0;
  619.         f->stream_id_1 = 0;
  620.         f->stream_id_2 = 0;
  621.         f->stream_id_3 = 1;
  622.     }

  623.     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;

  624.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  625.                    "http proxy header: %*xs%s, len: %uz",
  626.                    (size_t) ngx_min(b->last - b->pos, 256), b->pos,
  627.                    b->last - b->pos > 256 ? "..." : "",
  628.                    b->last - b->pos);

  629.     if (r->request_body_no_buffering) {

  630.         u->request_bufs = cl;

  631.     } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {

  632.         body = u->request_bufs;
  633.         u->request_bufs = cl;

  634.         if (body == NULL) {
  635.             f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  636.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
  637.         }

  638.         while (body) {
  639.             b = ngx_alloc_buf(r->pool);
  640.             if (b == NULL) {
  641.                 return NGX_ERROR;
  642.             }

  643.             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));

  644.             cl->next = ngx_alloc_chain_link(r->pool);
  645.             if (cl->next == NULL) {
  646.                 return NGX_ERROR;
  647.             }

  648.             cl = cl->next;
  649.             cl->buf = b;

  650.             body = body->next;
  651.         }

  652.         b->last_buf = 1;

  653.     } else if (body_len) {

  654.         u->request_bufs = cl;

  655.         b = ngx_create_temp_buf(r->pool, body_len);
  656.         if (b == NULL) {
  657.             return NGX_ERROR;
  658.         }

  659.         cl->next = ngx_alloc_chain_link(r->pool);
  660.         if (cl->next == NULL) {
  661.             return NGX_ERROR;
  662.         }

  663.         cl = cl->next;
  664.         cl->buf = b;

  665.         e.ip = plcf->body_values->elts;
  666.         e.pos = b->last;
  667.         e.request = r;
  668.         e.flushed = 1;
  669.         e.skip = 0;

  670.         while (*(uintptr_t *) e.ip) {
  671.             code = *(ngx_http_script_code_pt *) e.ip;
  672.             code((ngx_http_script_engine_t *) &e);
  673.         }

  674.         b->last = e.pos;
  675.         b->last_buf = 1;

  676.     } else {
  677.         u->request_bufs = cl;

  678.         f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  679.         f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  680.         b->last_buf = 1;
  681.     }

  682.     u->output.output_filter = ngx_http_proxy_v2_body_output_filter;
  683.     u->output.filter_ctx = r;

  684.     b->flush = 1;
  685.     cl->next = NULL;

  686.     return NGX_OK;
  687. }


  688. static ngx_int_t
  689. ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r)
  690. {
  691.     ngx_http_proxy_v2_ctx_t  *ctx;

  692.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  693.     if (ctx == NULL) {
  694.         return NGX_OK;
  695.     }

  696.     ctx->state = 0;
  697.     ctx->header_sent = 0;
  698.     ctx->output_closed = 0;
  699.     ctx->output_blocked = 0;
  700.     ctx->parsing_headers = 0;
  701.     ctx->end_stream = 0;
  702.     ctx->done = 0;
  703.     ctx->status = 0;
  704.     ctx->rst = 0;
  705.     ctx->goaway = 0;
  706.     ctx->connection = NULL;
  707.     ctx->in = NULL;
  708.     ctx->busy = NULL;
  709.     ctx->out = NULL;

  710.     return NGX_OK;
  711. }


  712. static ngx_int_t
  713. ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in)
  714. {
  715.     ngx_http_request_t  *r = data;

  716.     off_t                       file_pos;
  717.     u_char                     *p, *pos, *start;
  718.     size_t                      len, limit;
  719.     ngx_buf_t                  *b;
  720.     ngx_int_t                  rc;
  721.     ngx_uint_t                 next, last;
  722.     ngx_chain_t                *cl, *out, *ln, **ll;
  723.     ngx_http_upstream_t        *u;
  724.     ngx_http_proxy_v2_ctx_t    *ctx;
  725.     ngx_http_proxy_v2_frame_t  *f;

  726.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  727.                    "http proxy output filter");

  728.     ctx = ngx_http_proxy_v2_get_ctx(r);

  729.     if (ctx == NULL) {
  730.         return NGX_ERROR;
  731.     }

  732.     if (in) {
  733.         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
  734.             return NGX_ERROR;
  735.         }
  736.     }

  737.     out = NULL;
  738.     ll = &out;

  739.     if (!ctx->header_sent) {
  740.         /* first buffer contains headers */

  741.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  742.                        "http proxy output header");

  743.         ctx->header_sent = 1;

  744.         if (ctx->id != 1) {
  745.             /*
  746.              * keepalive connection: skip connection preface,
  747.              * update stream identifiers
  748.              */

  749.             b = ctx->in->buf;
  750.             b->pos += sizeof(ngx_http_proxy_v2_connection_start) - 1;

  751.             p = b->pos;

  752.             while (p < b->last) {
  753.                 f = (ngx_http_proxy_v2_frame_t *) p;
  754.                 p += sizeof(ngx_http_proxy_v2_frame_t);

  755.                 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  756.                 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  757.                 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  758.                 f->stream_id_3 = (u_char) (ctx->id & 0xff);

  759.                 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
  760.             }
  761.         }

  762.         if (ctx->in->buf->last_buf) {
  763.             ctx->output_closed = 1;
  764.         }

  765.         *ll = ctx->in;
  766.         ll = &ctx->in->next;

  767.         ctx->in = ctx->in->next;
  768.     }

  769.     if (ctx->out) {
  770.         /* queued control frames */

  771.         *ll = ctx->out;

  772.         for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
  773.             ll = &cl->next;
  774.         }

  775.         ctx->out = NULL;
  776.     }

  777.     f = NULL;
  778.     last = 0;

  779.     limit = ngx_max(0, ctx->send_window);

  780.     if (limit > ctx->connection->send_window) {
  781.         limit = ctx->connection->send_window;
  782.     }

  783.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  784.                    "http proxy output limit: %uz w:%z:%uz",
  785.                    limit, ctx->send_window, ctx->connection->send_window);

  786. #if (NGX_SUPPRESS_WARN)
  787.     file_pos = 0;
  788.     pos = NULL;
  789.     cl = NULL;
  790. #endif

  791.     in = ctx->in;

  792.     while (in && limit > 0) {

  793.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  794.                        "http proxy output in  l:%d f:%d %p, pos %p, size: %z "
  795.                        "file: %O, size: %O",
  796.                        in->buf->last_buf,
  797.                        in->buf->in_file,
  798.                        in->buf->start, in->buf->pos,
  799.                        in->buf->last - in->buf->pos,
  800.                        in->buf->file_pos,
  801.                        in->buf->file_last - in->buf->file_pos);

  802.         if (ngx_buf_special(in->buf)) {
  803.             goto next;
  804.         }

  805.         if (in->buf->in_file) {
  806.             file_pos = in->buf->file_pos;

  807.         } else {
  808.             pos = in->buf->pos;
  809.         }

  810.         next = 0;

  811.         do {

  812.             cl = ngx_http_proxy_v2_get_buf(r, ctx);
  813.             if (cl == NULL) {
  814.                 return NGX_ERROR;
  815.             }

  816.             b = cl->buf;

  817.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  818.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  819.             *ll = cl;
  820.             ll = &cl->next;

  821.             cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  822.             if (cl == NULL) {
  823.                 return NGX_ERROR;
  824.             }

  825.             b = cl->buf;
  826.             start = b->start;

  827.             ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));

  828.             /*
  829.              * restore b->start to preserve memory allocated in the buffer,
  830.              * to reuse it later for headers and control frames
  831.              */

  832.             b->start = start;

  833.             if (in->buf->in_file) {
  834.                 b->file_pos = file_pos;
  835.                 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  836.                 if (file_pos >= in->buf->file_last) {
  837.                     file_pos = in->buf->file_last;
  838.                     next = 1;
  839.                 }

  840.                 b->file_last = file_pos;
  841.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  842.             } else {
  843.                 b->pos = pos;
  844.                 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  845.                 if (pos >= in->buf->last) {
  846.                     pos = in->buf->last;
  847.                     next = 1;
  848.                 }

  849.                 b->last = pos;
  850.                 len = (ngx_uint_t) (pos - b->pos);
  851.             }

  852.             b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  853.             b->shadow = in->buf;
  854.             b->last_shadow = next;

  855.             b->last_buf = 0;
  856.             b->last_in_chain = 0;

  857.             *ll = cl;
  858.             ll = &cl->next;

  859.             f->length_0 = (u_char) ((len >> 16) & 0xff);
  860.             f->length_1 = (u_char) ((len >> 8) & 0xff);
  861.             f->length_2 = (u_char) (len & 0xff);
  862.             f->type = NGX_HTTP_V2_DATA_FRAME;
  863.             f->flags = 0;
  864.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  865.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  866.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  867.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  868.             limit -= len;
  869.             ctx->send_window -= len;
  870.             ctx->connection->send_window -= len;

  871.         } while (!next && limit > 0);

  872.         if (!next) {
  873.             /*
  874.              * if the buffer wasn't fully sent due to flow control limits,
  875.              * preserve position for future use
  876.              */

  877.             if (in->buf->in_file) {
  878.                 in->buf->file_pos = file_pos;

  879.             } else {
  880.                 in->buf->pos = pos;
  881.             }

  882.             break;
  883.         }

  884.     next:

  885.         if (in->buf->last_buf) {
  886.             last = 1;
  887.         }

  888.         ln = in;
  889.         in = in->next;

  890.         ngx_free_chain(r->pool, ln);
  891.     }

  892.     ctx->in = in;

  893.     if (last) {

  894.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  895.                        "http proxy output last");

  896.         ctx->output_closed = 1;

  897.         if (f) {
  898.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  899.         } else {
  900.             cl = ngx_http_proxy_v2_get_buf(r, ctx);
  901.             if (cl == NULL) {
  902.                 return NGX_ERROR;
  903.             }

  904.             b = cl->buf;

  905.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  906.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  907.             f->length_0 = 0;
  908.             f->length_1 = 0;
  909.             f->length_2 = 0;
  910.             f->type = NGX_HTTP_V2_DATA_FRAME;
  911.             f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
  912.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  913.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  914.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  915.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  916.             *ll = cl;
  917.             ll = &cl->next;
  918.         }

  919.         cl->buf->last_buf = 1;
  920.     }

  921.     *ll = NULL;

  922. #if (NGX_DEBUG)

  923.     for (cl = out; cl; cl = cl->next) {
  924.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  925.                        "http proxy output out l:%d f:%d %p, pos %p, size: %z "
  926.                        "file: %O, size: %O",
  927.                        cl->buf->last_buf,
  928.                        cl->buf->in_file,
  929.                        cl->buf->start, cl->buf->pos,
  930.                        cl->buf->last - cl->buf->pos,
  931.                        cl->buf->file_pos,
  932.                        cl->buf->file_last - cl->buf->file_pos);
  933.     }

  934.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  935.                    "http proxy output limit: %uz w:%z:%uz",
  936.                    limit, ctx->send_window, ctx->connection->send_window);

  937. #endif

  938.     rc = ngx_chain_writer(&r->upstream->writer, out);

  939.     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
  940.                          (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter);

  941.     for (cl = ctx->free; cl; cl = cl->next) {

  942.         /* mark original buffers as sent */

  943.         if (cl->buf->shadow) {
  944.             if (cl->buf->last_shadow) {
  945.                 b = cl->buf->shadow;
  946.                 b->pos = b->last;
  947.             }

  948.             cl->buf->shadow = NULL;
  949.         }
  950.     }

  951.     if (rc == NGX_OK && ctx->in) {
  952.         rc = NGX_AGAIN;
  953.     }

  954.     if (rc == NGX_AGAIN) {
  955.         ctx->output_blocked = 1;

  956.     } else {
  957.         ctx->output_blocked = 0;
  958.     }

  959.     if (ctx->done) {

  960.         /*
  961.          * We have already got the response and were sending some additional
  962.          * control frames.  Even if there is still something unsent, stop
  963.          * here anyway.
  964.          */

  965.         u = r->upstream;
  966.         u->length = 0;
  967.         u->pipe->length = 0;

  968.         if (ctx->in == NULL
  969.             && ctx->out == NULL
  970.             && ctx->output_closed
  971.             && !ctx->output_blocked
  972.             && !ctx->goaway
  973.             && ctx->state == ngx_http_proxy_v2_st_start)
  974.         {
  975.             u->keepalive = 1;
  976.         }

  977.         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
  978.     }

  979.     return rc;
  980. }


  981. static ngx_int_t
  982. ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
  983. {
  984.     u_char                         *pos;
  985.     ngx_str_t                      *status_line;
  986.     ngx_int_t                       rc, status;
  987.     ngx_buf_t                      *b;
  988.     ngx_table_elt_t                *h;
  989.     ngx_http_upstream_t            *u;
  990.     ngx_http_proxy_v2_ctx_t        *ctx;
  991.     ngx_http_upstream_header_t     *hh;
  992.     ngx_http_upstream_main_conf_t  *umcf;

  993.     u = r->upstream;
  994.     b = &u->buffer;
  995.     pos = b->pos;

  996.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  997.                    "http proxy response: %*xs%s, len: %uz",
  998.                    (size_t) ngx_min(b->last - b->pos, 256),
  999.                    b->pos, b->last - b->pos > 256 ? "..." : "",
  1000.                    b->last - b->pos);

  1001.     ctx = ngx_http_proxy_v2_get_ctx(r);

  1002.     if (ctx == NULL) {
  1003.         return NGX_ERROR;
  1004.     }

  1005.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1006.     for ( ;; ) {

  1007.         if (ctx->state < ngx_http_proxy_v2_st_payload) {

  1008.             rc = ngx_http_proxy_v2_parse_frame(r, ctx, b);

  1009.             if (rc == NGX_AGAIN) {

  1010.                 /*
  1011.                  * there can be a lot of window update frames,
  1012.                  * so we reset buffer if it is empty and we haven't
  1013.                  * started parsing headers yet
  1014.                  */

  1015.                 if (!ctx->parsing_headers) {
  1016.                     b->pos = pos;
  1017.                     b->last = b->pos;
  1018.                 }

  1019.                 return NGX_AGAIN;
  1020.             }

  1021.             if (rc == NGX_ERROR) {
  1022.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1023.             }

  1024.             /*
  1025.              * RFC 7540 says that implementations MUST discard frames
  1026.              * that have unknown or unsupported types.  However, extension
  1027.              * frames that appear in the middle of a header block are
  1028.              * not permitted.  Also, for obvious reasons CONTINUATION frames
  1029.              * cannot appear before headers, and DATA frames are not expected
  1030.              * to appear before all headers are parsed.
  1031.              */

  1032.             if (ctx->type == NGX_HTTP_V2_DATA_FRAME
  1033.                 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1034.                     && !ctx->parsing_headers)
  1035.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1036.                     && ctx->parsing_headers))
  1037.             {
  1038.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1039.                               "upstream sent unexpected http2 frame: %d",
  1040.                               ctx->type);
  1041.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1042.             }

  1043.             if (ctx->id && ctx->stream_id && ctx->stream_id != ctx->id) {
  1044.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1045.                               "upstream sent frame for unknown stream %ui",
  1046.                               ctx->stream_id);
  1047.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1048.             }
  1049.         }

  1050.         /* frame payload */

  1051.         if (u->peer.connection) {

  1052.             if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
  1053.                 rc = ngx_http_proxy_v2_parse_rst_stream(r, ctx, b);

  1054.                 if (rc == NGX_AGAIN) {
  1055.                     return NGX_AGAIN;
  1056.                 }

  1057.                 if (rc == NGX_ERROR) {
  1058.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1059.                 }

  1060.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1061.                               "upstream rejected request with error %ui",
  1062.                               ctx->error);

  1063.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1064.             }

  1065.             rc = ngx_http_proxy_v2_process_control_frame(r, ctx, b);

  1066.             if (rc == NGX_AGAIN) {
  1067.                 return NGX_AGAIN;
  1068.             }

  1069.             if (rc == NGX_ERROR) {
  1070.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1071.             }

  1072.             if (rc == NGX_OK) {
  1073.                 continue;
  1074.             }
  1075.         }

  1076.         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
  1077.             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
  1078.         {
  1079.             /* priority, unknown frames */

  1080.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1081.             if (rc == NGX_AGAIN) {
  1082.                 return NGX_AGAIN;
  1083.             }

  1084.             continue;
  1085.         }

  1086.         /* headers */

  1087.         for ( ;; ) {

  1088.             rc = ngx_http_proxy_v2_parse_header(r, ctx, b);

  1089.             if (rc == NGX_AGAIN) {
  1090.                 break;
  1091.             }

  1092.             if (rc == NGX_OK) {

  1093.                 /* a header line has been parsed successfully */

  1094.                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1095.                                "http proxy header: \"%V: %V\"",
  1096.                                &ctx->name, &ctx->value);

  1097.                 if (ctx->name.len && ctx->name.data[0] == ':') {

  1098.                     if (ctx->name.len != sizeof(":status") - 1
  1099.                         || ngx_strncmp(ctx->name.data, ":status",
  1100.                                        sizeof(":status") - 1)
  1101.                            != 0)
  1102.                     {
  1103.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1104.                                       "upstream sent invalid header \"%V: %V\"",
  1105.                                       &ctx->name, &ctx->value);
  1106.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1107.                     }

  1108.                     if (ctx->status) {
  1109.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1110.                                       "upstream sent duplicate :status header");
  1111.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1112.                     }

  1113.                     status_line = &ctx->value;

  1114.                     if (status_line->len != 3) {
  1115.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1116.                                       "upstream sent invalid :status \"%V\"",
  1117.                                       status_line);
  1118.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1119.                     }

  1120.                     status = ngx_atoi(status_line->data, 3);

  1121.                     if (status == NGX_ERROR) {
  1122.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1123.                                       "upstream sent invalid :status \"%V\"",
  1124.                                       status_line);
  1125.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1126.                     }

  1127.                     if (status < NGX_HTTP_OK && status != NGX_HTTP_EARLY_HINTS)
  1128.                     {
  1129.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1130.                                       "upstream sent unexpected :status \"%V\"",
  1131.                                       status_line);
  1132.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1133.                     }

  1134.                     u->headers_in.status_n = status;

  1135.                     if (u->state && u->state->status == 0) {
  1136.                         u->state->status = status;
  1137.                     }

  1138.                     ctx->status = 1;

  1139.                     continue;

  1140.                 } else if (!ctx->status) {
  1141.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1142.                                   "upstream sent no :status header");
  1143.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1144.                 }

  1145.                 h = ngx_list_push(&u->headers_in.headers);
  1146.                 if (h == NULL) {
  1147.                     return NGX_ERROR;
  1148.                 }

  1149.                 h->key = ctx->name;
  1150.                 h->value = ctx->value;
  1151.                 h->lowcase_key = h->key.data;
  1152.                 h->hash = ngx_hash_key(h->key.data, h->key.len);

  1153.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1154.                     continue;
  1155.                 }

  1156.                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
  1157.                                    h->lowcase_key, h->key.len);

  1158.                 if (hh) {
  1159.                     rc = hh->handler(r, h, hh->offset);

  1160.                     if (rc != NGX_OK) {
  1161.                         return rc;
  1162.                     }
  1163.                 }

  1164.                 continue;
  1165.             }

  1166.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

  1167.                 /* a whole header has been parsed successfully */

  1168.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1169.                                "http proxy header done");

  1170.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1171.                     if (ctx->end_stream) {
  1172.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1173.                                       "upstream prematurely closed stream");
  1174.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1175.                     }

  1176.                     ctx->status = 0;
  1177.                     return NGX_HTTP_UPSTREAM_EARLY_HINTS;
  1178.                 }

  1179.                 if (ctx->end_stream
  1180.                     && ctx->in == NULL
  1181.                     && ctx->out == NULL
  1182.                     && ctx->output_closed
  1183.                     && !ctx->output_blocked
  1184.                     && !ctx->goaway
  1185.                     && b->last == b->pos)
  1186.                 {
  1187.                     u->keepalive = 1;
  1188.                 }

  1189.                 return NGX_OK;
  1190.             }

  1191.             /* there was error while a header line parsing */

  1192.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1193.                           "upstream sent invalid header");

  1194.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1195.         }

  1196.         /* rc == NGX_AGAIN */

  1197.         if (ctx->rest == 0) {
  1198.             ctx->state = ngx_http_proxy_v2_st_start;
  1199.             continue;
  1200.         }

  1201.         return NGX_AGAIN;
  1202.     }
  1203. }


  1204. static ngx_int_t
  1205. ngx_http_proxy_v2_filter_init(void *data)
  1206. {
  1207.     ngx_http_request_t       *r = data;
  1208.     ngx_http_upstream_t      *u;
  1209.     ngx_http_proxy_v2_ctx_t  *ctx;

  1210.     u = r->upstream;
  1211.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1212.     if (ctx == NULL) {
  1213.         return NGX_ERROR;
  1214.     }

  1215.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1216.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1217.         || ctx->ctx.head)
  1218.     {
  1219.         ctx->length = 0;

  1220.     } else {
  1221.         ctx->length = u->headers_in.content_length_n;
  1222.     }

  1223.     if (ctx->end_stream) {

  1224.         if (ctx->length > 0) {
  1225.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1226.                           "upstream prematurely closed stream");
  1227.             return NGX_ERROR;
  1228.         }

  1229.         u->length = 0;
  1230.         u->pipe->length = 0;
  1231.         ctx->done = 1;

  1232.     } else {
  1233.         u->length = 1;
  1234.         u->pipe->length = 1;
  1235.     }

  1236.     return NGX_OK;
  1237. }


  1238. static ngx_int_t
  1239. ngx_http_proxy_v2_non_buffered_filter(void *data, ssize_t bytes)
  1240. {
  1241.     ngx_http_request_t   *r = data;

  1242.     ngx_int_t                 rc;
  1243.     ngx_buf_t                *b, *buf;
  1244.     ngx_chain_t              *cl, **ll;
  1245.     ngx_http_upstream_t      *u;
  1246.     ngx_http_proxy_v2_ctx_t  *ctx;

  1247.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1248.                    "http proxy filter bytes:%z", bytes);

  1249.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1250.     if (ctx == NULL) {
  1251.         return NGX_ERROR;
  1252.     }

  1253.     u = r->upstream;
  1254.     b = &u->buffer;

  1255.     b->pos = b->last;
  1256.     b->last += bytes;

  1257.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1258.         ll = &cl->next;
  1259.     }

  1260.     for ( ;; ) {

  1261.         rc = ngx_http_proxy_v2_process_frames(r, ctx, b);

  1262.         if (rc == NGX_OK) {

  1263.             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1264.             if (cl == NULL) {
  1265.                 return NGX_ERROR;
  1266.             }

  1267.             *ll = cl;
  1268.             ll = &cl->next;

  1269.             buf = cl->buf;

  1270.             buf->flush = 1;
  1271.             buf->memory = 1;

  1272.             buf->pos = b->pos;
  1273.             buf->tag = u->output.tag;

  1274.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1275.                 b->pos += ctx->rest - ctx->padding;
  1276.                 buf->last = b->pos;
  1277.                 ctx->rest = ctx->padding;

  1278.             } else {
  1279.                 ctx->rest -= b->last - b->pos;
  1280.                 b->pos = b->last;
  1281.                 buf->last = b->pos;
  1282.             }

  1283.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1284.                            "http proxy output buf %p", buf->pos);

  1285.             if (ctx->length != -1) {

  1286.                 if (buf->last - buf->pos > ctx->length) {
  1287.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1288.                                   "upstream sent response body larger "
  1289.                                   "than indicated content length");
  1290.                     return NGX_ERROR;
  1291.                 }

  1292.                 ctx->length -= buf->last - buf->pos;
  1293.             }

  1294.             continue;
  1295.         }

  1296.         if (rc == NGX_DONE) {
  1297.             u->length = 0;
  1298.             break;
  1299.         }

  1300.         if (rc == NGX_AGAIN) {
  1301.             return NGX_AGAIN;
  1302.         }

  1303.         /* invalid response */

  1304.         return NGX_ERROR;
  1305.     }

  1306.     return NGX_OK;
  1307. }


  1308. static ngx_int_t
  1309. ngx_http_proxy_v2_body_filter(ngx_event_pipe_t *p, ngx_buf_t *b)
  1310. {
  1311.     ngx_int_t                 rc;
  1312.     ngx_buf_t                *buf, **prev;
  1313.     ngx_chain_t              *cl;
  1314.     ngx_http_request_t       *r;
  1315.     ngx_http_proxy_v2_ctx_t  *ctx;

  1316.     if (b->pos == b->last) {
  1317.         return NGX_OK;
  1318.     }

  1319.     r = p->input_ctx;
  1320.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1321.     if (ctx == NULL) {
  1322.         return NGX_ERROR;
  1323.     }

  1324.     buf = NULL;
  1325.     prev = &b->shadow;

  1326.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1327.                    "http proxy filter bytes:%z", b->last - b->pos);

  1328.     for ( ;; ) {

  1329.         rc = ngx_http_proxy_v2_process_frames(r, ctx, b);

  1330.         if (rc == NGX_OK) {

  1331.             /* copy data frame payload for buffering */

  1332.             cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1333.             if (cl == NULL) {
  1334.                 return NGX_ERROR;
  1335.             }

  1336.             buf = cl->buf;

  1337.             ngx_memzero(buf, sizeof(ngx_buf_t));

  1338.             buf->pos = b->pos;
  1339.             buf->start = b->start;
  1340.             buf->end = b->end;
  1341.             buf->tag = p->tag;
  1342.             buf->temporary = 1;
  1343.             buf->recycled = 1;

  1344.             *prev = buf;
  1345.             prev = &buf->shadow;

  1346.             if (p->in) {
  1347.                 *p->last_in = cl;

  1348.             } else {
  1349.                 p->in = cl;
  1350.             }

  1351.             p->last_in = &cl->next;

  1352.             /* STUB */ buf->num = b->num;

  1353.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1354.                            "http proxy copy buf %p", buf->pos);

  1355.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1356.                 b->pos += ctx->rest - ctx->padding;
  1357.                 buf->last = b->pos;
  1358.                 ctx->rest = ctx->padding;

  1359.             } else {
  1360.                 ctx->rest -= b->last - b->pos;
  1361.                 b->pos = b->last;
  1362.                 buf->last = b->pos;
  1363.             }

  1364.             if (ctx->length != -1) {

  1365.                 if (buf->last - buf->pos > ctx->length) {
  1366.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1367.                                   "upstream sent response body larger "
  1368.                                   "than indicated content length");
  1369.                     return NGX_ERROR;
  1370.                 }

  1371.                 ctx->length -= buf->last - buf->pos;
  1372.             }

  1373.             continue;
  1374.         }

  1375.         if (rc == NGX_DONE) {
  1376.             p->length = 0;
  1377.             break;
  1378.         }

  1379.         if (rc == NGX_AGAIN) {
  1380.             break;
  1381.         }

  1382.         /* invalid response */

  1383.         return NGX_ERROR;
  1384.     }

  1385.     if (buf) {
  1386.         buf->shadow = b;
  1387.         buf->last_shadow = 1;

  1388.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
  1389.                        "input buf %p %z", buf->pos, buf->last - buf->pos);

  1390.         return NGX_OK;
  1391.     }

  1392.     /* there is no data record in the buf, add it to free chain */

  1393.     if (ngx_event_pipe_add_free_buf(p, b) != NGX_OK) {
  1394.         return NGX_ERROR;
  1395.     }

  1396.     return NGX_OK;
  1397. }


  1398. static ngx_int_t
  1399. ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
  1400.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1401. {
  1402.     ngx_int_t             rc;
  1403.     ngx_http_upstream_t  *u;

  1404.     u = r->upstream;

  1405.     if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {

  1406.         rc = ngx_http_proxy_v2_parse_goaway(r, ctx, b);

  1407.         if (rc == NGX_AGAIN) {
  1408.             return NGX_AGAIN;
  1409.         }

  1410.         if (rc == NGX_ERROR) {
  1411.             return NGX_ERROR;
  1412.         }

  1413.         /*
  1414.          * If stream_id is lower than one we use, our
  1415.          * request won't be processed and needs to be retried.
  1416.          * If stream_id is greater or equal to the one we use,
  1417.          * we can continue normally (except we can't use this
  1418.          * connection for additional requests).  If there is
  1419.          * a real error, the connection will be closed.
  1420.          */

  1421.         if (ctx->stream_id < ctx->id) {

  1422.             /* TODO: we can retry non-idempotent requests */

  1423.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1424.                           "upstream sent goaway with error %ui",
  1425.                           ctx->error);

  1426.             return NGX_ERROR;
  1427.         }

  1428.         ctx->goaway = 1;

  1429.         return NGX_OK;
  1430.     }

  1431.     if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {

  1432.         rc = ngx_http_proxy_v2_parse_window_update(r, ctx, b);

  1433.         if (rc == NGX_AGAIN) {
  1434.             return NGX_AGAIN;
  1435.         }

  1436.         if (rc == NGX_ERROR) {
  1437.             return NGX_ERROR;
  1438.         }

  1439.         if (ctx->in) {
  1440.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1441.         }

  1442.         return NGX_OK;
  1443.     }

  1444.     if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {

  1445.         rc = ngx_http_proxy_v2_parse_settings(r, ctx, b);

  1446.         if (rc == NGX_AGAIN) {
  1447.             return NGX_AGAIN;
  1448.         }

  1449.         if (rc == NGX_ERROR) {
  1450.             return NGX_ERROR;
  1451.         }

  1452.         if (ctx->in) {
  1453.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1454.         }

  1455.         return NGX_OK;
  1456.     }

  1457.     if (ctx->type == NGX_HTTP_V2_PING_FRAME) {

  1458.         rc = ngx_http_proxy_v2_parse_ping(r, ctx, b);

  1459.         if (rc == NGX_AGAIN) {
  1460.             return NGX_AGAIN;
  1461.         }

  1462.         if (rc == NGX_ERROR) {
  1463.             return NGX_ERROR;
  1464.         }

  1465.         ngx_post_event(u->peer.connection->write, &ngx_posted_events);

  1466.         return NGX_OK;
  1467.     }

  1468.     if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
  1469.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1470.                       "upstream sent unexpected push promise frame");
  1471.         return NGX_ERROR;
  1472.     }

  1473.     return NGX_DECLINED;
  1474. }


  1475. static ngx_int_t
  1476. ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1477. {
  1478.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  1479.         ctx->rest -= b->last - b->pos;
  1480.         b->pos = b->last;
  1481.         return NGX_AGAIN;
  1482.     }

  1483.     b->pos += ctx->rest;
  1484.     ctx->rest = 0;
  1485.     ctx->state = ngx_http_proxy_v2_st_start;

  1486.     return NGX_OK;
  1487. }


  1488. static ngx_int_t
  1489. ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
  1490.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1491. {
  1492.     ngx_int_t             rc;
  1493.     ngx_table_elt_t      *h;
  1494.     ngx_http_upstream_t  *u;

  1495.     u = r->upstream;

  1496.     for ( ;; ) {

  1497.         if (ctx->state < ngx_http_proxy_v2_st_payload) {

  1498.             rc = ngx_http_proxy_v2_parse_frame(r, ctx, b);

  1499.             if (rc == NGX_AGAIN) {

  1500.                 if (ctx->done) {

  1501.                     if (ctx->length > 0) {
  1502.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1503.                                       "upstream prematurely closed stream");
  1504.                         return NGX_ERROR;
  1505.                     }

  1506.                     /*
  1507.                      * We have finished parsing the response and the
  1508.                      * remaining control frames.  If there are unsent
  1509.                      * control frames, post a write event to send them.
  1510.                      */

  1511.                     if (ctx->out) {
  1512.                         ngx_post_event(u->peer.connection->write,
  1513.                                        &ngx_posted_events);
  1514.                         return NGX_AGAIN;
  1515.                     }

  1516.                     if (ctx->in == NULL
  1517.                         && ctx->output_closed
  1518.                         && !ctx->output_blocked
  1519.                         && !ctx->goaway
  1520.                         && ctx->state == ngx_http_proxy_v2_st_start)
  1521.                     {
  1522.                         u->keepalive = 1;
  1523.                     }

  1524.                     return NGX_DONE;
  1525.                 }

  1526.                 return NGX_AGAIN;
  1527.             }

  1528.             if (rc == NGX_ERROR) {
  1529.                 return NGX_ERROR;
  1530.             }

  1531.             if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1532.                  && !ctx->parsing_headers)
  1533.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1534.                     && ctx->parsing_headers))
  1535.             {
  1536.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1537.                               "upstream sent unexpected http2 frame: %d",
  1538.                               ctx->type);
  1539.                 return NGX_ERROR;
  1540.             }

  1541.             if (ctx->type == NGX_HTTP_V2_DATA_FRAME) {

  1542.                 if (ctx->stream_id != ctx->id) {
  1543.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1544.                                   "upstream sent data frame "
  1545.                                   "for unknown stream %ui",
  1546.                                   ctx->stream_id);
  1547.                     return NGX_ERROR;
  1548.                 }

  1549.                 if (ctx->rest > ctx->recv_window) {
  1550.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1551.                                   "upstream violated stream flow control, "
  1552.                                   "received %uz data frame with window %uz",
  1553.                                   ctx->rest, ctx->recv_window);
  1554.                     return NGX_ERROR;
  1555.                 }

  1556.                 if (ctx->rest > ctx->connection->recv_window) {
  1557.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1558.                                   "upstream violated connection flow control, "
  1559.                                   "received %uz data frame with window %uz",
  1560.                                   ctx->rest, ctx->connection->recv_window);
  1561.                     return NGX_ERROR;
  1562.                 }

  1563.                 ctx->recv_window -= ctx->rest;
  1564.                 ctx->connection->recv_window -= ctx->rest;

  1565.                 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
  1566.                     || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
  1567.                 {
  1568.                     if (ngx_http_proxy_v2_send_window_update(r, ctx)
  1569.                         != NGX_OK)
  1570.                     {
  1571.                         return NGX_ERROR;
  1572.                     }

  1573.                     ngx_post_event(u->peer.connection->write,
  1574.                                    &ngx_posted_events);
  1575.                 }
  1576.             }

  1577.             if (ctx->stream_id && ctx->stream_id != ctx->id) {
  1578.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1579.                               "upstream sent frame for unknown stream %ui",
  1580.                               ctx->stream_id);
  1581.                 return NGX_ERROR;
  1582.             }

  1583.             if (ctx->stream_id && ctx->done
  1584.                 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
  1585.                 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
  1586.             {
  1587.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1588.                               "upstream sent frame for closed stream %ui",
  1589.                               ctx->stream_id);
  1590.                 return NGX_ERROR;
  1591.             }

  1592.             ctx->padding = 0;
  1593.         }

  1594.         if (ctx->state == ngx_http_proxy_v2_st_padding) {

  1595.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1596.                 ctx->rest -= b->last - b->pos;
  1597.                 b->pos = b->last;
  1598.                 return NGX_AGAIN;
  1599.             }

  1600.             b->pos += ctx->rest;
  1601.             ctx->rest = 0;
  1602.             ctx->state = ngx_http_proxy_v2_st_start;

  1603.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1604.                 ctx->done = 1;
  1605.             }

  1606.             continue;
  1607.         }

  1608.         /* frame payload */

  1609.         if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {

  1610.             rc = ngx_http_proxy_v2_parse_rst_stream(r, ctx, b);

  1611.             if (rc == NGX_AGAIN) {
  1612.                 return NGX_AGAIN;
  1613.             }

  1614.             if (rc == NGX_ERROR) {
  1615.                 return NGX_ERROR;
  1616.             }

  1617.             if (ctx->error || !ctx->done) {
  1618.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1619.                               "upstream rejected request with error %ui",
  1620.                               ctx->error);
  1621.                 return NGX_ERROR;
  1622.             }

  1623.             if (ctx->rst) {
  1624.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1625.                               "upstream sent frame for closed stream %ui",
  1626.                               ctx->stream_id);
  1627.                 return NGX_ERROR;
  1628.             }

  1629.             ctx->rst = 1;

  1630.             continue;
  1631.         }

  1632.         rc = ngx_http_proxy_v2_process_control_frame(r, ctx, b);

  1633.         if (rc == NGX_AGAIN) {
  1634.             return NGX_AGAIN;
  1635.         }

  1636.         if (rc == NGX_ERROR) {
  1637.             return NGX_ERROR;
  1638.         }

  1639.         if (rc == NGX_OK) {
  1640.             continue;
  1641.         }

  1642.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
  1643.             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
  1644.         {
  1645.             for ( ;; ) {

  1646.                 rc = ngx_http_proxy_v2_parse_header(r, ctx, b);

  1647.                 if (rc == NGX_AGAIN) {
  1648.                     break;
  1649.                 }

  1650.                 if (rc == NGX_OK) {

  1651.                     /* a header line has been parsed successfully */

  1652.                     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1653.                                    "http proxy trailer: \"%V: %V\"",
  1654.                                    &ctx->name, &ctx->value);

  1655.                     if (ctx->name.len && ctx->name.data[0] == ':') {
  1656.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1657.                                       "upstream sent invalid "
  1658.                                       "trailer \"%V: %V\"",
  1659.                                       &ctx->name, &ctx->value);
  1660.                         return NGX_ERROR;
  1661.                     }

  1662.                     h = ngx_list_push(&u->headers_in.trailers);
  1663.                     if (h == NULL) {
  1664.                         return NGX_ERROR;
  1665.                     }

  1666.                     h->key = ctx->name;
  1667.                     h->value = ctx->value;
  1668.                     h->lowcase_key = h->key.data;
  1669.                     h->hash = ngx_hash_key(h->key.data, h->key.len);

  1670.                     continue;
  1671.                 }

  1672.                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

  1673.                     /* a whole header has been parsed successfully */

  1674.                     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1675.                                    "http proxy trailer done");

  1676.                     if (ctx->end_stream) {
  1677.                         ctx->done = 1;
  1678.                         break;
  1679.                     }

  1680.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1681.                                   "upstream sent trailer without "
  1682.                                   "end stream flag");
  1683.                     return NGX_ERROR;
  1684.                 }

  1685.                 /* there was error while a header line parsing */

  1686.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1687.                               "upstream sent invalid trailer");

  1688.                 return NGX_ERROR;
  1689.             }

  1690.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1691.                 continue;
  1692.             }

  1693.             /* rc == NGX_AGAIN */

  1694.             if (ctx->rest == 0) {
  1695.                 ctx->state = ngx_http_proxy_v2_st_start;
  1696.                 continue;
  1697.             }

  1698.             return NGX_AGAIN;
  1699.         }

  1700.         if (ctx->type != NGX_HTTP_V2_DATA_FRAME) {

  1701.             /* priority, unknown frames */

  1702.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1703.             if (rc == NGX_AGAIN) {
  1704.                 return NGX_AGAIN;
  1705.             }

  1706.             continue;
  1707.         }

  1708.         /*
  1709.          * data frame:
  1710.          *
  1711.          * +---------------+
  1712.          * |Pad Length? (8)|
  1713.          * +---------------+-----------------------------------------------+
  1714.          * |                            Data (*)                         ...
  1715.          * +---------------------------------------------------------------+
  1716.          * |                           Padding (*)                       ...
  1717.          * +---------------------------------------------------------------+
  1718.          */

  1719.         if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {

  1720.             if (ctx->rest == 0) {
  1721.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1722.                               "upstream sent too short http2 frame");
  1723.                 return NGX_ERROR;
  1724.             }

  1725.             if (b->pos == b->last) {
  1726.                 return NGX_AGAIN;
  1727.             }

  1728.             ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
  1729.             ctx->padding = *b->pos++;
  1730.             ctx->rest -= 1;

  1731.             if (ctx->padding > ctx->rest) {
  1732.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1733.                               "upstream sent http2 frame with too long "
  1734.                               "padding: %d in frame %uz",
  1735.                               ctx->padding, ctx->rest);
  1736.                 return NGX_ERROR;
  1737.             }

  1738.             continue;
  1739.         }

  1740.         if (ctx->padding == ctx->rest) {

  1741.             if (ctx->padding) {
  1742.                 ctx->state = ngx_http_proxy_v2_st_padding;

  1743.             } else {
  1744.                 ctx->state = ngx_http_proxy_v2_st_start;

  1745.                 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1746.                     ctx->done = 1;
  1747.                 }
  1748.             }

  1749.             continue;
  1750.         }

  1751.         if (b->pos == b->last) {
  1752.             return NGX_AGAIN;
  1753.         }

  1754.         return NGX_OK;
  1755.     }
  1756. }


  1757. static ngx_int_t
  1758. ngx_http_proxy_v2_parse_frame(ngx_http_request_t *r,
  1759.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1760. {
  1761.     u_char                     ch, *p;
  1762.     ngx_http_proxy_v2_state_e  state;

  1763.     state = ctx->state;

  1764.     for (p = b->pos; p < b->last; p++) {
  1765.         ch = *p;

  1766. #if 0
  1767.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1768.                        "http proxy frame byte: %02Xd, s:%d", ch, state);
  1769. #endif

  1770.         switch (state) {

  1771.         case ngx_http_proxy_v2_st_start:
  1772.             ctx->rest = ch << 16;
  1773.             state = ngx_http_proxy_v2_st_length_2;
  1774.             break;

  1775.         case ngx_http_proxy_v2_st_length_2:
  1776.             ctx->rest |= ch << 8;
  1777.             state = ngx_http_proxy_v2_st_length_3;
  1778.             break;

  1779.         case ngx_http_proxy_v2_st_length_3:
  1780.             ctx->rest |= ch;

  1781.             if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  1782.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1783.                               "upstream sent too large http2 frame: %uz",
  1784.                               ctx->rest);
  1785.                 return NGX_ERROR;
  1786.             }

  1787.             state = ngx_http_proxy_v2_st_type;
  1788.             break;

  1789.         case ngx_http_proxy_v2_st_type:
  1790.             ctx->type = ch;
  1791.             state = ngx_http_proxy_v2_st_flags;
  1792.             break;

  1793.         case ngx_http_proxy_v2_st_flags:
  1794.             ctx->flags = ch;
  1795.             state = ngx_http_proxy_v2_st_stream_id;
  1796.             break;

  1797.         case ngx_http_proxy_v2_st_stream_id:
  1798.             ctx->stream_id = (ch & 0x7f) << 24;
  1799.             state = ngx_http_proxy_v2_st_stream_id_2;
  1800.             break;

  1801.         case ngx_http_proxy_v2_st_stream_id_2:
  1802.             ctx->stream_id |= ch << 16;
  1803.             state = ngx_http_proxy_v2_st_stream_id_3;
  1804.             break;

  1805.         case ngx_http_proxy_v2_st_stream_id_3:
  1806.             ctx->stream_id |= ch << 8;
  1807.             state = ngx_http_proxy_v2_st_stream_id_4;
  1808.             break;

  1809.         case ngx_http_proxy_v2_st_stream_id_4:
  1810.             ctx->stream_id |= ch;

  1811.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1812.                            "http proxy frame: %d, len: %uz, f:%d, i:%ui",
  1813.                            ctx->type, ctx->rest, ctx->flags, ctx->stream_id);

  1814.             b->pos = p + 1;

  1815.             ctx->state = ngx_http_proxy_v2_st_payload;
  1816.             ctx->frame_state = 0;

  1817.             return NGX_OK;

  1818.         /* suppress warning */
  1819.         case ngx_http_proxy_v2_st_payload:
  1820.         case ngx_http_proxy_v2_st_padding:
  1821.             break;
  1822.         }
  1823.     }

  1824.     b->pos = p;
  1825.     ctx->state = state;

  1826.     return NGX_AGAIN;
  1827. }


  1828. static ngx_int_t
  1829. ngx_http_proxy_v2_parse_header(ngx_http_request_t *r,
  1830.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1831. {
  1832.     u_char     ch, *p, *last;
  1833.     size_t     min;
  1834.     ngx_int_t  rc;
  1835.     enum {
  1836.         sw_start = 0,
  1837.         sw_padding_length,
  1838.         sw_dependency,
  1839.         sw_dependency_2,
  1840.         sw_dependency_3,
  1841.         sw_dependency_4,
  1842.         sw_weight,
  1843.         sw_fragment,
  1844.         sw_padding
  1845.     } state;

  1846.     state = ctx->frame_state;

  1847.     if (state == sw_start) {

  1848.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1849.                        "http proxy parse header: start");

  1850.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
  1851.             ctx->parsing_headers = 1;
  1852.             ctx->fragment_state = 0;

  1853.             min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0)
  1854.                   + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0);

  1855.             if (ctx->rest < min) {
  1856.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1857.                               "upstream sent headers frame "
  1858.                               "with invalid length: %uz",
  1859.                               ctx->rest);
  1860.                 return NGX_ERROR;
  1861.             }

  1862.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1863.                 ctx->end_stream = 1;
  1864.             }

  1865.             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
  1866.                 state = sw_padding_length;

  1867.             } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
  1868.                 state = sw_dependency;

  1869.             } else {
  1870.                 state = sw_fragment;
  1871.             }

  1872.         } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
  1873.             state = sw_fragment;
  1874.         }

  1875.         ctx->padding = 0;
  1876.         ctx->frame_state = state;
  1877.     }

  1878.     if (state < sw_fragment) {

  1879.         if (b->last - b->pos < (ssize_t) ctx->rest) {
  1880.             last = b->last;

  1881.         } else {
  1882.             last = b->pos + ctx->rest;
  1883.         }

  1884.         for (p = b->pos; p < last; p++) {
  1885.             ch = *p;

  1886. #if 0
  1887.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1888.                            "http proxy header byte: %02Xd s:%d", ch, state);
  1889. #endif

  1890.             /*
  1891.              * headers frame:
  1892.              *
  1893.              * +---------------+
  1894.              * |Pad Length? (8)|
  1895.              * +-+-------------+----------------------------------------------+
  1896.              * |E|                 Stream Dependency? (31)                    |
  1897.              * +-+-------------+----------------------------------------------+
  1898.              * |  Weight? (8)  |
  1899.              * +-+-------------+----------------------------------------------+
  1900.              * |                   Header Block Fragment (*)                ...
  1901.              * +--------------------------------------------------------------+
  1902.              * |                           Padding (*)                      ...
  1903.              * +--------------------------------------------------------------+
  1904.              */

  1905.             switch (state) {

  1906.             case sw_padding_length:

  1907.                 ctx->padding = ch;

  1908.                 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
  1909.                     state = sw_dependency;
  1910.                     break;
  1911.                 }

  1912.                 goto fragment;

  1913.             case sw_dependency:
  1914.                 state = sw_dependency_2;
  1915.                 break;

  1916.             case sw_dependency_2:
  1917.                 state = sw_dependency_3;
  1918.                 break;

  1919.             case sw_dependency_3:
  1920.                 state = sw_dependency_4;
  1921.                 break;

  1922.             case sw_dependency_4:
  1923.                 state = sw_weight;
  1924.                 break;

  1925.             case sw_weight:
  1926.                 goto fragment;

  1927.             /* suppress warning */
  1928.             case sw_start:
  1929.             case sw_fragment:
  1930.             case sw_padding:
  1931.                 break;
  1932.             }
  1933.         }

  1934.         ctx->rest -= p - b->pos;
  1935.         b->pos = p;

  1936.         ctx->frame_state = state;
  1937.         return NGX_AGAIN;

  1938.     fragment:

  1939.         p++;
  1940.         ctx->rest -= p - b->pos;
  1941.         b->pos = p;

  1942.         if (ctx->padding > ctx->rest) {
  1943.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1944.                           "upstream sent http2 frame with too long "
  1945.                           "padding: %d in frame %uz",
  1946.                           ctx->padding, ctx->rest);
  1947.             return NGX_ERROR;
  1948.         }

  1949.         state = sw_fragment;
  1950.         ctx->frame_state = state;
  1951.     }

  1952.     if (state == sw_fragment) {

  1953.         rc = ngx_http_proxy_v2_parse_fragment(r, ctx, b);

  1954.         if (rc == NGX_AGAIN) {
  1955.             return NGX_AGAIN;
  1956.         }

  1957.         if (rc == NGX_ERROR) {
  1958.             return NGX_ERROR;
  1959.         }

  1960.         if (rc == NGX_OK) {
  1961.             return NGX_OK;
  1962.         }

  1963.         /* rc == NGX_DONE */

  1964.         state = sw_padding;
  1965.         ctx->frame_state = state;
  1966.     }

  1967.     if (state == sw_padding) {

  1968.         if (b->last - b->pos < (ssize_t) ctx->rest) {

  1969.             ctx->rest -= b->last - b->pos;
  1970.             b->pos = b->last;

  1971.             return NGX_AGAIN;
  1972.         }

  1973.         b->pos += ctx->rest;
  1974.         ctx->rest = 0;

  1975.         ctx->state = ngx_http_proxy_v2_st_start;

  1976.         if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) {

  1977.             if (ctx->fragment_state) {
  1978.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1979.                               "upstream sent truncated http2 header");
  1980.                 return NGX_ERROR;
  1981.             }

  1982.             ctx->parsing_headers = 0;

  1983.             return NGX_HTTP_PARSE_HEADER_DONE;
  1984.         }

  1985.         return NGX_AGAIN;
  1986.     }

  1987.     /* unreachable */

  1988.     return NGX_ERROR;
  1989. }


  1990. static ngx_int_t
  1991. ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
  1992.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1993. {
  1994.     u_char      ch, *p, *last;
  1995.     size_t      size;
  1996.     ngx_uint_t  index, size_update;
  1997.     enum {
  1998.         sw_start = 0,
  1999.         sw_index,
  2000.         sw_name_length,
  2001.         sw_name_length_2,
  2002.         sw_name_length_3,
  2003.         sw_name_length_4,
  2004.         sw_name,
  2005.         sw_name_bytes,
  2006.         sw_value_length,
  2007.         sw_value_length_2,
  2008.         sw_value_length_3,
  2009.         sw_value_length_4,
  2010.         sw_value,
  2011.         sw_value_bytes
  2012.     } state;

  2013.     /* header block fragment */

  2014. #if 0
  2015.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2016.                    "http proxy header fragment %p:%p rest:%uz",
  2017.                    b->pos, b->last, ctx->rest);
  2018. #endif

  2019.     if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
  2020.         last = b->last;

  2021.     } else {
  2022.         last = b->pos + ctx->rest - ctx->padding;
  2023.     }

  2024.     state = ctx->fragment_state;

  2025.     for (p = b->pos; p < last; p++) {
  2026.         ch = *p;

  2027. #if 0
  2028.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2029.                        "http proxy header byte: %02Xd s:%d", ch, state);
  2030. #endif

  2031.         switch (state) {

  2032.         case sw_start:
  2033.             ctx->index = 0;

  2034.             if ((ch & 0x80) == 0x80) {
  2035.                 /*
  2036.                  * indexed header:
  2037.                  *
  2038.                  *   0   1   2   3   4   5   6   7
  2039.                  * +---+---+---+---+---+---+---+---+
  2040.                  * | 1 |        Index (7+)         |
  2041.                  * +---+---------------------------+
  2042.                  */

  2043.                 index = ch & ~0x80;

  2044.                 if (index == 0 || index > 61) {
  2045.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2046.                                   "upstream sent invalid http2 "
  2047.                                   "table index: %ui", index);
  2048.                     return NGX_ERROR;
  2049.                 }

  2050.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2051.                                "http proxy indexed header: %ui", index);

  2052.                 ctx->index = index;
  2053.                 ctx->literal = 0;

  2054.                 goto done;

  2055.             } else if ((ch & 0xc0) == 0x40) {
  2056.                 /*
  2057.                  * literal header with incremental indexing:
  2058.                  *
  2059.                  *   0   1   2   3   4   5   6   7
  2060.                  * +---+---+---+---+---+---+---+---+
  2061.                  * | 0 | 1 |      Index (6+)       |
  2062.                  * +---+---+-----------------------+
  2063.                  * | H |     Value Length (7+)     |
  2064.                  * +---+---------------------------+
  2065.                  * | Value String (Length octets)  |
  2066.                  * +-------------------------------+
  2067.                  *
  2068.                  *   0   1   2   3   4   5   6   7
  2069.                  * +---+---+---+---+---+---+---+---+
  2070.                  * | 0 | 1 |           0           |
  2071.                  * +---+---+-----------------------+
  2072.                  * | H |     Name Length (7+)      |
  2073.                  * +---+---------------------------+
  2074.                  * |  Name String (Length octets)  |
  2075.                  * +---+---------------------------+
  2076.                  * | H |     Value Length (7+)     |
  2077.                  * +---+---------------------------+
  2078.                  * | Value String (Length octets)  |
  2079.                  * +-------------------------------+
  2080.                  */

  2081.                 index = ch & ~0xc0;

  2082.                 if (index > 61) {
  2083.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2084.                                   "upstream sent invalid http2 "
  2085.                                   "table index: %ui", index);
  2086.                     return NGX_ERROR;
  2087.                 }

  2088.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2089.                                "http proxy literal header: %ui", index);

  2090.                 if (index == 0) {
  2091.                     state = sw_name_length;
  2092.                     break;
  2093.                 }

  2094.                 ctx->index = index;
  2095.                 ctx->literal = 1;

  2096.                 state = sw_value_length;
  2097.                 break;

  2098.             } else if ((ch & 0xe0) == 0x20) {
  2099.                 /*
  2100.                  * dynamic table size update:
  2101.                  *
  2102.                  *   0   1   2   3   4   5   6   7
  2103.                  * +---+---+---+---+---+---+---+---+
  2104.                  * | 0 | 0 | 1 |   Max size (5+)   |
  2105.                  * +---+---------------------------+
  2106.                  */

  2107.                 size_update = ch & ~0xe0;

  2108.                 if (size_update > 0) {
  2109.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2110.                                   "upstream sent invalid http2 "
  2111.                                   "dynamic table size update: %ui",
  2112.                                   size_update);
  2113.                     return NGX_ERROR;
  2114.                 }

  2115.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2116.                                "http proxy table size update: %ui",
  2117.                                size_update);

  2118.                 break;

  2119.             } else if ((ch & 0xf0) == 0x10) {
  2120.                 /*
  2121.                  *  literal header field never indexed:
  2122.                  *
  2123.                  *   0   1   2   3   4   5   6   7
  2124.                  * +---+---+---+---+---+---+---+---+
  2125.                  * | 0 | 0 | 0 | 1 |  Index (4+)   |
  2126.                  * +---+---+-----------------------+
  2127.                  * | H |     Value Length (7+)     |
  2128.                  * +---+---------------------------+
  2129.                  * | Value String (Length octets)  |
  2130.                  * +-------------------------------+
  2131.                  *
  2132.                  *   0   1   2   3   4   5   6   7
  2133.                  * +---+---+---+---+---+---+---+---+
  2134.                  * | 0 | 0 | 0 | 1 |       0       |
  2135.                  * +---+---+-----------------------+
  2136.                  * | H |     Name Length (7+)      |
  2137.                  * +---+---------------------------+
  2138.                  * |  Name String (Length octets)  |
  2139.                  * +---+---------------------------+
  2140.                  * | H |     Value Length (7+)     |
  2141.                  * +---+---------------------------+
  2142.                  * | Value String (Length octets)  |
  2143.                  * +-------------------------------+
  2144.                  */

  2145.                 index = ch & ~0xf0;

  2146.                 if (index == 0x0f) {
  2147.                     ctx->index = index;
  2148.                     ctx->literal = 1;
  2149.                     state = sw_index;
  2150.                     break;
  2151.                 }

  2152.                 if (index == 0) {
  2153.                     state = sw_name_length;
  2154.                     break;
  2155.                 }

  2156.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2157.                                "http proxy literal header never indexed: %ui",
  2158.                                index);

  2159.                 ctx->index = index;
  2160.                 ctx->literal = 1;

  2161.                 state = sw_value_length;
  2162.                 break;

  2163.             } else if ((ch & 0xf0) == 0x00) {
  2164.                 /*
  2165.                  * literal header field without indexing:
  2166.                  *
  2167.                  *   0   1   2   3   4   5   6   7
  2168.                  * +---+---+---+---+---+---+---+---+
  2169.                  * | 0 | 0 | 0 | 0 |  Index (4+)   |
  2170.                  * +---+---+-----------------------+
  2171.                  * | H |     Value Length (7+)     |
  2172.                  * +---+---------------------------+
  2173.                  * | Value String (Length octets)  |
  2174.                  * +-------------------------------+
  2175.                  *
  2176.                  *   0   1   2   3   4   5   6   7
  2177.                  * +---+---+---+---+---+---+---+---+
  2178.                  * | 0 | 0 | 0 | 0 |       0       |
  2179.                  * +---+---+-----------------------+
  2180.                  * | H |     Name Length (7+)      |
  2181.                  * +---+---------------------------+
  2182.                  * |  Name String (Length octets)  |
  2183.                  * +---+---------------------------+
  2184.                  * | H |     Value Length (7+)     |
  2185.                  * +---+---------------------------+
  2186.                  * | Value String (Length octets)  |
  2187.                  * +-------------------------------+
  2188.                  */

  2189.                 index = ch & ~0xf0;

  2190.                 if (index == 0x0f) {
  2191.                     ctx->index = index;
  2192.                     ctx->literal = 1;
  2193.                     state = sw_index;
  2194.                     break;
  2195.                 }

  2196.                 if (index == 0) {
  2197.                     state = sw_name_length;
  2198.                     break;
  2199.                 }

  2200.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2201.                              "http proxy literal header without indexing: %ui",
  2202.                                index);

  2203.                 ctx->index = index;
  2204.                 ctx->literal = 1;

  2205.                 state = sw_value_length;
  2206.                 break;
  2207.             }

  2208.             /* not reached */

  2209.             return NGX_ERROR;

  2210.         case sw_index:
  2211.             ctx->index = ctx->index + (ch & ~0x80);

  2212.             if (ch & 0x80) {
  2213.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2214.                               "upstream sent http2 table index "
  2215.                               "with continuation flag");
  2216.                 return NGX_ERROR;
  2217.             }

  2218.             if (ctx->index > 61) {
  2219.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2220.                               "upstream sent invalid http2 "
  2221.                               "table index: %ui", ctx->index);
  2222.                 return NGX_ERROR;
  2223.             }

  2224.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2225.                            "http proxy header index: %ui", ctx->index);

  2226.             state = sw_value_length;
  2227.             break;

  2228.         case sw_name_length:
  2229.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2230.             ctx->field_length = ch & ~0x80;

  2231.             if (ctx->field_length == 0x7f) {
  2232.                 state = sw_name_length_2;
  2233.                 break;
  2234.             }

  2235.             if (ctx->field_length == 0) {
  2236.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2237.                               "upstream sent zero http2 "
  2238.                               "header name length");
  2239.                 return NGX_ERROR;
  2240.             }

  2241.             state = sw_name;
  2242.             break;

  2243.         case sw_name_length_2:
  2244.             ctx->field_length += ch & ~0x80;

  2245.             if (ch & 0x80) {
  2246.                 state = sw_name_length_3;
  2247.                 break;
  2248.             }

  2249.             state = sw_name;
  2250.             break;

  2251.         case sw_name_length_3:
  2252.             ctx->field_length += (ch & ~0x80) << 7;

  2253.             if (ch & 0x80) {
  2254.                 state = sw_name_length_4;
  2255.                 break;
  2256.             }

  2257.             state = sw_name;
  2258.             break;

  2259.         case sw_name_length_4:
  2260.             ctx->field_length += (ch & ~0x80) << 14;

  2261.             if (ch & 0x80) {
  2262.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2263.                               "upstream sent too large http2 "
  2264.                               "header name length");
  2265.                 return NGX_ERROR;
  2266.             }

  2267.             state = sw_name;
  2268.             break;

  2269.         case sw_name:
  2270.             ctx->name.len = ctx->field_huffman ?
  2271.                             ctx->field_length * 8 / 5 : ctx->field_length;

  2272.             ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
  2273.             if (ctx->name.data == NULL) {
  2274.                 return NGX_ERROR;
  2275.             }

  2276.             ctx->field_end = ctx->name.data;
  2277.             ctx->field_rest = ctx->field_length;
  2278.             ctx->field_state = 0;

  2279.             state = sw_name_bytes;

  2280.             /* fall through */

  2281.         case sw_name_bytes:

  2282.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2283.                            "http proxy name: len:%uz h:%d last:%uz, rest:%uz",
  2284.                            ctx->field_length,
  2285.                            ctx->field_huffman,
  2286.                            last - p,
  2287.                            ctx->rest - (p - b->pos));

  2288.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2289.             ctx->field_rest -= size;

  2290.             if (ctx->field_huffman) {
  2291.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2292.                                          &ctx->field_end,
  2293.                                          ctx->field_rest == 0,
  2294.                                          r->connection->log)
  2295.                     != NGX_OK)
  2296.                 {
  2297.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2298.                                   "upstream sent invalid encoded header");
  2299.                     return NGX_ERROR;
  2300.                 }

  2301.                 ctx->name.len = ctx->field_end - ctx->name.data;
  2302.                 ctx->name.data[ctx->name.len] = '\0';

  2303.             } else {
  2304.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2305.                 ctx->name.data[ctx->name.len] = '\0';
  2306.             }

  2307.             p += size - 1;

  2308.             if (ctx->field_rest == 0) {
  2309.                 state = sw_value_length;
  2310.             }

  2311.             break;

  2312.         case sw_value_length:
  2313.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2314.             ctx->field_length = ch & ~0x80;

  2315.             if (ctx->field_length == 0x7f) {
  2316.                 state = sw_value_length_2;
  2317.                 break;
  2318.             }

  2319.             if (ctx->field_length == 0) {
  2320.                 ngx_str_set(&ctx->value, "");
  2321.                 goto done;
  2322.             }

  2323.             state = sw_value;
  2324.             break;

  2325.         case sw_value_length_2:
  2326.             ctx->field_length += ch & ~0x80;

  2327.             if (ch & 0x80) {
  2328.                 state = sw_value_length_3;
  2329.                 break;
  2330.             }

  2331.             state = sw_value;
  2332.             break;

  2333.         case sw_value_length_3:
  2334.             ctx->field_length += (ch & ~0x80) << 7;

  2335.             if (ch & 0x80) {
  2336.                 state = sw_value_length_4;
  2337.                 break;
  2338.             }

  2339.             state = sw_value;
  2340.             break;

  2341.         case sw_value_length_4:
  2342.             ctx->field_length += (ch & ~0x80) << 14;

  2343.             if (ch & 0x80) {
  2344.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2345.                               "upstream sent too large http2 "
  2346.                               "header value length");
  2347.                 return NGX_ERROR;
  2348.             }

  2349.             state = sw_value;
  2350.             break;

  2351.         case sw_value:
  2352.             ctx->value.len = ctx->field_huffman ?
  2353.                              ctx->field_length * 8 / 5 : ctx->field_length;

  2354.             ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
  2355.             if (ctx->value.data == NULL) {
  2356.                 return NGX_ERROR;
  2357.             }

  2358.             ctx->field_end = ctx->value.data;
  2359.             ctx->field_rest = ctx->field_length;
  2360.             ctx->field_state = 0;

  2361.             state = sw_value_bytes;

  2362.             /* fall through */

  2363.         case sw_value_bytes:

  2364.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2365.                            "http proxy value: len:%uz h:%d last:%uz, rest:%uz",
  2366.                            ctx->field_length,
  2367.                            ctx->field_huffman,
  2368.                            last - p,
  2369.                            ctx->rest - (p - b->pos));

  2370.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2371.             ctx->field_rest -= size;

  2372.             if (ctx->field_huffman) {
  2373.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2374.                                          &ctx->field_end,
  2375.                                          ctx->field_rest == 0,
  2376.                                          r->connection->log)
  2377.                     != NGX_OK)
  2378.                 {
  2379.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2380.                                   "upstream sent invalid encoded header");
  2381.                     return NGX_ERROR;
  2382.                 }

  2383.                 ctx->value.len = ctx->field_end - ctx->value.data;
  2384.                 ctx->value.data[ctx->value.len] = '\0';

  2385.             } else {
  2386.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2387.                 ctx->value.data[ctx->value.len] = '\0';
  2388.             }

  2389.             p += size - 1;

  2390.             if (ctx->field_rest == 0) {
  2391.                 goto done;
  2392.             }

  2393.             break;
  2394.         }

  2395.         continue;

  2396.     done:

  2397.         p++;
  2398.         ctx->rest -= p - b->pos;
  2399.         ctx->fragment_state = sw_start;
  2400.         b->pos = p;

  2401.         if (ctx->index) {
  2402.             ctx->name = *ngx_http_v2_get_static_name(ctx->index);
  2403.         }

  2404.         if (ctx->index && !ctx->literal) {
  2405.             ctx->value = *ngx_http_v2_get_static_value(ctx->index);
  2406.         }

  2407.         if (!ctx->index) {
  2408.             if (ngx_http_proxy_v2_validate_header_name(r, &ctx->name)
  2409.                 != NGX_OK)
  2410.             {
  2411.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2412.                               "upstream sent invalid header: \"%V: %V\"",
  2413.                               &ctx->name, &ctx->value);
  2414.                 return NGX_ERROR;
  2415.             }
  2416.         }

  2417.         if (!ctx->index || ctx->literal) {
  2418.             if (ngx_http_proxy_v2_validate_header_value(r, &ctx->value)
  2419.                 != NGX_OK)
  2420.             {
  2421.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2422.                               "upstream sent invalid header: \"%V: %V\"",
  2423.                               &ctx->name, &ctx->value);
  2424.                 return NGX_ERROR;
  2425.             }
  2426.         }

  2427.         return NGX_OK;
  2428.     }

  2429.     ctx->rest -= p - b->pos;
  2430.     ctx->fragment_state = state;
  2431.     b->pos = p;

  2432.     if (ctx->rest > ctx->padding) {
  2433.         return NGX_AGAIN;
  2434.     }

  2435.     return NGX_DONE;
  2436. }


  2437. static ngx_int_t
  2438. ngx_http_proxy_v2_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
  2439. {
  2440.     u_char      ch;
  2441.     ngx_uint_t  i;

  2442.     for (i = 0; i < s->len; i++) {
  2443.         ch = s->data[i];

  2444.         if (ch == ':' && i > 0) {
  2445.             return NGX_ERROR;
  2446.         }

  2447.         if (ch >= 'A' && ch <= 'Z') {
  2448.             return NGX_ERROR;
  2449.         }

  2450.         if (ch <= 0x20 || ch == 0x7f) {
  2451.             return NGX_ERROR;
  2452.         }
  2453.     }

  2454.     return NGX_OK;
  2455. }


  2456. static ngx_int_t
  2457. ngx_http_proxy_v2_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
  2458. {
  2459.     u_char      ch;
  2460.     ngx_uint_t  i;

  2461.     for (i = 0; i < s->len; i++) {
  2462.         ch = s->data[i];

  2463.         if (ch == '\0' || ch == CR || ch == LF) {
  2464.             return NGX_ERROR;
  2465.         }
  2466.     }

  2467.     return NGX_OK;
  2468. }


  2469. static ngx_int_t
  2470. ngx_http_proxy_v2_parse_rst_stream(ngx_http_request_t *r,
  2471.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2472. {
  2473.     u_char  ch, *p, *last;
  2474.     enum {
  2475.         sw_start = 0,
  2476.         sw_error_2,
  2477.         sw_error_3,
  2478.         sw_error_4
  2479.     } state;

  2480.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  2481.         last = b->last;

  2482.     } else {
  2483.         last = b->pos + ctx->rest;
  2484.     }

  2485.     state = ctx->frame_state;

  2486.     if (state == sw_start) {
  2487.         if (ctx->rest != 4) {
  2488.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2489.                           "upstream sent rst stream frame "
  2490.                           "with invalid length: %uz",
  2491.                           ctx->rest);
  2492.             return NGX_ERROR;
  2493.         }
  2494.     }

  2495.     for (p = b->pos; p < last; p++) {
  2496.         ch = *p;

  2497. #if 0
  2498.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2499.                        "http proxy rst byte: %02Xd s:%d", ch, state);
  2500. #endif

  2501.         switch (state) {

  2502.         case sw_start:
  2503.             ctx->error = (ngx_uint_t) ch << 24;
  2504.             state = sw_error_2;
  2505.             break;

  2506.         case sw_error_2:
  2507.             ctx->error |= ch << 16;
  2508.             state = sw_error_3;
  2509.             break;

  2510.         case sw_error_3:
  2511.             ctx->error |= ch << 8;
  2512.             state = sw_error_4;
  2513.             break;

  2514.         case sw_error_4:
  2515.             ctx->error |= ch;
  2516.             state = sw_start;

  2517.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2518.                            "http proxy error: %ui", ctx->error);

  2519.             break;
  2520.         }
  2521.     }

  2522.     ctx->rest -= p - b->pos;
  2523.     ctx->frame_state = state;
  2524.     b->pos = p;

  2525.     if (ctx->rest > 0) {
  2526.         return NGX_AGAIN;
  2527.     }

  2528.     ctx->state = ngx_http_proxy_v2_st_start;

  2529.     return NGX_OK;
  2530. }


  2531. static ngx_int_t
  2532. ngx_http_proxy_v2_parse_goaway(ngx_http_request_t *r,
  2533.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2534. {
  2535.     u_char  ch, *p, *last;
  2536.     enum {
  2537.         sw_start = 0,
  2538.         sw_last_stream_id_2,
  2539.         sw_last_stream_id_3,
  2540.         sw_last_stream_id_4,
  2541.         sw_error,
  2542.         sw_error_2,
  2543.         sw_error_3,
  2544.         sw_error_4,
  2545.         sw_debug
  2546.     } state;

  2547.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  2548.         last = b->last;

  2549.     } else {
  2550.         last = b->pos + ctx->rest;
  2551.     }

  2552.     state = ctx->frame_state;

  2553.     if (state == sw_start) {

  2554.         if (ctx->stream_id) {
  2555.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2556.                           "upstream sent goaway frame "
  2557.                           "with non-zero stream id: %ui",
  2558.                           ctx->stream_id);
  2559.             return NGX_ERROR;
  2560.         }

  2561.         if (ctx->rest < 8) {
  2562.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2563.                           "upstream sent goaway frame "
  2564.                           "with invalid length: %uz",
  2565.                           ctx->rest);
  2566.             return NGX_ERROR;
  2567.         }
  2568.     }

  2569.     for (p = b->pos; p < last; p++) {
  2570.         ch = *p;

  2571. #if 0
  2572.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2573.                        "http proxy goaway byte: %02Xd s:%d", ch, state);
  2574. #endif

  2575.         switch (state) {

  2576.         case sw_start:
  2577.             ctx->stream_id = (ch & 0x7f) << 24;
  2578.             state = sw_last_stream_id_2;
  2579.             break;

  2580.         case sw_last_stream_id_2:
  2581.             ctx->stream_id |= ch << 16;
  2582.             state = sw_last_stream_id_3;
  2583.             break;

  2584.         case sw_last_stream_id_3:
  2585.             ctx->stream_id |= ch << 8;
  2586.             state = sw_last_stream_id_4;
  2587.             break;

  2588.         case sw_last_stream_id_4:
  2589.             ctx->stream_id |= ch;
  2590.             state = sw_error;
  2591.             break;

  2592.         case sw_error:
  2593.             ctx->error = (ngx_uint_t) ch << 24;
  2594.             state = sw_error_2;
  2595.             break;

  2596.         case sw_error_2:
  2597.             ctx->error |= ch << 16;
  2598.             state = sw_error_3;
  2599.             break;

  2600.         case sw_error_3:
  2601.             ctx->error |= ch << 8;
  2602.             state = sw_error_4;
  2603.             break;

  2604.         case sw_error_4:
  2605.             ctx->error |= ch;
  2606.             state = sw_debug;
  2607.             break;

  2608.         case sw_debug:
  2609.             break;
  2610.         }
  2611.     }

  2612.     ctx->rest -= p - b->pos;
  2613.     ctx->frame_state = state;
  2614.     b->pos = p;

  2615.     if (ctx->rest > 0) {
  2616.         return NGX_AGAIN;
  2617.     }

  2618.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2619.                    "http proxy goaway: %ui, stream %ui",
  2620.                    ctx->error, ctx->stream_id);

  2621.     ctx->state = ngx_http_proxy_v2_st_start;

  2622.     return NGX_OK;
  2623. }


  2624. static ngx_int_t
  2625. ngx_http_proxy_v2_parse_window_update(ngx_http_request_t *r,
  2626.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2627. {
  2628.     u_char  ch, *p, *last;
  2629.     enum {
  2630.         sw_start = 0,
  2631.         sw_size_2,
  2632.         sw_size_3,
  2633.         sw_size_4
  2634.     } state;

  2635.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  2636.         last = b->last;

  2637.     } else {
  2638.         last = b->pos + ctx->rest;
  2639.     }

  2640.     state = ctx->frame_state;

  2641.     if (state == sw_start) {
  2642.         if (ctx->rest != 4) {
  2643.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2644.                           "upstream sent window update frame "
  2645.                           "with invalid length: %uz",
  2646.                           ctx->rest);
  2647.             return NGX_ERROR;
  2648.         }
  2649.     }

  2650.     for (p = b->pos; p < last; p++) {
  2651.         ch = *p;

  2652. #if 0
  2653.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2654.                        "http proxy window update byte: %02Xd s:%d", ch, state);
  2655. #endif

  2656.         switch (state) {

  2657.         case sw_start:
  2658.             ctx->window_update = (ch & 0x7f) << 24;
  2659.             state = sw_size_2;
  2660.             break;

  2661.         case sw_size_2:
  2662.             ctx->window_update |= ch << 16;
  2663.             state = sw_size_3;
  2664.             break;

  2665.         case sw_size_3:
  2666.             ctx->window_update |= ch << 8;
  2667.             state = sw_size_4;
  2668.             break;

  2669.         case sw_size_4:
  2670.             ctx->window_update |= ch;
  2671.             state = sw_start;
  2672.             break;
  2673.         }
  2674.     }

  2675.     ctx->rest -= p - b->pos;
  2676.     ctx->frame_state = state;
  2677.     b->pos = p;

  2678.     if (ctx->rest > 0) {
  2679.         return NGX_AGAIN;
  2680.     }

  2681.     ctx->state = ngx_http_proxy_v2_st_start;

  2682.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2683.                    "http proxy window update: %ui", ctx->window_update);

  2684.     if (ctx->stream_id) {

  2685.         if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
  2686.                                  - ctx->send_window)
  2687.         {
  2688.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2689.                           "upstream sent too large window update");
  2690.             return NGX_ERROR;
  2691.         }

  2692.         ctx->send_window += ctx->window_update;

  2693.     } else {

  2694.         if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
  2695.                                  - ctx->connection->send_window)
  2696.         {
  2697.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2698.                           "upstream sent too large window update");
  2699.             return NGX_ERROR;
  2700.         }

  2701.         ctx->connection->send_window += ctx->window_update;
  2702.     }

  2703.     return NGX_OK;
  2704. }


  2705. static ngx_int_t
  2706. ngx_http_proxy_v2_parse_settings(ngx_http_request_t *r,
  2707.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2708. {
  2709.     u_char   ch, *p, *last;
  2710.     ssize_t  window_update;
  2711.     enum {
  2712.         sw_start = 0,
  2713.         sw_id,
  2714.         sw_id_2,
  2715.         sw_value,
  2716.         sw_value_2,
  2717.         sw_value_3,
  2718.         sw_value_4
  2719.     } state;

  2720.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  2721.         last = b->last;

  2722.     } else {
  2723.         last = b->pos + ctx->rest;
  2724.     }

  2725.     state = ctx->frame_state;

  2726.     if (state == sw_start) {

  2727.         if (ctx->stream_id) {
  2728.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2729.                           "upstream sent settings frame "
  2730.                           "with non-zero stream id: %ui",
  2731.                           ctx->stream_id);
  2732.             return NGX_ERROR;
  2733.         }

  2734.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  2735.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2736.                            "http proxy settings ack");

  2737.             if (ctx->rest != 0) {
  2738.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2739.                               "upstream sent settings frame "
  2740.                               "with ack flag and non-zero length: %uz",
  2741.                               ctx->rest);
  2742.                 return NGX_ERROR;
  2743.             }

  2744.             ctx->state = ngx_http_proxy_v2_st_start;

  2745.             return NGX_OK;
  2746.         }

  2747.         if (ctx->rest % 6 != 0) {
  2748.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2749.                           "upstream sent settings frame "
  2750.                           "with invalid length: %uz",
  2751.                           ctx->rest);
  2752.             return NGX_ERROR;
  2753.         }

  2754.         if (ctx->free == NULL && ctx->settings++ > 1000) {
  2755.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2756.                           "upstream sent too many settings frames");
  2757.             return NGX_ERROR;
  2758.         }
  2759.     }

  2760.     for (p = b->pos; p < last; p++) {
  2761.         ch = *p;

  2762. #if 0
  2763.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2764.                        "http proxy settings byte: %02Xd s:%d", ch, state);
  2765. #endif

  2766.         switch (state) {

  2767.         case sw_start:
  2768.         case sw_id:
  2769.             ctx->setting_id = ch << 8;
  2770.             state = sw_id_2;
  2771.             break;

  2772.         case sw_id_2:
  2773.             ctx->setting_id |= ch;
  2774.             state = sw_value;
  2775.             break;

  2776.         case sw_value:
  2777.             ctx->setting_value = (ngx_uint_t) ch << 24;
  2778.             state = sw_value_2;
  2779.             break;

  2780.         case sw_value_2:
  2781.             ctx->setting_value |= ch << 16;
  2782.             state = sw_value_3;
  2783.             break;

  2784.         case sw_value_3:
  2785.             ctx->setting_value |= ch << 8;
  2786.             state = sw_value_4;
  2787.             break;

  2788.         case sw_value_4:
  2789.             ctx->setting_value |= ch;
  2790.             state = sw_id;

  2791.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2792.                            "http proxy setting: %ui %ui",
  2793.                            ctx->setting_id, ctx->setting_value);

  2794.             /*
  2795.              * The following settings are defined by the protocol:
  2796.              *
  2797.              * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
  2798.              * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
  2799.              * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
  2800.              *
  2801.              * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
  2802.              * a simple client.
  2803.              */

  2804.             if (ctx->setting_id == 0x04) {
  2805.                 /* SETTINGS_INITIAL_WINDOW_SIZE */

  2806.                 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
  2807.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2808.                                   "upstream sent settings frame "
  2809.                                   "with too large initial window size: %ui",
  2810.                                   ctx->setting_value);
  2811.                     return NGX_ERROR;
  2812.                 }

  2813.                 window_update = ctx->setting_value
  2814.                                 - ctx->connection->init_window;
  2815.                 ctx->connection->init_window = ctx->setting_value;

  2816.                 if (ctx->send_window > 0
  2817.                     && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
  2818.                                        - ctx->send_window)
  2819.                 {
  2820.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2821.                                   "upstream sent settings frame "
  2822.                                   "with too large initial window size: %ui",
  2823.                                   ctx->setting_value);
  2824.                     return NGX_ERROR;
  2825.                 }

  2826.                 ctx->send_window += window_update;
  2827.             }

  2828.             break;
  2829.         }
  2830.     }

  2831.     ctx->rest -= p - b->pos;
  2832.     ctx->frame_state = state;
  2833.     b->pos = p;

  2834.     if (ctx->rest > 0) {
  2835.         return NGX_AGAIN;
  2836.     }

  2837.     ctx->state = ngx_http_proxy_v2_st_start;

  2838.     return ngx_http_proxy_v2_send_settings_ack(r, ctx);
  2839. }


  2840. static ngx_int_t
  2841. ngx_http_proxy_v2_parse_ping(ngx_http_request_t *r,
  2842.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2843. {
  2844.     u_char  ch, *p, *last;
  2845.     enum {
  2846.         sw_start = 0,
  2847.         sw_data_2,
  2848.         sw_data_3,
  2849.         sw_data_4,
  2850.         sw_data_5,
  2851.         sw_data_6,
  2852.         sw_data_7,
  2853.         sw_data_8
  2854.     } state;

  2855.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  2856.         last = b->last;

  2857.     } else {
  2858.         last = b->pos + ctx->rest;
  2859.     }

  2860.     state = ctx->frame_state;

  2861.     if (state == sw_start) {

  2862.         if (ctx->stream_id) {
  2863.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2864.                           "upstream sent ping frame "
  2865.                           "with non-zero stream id: %ui",
  2866.                           ctx->stream_id);
  2867.             return NGX_ERROR;
  2868.         }

  2869.         if (ctx->rest != 8) {
  2870.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2871.                           "upstream sent ping frame "
  2872.                           "with invalid length: %uz",
  2873.                           ctx->rest);
  2874.             return NGX_ERROR;
  2875.         }

  2876.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  2877.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2878.                           "upstream sent ping frame with ack flag");
  2879.             return NGX_ERROR;
  2880.         }

  2881.         if (ctx->free == NULL && ctx->pings++ > 1000) {
  2882.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2883.                           "upstream sent too many ping frames");
  2884.             return NGX_ERROR;
  2885.         }
  2886.     }

  2887.     for (p = b->pos; p < last; p++) {
  2888.         ch = *p;

  2889. #if 0
  2890.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2891.                        "http proxy ping byte: %02Xd s:%d", ch, state);
  2892. #endif

  2893.         if (state < sw_data_8) {
  2894.             ctx->ping_data[state] = ch;
  2895.             state++;

  2896.         } else {
  2897.             ctx->ping_data[7] = ch;
  2898.             state = sw_start;

  2899.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2900.                            "http proxy ping");
  2901.         }
  2902.     }

  2903.     ctx->rest -= p - b->pos;
  2904.     ctx->frame_state = state;
  2905.     b->pos = p;

  2906.     if (ctx->rest > 0) {
  2907.         return NGX_AGAIN;
  2908.     }

  2909.     ctx->state = ngx_http_proxy_v2_st_start;

  2910.     return ngx_http_proxy_v2_send_ping_ack(r, ctx);
  2911. }


  2912. static ngx_int_t
  2913. ngx_http_proxy_v2_send_settings_ack(ngx_http_request_t *r,
  2914.     ngx_http_proxy_v2_ctx_t *ctx)
  2915. {
  2916.     ngx_chain_t                *cl, **ll;
  2917.     ngx_http_proxy_v2_frame_t  *f;

  2918.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2919.                    "http proxy send settings ack");

  2920.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  2921.         ll = &cl->next;
  2922.     }

  2923.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  2924.     if (cl == NULL) {
  2925.         return NGX_ERROR;
  2926.     }

  2927.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  2928.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  2929.     f->length_0 = 0;
  2930.     f->length_1 = 0;
  2931.     f->length_2 = 0;
  2932.     f->type = NGX_HTTP_V2_SETTINGS_FRAME;
  2933.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  2934.     f->stream_id_0 = 0;
  2935.     f->stream_id_1 = 0;
  2936.     f->stream_id_2 = 0;
  2937.     f->stream_id_3 = 0;

  2938.     *ll = cl;

  2939.     return NGX_OK;
  2940. }


  2941. static ngx_int_t
  2942. ngx_http_proxy_v2_send_ping_ack(ngx_http_request_t *r,
  2943.     ngx_http_proxy_v2_ctx_t *ctx)
  2944. {
  2945.     ngx_chain_t                *cl, **ll;
  2946.     ngx_http_proxy_v2_frame_t  *f;

  2947.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2948.                    "http proxy send ping ack");

  2949.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  2950.         ll = &cl->next;
  2951.     }

  2952.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  2953.     if (cl == NULL) {
  2954.         return NGX_ERROR;
  2955.     }

  2956.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  2957.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  2958.     f->length_0 = 0;
  2959.     f->length_1 = 0;
  2960.     f->length_2 = 8;
  2961.     f->type = NGX_HTTP_V2_PING_FRAME;
  2962.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  2963.     f->stream_id_0 = 0;
  2964.     f->stream_id_1 = 0;
  2965.     f->stream_id_2 = 0;
  2966.     f->stream_id_3 = 0;

  2967.     cl->buf->last = ngx_copy(cl->buf->last, ctx->ping_data, 8);

  2968.     *ll = cl;

  2969.     return NGX_OK;
  2970. }


  2971. static ngx_int_t
  2972. ngx_http_proxy_v2_send_window_update(ngx_http_request_t *r,
  2973.     ngx_http_proxy_v2_ctx_t *ctx)
  2974. {
  2975.     size_t                      n;
  2976.     ngx_chain_t                *cl, **ll;
  2977.     ngx_http_proxy_v2_frame_t  *f;

  2978.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2979.                    "http proxy send window update: %uz %uz",
  2980.                    ctx->connection->recv_window, ctx->recv_window);

  2981.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  2982.         ll = &cl->next;
  2983.     }

  2984.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  2985.     if (cl == NULL) {
  2986.         return NGX_ERROR;
  2987.     }

  2988.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  2989.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  2990.     f->length_0 = 0;
  2991.     f->length_1 = 0;
  2992.     f->length_2 = 4;
  2993.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  2994.     f->flags = 0;
  2995.     f->stream_id_0 = 0;
  2996.     f->stream_id_1 = 0;
  2997.     f->stream_id_2 = 0;
  2998.     f->stream_id_3 = 0;

  2999.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
  3000.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3001.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3002.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3003.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3004.     *cl->buf->last++ = (u_char) (n & 0xff);

  3005.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3006.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3007.     f->length_0 = 0;
  3008.     f->length_1 = 0;
  3009.     f->length_2 = 4;
  3010.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3011.     f->flags = 0;
  3012.     f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  3013.     f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  3014.     f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  3015.     f->stream_id_3 = (u_char) (ctx->id & 0xff);

  3016.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
  3017.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3018.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3019.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3020.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3021.     *cl->buf->last++ = (u_char) (n & 0xff);

  3022.     *ll = cl;

  3023.     return NGX_OK;
  3024. }


  3025. static ngx_chain_t *
  3026. ngx_http_proxy_v2_get_buf(ngx_http_request_t *r, ngx_http_proxy_v2_ctx_t *ctx)
  3027. {
  3028.     u_char       *start;
  3029.     ngx_buf_t    *b;
  3030.     ngx_chain_t  *cl;

  3031.     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  3032.     if (cl == NULL) {
  3033.         return NULL;
  3034.     }

  3035.     b = cl->buf;
  3036.     start = b->start;

  3037.     if (start == NULL) {

  3038.         /*
  3039.          * each buffer is large enough to hold two window update
  3040.          * frames in a row
  3041.          */

  3042.         start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8);
  3043.         if (start == NULL) {
  3044.             return NULL;
  3045.         }

  3046.     }

  3047.     ngx_memzero(b, sizeof(ngx_buf_t));

  3048.     b->start = start;
  3049.     b->pos = start;
  3050.     b->last = start;
  3051.     b->end = start + 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8;

  3052.     b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  3053.     b->temporary = 1;
  3054.     b->flush = 1;

  3055.     return cl;
  3056. }


  3057. static ngx_http_proxy_v2_ctx_t *
  3058. ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r)
  3059. {
  3060.     ngx_http_upstream_t      *u;
  3061.     ngx_http_proxy_v2_ctx_t  *ctx;

  3062.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  3063.     if (ctx->connection == NULL) {
  3064.         u = r->upstream;

  3065.         if (ngx_http_proxy_v2_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
  3066.             return NULL;
  3067.         }
  3068.     }

  3069.     return ctx;
  3070. }


  3071. static ngx_int_t
  3072. ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
  3073.     ngx_http_proxy_v2_ctx_t *ctx, ngx_peer_connection_t *pc)
  3074. {
  3075.     ngx_connection_t    *c;
  3076.     ngx_pool_cleanup_t  *cln;

  3077.     c = pc->connection;

  3078.     if (c == NULL) {
  3079.         ctx->connection = ngx_palloc(r->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3080.         if (ctx->connection == NULL) {
  3081.             return NGX_ERROR;
  3082.         }

  3083.         ctx->id = 0;

  3084.         goto done;
  3085.     }

  3086.     if (pc->cached) {

  3087.         /*
  3088.          * for cached connections, connection data can be found
  3089.          * in the cleanup handler
  3090.          */

  3091.         for (cln = c->pool->cleanup; cln; cln = cln->next) {
  3092.             if (cln->handler == ngx_http_proxy_v2_cleanup) {
  3093.                 ctx->connection = cln->data;
  3094.                 break;
  3095.             }
  3096.         }

  3097.         if (ctx->connection == NULL) {
  3098.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  3099.                           "no connection data found for "
  3100.                           "keepalive http2 connection");
  3101.             return NGX_ERROR;
  3102.         }

  3103.         ctx->send_window = ctx->connection->init_window;
  3104.         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3105.         ctx->connection->last_stream_id += 2;
  3106.         ctx->id = ctx->connection->last_stream_id;

  3107.         return NGX_OK;
  3108.     }

  3109.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3110.     if (cln == NULL) {
  3111.         return NGX_ERROR;
  3112.     }

  3113.     cln->handler = ngx_http_proxy_v2_cleanup;
  3114.     ctx->connection = cln->data;

  3115.     ctx->id = 1;

  3116. done:

  3117.     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3118.     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3119.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3120.     ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3121.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3122.     ctx->connection->last_stream_id = 1;

  3123.     return NGX_OK;
  3124. }


  3125. static void
  3126. ngx_http_proxy_v2_cleanup(void *data)
  3127. {
  3128. #if 0
  3129.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  3130.                    "http proxy cleanup");
  3131. #endif
  3132.     return;
  3133. }


  3134. static void
  3135. ngx_http_proxy_v2_abort_request(ngx_http_request_t *r)
  3136. {
  3137.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3138.                    "abort proxy http2 request");
  3139.     return;
  3140. }


  3141. static void
  3142. ngx_http_proxy_v2_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  3143. {
  3144.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3145.                    "finalize proxy http2 request");
  3146.     return;
  3147. }