src/http/modules/ngx_http_proxy_v2_module.c - nginx-1.31.3 nginx/ @ 42f8df65b

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.         if (method.len > NGX_HTTP_V2_MAX_FIELD) {
  298.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  299.                           "too long http2 method: \"%V\"", &method);
  300.             return NGX_ERROR;
  301.         }

  302.         len += 1 + NGX_HTTP_V2_INT_OCTETS + method.len;
  303.         tmp_len = method.len;
  304.     }

  305.     /* :scheme header */

  306.     len += 1;

  307.     /* :path header */

  308.     escape = 0;
  309.     loc_len = 0;
  310.     unparsed_uri = 0;

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

  313.     } else if (ctx->ctx.vars.uri.len == 0 && r->valid_unparsed_uri) {
  314.         unparsed_uri = 1;
  315.         uri_len = r->unparsed_uri.len;

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

  319.         if (r->quoted_uri || r->internal) {
  320.             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  321.                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
  322.         }

  323.         uri_len = ctx->ctx.vars.uri.len + r->uri.len - loc_len + escape
  324.                   + sizeof("?") - 1 + r->args.len;
  325.     }

  326.     if (uri_len == 0) {
  327.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  328.                       "zero length URI to proxy");
  329.         return NGX_ERROR;
  330.     }

  331.     if (uri_len > NGX_HTTP_V2_MAX_FIELD) {
  332.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  333.                       "too long http2 URI");
  334.         return NGX_ERROR;
  335.     }

  336.     len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;

  337.     if (tmp_len < uri_len) {
  338.         tmp_len = uri_len;
  339.     }

  340.     /* :authority header */

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

  342.     if (!plcf->host_set) {
  343.         if (host->len > NGX_HTTP_V2_MAX_FIELD) {
  344.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  345.                           "too long http2 host: \"%V\"", host);
  346.             return NGX_ERROR;
  347.         }

  348.         len += 1 + NGX_HTTP_V2_INT_OCTETS + host->len;

  349.         if (tmp_len < host->len) {
  350.             tmp_len = host->len;
  351.         }
  352.     }

  353.     /* other headers */

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

  355.     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
  356.     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);

  357.     body_len = 0;

  358.     if (plcf->body_lengths) {
  359.         le.ip = plcf->body_lengths->elts;
  360.         le.request = r;
  361.         le.flushed = 1;

  362.         while (*(uintptr_t *) le.ip) {
  363.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  364.             body_len += lcode(&le);
  365.         }

  366.         ctx->ctx.internal_body_length = body_len;

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

  369.     } else {
  370.         ctx->ctx.internal_body_length = r->headers_in.content_length_n;
  371.     }

  372.     le.ip = headers->lengths->elts;
  373.     le.request = r;
  374.     le.flushed = 1;

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

  376.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  377.         key_len = lcode(&le);

  378.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  379.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  380.         }
  381.         le.ip += sizeof(uintptr_t);

  382.         if (val_len == 0) {
  383.             continue;
  384.         }

  385.         if (key_len > NGX_HTTP_V2_MAX_FIELD) {
  386.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  387.                           "too long http2 header name");
  388.             return NGX_ERROR;
  389.         }

  390.         if (val_len > NGX_HTTP_V2_MAX_FIELD) {
  391.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  392.                           "too long http2 header value");
  393.             return NGX_ERROR;
  394.         }

  395.         len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
  396.                  + NGX_HTTP_V2_INT_OCTETS + val_len;

  397.         if (tmp_len < key_len) {
  398.             tmp_len = key_len;
  399.         }

  400.         if (tmp_len < val_len) {
  401.             tmp_len = val_len;
  402.         }
  403.     }

  404.     if (plcf->upstream.pass_request_headers) {
  405.         part = &r->headers_in.headers.part;
  406.         header = part->elts;

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

  408.             if (i >= part->nelts) {
  409.                 if (part->next == NULL) {
  410.                     break;
  411.                 }

  412.                 part = part->next;
  413.                 header = part->elts;
  414.                 i = 0;
  415.             }

  416.             if (ngx_hash_find(&headers->hash, header[i].hash,
  417.                               header[i].lowcase_key, header[i].key.len))
  418.             {
  419.                 continue;
  420.             }

  421.             if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
  422.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  423.                               "too long http2 header name: \"%V\"",
  424.                               &header[i].key);
  425.                 return NGX_ERROR;
  426.             }

  427.             if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
  428.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  429.                               "too long http2 header value: \"%V: %V\"",
  430.                               &header[i].key, &header[i].value);
  431.                 return NGX_ERROR;
  432.             }

  433.             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
  434.                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;

  435.             if (tmp_len < header[i].key.len) {
  436.                 tmp_len = header[i].key.len;
  437.             }

  438.             if (tmp_len < header[i].value.len) {
  439.                 tmp_len = header[i].value.len;
  440.             }
  441.         }
  442.     }

  443.     /* continuation frames */

  444.     len += sizeof(ngx_http_proxy_v2_frame_t)
  445.            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);


  446.     b = ngx_create_temp_buf(r->pool, len);
  447.     if (b == NULL) {
  448.         return NGX_ERROR;
  449.     }

  450.     cl = ngx_alloc_chain_link(r->pool);
  451.     if (cl == NULL) {
  452.         return NGX_ERROR;
  453.     }

  454.     cl->buf = b;
  455.     cl->next = NULL;

  456.     tmp = ngx_palloc(r->pool, tmp_len * 3);
  457.     if (tmp == NULL) {
  458.         return NGX_ERROR;
  459.     }

  460.     key_tmp = tmp + tmp_len;
  461.     val_tmp = tmp + 2 * tmp_len;

  462.     /* connection preface */

  463.     b->last = ngx_copy(b->last, ngx_http_proxy_v2_connection_start,
  464.                        sizeof(ngx_http_proxy_v2_connection_start) - 1);

  465.     /* headers frame */

  466.     headers_frame = b->last;

  467.     f = (ngx_http_proxy_v2_frame_t *) b->last;
  468.     b->last += sizeof(ngx_http_proxy_v2_frame_t);

  469.     f->length_0 = 0;
  470.     f->length_1 = 0;
  471.     f->length_2 = 0;
  472.     f->type = NGX_HTTP_V2_HEADERS_FRAME;
  473.     f->flags = 0;
  474.     f->stream_id_0 = 0;
  475.     f->stream_id_1 = 0;
  476.     f->stream_id_2 = 0;
  477.     f->stream_id_3 = 1;

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

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

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

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

  486.     } else {
  487.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
  488.         b->last = ngx_http_v2_write_value(b->last, method.data,
  489.                                           method.len, tmp);

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

  493. #if (NGX_HTTP_SSL)
  494.     if (u->ssl) {
  495.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);

  496.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  497.                        "http proxy header: \":scheme: https\"");
  498.     } else
  499. #endif
  500.     {
  501.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);

  502.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  503.                        "http proxy header: \":scheme: http\"");
  504.     }

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

  506.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  507.         b->last = ngx_http_v2_write_value(b->last, ctx->ctx.vars.uri.data,
  508.                                           ctx->ctx.vars.uri.len, tmp);

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

  511.     } else if (unparsed_uri) {

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

  514.         } else {
  515.             *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  516.             b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
  517.                                               r->unparsed_uri.len, tmp);
  518.         }

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

  521.     } else {
  522.         p = val_tmp;

  523.         if (r->valid_location) {
  524.             p = ngx_copy(p, ctx->ctx.vars.uri.data, ctx->ctx.vars.uri.len);
  525.         }

  526.         if (escape) {
  527.             ngx_escape_uri(p, r->uri.data + loc_len,
  528.                            r->uri.len - loc_len, NGX_ESCAPE_URI);
  529.             p += r->uri.len - loc_len + escape;

  530.         } else {
  531.             p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
  532.         }

  533.         if (r->args.len > 0) {
  534.             *p++ = '?';
  535.             p = ngx_copy(p, r->args.data, r->args.len);
  536.         }

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

  539.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  540.                        "http proxy header: \":path: %*s\"", p - val_tmp,
  541.                        val_tmp);
  542.     }

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

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

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

  550.     e.ip = headers->values->elts;
  551.     e.request = r;
  552.     e.flushed = 1;

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

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

  555.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  556.         key_len = lcode(&le);

  557.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  558.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  559.         }
  560.         le.ip += sizeof(uintptr_t);

  561.         if (val_len == 0) {
  562.             e.skip = 1;

  563.             while (*(uintptr_t *) e.ip) {
  564.                 code = *(ngx_http_script_code_pt *) e.ip;
  565.                 code((ngx_http_script_engine_t *) &e);
  566.             }
  567.             e.ip += sizeof(uintptr_t);

  568.             e.skip = 0;

  569.             continue;
  570.         }

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

  572.         e.pos = key_tmp;

  573.         code = *(ngx_http_script_code_pt *) e.ip;
  574.         code((ngx_http_script_engine_t *) &e);

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

  576.         e.pos = val_tmp;

  577.         while (*(uintptr_t *) e.ip) {
  578.             code = *(ngx_http_script_code_pt *) e.ip;
  579.             code((ngx_http_script_engine_t *) &e);
  580.         }
  581.         e.ip += sizeof(uintptr_t);

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

  583. #if (NGX_DEBUG)
  584.         if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
  585.             ngx_strlow(key_tmp, key_tmp, key_len);

  586.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  587.                            "http proxy header: \"%*s: %*s\"",
  588.                            key_len, key_tmp, val_len, val_tmp);
  589.         }
  590. #endif
  591.     }

  592.     if (plcf->upstream.pass_request_headers) {
  593.         part = &r->headers_in.headers.part;
  594.         header = part->elts;

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

  596.             if (i >= part->nelts) {
  597.                 if (part->next == NULL) {
  598.                     break;
  599.                 }

  600.                 part = part->next;
  601.                 header = part->elts;
  602.                 i = 0;
  603.             }

  604.             if (ngx_hash_find(&headers->hash, header[i].hash,
  605.                               header[i].lowcase_key, header[i].key.len))
  606.             {
  607.                 continue;
  608.             }

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

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

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

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

  617.                 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  618.                                "http proxy header: \"%*s: %V\"",
  619.                                header[i].key.len, tmp, &header[i].value);
  620.             }
  621. #endif
  622.         }
  623.     }

  624.     /* update headers frame length */

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

  626.     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  627.         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  628.         next = 1;

  629.     } else {
  630.         next = 0;
  631.     }

  632.     f = (ngx_http_proxy_v2_frame_t *) headers_frame;

  633.     f->length_0 = (u_char) ((len >> 16) & 0xff);
  634.     f->length_1 = (u_char) ((len >> 8) & 0xff);
  635.     f->length_2 = (u_char) (len & 0xff);

  636.     /* create additional continuation frames */

  637.     p = headers_frame;

  638.     while (next) {
  639.         p += sizeof(ngx_http_proxy_v2_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  640.         len = b->last - p;

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

  643.         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  644.             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  645.             next = 1;

  646.         } else {
  647.             next = 0;
  648.         }

  649.         f = (ngx_http_proxy_v2_frame_t *) p;

  650.         f->length_0 = (u_char) ((len >> 16) & 0xff);
  651.         f->length_1 = (u_char) ((len >> 8) & 0xff);
  652.         f->length_2 = (u_char) (len & 0xff);
  653.         f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
  654.         f->flags = 0;
  655.         f->stream_id_0 = 0;
  656.         f->stream_id_1 = 0;
  657.         f->stream_id_2 = 0;
  658.         f->stream_id_3 = 1;
  659.     }

  660.     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;

  661.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  662.                    "http proxy header: %*xs%s, len: %uz",
  663.                    (size_t) ngx_min(b->last - b->pos, 256), b->pos,
  664.                    b->last - b->pos > 256 ? "..." : "",
  665.                    b->last - b->pos);

  666.     if (r->request_body_no_buffering) {

  667.         u->request_bufs = cl;

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

  669.         body = u->request_bufs;
  670.         u->request_bufs = cl;

  671.         if (body == NULL) {
  672.             f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  673.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
  674.         }

  675.         while (body) {
  676.             b = ngx_alloc_buf(r->pool);
  677.             if (b == NULL) {
  678.                 return NGX_ERROR;
  679.             }

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

  681.             cl->next = ngx_alloc_chain_link(r->pool);
  682.             if (cl->next == NULL) {
  683.                 return NGX_ERROR;
  684.             }

  685.             cl = cl->next;
  686.             cl->buf = b;

  687.             body = body->next;
  688.         }

  689.         b->last_buf = 1;

  690.     } else if (body_len) {

  691.         u->request_bufs = cl;

  692.         b = ngx_create_temp_buf(r->pool, body_len);
  693.         if (b == NULL) {
  694.             return NGX_ERROR;
  695.         }

  696.         cl->next = ngx_alloc_chain_link(r->pool);
  697.         if (cl->next == NULL) {
  698.             return NGX_ERROR;
  699.         }

  700.         cl = cl->next;
  701.         cl->buf = b;

  702.         e.ip = plcf->body_values->elts;
  703.         e.pos = b->last;
  704.         e.request = r;
  705.         e.flushed = 1;
  706.         e.skip = 0;

  707.         while (*(uintptr_t *) e.ip) {
  708.             code = *(ngx_http_script_code_pt *) e.ip;
  709.             code((ngx_http_script_engine_t *) &e);
  710.         }

  711.         b->last = e.pos;
  712.         b->last_buf = 1;

  713.     } else {
  714.         u->request_bufs = cl;

  715.         f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  716.         f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  717.         b->last_buf = 1;
  718.     }

  719.     u->output.output_filter = ngx_http_proxy_v2_body_output_filter;
  720.     u->output.filter_ctx = r;

  721.     b->flush = 1;
  722.     cl->next = NULL;

  723.     return NGX_OK;
  724. }


  725. static ngx_int_t
  726. ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r)
  727. {
  728.     ngx_http_proxy_v2_ctx_t  *ctx;

  729.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  730.     if (ctx == NULL) {
  731.         return NGX_OK;
  732.     }

  733.     ctx->state = 0;
  734.     ctx->header_sent = 0;
  735.     ctx->output_closed = 0;
  736.     ctx->output_blocked = 0;
  737.     ctx->parsing_headers = 0;
  738.     ctx->end_stream = 0;
  739.     ctx->done = 0;
  740.     ctx->status = 0;
  741.     ctx->rst = 0;
  742.     ctx->goaway = 0;
  743.     ctx->connection = NULL;
  744.     ctx->in = NULL;
  745.     ctx->busy = NULL;
  746.     ctx->out = NULL;

  747.     return NGX_OK;
  748. }


  749. static ngx_int_t
  750. ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in)
  751. {
  752.     ngx_http_request_t  *r = data;

  753.     off_t                       file_pos;
  754.     u_char                     *p, *pos, *start;
  755.     size_t                      len, limit;
  756.     ngx_buf_t                  *b;
  757.     ngx_int_t                  rc;
  758.     ngx_uint_t                 next, last;
  759.     ngx_chain_t                *cl, *out, *ln, **ll;
  760.     ngx_http_upstream_t        *u;
  761.     ngx_http_proxy_v2_ctx_t    *ctx;
  762.     ngx_http_proxy_v2_frame_t  *f;

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

  765.     ctx = ngx_http_proxy_v2_get_ctx(r);

  766.     if (ctx == NULL) {
  767.         return NGX_ERROR;
  768.     }

  769.     if (in) {
  770.         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
  771.             return NGX_ERROR;
  772.         }
  773.     }

  774.     out = NULL;
  775.     ll = &out;

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

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

  780.         ctx->header_sent = 1;

  781.         if (ctx->id != 1) {
  782.             /*
  783.              * keepalive connection: skip connection preface,
  784.              * update stream identifiers
  785.              */

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

  788.             p = b->pos;

  789.             while (p < b->last) {
  790.                 f = (ngx_http_proxy_v2_frame_t *) p;
  791.                 p += sizeof(ngx_http_proxy_v2_frame_t);

  792.                 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  793.                 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  794.                 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  795.                 f->stream_id_3 = (u_char) (ctx->id & 0xff);

  796.                 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
  797.             }
  798.         }

  799.         if (ctx->in->buf->last_buf) {
  800.             ctx->output_closed = 1;
  801.         }

  802.         *ll = ctx->in;
  803.         ll = &ctx->in->next;

  804.         ctx->in = ctx->in->next;
  805.     }

  806.     if (ctx->out) {
  807.         /* queued control frames */

  808.         *ll = ctx->out;

  809.         for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
  810.             ll = &cl->next;
  811.         }

  812.         ctx->out = NULL;
  813.     }

  814.     f = NULL;
  815.     last = 0;

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

  817.     if (limit > ctx->connection->send_window) {
  818.         limit = ctx->connection->send_window;
  819.     }

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

  823. #if (NGX_SUPPRESS_WARN)
  824.     file_pos = 0;
  825.     pos = NULL;
  826.     cl = NULL;
  827. #endif

  828.     in = ctx->in;

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

  830.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  831.                        "http proxy output in  l:%d f:%d %p, pos %p, size: %z "
  832.                        "file: %O, size: %O",
  833.                        in->buf->last_buf,
  834.                        in->buf->in_file,
  835.                        in->buf->start, in->buf->pos,
  836.                        in->buf->last - in->buf->pos,
  837.                        in->buf->file_pos,
  838.                        in->buf->file_last - in->buf->file_pos);

  839.         if (ngx_buf_special(in->buf)) {
  840.             goto next;
  841.         }

  842.         if (in->buf->in_file) {
  843.             file_pos = in->buf->file_pos;

  844.         } else {
  845.             pos = in->buf->pos;
  846.         }

  847.         next = 0;

  848.         do {

  849.             cl = ngx_http_proxy_v2_get_buf(r, ctx);
  850.             if (cl == NULL) {
  851.                 return NGX_ERROR;
  852.             }

  853.             b = cl->buf;

  854.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  855.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

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

  858.             cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  859.             if (cl == NULL) {
  860.                 return NGX_ERROR;
  861.             }

  862.             b = cl->buf;
  863.             start = b->start;

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

  865.             /*
  866.              * restore b->start to preserve memory allocated in the buffer,
  867.              * to reuse it later for headers and control frames
  868.              */

  869.             b->start = start;

  870.             if (in->buf->in_file) {
  871.                 b->file_pos = file_pos;
  872.                 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  873.                 if (file_pos >= in->buf->file_last) {
  874.                     file_pos = in->buf->file_last;
  875.                     next = 1;
  876.                 }

  877.                 b->file_last = file_pos;
  878.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  879.             } else {
  880.                 b->pos = pos;
  881.                 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  882.                 if (pos >= in->buf->last) {
  883.                     pos = in->buf->last;
  884.                     next = 1;
  885.                 }

  886.                 b->last = pos;
  887.                 len = (ngx_uint_t) (pos - b->pos);
  888.             }

  889.             b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  890.             b->shadow = in->buf;
  891.             b->last_shadow = next;

  892.             b->last_buf = 0;
  893.             b->last_in_chain = 0;

  894.             *ll = cl;
  895.             ll = &cl->next;

  896.             f->length_0 = (u_char) ((len >> 16) & 0xff);
  897.             f->length_1 = (u_char) ((len >> 8) & 0xff);
  898.             f->length_2 = (u_char) (len & 0xff);
  899.             f->type = NGX_HTTP_V2_DATA_FRAME;
  900.             f->flags = 0;
  901.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  902.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  903.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  904.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  905.             limit -= len;
  906.             ctx->send_window -= len;
  907.             ctx->connection->send_window -= len;

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

  909.         if (!next) {
  910.             /*
  911.              * if the buffer wasn't fully sent due to flow control limits,
  912.              * preserve position for future use
  913.              */

  914.             if (in->buf->in_file) {
  915.                 in->buf->file_pos = file_pos;

  916.             } else {
  917.                 in->buf->pos = pos;
  918.             }

  919.             break;
  920.         }

  921.     next:

  922.         if (in->buf->last_buf) {
  923.             last = 1;
  924.         }

  925.         ln = in;
  926.         in = in->next;

  927.         ngx_free_chain(r->pool, ln);
  928.     }

  929.     ctx->in = in;

  930.     if (last) {

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

  933.         ctx->output_closed = 1;

  934.         if (f) {
  935.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  936.         } else {
  937.             cl = ngx_http_proxy_v2_get_buf(r, ctx);
  938.             if (cl == NULL) {
  939.                 return NGX_ERROR;
  940.             }

  941.             b = cl->buf;

  942.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  943.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  944.             f->length_0 = 0;
  945.             f->length_1 = 0;
  946.             f->length_2 = 0;
  947.             f->type = NGX_HTTP_V2_DATA_FRAME;
  948.             f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
  949.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  950.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  951.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  952.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  953.             *ll = cl;
  954.             ll = &cl->next;
  955.         }

  956.         cl->buf->last_buf = 1;
  957.     }

  958.     *ll = NULL;

  959. #if (NGX_DEBUG)

  960.     for (cl = out; cl; cl = cl->next) {
  961.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  962.                        "http proxy output out l:%d f:%d %p, pos %p, size: %z "
  963.                        "file: %O, size: %O",
  964.                        cl->buf->last_buf,
  965.                        cl->buf->in_file,
  966.                        cl->buf->start, cl->buf->pos,
  967.                        cl->buf->last - cl->buf->pos,
  968.                        cl->buf->file_pos,
  969.                        cl->buf->file_last - cl->buf->file_pos);
  970.     }

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

  974. #endif

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

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

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

  979.         /* mark original buffers as sent */

  980.         if (cl->buf->shadow) {
  981.             if (cl->buf->last_shadow) {
  982.                 b = cl->buf->shadow;
  983.                 b->pos = b->last;
  984.             }

  985.             cl->buf->shadow = NULL;
  986.         }
  987.     }

  988.     if (rc == NGX_OK && ctx->in) {
  989.         rc = NGX_AGAIN;
  990.     }

  991.     if (rc == NGX_AGAIN) {
  992.         ctx->output_blocked = 1;

  993.     } else {
  994.         ctx->output_blocked = 0;
  995.     }

  996.     if (ctx->done) {

  997.         /*
  998.          * We have already got the response and were sending some additional
  999.          * control frames.  Even if there is still something unsent, stop
  1000.          * here anyway.
  1001.          */

  1002.         u = r->upstream;
  1003.         u->length = 0;
  1004.         u->pipe->length = 0;

  1005.         if (ctx->in == NULL
  1006.             && ctx->out == NULL
  1007.             && ctx->output_closed
  1008.             && !ctx->output_blocked
  1009.             && !ctx->goaway
  1010.             && ctx->state == ngx_http_proxy_v2_st_start)
  1011.         {
  1012.             u->keepalive = 1;
  1013.         }

  1014.         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
  1015.     }

  1016.     return rc;
  1017. }


  1018. static ngx_int_t
  1019. ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
  1020. {
  1021.     u_char                         *pos;
  1022.     ngx_str_t                      *status_line;
  1023.     ngx_int_t                       rc, status;
  1024.     ngx_buf_t                      *b;
  1025.     ngx_table_elt_t                *h;
  1026.     ngx_http_upstream_t            *u;
  1027.     ngx_http_proxy_v2_ctx_t        *ctx;
  1028.     ngx_http_upstream_header_t     *hh;
  1029.     ngx_http_upstream_main_conf_t  *umcf;

  1030.     u = r->upstream;
  1031.     b = &u->buffer;
  1032.     pos = b->pos;

  1033.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1034.                    "http proxy response: %*xs%s, len: %uz",
  1035.                    (size_t) ngx_min(b->last - b->pos, 256),
  1036.                    b->pos, b->last - b->pos > 256 ? "..." : "",
  1037.                    b->last - b->pos);

  1038.     ctx = ngx_http_proxy_v2_get_ctx(r);

  1039.     if (ctx == NULL) {
  1040.         return NGX_ERROR;
  1041.     }

  1042.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1043.     for ( ;; ) {

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

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

  1046.             if (rc == NGX_AGAIN) {

  1047.                 /*
  1048.                  * there can be a lot of window update frames,
  1049.                  * so we reset buffer if it is empty and we haven't
  1050.                  * started parsing headers yet
  1051.                  */

  1052.                 if (!ctx->parsing_headers) {
  1053.                     b->pos = pos;
  1054.                     b->last = b->pos;
  1055.                 }

  1056.                 return NGX_AGAIN;
  1057.             }

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

  1061.             /*
  1062.              * RFC 7540 says that implementations MUST discard frames
  1063.              * that have unknown or unsupported types.  However, extension
  1064.              * frames that appear in the middle of a header block are
  1065.              * not permitted.  Also, for obvious reasons CONTINUATION frames
  1066.              * cannot appear before headers, and DATA frames are not expected
  1067.              * to appear before all headers are parsed.
  1068.              */

  1069.             if (ctx->type == NGX_HTTP_V2_DATA_FRAME
  1070.                 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1071.                     && !ctx->parsing_headers)
  1072.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1073.                     && ctx->parsing_headers))
  1074.             {
  1075.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1076.                               "upstream sent unexpected http2 frame: %d",
  1077.                               ctx->type);
  1078.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1079.             }

  1080.             if (ctx->id && ctx->stream_id && ctx->stream_id != ctx->id) {
  1081.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1082.                               "upstream sent frame for unknown stream %ui",
  1083.                               ctx->stream_id);
  1084.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1085.             }
  1086.         }

  1087.         /* frame payload */

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

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

  1091.                 if (rc == NGX_AGAIN) {
  1092.                     return NGX_AGAIN;
  1093.                 }

  1094.                 if (rc == NGX_ERROR) {
  1095.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1096.                 }

  1097.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1098.                               "upstream rejected request with error %ui",
  1099.                               ctx->error);

  1100.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1101.             }

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

  1103.             if (rc == NGX_AGAIN) {
  1104.                 return NGX_AGAIN;
  1105.             }

  1106.             if (rc == NGX_ERROR) {
  1107.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1108.             }

  1109.             if (rc == NGX_OK) {
  1110.                 continue;
  1111.             }
  1112.         }

  1113.         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
  1114.             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
  1115.         {
  1116.             /* priority, unknown frames */

  1117.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1118.             if (rc == NGX_AGAIN) {
  1119.                 return NGX_AGAIN;
  1120.             }

  1121.             continue;
  1122.         }

  1123.         /* headers */

  1124.         for ( ;; ) {

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

  1126.             if (rc == NGX_AGAIN) {
  1127.                 break;
  1128.             }

  1129.             if (rc == NGX_OK) {

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

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

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

  1135.                     if (ctx->name.len != sizeof(":status") - 1
  1136.                         || ngx_strncmp(ctx->name.data, ":status",
  1137.                                        sizeof(":status") - 1)
  1138.                            != 0)
  1139.                     {
  1140.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1141.                                       "upstream sent invalid header \"%V: %V\"",
  1142.                                       &ctx->name, &ctx->value);
  1143.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1144.                     }

  1145.                     if (ctx->status) {
  1146.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1147.                                       "upstream sent duplicate :status header");
  1148.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1149.                     }

  1150.                     status_line = &ctx->value;

  1151.                     if (status_line->len != 3) {
  1152.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1153.                                       "upstream sent invalid :status \"%V\"",
  1154.                                       status_line);
  1155.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1156.                     }

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

  1158.                     if (status == NGX_ERROR) {
  1159.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1160.                                       "upstream sent invalid :status \"%V\"",
  1161.                                       status_line);
  1162.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1163.                     }

  1164.                     if (status < NGX_HTTP_OK && status != NGX_HTTP_EARLY_HINTS)
  1165.                     {
  1166.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1167.                                       "upstream sent unexpected :status \"%V\"",
  1168.                                       status_line);
  1169.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1170.                     }

  1171.                     u->headers_in.status_n = status;

  1172.                     if (u->state && u->state->status == 0) {
  1173.                         u->state->status = status;
  1174.                     }

  1175.                     ctx->status = 1;

  1176.                     continue;

  1177.                 } else if (!ctx->status) {
  1178.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1179.                                   "upstream sent no :status header");
  1180.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1181.                 }

  1182.                 h = ngx_list_push(&u->headers_in.headers);
  1183.                 if (h == NULL) {
  1184.                     return NGX_ERROR;
  1185.                 }

  1186.                 h->key = ctx->name;
  1187.                 h->value = ctx->value;
  1188.                 h->lowcase_key = h->key.data;
  1189.                 h->hash = ngx_hash_key(h->key.data, h->key.len);

  1190.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1191.                     continue;
  1192.                 }

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

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

  1197.                     if (rc != NGX_OK) {
  1198.                         return rc;
  1199.                     }
  1200.                 }

  1201.                 continue;
  1202.             }

  1203.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1207.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1208.                     if (ctx->end_stream) {
  1209.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1210.                                       "upstream prematurely closed stream");
  1211.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1212.                     }

  1213.                     ctx->status = 0;
  1214.                     return NGX_HTTP_UPSTREAM_EARLY_HINTS;
  1215.                 }

  1216.                 if (ctx->end_stream
  1217.                     && ctx->in == NULL
  1218.                     && ctx->out == NULL
  1219.                     && ctx->output_closed
  1220.                     && !ctx->output_blocked
  1221.                     && !ctx->goaway
  1222.                     && b->last == b->pos)
  1223.                 {
  1224.                     u->keepalive = 1;
  1225.                 }

  1226.                 return NGX_OK;
  1227.             }

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

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

  1231.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1232.         }

  1233.         /* rc == NGX_AGAIN */

  1234.         if (ctx->rest == 0) {
  1235.             ctx->state = ngx_http_proxy_v2_st_start;
  1236.             continue;
  1237.         }

  1238.         return NGX_AGAIN;
  1239.     }
  1240. }


  1241. static ngx_int_t
  1242. ngx_http_proxy_v2_filter_init(void *data)
  1243. {
  1244.     ngx_http_request_t       *r = data;
  1245.     ngx_http_upstream_t      *u;
  1246.     ngx_http_proxy_v2_ctx_t  *ctx;

  1247.     u = r->upstream;
  1248.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

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

  1252.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1253.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1254.         || ctx->ctx.head)
  1255.     {
  1256.         ctx->length = 0;

  1257.     } else {
  1258.         ctx->length = u->headers_in.content_length_n;
  1259.     }

  1260.     if (ctx->end_stream) {

  1261.         if (ctx->length > 0) {
  1262.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1263.                           "upstream prematurely closed stream");
  1264.             return NGX_ERROR;
  1265.         }

  1266.         u->length = 0;
  1267.         u->pipe->length = 0;
  1268.         ctx->done = 1;

  1269.     } else {
  1270.         u->length = 1;
  1271.         u->pipe->length = 1;
  1272.     }

  1273.     return NGX_OK;
  1274. }


  1275. static ngx_int_t
  1276. ngx_http_proxy_v2_non_buffered_filter(void *data, ssize_t bytes)
  1277. {
  1278.     ngx_http_request_t   *r = data;

  1279.     ngx_int_t                 rc;
  1280.     ngx_buf_t                *b, *buf;
  1281.     ngx_chain_t              *cl, **ll;
  1282.     ngx_http_upstream_t      *u;
  1283.     ngx_http_proxy_v2_ctx_t  *ctx;

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

  1286.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1287.     if (ctx == NULL) {
  1288.         return NGX_ERROR;
  1289.     }

  1290.     u = r->upstream;
  1291.     b = &u->buffer;

  1292.     b->pos = b->last;
  1293.     b->last += bytes;

  1294.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1295.         ll = &cl->next;
  1296.     }

  1297.     for ( ;; ) {

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

  1299.         if (rc == NGX_OK) {

  1300.             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1301.             if (cl == NULL) {
  1302.                 return NGX_ERROR;
  1303.             }

  1304.             *ll = cl;
  1305.             ll = &cl->next;

  1306.             buf = cl->buf;

  1307.             buf->flush = 1;
  1308.             buf->memory = 1;

  1309.             buf->pos = b->pos;
  1310.             buf->tag = u->output.tag;

  1311.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1312.                 b->pos += ctx->rest - ctx->padding;
  1313.                 buf->last = b->pos;
  1314.                 ctx->rest = ctx->padding;

  1315.             } else {
  1316.                 ctx->rest -= b->last - b->pos;
  1317.                 b->pos = b->last;
  1318.                 buf->last = b->pos;
  1319.             }

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

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

  1323.                 if (buf->last - buf->pos > ctx->length) {
  1324.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1325.                                   "upstream sent response body larger "
  1326.                                   "than indicated content length");
  1327.                     return NGX_ERROR;
  1328.                 }

  1329.                 ctx->length -= buf->last - buf->pos;
  1330.             }

  1331.             continue;
  1332.         }

  1333.         if (rc == NGX_DONE) {
  1334.             u->length = 0;
  1335.             break;
  1336.         }

  1337.         if (rc == NGX_AGAIN) {
  1338.             return NGX_AGAIN;
  1339.         }

  1340.         /* invalid response */

  1341.         return NGX_ERROR;
  1342.     }

  1343.     return NGX_OK;
  1344. }


  1345. static ngx_int_t
  1346. ngx_http_proxy_v2_body_filter(ngx_event_pipe_t *p, ngx_buf_t *b)
  1347. {
  1348.     ngx_int_t                 rc;
  1349.     ngx_buf_t                *buf, **prev;
  1350.     ngx_chain_t              *cl;
  1351.     ngx_http_request_t       *r;
  1352.     ngx_http_proxy_v2_ctx_t  *ctx;

  1353.     if (b->pos == b->last) {
  1354.         return NGX_OK;
  1355.     }

  1356.     r = p->input_ctx;
  1357.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1358.     if (ctx == NULL) {
  1359.         return NGX_ERROR;
  1360.     }

  1361.     buf = NULL;
  1362.     prev = &b->shadow;

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

  1365.     for ( ;; ) {

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

  1367.         if (rc == NGX_OK) {

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

  1369.             cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1370.             if (cl == NULL) {
  1371.                 return NGX_ERROR;
  1372.             }

  1373.             buf = cl->buf;

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

  1375.             buf->pos = b->pos;
  1376.             buf->start = b->start;
  1377.             buf->end = b->end;
  1378.             buf->tag = p->tag;
  1379.             buf->temporary = 1;
  1380.             buf->recycled = 1;

  1381.             *prev = buf;
  1382.             prev = &buf->shadow;

  1383.             if (p->in) {
  1384.                 *p->last_in = cl;

  1385.             } else {
  1386.                 p->in = cl;
  1387.             }

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

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

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

  1392.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1393.                 b->pos += ctx->rest - ctx->padding;
  1394.                 buf->last = b->pos;
  1395.                 ctx->rest = ctx->padding;

  1396.             } else {
  1397.                 ctx->rest -= b->last - b->pos;
  1398.                 b->pos = b->last;
  1399.                 buf->last = b->pos;
  1400.             }

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

  1402.                 if (buf->last - buf->pos > ctx->length) {
  1403.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1404.                                   "upstream sent response body larger "
  1405.                                   "than indicated content length");
  1406.                     return NGX_ERROR;
  1407.                 }

  1408.                 ctx->length -= buf->last - buf->pos;
  1409.             }

  1410.             continue;
  1411.         }

  1412.         if (rc == NGX_DONE) {
  1413.             p->length = 0;
  1414.             break;
  1415.         }

  1416.         if (rc == NGX_AGAIN) {
  1417.             break;
  1418.         }

  1419.         /* invalid response */

  1420.         return NGX_ERROR;
  1421.     }

  1422.     if (buf) {
  1423.         buf->shadow = b;
  1424.         buf->last_shadow = 1;

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

  1427.         return NGX_OK;
  1428.     }

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

  1430.     if (ngx_event_pipe_add_free_buf(p, b) != NGX_OK) {
  1431.         return NGX_ERROR;
  1432.     }

  1433.     return NGX_OK;
  1434. }


  1435. static ngx_int_t
  1436. ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
  1437.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1438. {
  1439.     ngx_int_t             rc;
  1440.     ngx_http_upstream_t  *u;

  1441.     u = r->upstream;

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

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

  1444.         if (rc == NGX_AGAIN) {
  1445.             return NGX_AGAIN;
  1446.         }

  1447.         if (rc == NGX_ERROR) {
  1448.             return NGX_ERROR;
  1449.         }

  1450.         /*
  1451.          * If stream_id is lower than one we use, our
  1452.          * request won't be processed and needs to be retried.
  1453.          * If stream_id is greater or equal to the one we use,
  1454.          * we can continue normally (except we can't use this
  1455.          * connection for additional requests).  If there is
  1456.          * a real error, the connection will be closed.
  1457.          */

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

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

  1460.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1461.                           "upstream sent goaway with error %ui",
  1462.                           ctx->error);

  1463.             return NGX_ERROR;
  1464.         }

  1465.         ctx->goaway = 1;

  1466.         return NGX_OK;
  1467.     }

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

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

  1470.         if (rc == NGX_AGAIN) {
  1471.             return NGX_AGAIN;
  1472.         }

  1473.         if (rc == NGX_ERROR) {
  1474.             return NGX_ERROR;
  1475.         }

  1476.         if (ctx->in) {
  1477.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1478.         }

  1479.         return NGX_OK;
  1480.     }

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

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

  1483.         if (rc == NGX_AGAIN) {
  1484.             return NGX_AGAIN;
  1485.         }

  1486.         if (rc == NGX_ERROR) {
  1487.             return NGX_ERROR;
  1488.         }

  1489.         if (ctx->in) {
  1490.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1491.         }

  1492.         return NGX_OK;
  1493.     }

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

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

  1496.         if (rc == NGX_AGAIN) {
  1497.             return NGX_AGAIN;
  1498.         }

  1499.         if (rc == NGX_ERROR) {
  1500.             return NGX_ERROR;
  1501.         }

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

  1503.         return NGX_OK;
  1504.     }

  1505.     if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
  1506.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1507.                       "upstream sent unexpected push promise frame");
  1508.         return NGX_ERROR;
  1509.     }

  1510.     return NGX_DECLINED;
  1511. }


  1512. static ngx_int_t
  1513. ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1514. {
  1515.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  1516.         ctx->rest -= b->last - b->pos;
  1517.         b->pos = b->last;
  1518.         return NGX_AGAIN;
  1519.     }

  1520.     b->pos += ctx->rest;
  1521.     ctx->rest = 0;
  1522.     ctx->state = ngx_http_proxy_v2_st_start;

  1523.     return NGX_OK;
  1524. }


  1525. static ngx_int_t
  1526. ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
  1527.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1528. {
  1529.     ngx_int_t             rc;
  1530.     ngx_table_elt_t      *h;
  1531.     ngx_http_upstream_t  *u;

  1532.     u = r->upstream;

  1533.     for ( ;; ) {

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

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

  1536.             if (rc == NGX_AGAIN) {

  1537.                 if (ctx->done) {

  1538.                     if (ctx->length > 0) {
  1539.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1540.                                       "upstream prematurely closed stream");
  1541.                         return NGX_ERROR;
  1542.                     }

  1543.                     /*
  1544.                      * We have finished parsing the response and the
  1545.                      * remaining control frames.  If there are unsent
  1546.                      * control frames, post a write event to send them.
  1547.                      */

  1548.                     if (ctx->out) {
  1549.                         ngx_post_event(u->peer.connection->write,
  1550.                                        &ngx_posted_events);
  1551.                         return NGX_AGAIN;
  1552.                     }

  1553.                     if (ctx->in == NULL
  1554.                         && ctx->output_closed
  1555.                         && !ctx->output_blocked
  1556.                         && !ctx->goaway
  1557.                         && ctx->state == ngx_http_proxy_v2_st_start)
  1558.                     {
  1559.                         u->keepalive = 1;
  1560.                     }

  1561.                     return NGX_DONE;
  1562.                 }

  1563.                 return NGX_AGAIN;
  1564.             }

  1565.             if (rc == NGX_ERROR) {
  1566.                 return NGX_ERROR;
  1567.             }

  1568.             if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1569.                  && !ctx->parsing_headers)
  1570.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1571.                     && ctx->parsing_headers))
  1572.             {
  1573.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1574.                               "upstream sent unexpected http2 frame: %d",
  1575.                               ctx->type);
  1576.                 return NGX_ERROR;
  1577.             }

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

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

  1586.                 if (ctx->rest > ctx->recv_window) {
  1587.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1588.                                   "upstream violated stream flow control, "
  1589.                                   "received %uz data frame with window %uz",
  1590.                                   ctx->rest, ctx->recv_window);
  1591.                     return NGX_ERROR;
  1592.                 }

  1593.                 if (ctx->rest > ctx->connection->recv_window) {
  1594.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1595.                                   "upstream violated connection flow control, "
  1596.                                   "received %uz data frame with window %uz",
  1597.                                   ctx->rest, ctx->connection->recv_window);
  1598.                     return NGX_ERROR;
  1599.                 }

  1600.                 ctx->recv_window -= ctx->rest;
  1601.                 ctx->connection->recv_window -= ctx->rest;

  1602.                 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
  1603.                     || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
  1604.                 {
  1605.                     if (ngx_http_proxy_v2_send_window_update(r, ctx)
  1606.                         != NGX_OK)
  1607.                     {
  1608.                         return NGX_ERROR;
  1609.                     }

  1610.                     ngx_post_event(u->peer.connection->write,
  1611.                                    &ngx_posted_events);
  1612.                 }
  1613.             }

  1614.             if (ctx->stream_id && ctx->stream_id != ctx->id) {
  1615.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1616.                               "upstream sent frame for unknown stream %ui",
  1617.                               ctx->stream_id);
  1618.                 return NGX_ERROR;
  1619.             }

  1620.             if (ctx->stream_id && ctx->done
  1621.                 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
  1622.                 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
  1623.             {
  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->padding = 0;
  1630.         }

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

  1632.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1633.                 ctx->rest -= b->last - b->pos;
  1634.                 b->pos = b->last;
  1635.                 return NGX_AGAIN;
  1636.             }

  1637.             b->pos += ctx->rest;
  1638.             ctx->rest = 0;
  1639.             ctx->state = ngx_http_proxy_v2_st_start;

  1640.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1641.                 ctx->done = 1;
  1642.             }

  1643.             continue;
  1644.         }

  1645.         /* frame payload */

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

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

  1648.             if (rc == NGX_AGAIN) {
  1649.                 return NGX_AGAIN;
  1650.             }

  1651.             if (rc == NGX_ERROR) {
  1652.                 return NGX_ERROR;
  1653.             }

  1654.             if (ctx->error || !ctx->done) {
  1655.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1656.                               "upstream rejected request with error %ui",
  1657.                               ctx->error);
  1658.                 return NGX_ERROR;
  1659.             }

  1660.             if (ctx->rst) {
  1661.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1662.                               "upstream sent frame for closed stream %ui",
  1663.                               ctx->stream_id);
  1664.                 return NGX_ERROR;
  1665.             }

  1666.             ctx->rst = 1;

  1667.             continue;
  1668.         }

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

  1670.         if (rc == NGX_AGAIN) {
  1671.             return NGX_AGAIN;
  1672.         }

  1673.         if (rc == NGX_ERROR) {
  1674.             return NGX_ERROR;
  1675.         }

  1676.         if (rc == NGX_OK) {
  1677.             continue;
  1678.         }

  1679.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
  1680.             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
  1681.         {
  1682.             for ( ;; ) {

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

  1684.                 if (rc == NGX_AGAIN) {
  1685.                     break;
  1686.                 }

  1687.                 if (rc == NGX_OK) {

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

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

  1692.                     if (ctx->name.len && ctx->name.data[0] == ':') {
  1693.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1694.                                       "upstream sent invalid "
  1695.                                       "trailer \"%V: %V\"",
  1696.                                       &ctx->name, &ctx->value);
  1697.                         return NGX_ERROR;
  1698.                     }

  1699.                     h = ngx_list_push(&u->headers_in.trailers);
  1700.                     if (h == NULL) {
  1701.                         return NGX_ERROR;
  1702.                     }

  1703.                     h->key = ctx->name;
  1704.                     h->value = ctx->value;
  1705.                     h->lowcase_key = h->key.data;
  1706.                     h->hash = ngx_hash_key(h->key.data, h->key.len);

  1707.                     continue;
  1708.                 }

  1709.                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1713.                     if (ctx->end_stream) {
  1714.                         ctx->done = 1;
  1715.                         break;
  1716.                     }

  1717.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1718.                                   "upstream sent trailer without "
  1719.                                   "end stream flag");
  1720.                     return NGX_ERROR;
  1721.                 }

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

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

  1725.                 return NGX_ERROR;
  1726.             }

  1727.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1728.                 continue;
  1729.             }

  1730.             /* rc == NGX_AGAIN */

  1731.             if (ctx->rest == 0) {
  1732.                 ctx->state = ngx_http_proxy_v2_st_start;
  1733.                 continue;
  1734.             }

  1735.             return NGX_AGAIN;
  1736.         }

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

  1738.             /* priority, unknown frames */

  1739.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1740.             if (rc == NGX_AGAIN) {
  1741.                 return NGX_AGAIN;
  1742.             }

  1743.             continue;
  1744.         }

  1745.         /*
  1746.          * data frame:
  1747.          *
  1748.          * +---------------+
  1749.          * |Pad Length? (8)|
  1750.          * +---------------+-----------------------------------------------+
  1751.          * |                            Data (*)                         ...
  1752.          * +---------------------------------------------------------------+
  1753.          * |                           Padding (*)                       ...
  1754.          * +---------------------------------------------------------------+
  1755.          */

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

  1757.             if (ctx->rest == 0) {
  1758.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1759.                               "upstream sent too short http2 frame");
  1760.                 return NGX_ERROR;
  1761.             }

  1762.             if (b->pos == b->last) {
  1763.                 return NGX_AGAIN;
  1764.             }

  1765.             ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
  1766.             ctx->padding = *b->pos++;
  1767.             ctx->rest -= 1;

  1768.             if (ctx->padding > ctx->rest) {
  1769.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1770.                               "upstream sent http2 frame with too long "
  1771.                               "padding: %d in frame %uz",
  1772.                               ctx->padding, ctx->rest);
  1773.                 return NGX_ERROR;
  1774.             }

  1775.             continue;
  1776.         }

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

  1778.             if (ctx->padding) {
  1779.                 ctx->state = ngx_http_proxy_v2_st_padding;

  1780.             } else {
  1781.                 ctx->state = ngx_http_proxy_v2_st_start;

  1782.                 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1783.                     ctx->done = 1;
  1784.                 }
  1785.             }

  1786.             continue;
  1787.         }

  1788.         if (b->pos == b->last) {
  1789.             return NGX_AGAIN;
  1790.         }

  1791.         return NGX_OK;
  1792.     }
  1793. }


  1794. static ngx_int_t
  1795. ngx_http_proxy_v2_parse_frame(ngx_http_request_t *r,
  1796.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1797. {
  1798.     u_char                     ch, *p;
  1799.     ngx_http_proxy_v2_state_e  state;

  1800.     state = ctx->state;

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

  1803. #if 0
  1804.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1805.                        "http proxy frame byte: %02Xd, s:%d", ch, state);
  1806. #endif

  1807.         switch (state) {

  1808.         case ngx_http_proxy_v2_st_start:
  1809.             ctx->rest = ch << 16;
  1810.             state = ngx_http_proxy_v2_st_length_2;
  1811.             break;

  1812.         case ngx_http_proxy_v2_st_length_2:
  1813.             ctx->rest |= ch << 8;
  1814.             state = ngx_http_proxy_v2_st_length_3;
  1815.             break;

  1816.         case ngx_http_proxy_v2_st_length_3:
  1817.             ctx->rest |= ch;

  1818.             if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  1819.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1820.                               "upstream sent too large http2 frame: %uz",
  1821.                               ctx->rest);
  1822.                 return NGX_ERROR;
  1823.             }

  1824.             state = ngx_http_proxy_v2_st_type;
  1825.             break;

  1826.         case ngx_http_proxy_v2_st_type:
  1827.             ctx->type = ch;
  1828.             state = ngx_http_proxy_v2_st_flags;
  1829.             break;

  1830.         case ngx_http_proxy_v2_st_flags:
  1831.             ctx->flags = ch;
  1832.             state = ngx_http_proxy_v2_st_stream_id;
  1833.             break;

  1834.         case ngx_http_proxy_v2_st_stream_id:
  1835.             ctx->stream_id = (ch & 0x7f) << 24;
  1836.             state = ngx_http_proxy_v2_st_stream_id_2;
  1837.             break;

  1838.         case ngx_http_proxy_v2_st_stream_id_2:
  1839.             ctx->stream_id |= ch << 16;
  1840.             state = ngx_http_proxy_v2_st_stream_id_3;
  1841.             break;

  1842.         case ngx_http_proxy_v2_st_stream_id_3:
  1843.             ctx->stream_id |= ch << 8;
  1844.             state = ngx_http_proxy_v2_st_stream_id_4;
  1845.             break;

  1846.         case ngx_http_proxy_v2_st_stream_id_4:
  1847.             ctx->stream_id |= ch;

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

  1851.             b->pos = p + 1;

  1852.             ctx->state = ngx_http_proxy_v2_st_payload;
  1853.             ctx->frame_state = 0;

  1854.             return NGX_OK;

  1855.         /* suppress warning */
  1856.         case ngx_http_proxy_v2_st_payload:
  1857.         case ngx_http_proxy_v2_st_padding:
  1858.             break;
  1859.         }
  1860.     }

  1861.     b->pos = p;
  1862.     ctx->state = state;

  1863.     return NGX_AGAIN;
  1864. }


  1865. static ngx_int_t
  1866. ngx_http_proxy_v2_parse_header(ngx_http_request_t *r,
  1867.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1868. {
  1869.     u_char     ch, *p, *last;
  1870.     size_t     min;
  1871.     ngx_int_t  rc;
  1872.     enum {
  1873.         sw_start = 0,
  1874.         sw_padding_length,
  1875.         sw_dependency,
  1876.         sw_dependency_2,
  1877.         sw_dependency_3,
  1878.         sw_dependency_4,
  1879.         sw_weight,
  1880.         sw_fragment,
  1881.         sw_padding
  1882.     } state;

  1883.     state = ctx->frame_state;

  1884.     if (state == sw_start) {

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

  1887.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
  1888.             ctx->parsing_headers = 1;
  1889.             ctx->fragment_state = 0;

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

  1892.             if (ctx->rest < min) {
  1893.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1894.                               "upstream sent headers frame "
  1895.                               "with invalid length: %uz",
  1896.                               ctx->rest);
  1897.                 return NGX_ERROR;
  1898.             }

  1899.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1900.                 ctx->end_stream = 1;
  1901.             }

  1902.             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
  1903.                 state = sw_padding_length;

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

  1906.             } else {
  1907.                 state = sw_fragment;
  1908.             }

  1909.         } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
  1910.             state = sw_fragment;
  1911.         }

  1912.         ctx->padding = 0;
  1913.         ctx->frame_state = state;
  1914.     }

  1915.     if (state < sw_fragment) {

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

  1918.         } else {
  1919.             last = b->pos + ctx->rest;
  1920.         }

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

  1923. #if 0
  1924.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1925.                            "http proxy header byte: %02Xd s:%d", ch, state);
  1926. #endif

  1927.             /*
  1928.              * headers frame:
  1929.              *
  1930.              * +---------------+
  1931.              * |Pad Length? (8)|
  1932.              * +-+-------------+----------------------------------------------+
  1933.              * |E|                 Stream Dependency? (31)                    |
  1934.              * +-+-------------+----------------------------------------------+
  1935.              * |  Weight? (8)  |
  1936.              * +-+-------------+----------------------------------------------+
  1937.              * |                   Header Block Fragment (*)                ...
  1938.              * +--------------------------------------------------------------+
  1939.              * |                           Padding (*)                      ...
  1940.              * +--------------------------------------------------------------+
  1941.              */

  1942.             switch (state) {

  1943.             case sw_padding_length:

  1944.                 ctx->padding = ch;

  1945.                 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
  1946.                     state = sw_dependency;
  1947.                     break;
  1948.                 }

  1949.                 goto fragment;

  1950.             case sw_dependency:
  1951.                 state = sw_dependency_2;
  1952.                 break;

  1953.             case sw_dependency_2:
  1954.                 state = sw_dependency_3;
  1955.                 break;

  1956.             case sw_dependency_3:
  1957.                 state = sw_dependency_4;
  1958.                 break;

  1959.             case sw_dependency_4:
  1960.                 state = sw_weight;
  1961.                 break;

  1962.             case sw_weight:
  1963.                 goto fragment;

  1964.             /* suppress warning */
  1965.             case sw_start:
  1966.             case sw_fragment:
  1967.             case sw_padding:
  1968.                 break;
  1969.             }
  1970.         }

  1971.         ctx->rest -= p - b->pos;
  1972.         b->pos = p;

  1973.         ctx->frame_state = state;
  1974.         return NGX_AGAIN;

  1975.     fragment:

  1976.         p++;
  1977.         ctx->rest -= p - b->pos;
  1978.         b->pos = p;

  1979.         if (ctx->padding > ctx->rest) {
  1980.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1981.                           "upstream sent http2 frame with too long "
  1982.                           "padding: %d in frame %uz",
  1983.                           ctx->padding, ctx->rest);
  1984.             return NGX_ERROR;
  1985.         }

  1986.         state = sw_fragment;
  1987.         ctx->frame_state = state;
  1988.     }

  1989.     if (state == sw_fragment) {

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

  1991.         if (rc == NGX_AGAIN) {
  1992.             return NGX_AGAIN;
  1993.         }

  1994.         if (rc == NGX_ERROR) {
  1995.             return NGX_ERROR;
  1996.         }

  1997.         if (rc == NGX_OK) {
  1998.             return NGX_OK;
  1999.         }

  2000.         /* rc == NGX_DONE */

  2001.         state = sw_padding;
  2002.         ctx->frame_state = state;
  2003.     }

  2004.     if (state == sw_padding) {

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

  2006.             ctx->rest -= b->last - b->pos;
  2007.             b->pos = b->last;

  2008.             return NGX_AGAIN;
  2009.         }

  2010.         b->pos += ctx->rest;
  2011.         ctx->rest = 0;

  2012.         ctx->state = ngx_http_proxy_v2_st_start;

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

  2014.             if (ctx->fragment_state) {
  2015.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2016.                               "upstream sent truncated http2 header");
  2017.                 return NGX_ERROR;
  2018.             }

  2019.             ctx->parsing_headers = 0;

  2020.             return NGX_HTTP_PARSE_HEADER_DONE;
  2021.         }

  2022.         return NGX_AGAIN;
  2023.     }

  2024.     /* unreachable */

  2025.     return NGX_ERROR;
  2026. }


  2027. static ngx_int_t
  2028. ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
  2029.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2030. {
  2031.     u_char      ch, *p, *last;
  2032.     size_t      size;
  2033.     ngx_uint_t  index, size_update;
  2034.     enum {
  2035.         sw_start = 0,
  2036.         sw_index,
  2037.         sw_name_length,
  2038.         sw_name_length_2,
  2039.         sw_name_length_3,
  2040.         sw_name_length_4,
  2041.         sw_name,
  2042.         sw_name_bytes,
  2043.         sw_value_length,
  2044.         sw_value_length_2,
  2045.         sw_value_length_3,
  2046.         sw_value_length_4,
  2047.         sw_value,
  2048.         sw_value_bytes
  2049.     } state;

  2050.     /* header block fragment */

  2051. #if 0
  2052.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2053.                    "http proxy header fragment %p:%p rest:%uz",
  2054.                    b->pos, b->last, ctx->rest);
  2055. #endif

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

  2058.     } else {
  2059.         last = b->pos + ctx->rest - ctx->padding;
  2060.     }

  2061.     state = ctx->fragment_state;

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

  2064. #if 0
  2065.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2066.                        "http proxy header byte: %02Xd s:%d", ch, state);
  2067. #endif

  2068.         switch (state) {

  2069.         case sw_start:
  2070.             ctx->index = 0;

  2071.             if ((ch & 0x80) == 0x80) {
  2072.                 /*
  2073.                  * indexed header:
  2074.                  *
  2075.                  *   0   1   2   3   4   5   6   7
  2076.                  * +---+---+---+---+---+---+---+---+
  2077.                  * | 1 |        Index (7+)         |
  2078.                  * +---+---------------------------+
  2079.                  */

  2080.                 index = ch & ~0x80;

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

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

  2089.                 ctx->index = index;
  2090.                 ctx->literal = 0;

  2091.                 goto done;

  2092.             } else if ((ch & 0xc0) == 0x40) {
  2093.                 /*
  2094.                  * literal header with incremental indexing:
  2095.                  *
  2096.                  *   0   1   2   3   4   5   6   7
  2097.                  * +---+---+---+---+---+---+---+---+
  2098.                  * | 0 | 1 |      Index (6+)       |
  2099.                  * +---+---+-----------------------+
  2100.                  * | H |     Value Length (7+)     |
  2101.                  * +---+---------------------------+
  2102.                  * | Value String (Length octets)  |
  2103.                  * +-------------------------------+
  2104.                  *
  2105.                  *   0   1   2   3   4   5   6   7
  2106.                  * +---+---+---+---+---+---+---+---+
  2107.                  * | 0 | 1 |           0           |
  2108.                  * +---+---+-----------------------+
  2109.                  * | H |     Name Length (7+)      |
  2110.                  * +---+---------------------------+
  2111.                  * |  Name String (Length octets)  |
  2112.                  * +---+---------------------------+
  2113.                  * | H |     Value Length (7+)     |
  2114.                  * +---+---------------------------+
  2115.                  * | Value String (Length octets)  |
  2116.                  * +-------------------------------+
  2117.                  */

  2118.                 index = ch & ~0xc0;

  2119.                 if (index > 61) {
  2120.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2121.                                   "upstream sent invalid http2 "
  2122.                                   "table index: %ui", index);
  2123.                     return NGX_ERROR;
  2124.                 }

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

  2127.                 if (index == 0) {
  2128.                     state = sw_name_length;
  2129.                     break;
  2130.                 }

  2131.                 ctx->index = index;
  2132.                 ctx->literal = 1;

  2133.                 state = sw_value_length;
  2134.                 break;

  2135.             } else if ((ch & 0xe0) == 0x20) {
  2136.                 /*
  2137.                  * dynamic table size update:
  2138.                  *
  2139.                  *   0   1   2   3   4   5   6   7
  2140.                  * +---+---+---+---+---+---+---+---+
  2141.                  * | 0 | 0 | 1 |   Max size (5+)   |
  2142.                  * +---+---------------------------+
  2143.                  */

  2144.                 size_update = ch & ~0xe0;

  2145.                 if (size_update > 0) {
  2146.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2147.                                   "upstream sent invalid http2 "
  2148.                                   "dynamic table size update: %ui",
  2149.                                   size_update);
  2150.                     return NGX_ERROR;
  2151.                 }

  2152.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2153.                                "http proxy table size update: %ui",
  2154.                                size_update);

  2155.                 break;

  2156.             } else if ((ch & 0xf0) == 0x10) {
  2157.                 /*
  2158.                  *  literal header field never indexed:
  2159.                  *
  2160.                  *   0   1   2   3   4   5   6   7
  2161.                  * +---+---+---+---+---+---+---+---+
  2162.                  * | 0 | 0 | 0 | 1 |  Index (4+)   |
  2163.                  * +---+---+-----------------------+
  2164.                  * | H |     Value Length (7+)     |
  2165.                  * +---+---------------------------+
  2166.                  * | Value String (Length octets)  |
  2167.                  * +-------------------------------+
  2168.                  *
  2169.                  *   0   1   2   3   4   5   6   7
  2170.                  * +---+---+---+---+---+---+---+---+
  2171.                  * | 0 | 0 | 0 | 1 |       0       |
  2172.                  * +---+---+-----------------------+
  2173.                  * | H |     Name Length (7+)      |
  2174.                  * +---+---------------------------+
  2175.                  * |  Name String (Length octets)  |
  2176.                  * +---+---------------------------+
  2177.                  * | H |     Value Length (7+)     |
  2178.                  * +---+---------------------------+
  2179.                  * | Value String (Length octets)  |
  2180.                  * +-------------------------------+
  2181.                  */

  2182.                 index = ch & ~0xf0;

  2183.                 if (index == 0x0f) {
  2184.                     ctx->index = index;
  2185.                     ctx->literal = 1;
  2186.                     state = sw_index;
  2187.                     break;
  2188.                 }

  2189.                 if (index == 0) {
  2190.                     state = sw_name_length;
  2191.                     break;
  2192.                 }

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

  2196.                 ctx->index = index;
  2197.                 ctx->literal = 1;

  2198.                 state = sw_value_length;
  2199.                 break;

  2200.             } else if ((ch & 0xf0) == 0x00) {
  2201.                 /*
  2202.                  * literal header field without indexing:
  2203.                  *
  2204.                  *   0   1   2   3   4   5   6   7
  2205.                  * +---+---+---+---+---+---+---+---+
  2206.                  * | 0 | 0 | 0 | 0 |  Index (4+)   |
  2207.                  * +---+---+-----------------------+
  2208.                  * | H |     Value Length (7+)     |
  2209.                  * +---+---------------------------+
  2210.                  * | Value String (Length octets)  |
  2211.                  * +-------------------------------+
  2212.                  *
  2213.                  *   0   1   2   3   4   5   6   7
  2214.                  * +---+---+---+---+---+---+---+---+
  2215.                  * | 0 | 0 | 0 | 0 |       0       |
  2216.                  * +---+---+-----------------------+
  2217.                  * | H |     Name Length (7+)      |
  2218.                  * +---+---------------------------+
  2219.                  * |  Name String (Length octets)  |
  2220.                  * +---+---------------------------+
  2221.                  * | H |     Value Length (7+)     |
  2222.                  * +---+---------------------------+
  2223.                  * | Value String (Length octets)  |
  2224.                  * +-------------------------------+
  2225.                  */

  2226.                 index = ch & ~0xf0;

  2227.                 if (index == 0x0f) {
  2228.                     ctx->index = index;
  2229.                     ctx->literal = 1;
  2230.                     state = sw_index;
  2231.                     break;
  2232.                 }

  2233.                 if (index == 0) {
  2234.                     state = sw_name_length;
  2235.                     break;
  2236.                 }

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

  2240.                 ctx->index = index;
  2241.                 ctx->literal = 1;

  2242.                 state = sw_value_length;
  2243.                 break;
  2244.             }

  2245.             /* not reached */

  2246.             return NGX_ERROR;

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

  2249.             if (ch & 0x80) {
  2250.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2251.                               "upstream sent http2 table index "
  2252.                               "with continuation flag");
  2253.                 return NGX_ERROR;
  2254.             }

  2255.             if (ctx->index > 61) {
  2256.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2257.                               "upstream sent invalid http2 "
  2258.                               "table index: %ui", ctx->index);
  2259.                 return NGX_ERROR;
  2260.             }

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

  2263.             state = sw_value_length;
  2264.             break;

  2265.         case sw_name_length:
  2266.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2267.             ctx->field_length = ch & ~0x80;

  2268.             if (ctx->field_length == 0x7f) {
  2269.                 state = sw_name_length_2;
  2270.                 break;
  2271.             }

  2272.             if (ctx->field_length == 0) {
  2273.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2274.                               "upstream sent zero http2 "
  2275.                               "header name length");
  2276.                 return NGX_ERROR;
  2277.             }

  2278.             state = sw_name;
  2279.             break;

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

  2282.             if (ch & 0x80) {
  2283.                 state = sw_name_length_3;
  2284.                 break;
  2285.             }

  2286.             state = sw_name;
  2287.             break;

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

  2290.             if (ch & 0x80) {
  2291.                 state = sw_name_length_4;
  2292.                 break;
  2293.             }

  2294.             state = sw_name;
  2295.             break;

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

  2298.             if (ch & 0x80) {
  2299.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2300.                               "upstream sent too large http2 "
  2301.                               "header name length");
  2302.                 return NGX_ERROR;
  2303.             }

  2304.             state = sw_name;
  2305.             break;

  2306.         case sw_name:
  2307.             ctx->name.len = ctx->field_huffman ?
  2308.                             ctx->field_length * 8 / 5 : ctx->field_length;

  2309.             ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
  2310.             if (ctx->name.data == NULL) {
  2311.                 return NGX_ERROR;
  2312.             }

  2313.             ctx->field_end = ctx->name.data;
  2314.             ctx->field_rest = ctx->field_length;
  2315.             ctx->field_state = 0;

  2316.             state = sw_name_bytes;

  2317.             /* fall through */

  2318.         case sw_name_bytes:

  2319.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2320.                            "http proxy name: len:%uz h:%d last:%uz, rest:%uz",
  2321.                            ctx->field_length,
  2322.                            ctx->field_huffman,
  2323.                            last - p,
  2324.                            ctx->rest - (p - b->pos));

  2325.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2326.             ctx->field_rest -= size;

  2327.             if (ctx->field_huffman) {
  2328.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2329.                                          &ctx->field_end,
  2330.                                          ctx->field_rest == 0,
  2331.                                          r->connection->log)
  2332.                     != NGX_OK)
  2333.                 {
  2334.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2335.                                   "upstream sent invalid encoded header");
  2336.                     return NGX_ERROR;
  2337.                 }

  2338.                 ctx->name.len = ctx->field_end - ctx->name.data;
  2339.                 ctx->name.data[ctx->name.len] = '\0';

  2340.             } else {
  2341.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2342.                 ctx->name.data[ctx->name.len] = '\0';
  2343.             }

  2344.             p += size - 1;

  2345.             if (ctx->field_rest == 0) {
  2346.                 state = sw_value_length;
  2347.             }

  2348.             break;

  2349.         case sw_value_length:
  2350.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2351.             ctx->field_length = ch & ~0x80;

  2352.             if (ctx->field_length == 0x7f) {
  2353.                 state = sw_value_length_2;
  2354.                 break;
  2355.             }

  2356.             if (ctx->field_length == 0) {
  2357.                 ngx_str_set(&ctx->value, "");
  2358.                 goto done;
  2359.             }

  2360.             state = sw_value;
  2361.             break;

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

  2364.             if (ch & 0x80) {
  2365.                 state = sw_value_length_3;
  2366.                 break;
  2367.             }

  2368.             state = sw_value;
  2369.             break;

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

  2372.             if (ch & 0x80) {
  2373.                 state = sw_value_length_4;
  2374.                 break;
  2375.             }

  2376.             state = sw_value;
  2377.             break;

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

  2380.             if (ch & 0x80) {
  2381.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2382.                               "upstream sent too large http2 "
  2383.                               "header value length");
  2384.                 return NGX_ERROR;
  2385.             }

  2386.             state = sw_value;
  2387.             break;

  2388.         case sw_value:
  2389.             ctx->value.len = ctx->field_huffman ?
  2390.                              ctx->field_length * 8 / 5 : ctx->field_length;

  2391.             ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
  2392.             if (ctx->value.data == NULL) {
  2393.                 return NGX_ERROR;
  2394.             }

  2395.             ctx->field_end = ctx->value.data;
  2396.             ctx->field_rest = ctx->field_length;
  2397.             ctx->field_state = 0;

  2398.             state = sw_value_bytes;

  2399.             /* fall through */

  2400.         case sw_value_bytes:

  2401.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2402.                            "http proxy value: len:%uz h:%d last:%uz, rest:%uz",
  2403.                            ctx->field_length,
  2404.                            ctx->field_huffman,
  2405.                            last - p,
  2406.                            ctx->rest - (p - b->pos));

  2407.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2408.             ctx->field_rest -= size;

  2409.             if (ctx->field_huffman) {
  2410.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2411.                                          &ctx->field_end,
  2412.                                          ctx->field_rest == 0,
  2413.                                          r->connection->log)
  2414.                     != NGX_OK)
  2415.                 {
  2416.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2417.                                   "upstream sent invalid encoded header");
  2418.                     return NGX_ERROR;
  2419.                 }

  2420.                 ctx->value.len = ctx->field_end - ctx->value.data;
  2421.                 ctx->value.data[ctx->value.len] = '\0';

  2422.             } else {
  2423.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2424.                 ctx->value.data[ctx->value.len] = '\0';
  2425.             }

  2426.             p += size - 1;

  2427.             if (ctx->field_rest == 0) {
  2428.                 goto done;
  2429.             }

  2430.             break;
  2431.         }

  2432.         continue;

  2433.     done:

  2434.         p++;
  2435.         ctx->rest -= p - b->pos;
  2436.         ctx->fragment_state = sw_start;
  2437.         b->pos = p;

  2438.         if (ctx->index) {
  2439.             ctx->name = *ngx_http_v2_get_static_name(ctx->index);
  2440.         }

  2441.         if (ctx->index && !ctx->literal) {
  2442.             ctx->value = *ngx_http_v2_get_static_value(ctx->index);
  2443.         }

  2444.         if (!ctx->index) {
  2445.             if (ngx_http_proxy_v2_validate_header_name(r, &ctx->name)
  2446.                 != NGX_OK)
  2447.             {
  2448.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2449.                               "upstream sent invalid header: \"%V: %V\"",
  2450.                               &ctx->name, &ctx->value);
  2451.                 return NGX_ERROR;
  2452.             }
  2453.         }

  2454.         if (!ctx->index || ctx->literal) {
  2455.             if (ngx_http_proxy_v2_validate_header_value(r, &ctx->value)
  2456.                 != NGX_OK)
  2457.             {
  2458.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2459.                               "upstream sent invalid header: \"%V: %V\"",
  2460.                               &ctx->name, &ctx->value);
  2461.                 return NGX_ERROR;
  2462.             }
  2463.         }

  2464.         return NGX_OK;
  2465.     }

  2466.     ctx->rest -= p - b->pos;
  2467.     ctx->fragment_state = state;
  2468.     b->pos = p;

  2469.     if (ctx->rest > ctx->padding) {
  2470.         return NGX_AGAIN;
  2471.     }

  2472.     return NGX_DONE;
  2473. }


  2474. static ngx_int_t
  2475. ngx_http_proxy_v2_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
  2476. {
  2477.     u_char      ch;
  2478.     ngx_uint_t  i;

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

  2481.         if (ch == ':' && i > 0) {
  2482.             return NGX_ERROR;
  2483.         }

  2484.         if (ch >= 'A' && ch <= 'Z') {
  2485.             return NGX_ERROR;
  2486.         }

  2487.         if (ch <= 0x20 || ch == 0x7f) {
  2488.             return NGX_ERROR;
  2489.         }
  2490.     }

  2491.     return NGX_OK;
  2492. }


  2493. static ngx_int_t
  2494. ngx_http_proxy_v2_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
  2495. {
  2496.     u_char      ch;
  2497.     ngx_uint_t  i;

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

  2500.         if (ch == '\0' || ch == CR || ch == LF) {
  2501.             return NGX_ERROR;
  2502.         }
  2503.     }

  2504.     return NGX_OK;
  2505. }


  2506. static ngx_int_t
  2507. ngx_http_proxy_v2_parse_rst_stream(ngx_http_request_t *r,
  2508.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2509. {
  2510.     u_char  ch, *p, *last;
  2511.     enum {
  2512.         sw_start = 0,
  2513.         sw_error_2,
  2514.         sw_error_3,
  2515.         sw_error_4
  2516.     } state;

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

  2519.     } else {
  2520.         last = b->pos + ctx->rest;
  2521.     }

  2522.     state = ctx->frame_state;

  2523.     if (state == sw_start) {
  2524.         if (ctx->rest != 4) {
  2525.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2526.                           "upstream sent rst stream frame "
  2527.                           "with invalid length: %uz",
  2528.                           ctx->rest);
  2529.             return NGX_ERROR;
  2530.         }
  2531.     }

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

  2534. #if 0
  2535.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2536.                        "http proxy rst byte: %02Xd s:%d", ch, state);
  2537. #endif

  2538.         switch (state) {

  2539.         case sw_start:
  2540.             ctx->error = (ngx_uint_t) ch << 24;
  2541.             state = sw_error_2;
  2542.             break;

  2543.         case sw_error_2:
  2544.             ctx->error |= ch << 16;
  2545.             state = sw_error_3;
  2546.             break;

  2547.         case sw_error_3:
  2548.             ctx->error |= ch << 8;
  2549.             state = sw_error_4;
  2550.             break;

  2551.         case sw_error_4:
  2552.             ctx->error |= ch;
  2553.             state = sw_start;

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

  2556.             break;
  2557.         }
  2558.     }

  2559.     ctx->rest -= p - b->pos;
  2560.     ctx->frame_state = state;
  2561.     b->pos = p;

  2562.     if (ctx->rest > 0) {
  2563.         return NGX_AGAIN;
  2564.     }

  2565.     ctx->state = ngx_http_proxy_v2_st_start;

  2566.     return NGX_OK;
  2567. }


  2568. static ngx_int_t
  2569. ngx_http_proxy_v2_parse_goaway(ngx_http_request_t *r,
  2570.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2571. {
  2572.     u_char  ch, *p, *last;
  2573.     enum {
  2574.         sw_start = 0,
  2575.         sw_last_stream_id_2,
  2576.         sw_last_stream_id_3,
  2577.         sw_last_stream_id_4,
  2578.         sw_error,
  2579.         sw_error_2,
  2580.         sw_error_3,
  2581.         sw_error_4,
  2582.         sw_debug
  2583.     } state;

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

  2586.     } else {
  2587.         last = b->pos + ctx->rest;
  2588.     }

  2589.     state = ctx->frame_state;

  2590.     if (state == sw_start) {

  2591.         if (ctx->stream_id) {
  2592.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2593.                           "upstream sent goaway frame "
  2594.                           "with non-zero stream id: %ui",
  2595.                           ctx->stream_id);
  2596.             return NGX_ERROR;
  2597.         }

  2598.         if (ctx->rest < 8) {
  2599.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2600.                           "upstream sent goaway frame "
  2601.                           "with invalid length: %uz",
  2602.                           ctx->rest);
  2603.             return NGX_ERROR;
  2604.         }
  2605.     }

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

  2608. #if 0
  2609.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2610.                        "http proxy goaway byte: %02Xd s:%d", ch, state);
  2611. #endif

  2612.         switch (state) {

  2613.         case sw_start:
  2614.             ctx->stream_id = (ch & 0x7f) << 24;
  2615.             state = sw_last_stream_id_2;
  2616.             break;

  2617.         case sw_last_stream_id_2:
  2618.             ctx->stream_id |= ch << 16;
  2619.             state = sw_last_stream_id_3;
  2620.             break;

  2621.         case sw_last_stream_id_3:
  2622.             ctx->stream_id |= ch << 8;
  2623.             state = sw_last_stream_id_4;
  2624.             break;

  2625.         case sw_last_stream_id_4:
  2626.             ctx->stream_id |= ch;
  2627.             state = sw_error;
  2628.             break;

  2629.         case sw_error:
  2630.             ctx->error = (ngx_uint_t) ch << 24;
  2631.             state = sw_error_2;
  2632.             break;

  2633.         case sw_error_2:
  2634.             ctx->error |= ch << 16;
  2635.             state = sw_error_3;
  2636.             break;

  2637.         case sw_error_3:
  2638.             ctx->error |= ch << 8;
  2639.             state = sw_error_4;
  2640.             break;

  2641.         case sw_error_4:
  2642.             ctx->error |= ch;
  2643.             state = sw_debug;
  2644.             break;

  2645.         case sw_debug:
  2646.             break;
  2647.         }
  2648.     }

  2649.     ctx->rest -= p - b->pos;
  2650.     ctx->frame_state = state;
  2651.     b->pos = p;

  2652.     if (ctx->rest > 0) {
  2653.         return NGX_AGAIN;
  2654.     }

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

  2658.     ctx->state = ngx_http_proxy_v2_st_start;

  2659.     return NGX_OK;
  2660. }


  2661. static ngx_int_t
  2662. ngx_http_proxy_v2_parse_window_update(ngx_http_request_t *r,
  2663.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2664. {
  2665.     u_char  ch, *p, *last;
  2666.     enum {
  2667.         sw_start = 0,
  2668.         sw_size_2,
  2669.         sw_size_3,
  2670.         sw_size_4
  2671.     } state;

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

  2674.     } else {
  2675.         last = b->pos + ctx->rest;
  2676.     }

  2677.     state = ctx->frame_state;

  2678.     if (state == sw_start) {
  2679.         if (ctx->rest != 4) {
  2680.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2681.                           "upstream sent window update frame "
  2682.                           "with invalid length: %uz",
  2683.                           ctx->rest);
  2684.             return NGX_ERROR;
  2685.         }
  2686.     }

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

  2689. #if 0
  2690.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2691.                        "http proxy window update byte: %02Xd s:%d", ch, state);
  2692. #endif

  2693.         switch (state) {

  2694.         case sw_start:
  2695.             ctx->window_update = (ch & 0x7f) << 24;
  2696.             state = sw_size_2;
  2697.             break;

  2698.         case sw_size_2:
  2699.             ctx->window_update |= ch << 16;
  2700.             state = sw_size_3;
  2701.             break;

  2702.         case sw_size_3:
  2703.             ctx->window_update |= ch << 8;
  2704.             state = sw_size_4;
  2705.             break;

  2706.         case sw_size_4:
  2707.             ctx->window_update |= ch;
  2708.             state = sw_start;
  2709.             break;
  2710.         }
  2711.     }

  2712.     ctx->rest -= p - b->pos;
  2713.     ctx->frame_state = state;
  2714.     b->pos = p;

  2715.     if (ctx->rest > 0) {
  2716.         return NGX_AGAIN;
  2717.     }

  2718.     ctx->state = ngx_http_proxy_v2_st_start;

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

  2721.     if (ctx->stream_id) {

  2722.         if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
  2723.                                  - ctx->send_window)
  2724.         {
  2725.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2726.                           "upstream sent too large window update");
  2727.             return NGX_ERROR;
  2728.         }

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

  2730.     } else {

  2731.         if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
  2732.                                  - ctx->connection->send_window)
  2733.         {
  2734.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2735.                           "upstream sent too large window update");
  2736.             return NGX_ERROR;
  2737.         }

  2738.         ctx->connection->send_window += ctx->window_update;
  2739.     }

  2740.     return NGX_OK;
  2741. }


  2742. static ngx_int_t
  2743. ngx_http_proxy_v2_parse_settings(ngx_http_request_t *r,
  2744.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2745. {
  2746.     u_char   ch, *p, *last;
  2747.     ssize_t  window_update;
  2748.     enum {
  2749.         sw_start = 0,
  2750.         sw_id,
  2751.         sw_id_2,
  2752.         sw_value,
  2753.         sw_value_2,
  2754.         sw_value_3,
  2755.         sw_value_4
  2756.     } state;

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

  2759.     } else {
  2760.         last = b->pos + ctx->rest;
  2761.     }

  2762.     state = ctx->frame_state;

  2763.     if (state == sw_start) {

  2764.         if (ctx->stream_id) {
  2765.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2766.                           "upstream sent settings frame "
  2767.                           "with non-zero stream id: %ui",
  2768.                           ctx->stream_id);
  2769.             return NGX_ERROR;
  2770.         }

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

  2774.             if (ctx->rest != 0) {
  2775.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2776.                               "upstream sent settings frame "
  2777.                               "with ack flag and non-zero length: %uz",
  2778.                               ctx->rest);
  2779.                 return NGX_ERROR;
  2780.             }

  2781.             ctx->state = ngx_http_proxy_v2_st_start;

  2782.             return NGX_OK;
  2783.         }

  2784.         if (ctx->rest % 6 != 0) {
  2785.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2786.                           "upstream sent settings frame "
  2787.                           "with invalid length: %uz",
  2788.                           ctx->rest);
  2789.             return NGX_ERROR;
  2790.         }

  2791.         if (ctx->free == NULL && ctx->settings++ > 1000) {
  2792.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2793.                           "upstream sent too many settings frames");
  2794.             return NGX_ERROR;
  2795.         }
  2796.     }

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

  2799. #if 0
  2800.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2801.                        "http proxy settings byte: %02Xd s:%d", ch, state);
  2802. #endif

  2803.         switch (state) {

  2804.         case sw_start:
  2805.         case sw_id:
  2806.             ctx->setting_id = ch << 8;
  2807.             state = sw_id_2;
  2808.             break;

  2809.         case sw_id_2:
  2810.             ctx->setting_id |= ch;
  2811.             state = sw_value;
  2812.             break;

  2813.         case sw_value:
  2814.             ctx->setting_value = (ngx_uint_t) ch << 24;
  2815.             state = sw_value_2;
  2816.             break;

  2817.         case sw_value_2:
  2818.             ctx->setting_value |= ch << 16;
  2819.             state = sw_value_3;
  2820.             break;

  2821.         case sw_value_3:
  2822.             ctx->setting_value |= ch << 8;
  2823.             state = sw_value_4;
  2824.             break;

  2825.         case sw_value_4:
  2826.             ctx->setting_value |= ch;
  2827.             state = sw_id;

  2828.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2829.                            "http proxy setting: %ui %ui",
  2830.                            ctx->setting_id, ctx->setting_value);

  2831.             /*
  2832.              * The following settings are defined by the protocol:
  2833.              *
  2834.              * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
  2835.              * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
  2836.              * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
  2837.              *
  2838.              * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
  2839.              * a simple client.
  2840.              */

  2841.             if (ctx->setting_id == 0x04) {
  2842.                 /* SETTINGS_INITIAL_WINDOW_SIZE */

  2843.                 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
  2844.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2845.                                   "upstream sent settings frame "
  2846.                                   "with too large initial window size: %ui",
  2847.                                   ctx->setting_value);
  2848.                     return NGX_ERROR;
  2849.                 }

  2850.                 window_update = ctx->setting_value
  2851.                                 - ctx->connection->init_window;
  2852.                 ctx->connection->init_window = ctx->setting_value;

  2853.                 if (ctx->send_window > 0
  2854.                     && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
  2855.                                        - ctx->send_window)
  2856.                 {
  2857.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2858.                                   "upstream sent settings frame "
  2859.                                   "with too large initial window size: %ui",
  2860.                                   ctx->setting_value);
  2861.                     return NGX_ERROR;
  2862.                 }

  2863.                 ctx->send_window += window_update;
  2864.             }

  2865.             break;
  2866.         }
  2867.     }

  2868.     ctx->rest -= p - b->pos;
  2869.     ctx->frame_state = state;
  2870.     b->pos = p;

  2871.     if (ctx->rest > 0) {
  2872.         return NGX_AGAIN;
  2873.     }

  2874.     ctx->state = ngx_http_proxy_v2_st_start;

  2875.     return ngx_http_proxy_v2_send_settings_ack(r, ctx);
  2876. }


  2877. static ngx_int_t
  2878. ngx_http_proxy_v2_parse_ping(ngx_http_request_t *r,
  2879.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2880. {
  2881.     u_char  ch, *p, *last;
  2882.     enum {
  2883.         sw_start = 0,
  2884.         sw_data_2,
  2885.         sw_data_3,
  2886.         sw_data_4,
  2887.         sw_data_5,
  2888.         sw_data_6,
  2889.         sw_data_7,
  2890.         sw_data_8
  2891.     } state;

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

  2894.     } else {
  2895.         last = b->pos + ctx->rest;
  2896.     }

  2897.     state = ctx->frame_state;

  2898.     if (state == sw_start) {

  2899.         if (ctx->stream_id) {
  2900.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2901.                           "upstream sent ping frame "
  2902.                           "with non-zero stream id: %ui",
  2903.                           ctx->stream_id);
  2904.             return NGX_ERROR;
  2905.         }

  2906.         if (ctx->rest != 8) {
  2907.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2908.                           "upstream sent ping frame "
  2909.                           "with invalid length: %uz",
  2910.                           ctx->rest);
  2911.             return NGX_ERROR;
  2912.         }

  2913.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  2914.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2915.                           "upstream sent ping frame with ack flag");
  2916.             return NGX_ERROR;
  2917.         }

  2918.         if (ctx->free == NULL && ctx->pings++ > 1000) {
  2919.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2920.                           "upstream sent too many ping frames");
  2921.             return NGX_ERROR;
  2922.         }
  2923.     }

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

  2926. #if 0
  2927.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2928.                        "http proxy ping byte: %02Xd s:%d", ch, state);
  2929. #endif

  2930.         if (state < sw_data_8) {
  2931.             ctx->ping_data[state] = ch;
  2932.             state++;

  2933.         } else {
  2934.             ctx->ping_data[7] = ch;
  2935.             state = sw_start;

  2936.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2937.                            "http proxy ping");
  2938.         }
  2939.     }

  2940.     ctx->rest -= p - b->pos;
  2941.     ctx->frame_state = state;
  2942.     b->pos = p;

  2943.     if (ctx->rest > 0) {
  2944.         return NGX_AGAIN;
  2945.     }

  2946.     ctx->state = ngx_http_proxy_v2_st_start;

  2947.     return ngx_http_proxy_v2_send_ping_ack(r, ctx);
  2948. }


  2949. static ngx_int_t
  2950. ngx_http_proxy_v2_send_settings_ack(ngx_http_request_t *r,
  2951.     ngx_http_proxy_v2_ctx_t *ctx)
  2952. {
  2953.     ngx_chain_t                *cl, **ll;
  2954.     ngx_http_proxy_v2_frame_t  *f;

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

  2957.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  2958.         ll = &cl->next;
  2959.     }

  2960.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  2961.     if (cl == NULL) {
  2962.         return NGX_ERROR;
  2963.     }

  2964.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  2965.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  2966.     f->length_0 = 0;
  2967.     f->length_1 = 0;
  2968.     f->length_2 = 0;
  2969.     f->type = NGX_HTTP_V2_SETTINGS_FRAME;
  2970.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  2971.     f->stream_id_0 = 0;
  2972.     f->stream_id_1 = 0;
  2973.     f->stream_id_2 = 0;
  2974.     f->stream_id_3 = 0;

  2975.     *ll = cl;

  2976.     return NGX_OK;
  2977. }


  2978. static ngx_int_t
  2979. ngx_http_proxy_v2_send_ping_ack(ngx_http_request_t *r,
  2980.     ngx_http_proxy_v2_ctx_t *ctx)
  2981. {
  2982.     ngx_chain_t                *cl, **ll;
  2983.     ngx_http_proxy_v2_frame_t  *f;

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

  2986.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  2987.         ll = &cl->next;
  2988.     }

  2989.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  2990.     if (cl == NULL) {
  2991.         return NGX_ERROR;
  2992.     }

  2993.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  2994.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  2995.     f->length_0 = 0;
  2996.     f->length_1 = 0;
  2997.     f->length_2 = 8;
  2998.     f->type = NGX_HTTP_V2_PING_FRAME;
  2999.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  3000.     f->stream_id_0 = 0;
  3001.     f->stream_id_1 = 0;
  3002.     f->stream_id_2 = 0;
  3003.     f->stream_id_3 = 0;

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

  3005.     *ll = cl;

  3006.     return NGX_OK;
  3007. }


  3008. static ngx_int_t
  3009. ngx_http_proxy_v2_send_window_update(ngx_http_request_t *r,
  3010.     ngx_http_proxy_v2_ctx_t *ctx)
  3011. {
  3012.     size_t                      n;
  3013.     ngx_chain_t                *cl, **ll;
  3014.     ngx_http_proxy_v2_frame_t  *f;

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

  3018.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3019.         ll = &cl->next;
  3020.     }

  3021.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  3022.     if (cl == NULL) {
  3023.         return NGX_ERROR;
  3024.     }

  3025.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3026.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3027.     f->length_0 = 0;
  3028.     f->length_1 = 0;
  3029.     f->length_2 = 4;
  3030.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3031.     f->flags = 0;
  3032.     f->stream_id_0 = 0;
  3033.     f->stream_id_1 = 0;
  3034.     f->stream_id_2 = 0;
  3035.     f->stream_id_3 = 0;

  3036.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
  3037.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3038.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3039.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3040.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3041.     *cl->buf->last++ = (u_char) (n & 0xff);

  3042.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3043.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3044.     f->length_0 = 0;
  3045.     f->length_1 = 0;
  3046.     f->length_2 = 4;
  3047.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3048.     f->flags = 0;
  3049.     f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  3050.     f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  3051.     f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  3052.     f->stream_id_3 = (u_char) (ctx->id & 0xff);

  3053.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
  3054.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3055.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3056.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3057.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3058.     *cl->buf->last++ = (u_char) (n & 0xff);

  3059.     *ll = cl;

  3060.     return NGX_OK;
  3061. }


  3062. static ngx_chain_t *
  3063. ngx_http_proxy_v2_get_buf(ngx_http_request_t *r, ngx_http_proxy_v2_ctx_t *ctx)
  3064. {
  3065.     u_char       *start;
  3066.     ngx_buf_t    *b;
  3067.     ngx_chain_t  *cl;

  3068.     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  3069.     if (cl == NULL) {
  3070.         return NULL;
  3071.     }

  3072.     b = cl->buf;
  3073.     start = b->start;

  3074.     if (start == NULL) {

  3075.         /*
  3076.          * each buffer is large enough to hold two window update
  3077.          * frames in a row
  3078.          */

  3079.         start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8);
  3080.         if (start == NULL) {
  3081.             return NULL;
  3082.         }

  3083.     }

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

  3085.     b->start = start;
  3086.     b->pos = start;
  3087.     b->last = start;
  3088.     b->end = start + 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8;

  3089.     b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  3090.     b->temporary = 1;
  3091.     b->flush = 1;

  3092.     return cl;
  3093. }


  3094. static ngx_http_proxy_v2_ctx_t *
  3095. ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r)
  3096. {
  3097.     ngx_http_upstream_t      *u;
  3098.     ngx_http_proxy_v2_ctx_t  *ctx;

  3099.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  3100.     if (ctx->connection == NULL) {
  3101.         u = r->upstream;

  3102.         if (ngx_http_proxy_v2_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
  3103.             return NULL;
  3104.         }
  3105.     }

  3106.     return ctx;
  3107. }


  3108. static ngx_int_t
  3109. ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
  3110.     ngx_http_proxy_v2_ctx_t *ctx, ngx_peer_connection_t *pc)
  3111. {
  3112.     ngx_connection_t    *c;
  3113.     ngx_pool_cleanup_t  *cln;

  3114.     c = pc->connection;

  3115.     if (c == NULL) {
  3116.         ctx->connection = ngx_palloc(r->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3117.         if (ctx->connection == NULL) {
  3118.             return NGX_ERROR;
  3119.         }

  3120.         ctx->id = 0;

  3121.         goto done;
  3122.     }

  3123.     if (pc->cached) {

  3124.         /*
  3125.          * for cached connections, connection data can be found
  3126.          * in the cleanup handler
  3127.          */

  3128.         for (cln = c->pool->cleanup; cln; cln = cln->next) {
  3129.             if (cln->handler == ngx_http_proxy_v2_cleanup) {
  3130.                 ctx->connection = cln->data;
  3131.                 break;
  3132.             }
  3133.         }

  3134.         if (ctx->connection == NULL) {
  3135.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  3136.                           "no connection data found for "
  3137.                           "keepalive http2 connection");
  3138.             return NGX_ERROR;
  3139.         }

  3140.         ctx->send_window = ctx->connection->init_window;
  3141.         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3142.         ctx->connection->last_stream_id += 2;
  3143.         ctx->id = ctx->connection->last_stream_id;

  3144.         return NGX_OK;
  3145.     }

  3146.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3147.     if (cln == NULL) {
  3148.         return NGX_ERROR;
  3149.     }

  3150.     cln->handler = ngx_http_proxy_v2_cleanup;
  3151.     ctx->connection = cln->data;

  3152.     ctx->id = 1;

  3153. done:

  3154.     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3155.     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3156.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3157.     ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3158.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

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

  3160.     return NGX_OK;
  3161. }


  3162. static void
  3163. ngx_http_proxy_v2_cleanup(void *data)
  3164. {
  3165. #if 0
  3166.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  3167.                    "http proxy cleanup");
  3168. #endif
  3169.     return;
  3170. }


  3171. static void
  3172. ngx_http_proxy_v2_abort_request(ngx_http_request_t *r)
  3173. {
  3174.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3175.                    "abort proxy http2 request");
  3176.     return;
  3177. }


  3178. static void
  3179. ngx_http_proxy_v2_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  3180. {
  3181.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3182.                    "finalize proxy http2 request");
  3183.     return;
  3184. }