src/http/modules/ngx_http_proxy_v2_module.c - nginx-1.31.9 nginx/ @ 2a3a19c6f

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                         header_limit;
  59.     size_t                         field_length;
  60.     size_t                         field_rest;
  61.     u_char                         field_state;

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

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


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


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

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

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

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

  135. static void ngx_http_proxy_v2_abort_request(ngx_http_request_t *r);
  136. static void ngx_http_proxy_v2_finalize_request(ngx_http_request_t *r,
  137.     ngx_int_t rc);


  138. ‌static ngx_http_module_t  ngx_http_proxy_v2_module_ctx = {
  139.     NULL,                                  /* preconfiguration */
  140.     NULL,                                  /* postconfiguration */

  141.     NULL,                                  /* create main configuration */
  142.     NULL,                                  /* init main configuration */

  143.     NULL,                                  /* create server configuration */
  144.     NULL,                                  /* merge server configuration */

  145.     NULL,                                  /* create location configuration */
  146.     NULL                                   /* merge location configuration */
  147. };


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


  162. ‌static u_char  ngx_http_proxy_v2_connection_start[] =
  163.     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"         /* connection preface */

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

  168.     "\x00\x00\x04\x08\x00\x00\x00\x00\x00"     /* window update frame */
  169.     "\x7f\xff\x00\x00";


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

  180.     if (ngx_http_upstream_create(r) != NGX_OK) {
  181.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  182.     }

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

  187.     ngx_http_set_ctx(r, ctx, ngx_http_proxy_v2_module);

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

  189.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  190.     plcf->upstream.preserve_output = 1;

  191.     u = r->upstream;

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

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

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

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

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

  208. #if (NGX_HTTP_CACHE)
  209.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);

  210.     u->caches = &pmcf->caches;
  211.     u->create_key = ngx_http_proxy_create_key;
  212. #endif

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

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

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

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

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

  229.     u->pipe->input_filter = ngx_http_proxy_v2_body_filter;
  230.     u->pipe->input_ctx = r;

  231.     u->input_filter_init = ngx_http_proxy_v2_filter_init;
  232.     u->input_filter = ngx_http_proxy_v2_non_buffered_filter;
  233.     u->input_filter_ctx = r;

  234.     u->accel = 1;

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

  240.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  241.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  242.         return rc;
  243.     }

  244.     return NGX_DONE;
  245. }


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

  269.     u = r->upstream;

  270.     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);

  271. #if (NGX_HTTP_CACHE)
  272.     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
  273. #else
  274.     headers = &plcf->headers;
  275. #endif

  276.     if (u->method.len) {
  277.         /* HEAD was changed to GET to cache response */
  278.         method = u->method;

  279.     } else if (plcf->method) {
  280.         if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
  281.             return NGX_ERROR;
  282.         }

  283.     } else {
  284.         method = r->method_name;
  285.     }

  286.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  287.     if (method.len == 4
  288.         && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
  289.     {
  290.         ctx->ctx.head = 1;
  291.     }

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

  294.     headers_len = 0;

  295.     /* :method header */

  296.     if ((method.len == 3 && ngx_strncmp(method.data, "GET", 3) == 0)
  297.         || (method.len == 4 && ngx_strncmp(method.data, "POST", 4) == 0))
  298.     {
  299.         len += 1;
  300.         tmp_len = 0;

  301.     } else {
  302.         if (method.len > NGX_HTTP_V2_MAX_FIELD) {
  303.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  304.                           "too long http2 method: \"%V\"", &method);
  305.             return NGX_ERROR;
  306.         }

  307.         len += 1 + NGX_HTTP_V2_INT_OCTETS + method.len;
  308.         tmp_len = method.len;
  309.     }

  310.     /* :scheme header */

  311.     len += 1;

  312.     /* :path header */

  313.     escape = 0;
  314.     loc_len = 0;
  315.     unparsed_uri = 0;

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

  318.     } else if (ctx->ctx.vars.uri.len == 0 && r->valid_unparsed_uri) {
  319.         unparsed_uri = 1;
  320.         uri_len = r->unparsed_uri.len;

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

  324.         if (r->quoted_uri || r->internal) {
  325.             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
  326.                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
  327.         }

  328.         uri_len = ctx->ctx.vars.uri.len + r->uri.len - loc_len + escape
  329.                   + sizeof("?") - 1 + r->args.len;
  330.     }

  331.     if (uri_len == 0) {
  332.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  333.                       "zero length URI to proxy");
  334.         return NGX_ERROR;
  335.     }

  336.     if (uri_len > NGX_HTTP_V2_MAX_FIELD) {
  337.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  338.                       "too long http2 URI");
  339.         return NGX_ERROR;
  340.     }

  341.     len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;

  342.     if (tmp_len < uri_len) {
  343.         tmp_len = uri_len;
  344.     }

  345.     /* :authority header */

  346.     host.len = 0;
  347. #if (NGX_SUPPRESS_WARN)
  348.     host.data = NULL;
  349. #endif

  350.     if (plcf->host_value
  351.         && ngx_http_complex_value(r, plcf->host_value, &host) != NGX_OK)
  352.     {
  353.         return NGX_ERROR;
  354.     }

  355.     if (host.len == 0) {
  356.         host = ctx->ctx.vars.host_header;
  357.     }

  358.     if (host.len > NGX_HTTP_V2_MAX_FIELD) {
  359.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  360.                       "too long http2 host: \"%V\"", &host);
  361.         return NGX_ERROR;
  362.     }

  363.     len += 1 + NGX_HTTP_V2_INT_OCTETS + host.len;

  364.     if (tmp_len < host.len) {
  365.         tmp_len = host.len;
  366.     }

  367.     /* other headers */

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

  369.     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
  370.     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);

  371.     body_len = 0;

  372.     if (plcf->body_lengths) {
  373.         le.ip = plcf->body_lengths->elts;
  374.         le.request = r;
  375.         le.flushed = 1;

  376.         while (*(uintptr_t *) le.ip) {
  377.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  378.             body_len += lcode(&le);
  379.         }

  380.         ctx->ctx.internal_body_length = body_len;

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

  383.     } else if (r->discard_body) {
  384.         ctx->ctx.internal_body_length = 0;

  385.     } else {
  386.         ctx->ctx.internal_body_length = r->headers_in.content_length_n;
  387.     }

  388.     le.ip = headers->lengths->elts;
  389.     le.request = r;
  390.     le.flushed = 1;

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

  392.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  393.         key_len = lcode(&le);

  394.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  395.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  396.         }
  397.         le.ip += sizeof(uintptr_t);

  398.         if (val_len == 0) {
  399.             continue;
  400.         }

  401.         if (key_len > NGX_HTTP_V2_MAX_FIELD) {
  402.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  403.                           "too long http2 header name");
  404.             return NGX_ERROR;
  405.         }

  406.         if (val_len > NGX_HTTP_V2_MAX_FIELD) {
  407.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  408.                           "too long http2 header value");
  409.             return NGX_ERROR;
  410.         }

  411.         headers_len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
  412.                          + NGX_HTTP_V2_INT_OCTETS + val_len;

  413.         if (tmp_len < key_len) {
  414.             tmp_len = key_len;
  415.         }

  416.         if (tmp_len < val_len) {
  417.             tmp_len = val_len;
  418.         }
  419.     }

  420.     len += headers_len;

  421.     if (plcf->upstream.pass_request_headers) {
  422.         part = &r->headers_in.headers.part;
  423.         header = part->elts;

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

  425.             if (i >= part->nelts) {
  426.                 if (part->next == NULL) {
  427.                     break;
  428.                 }

  429.                 part = part->next;
  430.                 header = part->elts;
  431.                 i = 0;
  432.             }

  433.             if (ngx_hash_find(&headers->hash, header[i].hash,
  434.                               header[i].lowcase_key, header[i].key.len))
  435.             {
  436.                 continue;
  437.             }

  438.             if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
  439.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  440.                               "too long http2 header name: \"%V\"",
  441.                               &header[i].key);
  442.                 return NGX_ERROR;
  443.             }

  444.             if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
  445.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  446.                               "too long http2 header value: \"%V: %V\"",
  447.                               &header[i].key, &header[i].value);
  448.                 return NGX_ERROR;
  449.             }

  450.             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
  451.                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;

  452.             if (tmp_len < header[i].key.len) {
  453.                 tmp_len = header[i].key.len;
  454.             }

  455.             if (tmp_len < header[i].value.len) {
  456.                 tmp_len = header[i].value.len;
  457.             }
  458.         }
  459.     }

  460.     /* continuation frames */

  461.     len += sizeof(ngx_http_proxy_v2_frame_t)
  462.            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);


  463.     b = ngx_create_temp_buf(r->pool, len);
  464.     if (b == NULL) {
  465.         return NGX_ERROR;
  466.     }

  467.     cl = ngx_alloc_chain_link(r->pool);
  468.     if (cl == NULL) {
  469.         return NGX_ERROR;
  470.     }

  471.     cl->buf = b;
  472.     cl->next = NULL;

  473.     tmp = ngx_palloc(r->pool, tmp_len * 3);
  474.     if (tmp == NULL) {
  475.         return NGX_ERROR;
  476.     }

  477.     key_tmp = tmp + tmp_len;
  478.     val_tmp = tmp + 2 * tmp_len;

  479.     /* connection preface */

  480.     b->last = ngx_copy(b->last, ngx_http_proxy_v2_connection_start,
  481.                        sizeof(ngx_http_proxy_v2_connection_start) - 1);

  482.     /* headers frame */

  483.     headers_frame = b->last;

  484.     f = (ngx_http_proxy_v2_frame_t *) b->last;
  485.     b->last += sizeof(ngx_http_proxy_v2_frame_t);

  486.     f->length_0 = 0;
  487.     f->length_1 = 0;
  488.     f->length_2 = 0;
  489.     f->type = NGX_HTTP_V2_HEADERS_FRAME;
  490.     f->flags = 0;
  491.     f->stream_id_0 = 0;
  492.     f->stream_id_1 = 0;
  493.     f->stream_id_2 = 0;
  494.     f->stream_id_3 = 1;

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

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

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

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

  503.     } else {
  504.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
  505.         b->last = ngx_http_v2_write_value(b->last, method.data,
  506.                                           method.len, tmp);

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

  510. #if (NGX_HTTP_SSL)
  511.     if (u->ssl) {
  512.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);

  513.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  514.                        "http proxy header: \":scheme: https\"");
  515.     } else
  516. #endif
  517.     {
  518.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);

  519.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  520.                        "http proxy header: \":scheme: http\"");
  521.     }

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

  523.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  524.         b->last = ngx_http_v2_write_value(b->last, ctx->ctx.vars.uri.data,
  525.                                           ctx->ctx.vars.uri.len, tmp);

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

  528.     } else if (unparsed_uri) {

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

  531.         } else {
  532.             *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  533.             b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
  534.                                               r->unparsed_uri.len, tmp);
  535.         }

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

  538.     } else {
  539.         p = val_tmp;

  540.         if (r->valid_location) {
  541.             p = ngx_copy(p, ctx->ctx.vars.uri.data, ctx->ctx.vars.uri.len);
  542.         }

  543.         if (escape) {
  544.             ngx_escape_uri(p, r->uri.data + loc_len,
  545.                            r->uri.len - loc_len, NGX_ESCAPE_URI);
  546.             p += r->uri.len - loc_len + escape;

  547.         } else {
  548.             p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
  549.         }

  550.         if (r->args.len > 0) {
  551.             *p++ = '?';
  552.             p = ngx_copy(p, r->args.data, r->args.len);
  553.         }

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

  556.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  557.                        "http proxy header: \":path: %*s\"", p - val_tmp,
  558.                        val_tmp);
  559.     }

  560.     *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
  561.     b->last = ngx_http_v2_write_value(b->last, host.data, host.len, tmp);

  562.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  563.                    "http proxy header: \":authority: %V\"", &host);

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

  565.     e.ip = headers->values->elts;
  566.     e.request = r;
  567.     e.flushed = 1;

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

  569.     headers_end = b->last + headers_len;

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

  571.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  572.         key_len = lcode(&le);

  573.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  574.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  575.         }
  576.         le.ip += sizeof(uintptr_t);

  577.         if (val_len == 0) {
  578.             e.skip = 1;

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

  584.             e.skip = 0;

  585.             continue;
  586.         }

  587.         if (headers_end - b->last < 1) {
  588.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  589.                           "no buffer space in HTTP/2 create request");
  590.             return NGX_ERROR;
  591.         }

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

  593.         e.pos = key_tmp;
  594.         e.end = key_tmp + tmp_len;

  595.         code = *(ngx_http_script_code_pt *) e.ip;
  596.         code((ngx_http_script_engine_t *) &e);

  597.         if (e.status) {
  598.             return NGX_ERROR;
  599.         }

  600.         key_len = e.pos - key_tmp;

  601.         if (headers_end - b->last
  602.             < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + key_len))
  603.         {
  604.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  605.                           "no buffer space in HTTP/2 create request");
  606.             return NGX_ERROR;
  607.         }

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

  609.         e.pos = val_tmp;
  610.         e.end = val_tmp + tmp_len;

  611.         while (*(uintptr_t *) e.ip) {
  612.             code = *(ngx_http_script_code_pt *) e.ip;
  613.             code((ngx_http_script_engine_t *) &e);
  614.         }
  615.         e.ip += sizeof(uintptr_t);

  616.         if (e.status) {
  617.             return NGX_ERROR;
  618.         }

  619.         val_len = e.pos - val_tmp;

  620.         if (headers_end - b->last
  621.             < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + val_len))
  622.         {
  623.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  624.                           "no buffer space in HTTP/2 create request");
  625.             return NGX_ERROR;
  626.         }

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

  628. #if (NGX_DEBUG)
  629.         if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
  630.             ngx_strlow(key_tmp, key_tmp, key_len);

  631.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  632.                            "http proxy header: \"%*s: %*s\"",
  633.                            key_len, key_tmp, val_len, val_tmp);
  634.         }
  635. #endif
  636.     }

  637.     if (plcf->upstream.pass_request_headers) {
  638.         part = &r->headers_in.headers.part;
  639.         header = part->elts;

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

  641.             if (i >= part->nelts) {
  642.                 if (part->next == NULL) {
  643.                     break;
  644.                 }

  645.                 part = part->next;
  646.                 header = part->elts;
  647.                 i = 0;
  648.             }

  649.             if (ngx_hash_find(&headers->hash, header[i].hash,
  650.                               header[i].lowcase_key, header[i].key.len))
  651.             {
  652.                 continue;
  653.             }

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

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

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

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

  662.                 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  663.                                "http proxy header: \"%*s: %V\"",
  664.                                header[i].key.len, tmp, &header[i].value);
  665.             }
  666. #endif
  667.         }
  668.     }

  669.     /* update headers frame length */

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

  671.     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  672.         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  673.         next = 1;

  674.     } else {
  675.         next = 0;
  676.     }

  677.     f = (ngx_http_proxy_v2_frame_t *) headers_frame;

  678.     f->length_0 = (u_char) ((len >> 16) & 0xff);
  679.     f->length_1 = (u_char) ((len >> 8) & 0xff);
  680.     f->length_2 = (u_char) (len & 0xff);

  681.     /* create additional continuation frames */

  682.     p = headers_frame;

  683.     while (next) {
  684.         p += sizeof(ngx_http_proxy_v2_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  685.         len = b->last - p;

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

  688.         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  689.             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  690.             next = 1;

  691.         } else {
  692.             next = 0;
  693.         }

  694.         f = (ngx_http_proxy_v2_frame_t *) p;

  695.         f->length_0 = (u_char) ((len >> 16) & 0xff);
  696.         f->length_1 = (u_char) ((len >> 8) & 0xff);
  697.         f->length_2 = (u_char) (len & 0xff);
  698.         f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
  699.         f->flags = 0;
  700.         f->stream_id_0 = 0;
  701.         f->stream_id_1 = 0;
  702.         f->stream_id_2 = 0;
  703.         f->stream_id_3 = 1;
  704.     }

  705.     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;

  706.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  707.                    "http proxy header: %*xs%s, len: %uz",
  708.                    (size_t) ngx_min(b->last - b->pos, 256), b->pos,
  709.                    b->last - b->pos > 256 ? "..." : "",
  710.                    b->last - b->pos);

  711.     if (r->request_body_no_buffering) {

  712.         u->request_bufs = cl;

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

  714.         body = u->request_bufs;
  715.         u->request_bufs = cl;

  716.         if (body == NULL) {
  717.             f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  718.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
  719.         }

  720.         while (body) {
  721.             b = ngx_alloc_buf(r->pool);
  722.             if (b == NULL) {
  723.                 return NGX_ERROR;
  724.             }

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

  726.             cl->next = ngx_alloc_chain_link(r->pool);
  727.             if (cl->next == NULL) {
  728.                 return NGX_ERROR;
  729.             }

  730.             cl = cl->next;
  731.             cl->buf = b;

  732.             body = body->next;
  733.         }

  734.         b->last_buf = 1;

  735.     } else if (body_len) {

  736.         u->request_bufs = cl;

  737.         b = ngx_create_temp_buf(r->pool, body_len);
  738.         if (b == NULL) {
  739.             return NGX_ERROR;
  740.         }

  741.         cl->next = ngx_alloc_chain_link(r->pool);
  742.         if (cl->next == NULL) {
  743.             return NGX_ERROR;
  744.         }

  745.         cl = cl->next;
  746.         cl->buf = b;

  747.         e.ip = plcf->body_values->elts;
  748.         e.pos = b->last;
  749.         e.end = b->last + body_len;
  750.         e.request = r;
  751.         e.flushed = 1;
  752.         e.skip = 0;

  753.         while (*(uintptr_t *) e.ip) {
  754.             code = *(ngx_http_script_code_pt *) e.ip;
  755.             code((ngx_http_script_engine_t *) &e);
  756.         }

  757.         if (e.status) {
  758.             return NGX_ERROR;
  759.         }

  760.         b->last = e.pos;
  761.         b->last_buf = 1;

  762.     } else {
  763.         u->request_bufs = cl;

  764.         f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  765.         f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  766.         b->last_buf = 1;
  767.     }

  768.     u->output.output_filter = ngx_http_proxy_v2_body_output_filter;
  769.     u->output.filter_ctx = r;

  770.     b->flush = 1;
  771.     cl->next = NULL;

  772.     return NGX_OK;
  773. }


  774. static ngx_int_t
  775. ‌ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r)
  776. {
  777.     ngx_http_proxy_v2_ctx_t  *ctx;

  778.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  779.     if (ctx == NULL) {
  780.         return NGX_OK;
  781.     }

  782.     ctx->state = 0;
  783.     ctx->header_sent = 0;
  784.     ctx->output_closed = 0;
  785.     ctx->output_blocked = 0;
  786.     ctx->parsing_headers = 0;
  787.     ctx->end_stream = 0;
  788.     ctx->done = 0;
  789.     ctx->status = 0;
  790.     ctx->rst = 0;
  791.     ctx->goaway = 0;
  792.     ctx->connection = NULL;
  793.     ctx->in = NULL;
  794.     ctx->busy = NULL;
  795.     ctx->out = NULL;

  796.     return NGX_OK;
  797. }


  798. static ngx_int_t
  799. ‌ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in)
  800. {
  801.     ngx_http_request_t  *r = data;

  802.     off_t                       file_pos;
  803.     u_char                     *p, *pos, *start;
  804.     size_t                      len, limit;
  805.     ngx_buf_t                  *b;
  806.     ngx_int_t                  rc;
  807.     ngx_uint_t                 next, last;
  808.     ngx_chain_t                *cl, *out, *ln, **ll;
  809.     ngx_http_upstream_t        *u;
  810.     ngx_http_proxy_v2_ctx_t    *ctx;
  811.     ngx_http_proxy_v2_frame_t  *f;

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

  814.     ctx = ngx_http_proxy_v2_get_ctx(r);

  815.     if (ctx == NULL) {
  816.         return NGX_ERROR;
  817.     }

  818.     if (in) {
  819.         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
  820.             return NGX_ERROR;
  821.         }
  822.     }

  823.     out = NULL;
  824.     ll = &out;

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

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

  829.         ctx->header_sent = 1;

  830.         if (ctx->id != 1) {
  831.             /*
  832.              * keepalive connection: skip connection preface,
  833.              * update stream identifiers
  834.              */

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

  837.             p = b->pos;

  838.             while (p < b->last) {
  839.                 f = (ngx_http_proxy_v2_frame_t *) p;
  840.                 p += sizeof(ngx_http_proxy_v2_frame_t);

  841.                 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  842.                 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  843.                 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  844.                 f->stream_id_3 = (u_char) (ctx->id & 0xff);

  845.                 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
  846.             }
  847.         }

  848.         if (ctx->in->buf->last_buf) {
  849.             ctx->output_closed = 1;
  850.         }

  851.         *ll = ctx->in;
  852.         ll = &ctx->in->next;

  853.         ctx->in = ctx->in->next;
  854.     }

  855.     if (ctx->out) {
  856.         /* queued control frames */

  857.         *ll = ctx->out;

  858.         for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
  859.             ll = &cl->next;
  860.         }

  861.         ctx->out = NULL;
  862.     }

  863.     f = NULL;
  864.     last = 0;

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

  866.     if (limit > ctx->connection->send_window) {
  867.         limit = ctx->connection->send_window;
  868.     }

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

  872. #if (NGX_SUPPRESS_WARN)
  873.     file_pos = 0;
  874.     pos = NULL;
  875.     cl = NULL;
  876. #endif

  877.     in = ctx->in;

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

  879.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  880.                        "http proxy output in  l:%d f:%d %p, pos %p, size: %z "
  881.                        "file: %O, size: %O",
  882.                        in->buf->last_buf,
  883.                        in->buf->in_file,
  884.                        in->buf->start, in->buf->pos,
  885.                        in->buf->last - in->buf->pos,
  886.                        in->buf->file_pos,
  887.                        in->buf->file_last - in->buf->file_pos);

  888.         if (ngx_buf_special(in->buf)) {
  889.             goto next;
  890.         }

  891.         if (in->buf->in_file) {
  892.             file_pos = in->buf->file_pos;

  893.         } else {
  894.             pos = in->buf->pos;
  895.         }

  896.         next = 0;

  897.         do {

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

  902.             b = cl->buf;

  903.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  904.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  905.             *ll = cl;
  906.             ll = &cl->next;

  907.             cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  908.             if (cl == NULL) {
  909.                 return NGX_ERROR;
  910.             }

  911.             b = cl->buf;
  912.             start = b->start;

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

  914.             /*
  915.              * restore b->start to preserve memory allocated in the buffer,
  916.              * to reuse it later for headers and control frames
  917.              */

  918.             b->start = start;

  919.             if (in->buf->in_file) {
  920.                 b->file_pos = file_pos;
  921.                 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  922.                 if (file_pos >= in->buf->file_last) {
  923.                     file_pos = in->buf->file_last;
  924.                     next = 1;
  925.                 }

  926.                 b->file_last = file_pos;
  927.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  928.             } else {
  929.                 b->pos = pos;
  930.                 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  931.                 if (pos >= in->buf->last) {
  932.                     pos = in->buf->last;
  933.                     next = 1;
  934.                 }

  935.                 b->last = pos;
  936.                 len = (ngx_uint_t) (pos - b->pos);
  937.             }

  938.             b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  939.             b->shadow = in->buf;
  940.             b->last_shadow = next;

  941.             b->last_buf = 0;
  942.             b->last_in_chain = 0;

  943.             *ll = cl;
  944.             ll = &cl->next;

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

  954.             limit -= len;
  955.             ctx->send_window -= len;
  956.             ctx->connection->send_window -= len;

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

  958.         if (!next) {
  959.             /*
  960.              * if the buffer wasn't fully sent due to flow control limits,
  961.              * preserve position for future use
  962.              */

  963.             if (in->buf->in_file) {
  964.                 in->buf->file_pos = file_pos;

  965.             } else {
  966.                 in->buf->pos = pos;
  967.             }

  968.             break;
  969.         }

  970.     next:

  971.         if (in->buf->last_buf) {
  972.             last = 1;
  973.         }

  974.         ln = in;
  975.         in = in->next;

  976.         ngx_free_chain(r->pool, ln);
  977.     }

  978.     ctx->in = in;

  979.     if (last) {

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

  982.         ctx->output_closed = 1;

  983.         if (f) {
  984.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  985.         } else {
  986.             cl = ngx_http_proxy_v2_get_buf(r, ctx);
  987.             if (cl == NULL) {
  988.                 return NGX_ERROR;
  989.             }

  990.             b = cl->buf;

  991.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  992.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  993.             f->length_0 = 0;
  994.             f->length_1 = 0;
  995.             f->length_2 = 0;
  996.             f->type = NGX_HTTP_V2_DATA_FRAME;
  997.             f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
  998.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  999.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  1000.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  1001.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  1002.             *ll = cl;
  1003.             ll = &cl->next;
  1004.         }

  1005.         cl->buf->last_buf = 1;
  1006.     }

  1007.     *ll = NULL;

  1008. #if (NGX_DEBUG)

  1009.     for (cl = out; cl; cl = cl->next) {
  1010.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1011.                        "http proxy output out l:%d f:%d %p, pos %p, size: %z "
  1012.                        "file: %O, size: %O",
  1013.                        cl->buf->last_buf,
  1014.                        cl->buf->in_file,
  1015.                        cl->buf->start, cl->buf->pos,
  1016.                        cl->buf->last - cl->buf->pos,
  1017.                        cl->buf->file_pos,
  1018.                        cl->buf->file_last - cl->buf->file_pos);
  1019.     }

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

  1023. #endif

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

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

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

  1028.         /* mark original buffers as sent */

  1029.         if (cl->buf->shadow) {
  1030.             if (cl->buf->last_shadow) {
  1031.                 b = cl->buf->shadow;
  1032.                 b->pos = b->last;
  1033.             }

  1034.             cl->buf->shadow = NULL;
  1035.         }
  1036.     }

  1037.     if (rc == NGX_OK && ctx->in) {
  1038.         rc = NGX_AGAIN;
  1039.     }

  1040.     if (rc == NGX_AGAIN) {
  1041.         ctx->output_blocked = 1;

  1042.     } else {
  1043.         ctx->output_blocked = 0;
  1044.     }

  1045.     if (ctx->done) {

  1046.         /*
  1047.          * We have already got the response and were sending some additional
  1048.          * control frames.  Even if there is still something unsent, stop
  1049.          * here anyway.
  1050.          */

  1051.         u = r->upstream;
  1052.         u->length = 0;
  1053.         u->pipe->length = 0;

  1054.         if (ctx->in == NULL
  1055.             && ctx->out == NULL
  1056.             && ctx->output_closed
  1057.             && !ctx->output_blocked
  1058.             && !ctx->goaway
  1059.             && ctx->state == ngx_http_proxy_v2_st_start)
  1060.         {
  1061.             u->keepalive = 1;
  1062.         }

  1063.         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
  1064.     }

  1065.     return rc;
  1066. }


  1067. static ngx_int_t
  1068. ‌ngx_http_proxy_v2_process_header(ngx_http_request_t *r)
  1069. {
  1070.     u_char                         *pos;
  1071.     ngx_str_t                      *status_line;
  1072.     ngx_int_t                       rc, status;
  1073.     ngx_buf_t                      *b;
  1074.     ngx_table_elt_t                *h;
  1075.     ngx_http_upstream_t            *u;
  1076.     ngx_http_proxy_v2_ctx_t        *ctx;
  1077.     ngx_http_upstream_header_t     *hh;
  1078.     ngx_http_upstream_main_conf_t  *umcf;

  1079.     u = r->upstream;
  1080.     b = &u->buffer;
  1081.     pos = b->pos;

  1082.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1083.                    "http proxy response: %*xs%s, len: %uz",
  1084.                    (size_t) ngx_min(b->last - b->pos, 256),
  1085.                    b->pos, b->last - b->pos > 256 ? "..." : "",
  1086.                    b->last - b->pos);

  1087.     ctx = ngx_http_proxy_v2_get_ctx(r);

  1088.     if (ctx == NULL) {
  1089.         return NGX_ERROR;
  1090.     }

  1091.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1092.     for ( ;; ) {

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

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

  1095.             if (rc == NGX_AGAIN) {

  1096.                 /*
  1097.                  * there can be a lot of window update frames,
  1098.                  * so we reset buffer if it is empty and we haven't
  1099.                  * started parsing headers yet
  1100.                  */

  1101.                 if (!ctx->parsing_headers) {
  1102.                     b->pos = pos;
  1103.                     b->last = b->pos;
  1104.                 }

  1105.                 return NGX_AGAIN;
  1106.             }

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

  1110.             /*
  1111.              * RFC 7540 says that implementations MUST discard frames
  1112.              * that have unknown or unsupported types.  However, extension
  1113.              * frames that appear in the middle of a header block are
  1114.              * not permitted.  Also, for obvious reasons CONTINUATION frames
  1115.              * cannot appear before headers, and DATA frames are not expected
  1116.              * to appear before all headers are parsed.
  1117.              */

  1118.             if (ctx->type == NGX_HTTP_V2_DATA_FRAME
  1119.                 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1120.                     && !ctx->parsing_headers)
  1121.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1122.                     && ctx->parsing_headers))
  1123.             {
  1124.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1125.                               "upstream sent unexpected http2 frame: %d",
  1126.                               ctx->type);
  1127.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1128.             }

  1129.             if (ctx->id && ctx->stream_id && ctx->stream_id != ctx->id) {
  1130.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1131.                               "upstream sent frame for unknown stream %ui",
  1132.                               ctx->stream_id);
  1133.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1134.             }
  1135.         }

  1136.         /* frame payload */

  1137.         if (!ngx_http_proxy_v2_cached(r)) {

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

  1140.                 if (rc == NGX_AGAIN) {
  1141.                     return NGX_AGAIN;
  1142.                 }

  1143.                 if (rc == NGX_ERROR) {
  1144.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1145.                 }

  1146.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1147.                               "upstream rejected request with error %ui",
  1148.                               ctx->error);

  1149.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1150.             }

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

  1152.             if (rc == NGX_AGAIN) {
  1153.                 return NGX_AGAIN;
  1154.             }

  1155.             if (rc == NGX_ERROR) {
  1156.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1157.             }

  1158.             if (rc == NGX_OK) {
  1159.                 continue;
  1160.             }
  1161.         }

  1162.         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
  1163.             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
  1164.         {
  1165.             /* priority, unknown frames */

  1166.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1167.             if (rc == NGX_AGAIN) {
  1168.                 return NGX_AGAIN;
  1169.             }

  1170.             continue;
  1171.         }

  1172.         /* headers */

  1173.         for ( ;; ) {

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

  1175.             if (rc == NGX_AGAIN) {
  1176.                 break;
  1177.             }

  1178.             if (rc == NGX_OK) {

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

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

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

  1184.                     if (ctx->name.len != sizeof(":status") - 1
  1185.                         || ngx_strncmp(ctx->name.data, ":status",
  1186.                                        sizeof(":status") - 1)
  1187.                            != 0)
  1188.                     {
  1189.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1190.                                       "upstream sent invalid header \"%V: %V\"",
  1191.                                       &ctx->name, &ctx->value);
  1192.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1193.                     }

  1194.                     if (ctx->status) {
  1195.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1196.                                       "upstream sent duplicate :status header");
  1197.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1198.                     }

  1199.                     status_line = &ctx->value;

  1200.                     if (status_line->len != 3) {
  1201.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1202.                                       "upstream sent invalid :status \"%V\"",
  1203.                                       status_line);
  1204.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1205.                     }

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

  1207.                     if (status == NGX_ERROR) {
  1208.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1209.                                       "upstream sent invalid :status \"%V\"",
  1210.                                       status_line);
  1211.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1212.                     }

  1213.                     if (status < NGX_HTTP_OK && status != NGX_HTTP_EARLY_HINTS)
  1214.                     {
  1215.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1216.                                       "upstream sent unexpected :status \"%V\"",
  1217.                                       status_line);
  1218.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1219.                     }

  1220.                     u->headers_in.status_n = status;

  1221.                     if (u->state && u->state->status == 0) {
  1222.                         u->state->status = status;
  1223.                     }

  1224.                     ctx->status = 1;

  1225.                     continue;

  1226.                 } else if (!ctx->status) {
  1227.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1228.                                   "upstream sent no :status header");
  1229.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1230.                 }

  1231.                 h = ngx_list_push(&u->headers_in.headers);
  1232.                 if (h == NULL) {
  1233.                     return NGX_ERROR;
  1234.                 }

  1235.                 h->key = ctx->name;
  1236.                 h->value = ctx->value;
  1237.                 h->lowcase_key = h->key.data;
  1238.                 h->hash = ngx_hash_key(h->key.data, h->key.len);

  1239.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1240.                     continue;
  1241.                 }

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

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

  1246.                     if (rc != NGX_OK) {
  1247.                         return rc;
  1248.                     }
  1249.                 }

  1250.                 continue;
  1251.             }

  1252.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1256.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1257.                     if (ctx->end_stream) {
  1258.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1259.                                       "upstream prematurely closed stream");
  1260.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1261.                     }

  1262.                     ctx->status = 0;
  1263.                     return NGX_HTTP_UPSTREAM_EARLY_HINTS;
  1264.                 }

  1265.                 if (ctx->end_stream
  1266.                     && ctx->in == NULL
  1267.                     && ctx->out == NULL
  1268.                     && ctx->output_closed
  1269.                     && !ctx->output_blocked
  1270.                     && !ctx->goaway
  1271.                     && b->last == b->pos)
  1272.                 {
  1273.                     u->keepalive = 1;
  1274.                 }

  1275.                 return NGX_OK;
  1276.             }

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

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

  1280.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1281.         }

  1282.         /* rc == NGX_AGAIN */

  1283.         if (ctx->rest == 0) {
  1284.             ctx->state = ngx_http_proxy_v2_st_start;
  1285.             continue;
  1286.         }

  1287.         return NGX_AGAIN;
  1288.     }
  1289. }


  1290. static ngx_int_t
  1291. ‌ngx_http_proxy_v2_filter_init(void *data)
  1292. {
  1293.     ngx_http_request_t       *r = data;
  1294.     ngx_http_upstream_t      *u;
  1295.     ngx_http_proxy_v2_ctx_t  *ctx;

  1296.     u = r->upstream;
  1297.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1298.     if (ctx == NULL) {
  1299.         return NGX_ERROR;
  1300.     }

  1301.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1302.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1303.         || ctx->ctx.head)
  1304.     {
  1305.         ctx->length = 0;

  1306.     } else {
  1307.         ctx->length = u->headers_in.content_length_n;
  1308.     }

  1309.     if (ctx->end_stream) {

  1310.         if (ctx->length > 0) {
  1311.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1312.                           "upstream prematurely closed stream");
  1313.             return NGX_ERROR;
  1314.         }

  1315.         u->length = 0;
  1316.         u->pipe->length = 0;
  1317.         ctx->done = 1;

  1318.     } else {
  1319.         u->length = 1;
  1320.         u->pipe->length = 1;
  1321.     }

  1322.     return NGX_OK;
  1323. }


  1324. static ngx_int_t
  1325. ‌ngx_http_proxy_v2_non_buffered_filter(void *data, ssize_t bytes)
  1326. {
  1327.     ngx_http_request_t   *r = data;

  1328.     ngx_int_t                 rc;
  1329.     ngx_buf_t                *b, *buf;
  1330.     ngx_chain_t              *cl, **ll;
  1331.     ngx_http_upstream_t      *u;
  1332.     ngx_http_proxy_v2_ctx_t  *ctx;

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

  1335.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1336.     if (ctx == NULL) {
  1337.         return NGX_ERROR;
  1338.     }

  1339.     u = r->upstream;
  1340.     b = &u->buffer;

  1341.     b->pos = b->last;
  1342.     b->last += bytes;

  1343.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1344.         ll = &cl->next;
  1345.     }

  1346.     for ( ;; ) {

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

  1348.         if (rc == NGX_OK) {

  1349.             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1350.             if (cl == NULL) {
  1351.                 return NGX_ERROR;
  1352.             }

  1353.             *ll = cl;
  1354.             ll = &cl->next;

  1355.             buf = cl->buf;

  1356.             buf->flush = 1;
  1357.             buf->memory = 1;

  1358.             buf->pos = b->pos;
  1359.             buf->tag = u->output.tag;

  1360.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1361.                 b->pos += ctx->rest - ctx->padding;
  1362.                 buf->last = b->pos;
  1363.                 ctx->rest = ctx->padding;

  1364.             } else {
  1365.                 ctx->rest -= b->last - b->pos;
  1366.                 b->pos = b->last;
  1367.                 buf->last = b->pos;
  1368.             }

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

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

  1372.                 if (buf->last - buf->pos > ctx->length) {
  1373.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1374.                                   "upstream sent response body larger "
  1375.                                   "than indicated content length");
  1376.                     return NGX_ERROR;
  1377.                 }

  1378.                 ctx->length -= buf->last - buf->pos;
  1379.             }

  1380.             continue;
  1381.         }

  1382.         if (rc == NGX_DONE) {
  1383.             u->length = 0;
  1384.             break;
  1385.         }

  1386.         if (rc == NGX_AGAIN) {
  1387.             return NGX_AGAIN;
  1388.         }

  1389.         /* invalid response */

  1390.         return NGX_ERROR;
  1391.     }

  1392.     return NGX_OK;
  1393. }


  1394. static ngx_int_t
  1395. ‌ngx_http_proxy_v2_body_filter(ngx_event_pipe_t *p, ngx_buf_t *b)
  1396. {
  1397.     ngx_int_t                 rc;
  1398.     ngx_buf_t                *buf, **prev;
  1399.     ngx_chain_t              *cl;
  1400.     ngx_http_request_t       *r;
  1401.     ngx_http_proxy_v2_ctx_t  *ctx;

  1402.     if (b->pos == b->last) {
  1403.         return NGX_OK;
  1404.     }

  1405.     r = p->input_ctx;
  1406.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1407.     if (ctx == NULL) {
  1408.         return NGX_ERROR;
  1409.     }

  1410.     buf = NULL;
  1411.     prev = &b->shadow;

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

  1414.     for ( ;; ) {

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

  1416.         if (rc == NGX_OK) {

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

  1418.             cl = ngx_chain_get_free_buf(p->pool, &p->free);
  1419.             if (cl == NULL) {
  1420.                 return NGX_ERROR;
  1421.             }

  1422.             buf = cl->buf;

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

  1424.             buf->pos = b->pos;
  1425.             buf->start = b->start;
  1426.             buf->end = b->end;
  1427.             buf->tag = p->tag;
  1428.             buf->temporary = 1;
  1429.             buf->recycled = 1;

  1430.             *prev = buf;
  1431.             prev = &buf->shadow;

  1432.             if (p->in) {
  1433.                 *p->last_in = cl;

  1434.             } else {
  1435.                 p->in = cl;
  1436.             }

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

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

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

  1441.             if (b->last - b->pos >= (ssize_t) ctx->rest - ctx->padding) {
  1442.                 b->pos += ctx->rest - ctx->padding;
  1443.                 buf->last = b->pos;
  1444.                 ctx->rest = ctx->padding;

  1445.             } else {
  1446.                 ctx->rest -= b->last - b->pos;
  1447.                 b->pos = b->last;
  1448.                 buf->last = b->pos;
  1449.             }

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

  1451.                 if (buf->last - buf->pos > ctx->length) {
  1452.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1453.                                   "upstream sent response body larger "
  1454.                                   "than indicated content length");
  1455.                     return NGX_ERROR;
  1456.                 }

  1457.                 ctx->length -= buf->last - buf->pos;
  1458.             }

  1459.             continue;
  1460.         }

  1461.         if (rc == NGX_DONE) {
  1462.             p->length = 0;
  1463.             break;
  1464.         }

  1465.         if (rc == NGX_AGAIN) {
  1466.             break;
  1467.         }

  1468.         /* invalid response */

  1469.         return NGX_ERROR;
  1470.     }

  1471.     if (buf) {
  1472.         buf->shadow = b;
  1473.         buf->last_shadow = 1;

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

  1476.         return NGX_OK;
  1477.     }

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

  1479.     if (ngx_event_pipe_add_free_buf(p, b) != NGX_OK) {
  1480.         return NGX_ERROR;
  1481.     }

  1482.     return NGX_OK;
  1483. }


  1484. static ngx_int_t
  1485. ‌ngx_http_proxy_v2_process_control_frame(ngx_http_request_t *r,
  1486.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1487. {
  1488.     ngx_int_t             rc;
  1489.     ngx_http_upstream_t  *u;

  1490.     u = r->upstream;

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

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

  1493.         if (rc == NGX_AGAIN) {
  1494.             return NGX_AGAIN;
  1495.         }

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

  1499.         /*
  1500.          * If stream_id is lower than one we use, our
  1501.          * request won't be processed and needs to be retried.
  1502.          * If stream_id is greater or equal to the one we use,
  1503.          * we can continue normally (except we can't use this
  1504.          * connection for additional requests).  If there is
  1505.          * a real error, the connection will be closed.
  1506.          */

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

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

  1509.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1510.                           "upstream sent goaway with error %ui",
  1511.                           ctx->error);

  1512.             return NGX_ERROR;
  1513.         }

  1514.         ctx->goaway = 1;

  1515.         return NGX_OK;
  1516.     }

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

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

  1519.         if (rc == NGX_AGAIN) {
  1520.             return NGX_AGAIN;
  1521.         }

  1522.         if (rc == NGX_ERROR) {
  1523.             return NGX_ERROR;
  1524.         }

  1525.         if (ctx->in) {
  1526.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1527.         }

  1528.         return NGX_OK;
  1529.     }

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

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

  1532.         if (rc == NGX_AGAIN) {
  1533.             return NGX_AGAIN;
  1534.         }

  1535.         if (rc == NGX_ERROR) {
  1536.             return NGX_ERROR;
  1537.         }

  1538.         if (ctx->in) {
  1539.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1540.         }

  1541.         return NGX_OK;
  1542.     }

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

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

  1545.         if (rc == NGX_AGAIN) {
  1546.             return NGX_AGAIN;
  1547.         }

  1548.         if (rc == NGX_ERROR) {
  1549.             return NGX_ERROR;
  1550.         }

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

  1552.         return NGX_OK;
  1553.     }

  1554.     if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
  1555.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1556.                       "upstream sent unexpected push promise frame");
  1557.         return NGX_ERROR;
  1558.     }

  1559.     return NGX_DECLINED;
  1560. }


  1561. static ngx_int_t
  1562. ‌ngx_http_proxy_v2_skip_frame(ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1563. {
  1564.     if (b->last - b->pos < (ssize_t) ctx->rest) {
  1565.         ctx->rest -= b->last - b->pos;
  1566.         b->pos = b->last;
  1567.         return NGX_AGAIN;
  1568.     }

  1569.     b->pos += ctx->rest;
  1570.     ctx->rest = 0;
  1571.     ctx->state = ngx_http_proxy_v2_st_start;

  1572.     return NGX_OK;
  1573. }


  1574. static ngx_int_t
  1575. ‌ngx_http_proxy_v2_process_frames(ngx_http_request_t *r,
  1576.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1577. {
  1578.     ngx_int_t             rc;
  1579.     ngx_table_elt_t      *h;
  1580.     ngx_http_upstream_t  *u;

  1581.     u = r->upstream;

  1582.     for ( ;; ) {

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

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

  1585.             if (rc == NGX_AGAIN) {

  1586.                 if (ctx->done) {

  1587.                     if (ctx->length > 0) {
  1588.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1589.                                       "upstream prematurely closed stream");
  1590.                         return NGX_ERROR;
  1591.                     }

  1592.                     /*
  1593.                      * We have finished parsing the response and the
  1594.                      * remaining control frames.  If there are unsent
  1595.                      * control frames, post a write event to send them.
  1596.                      */

  1597.                     if (ctx->out) {
  1598.                         ngx_post_event(u->peer.connection->write,
  1599.                                        &ngx_posted_events);
  1600.                         return NGX_AGAIN;
  1601.                     }

  1602.                     if (ctx->in == NULL
  1603.                         && ctx->output_closed
  1604.                         && !ctx->output_blocked
  1605.                         && !ctx->goaway
  1606.                         && ctx->state == ngx_http_proxy_v2_st_start)
  1607.                     {
  1608.                         u->keepalive = 1;
  1609.                     }

  1610.                     return NGX_DONE;
  1611.                 }

  1612.                 return NGX_AGAIN;
  1613.             }

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

  1617.             if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1618.                  && !ctx->parsing_headers)
  1619.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1620.                     && ctx->parsing_headers))
  1621.             {
  1622.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1623.                               "upstream sent unexpected http2 frame: %d",
  1624.                               ctx->type);
  1625.                 return NGX_ERROR;
  1626.             }

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

  1628.                 if (ctx->stream_id != ctx->id) {
  1629.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1630.                                   "upstream sent data frame "
  1631.                                   "for unknown stream %ui",
  1632.                                   ctx->stream_id);
  1633.                     return NGX_ERROR;
  1634.                 }

  1635.                 if (ctx->rest > ctx->recv_window) {
  1636.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1637.                                   "upstream violated stream flow control, "
  1638.                                   "received %uz data frame with window %uz",
  1639.                                   ctx->rest, ctx->recv_window);
  1640.                     return NGX_ERROR;
  1641.                 }

  1642.                 if (ctx->rest > ctx->connection->recv_window) {
  1643.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1644.                                   "upstream violated connection flow control, "
  1645.                                   "received %uz data frame with window %uz",
  1646.                                   ctx->rest, ctx->connection->recv_window);
  1647.                     return NGX_ERROR;
  1648.                 }

  1649.                 ctx->recv_window -= ctx->rest;
  1650.                 ctx->connection->recv_window -= ctx->rest;

  1651.                 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
  1652.                     || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
  1653.                 {
  1654.                     if (ngx_http_proxy_v2_send_window_update(r, ctx)
  1655.                         != NGX_OK)
  1656.                     {
  1657.                         return NGX_ERROR;
  1658.                     }

  1659.                     ngx_post_event(u->peer.connection->write,
  1660.                                    &ngx_posted_events);
  1661.                 }
  1662.             }

  1663.             if (ctx->stream_id && ctx->stream_id != ctx->id) {
  1664.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1665.                               "upstream sent frame for unknown stream %ui",
  1666.                               ctx->stream_id);
  1667.                 return NGX_ERROR;
  1668.             }

  1669.             if (ctx->stream_id && ctx->done
  1670.                 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
  1671.                 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
  1672.             {
  1673.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1674.                               "upstream sent frame for closed stream %ui",
  1675.                               ctx->stream_id);
  1676.                 return NGX_ERROR;
  1677.             }

  1678.             ctx->padding = 0;
  1679.         }

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

  1681.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1682.                 ctx->rest -= b->last - b->pos;
  1683.                 b->pos = b->last;
  1684.                 return NGX_AGAIN;
  1685.             }

  1686.             b->pos += ctx->rest;
  1687.             ctx->rest = 0;
  1688.             ctx->state = ngx_http_proxy_v2_st_start;

  1689.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1690.                 ctx->done = 1;
  1691.             }

  1692.             continue;
  1693.         }

  1694.         /* frame payload */

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

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

  1697.             if (rc == NGX_AGAIN) {
  1698.                 return NGX_AGAIN;
  1699.             }

  1700.             if (rc == NGX_ERROR) {
  1701.                 return NGX_ERROR;
  1702.             }

  1703.             if (ctx->error || !ctx->done) {
  1704.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1705.                               "upstream rejected request with error %ui",
  1706.                               ctx->error);
  1707.                 return NGX_ERROR;
  1708.             }

  1709.             if (ctx->rst) {
  1710.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1711.                               "upstream sent frame for closed stream %ui",
  1712.                               ctx->stream_id);
  1713.                 return NGX_ERROR;
  1714.             }

  1715.             ctx->rst = 1;

  1716.             continue;
  1717.         }

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

  1719.         if (rc == NGX_AGAIN) {
  1720.             return NGX_AGAIN;
  1721.         }

  1722.         if (rc == NGX_ERROR) {
  1723.             return NGX_ERROR;
  1724.         }

  1725.         if (rc == NGX_OK) {
  1726.             continue;
  1727.         }

  1728.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
  1729.             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
  1730.         {
  1731.             for ( ;; ) {

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

  1733.                 if (rc == NGX_AGAIN) {
  1734.                     break;
  1735.                 }

  1736.                 if (rc == NGX_OK) {

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

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

  1741.                     if (ctx->name.len && ctx->name.data[0] == ':') {
  1742.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1743.                                       "upstream sent invalid "
  1744.                                       "trailer \"%V: %V\"",
  1745.                                       &ctx->name, &ctx->value);
  1746.                         return NGX_ERROR;
  1747.                     }

  1748.                     h = ngx_list_push(&u->headers_in.trailers);
  1749.                     if (h == NULL) {
  1750.                         return NGX_ERROR;
  1751.                     }

  1752.                     h->key = ctx->name;
  1753.                     h->value = ctx->value;
  1754.                     h->lowcase_key = h->key.data;
  1755.                     h->hash = ngx_hash_key(h->key.data, h->key.len);

  1756.                     continue;
  1757.                 }

  1758.                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

  1762.                     if (ctx->end_stream) {
  1763.                         ctx->done = 1;
  1764.                         break;
  1765.                     }

  1766.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1767.                                   "upstream sent trailer without "
  1768.                                   "end stream flag");
  1769.                     return NGX_ERROR;
  1770.                 }

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

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

  1774.                 return NGX_ERROR;
  1775.             }

  1776.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1777.                 continue;
  1778.             }

  1779.             /* rc == NGX_AGAIN */

  1780.             if (ctx->rest == 0) {
  1781.                 ctx->state = ngx_http_proxy_v2_st_start;
  1782.                 continue;
  1783.             }

  1784.             return NGX_AGAIN;
  1785.         }

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

  1787.             /* priority, unknown frames */

  1788.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1789.             if (rc == NGX_AGAIN) {
  1790.                 return NGX_AGAIN;
  1791.             }

  1792.             continue;
  1793.         }

  1794.         /*
  1795.          * data frame:
  1796.          *
  1797.          * +---------------+
  1798.          * |Pad Length? (8)|
  1799.          * +---------------+-----------------------------------------------+
  1800.          * |                            Data (*)                         ...
  1801.          * +---------------------------------------------------------------+
  1802.          * |                           Padding (*)                       ...
  1803.          * +---------------------------------------------------------------+
  1804.          */

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

  1806.             if (ctx->rest == 0) {
  1807.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1808.                               "upstream sent too short http2 frame");
  1809.                 return NGX_ERROR;
  1810.             }

  1811.             if (b->pos == b->last) {
  1812.                 return NGX_AGAIN;
  1813.             }

  1814.             ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
  1815.             ctx->padding = *b->pos++;
  1816.             ctx->rest -= 1;

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

  1824.             continue;
  1825.         }

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

  1827.             if (ctx->padding) {
  1828.                 ctx->state = ngx_http_proxy_v2_st_padding;

  1829.             } else {
  1830.                 ctx->state = ngx_http_proxy_v2_st_start;

  1831.                 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1832.                     ctx->done = 1;
  1833.                 }
  1834.             }

  1835.             continue;
  1836.         }

  1837.         if (b->pos == b->last) {
  1838.             return NGX_AGAIN;
  1839.         }

  1840.         return NGX_OK;
  1841.     }
  1842. }


  1843. static ngx_int_t
  1844. ‌ngx_http_proxy_v2_parse_frame(ngx_http_request_t *r,
  1845.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1846. {
  1847.     u_char                     ch, *p;
  1848.     ngx_http_proxy_v2_state_e  state;

  1849.     state = ctx->state;

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

  1852. #if 0
  1853.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1854.                        "http proxy frame byte: %02Xd, s:%d", ch, state);
  1855. #endif

  1856.         switch (state) {

  1857.         case ngx_http_proxy_v2_st_start:
  1858.             ctx->rest = ch << 16;
  1859.             state = ngx_http_proxy_v2_st_length_2;
  1860.             break;

  1861.         case ngx_http_proxy_v2_st_length_2:
  1862.             ctx->rest |= ch << 8;
  1863.             state = ngx_http_proxy_v2_st_length_3;
  1864.             break;

  1865.         case ngx_http_proxy_v2_st_length_3:
  1866.             ctx->rest |= ch;

  1867.             if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  1868.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1869.                               "upstream sent too large http2 frame: %uz",
  1870.                               ctx->rest);
  1871.                 return NGX_ERROR;
  1872.             }

  1873.             state = ngx_http_proxy_v2_st_type;
  1874.             break;

  1875.         case ngx_http_proxy_v2_st_type:
  1876.             ctx->type = ch;
  1877.             state = ngx_http_proxy_v2_st_flags;
  1878.             break;

  1879.         case ngx_http_proxy_v2_st_flags:
  1880.             ctx->flags = ch;
  1881.             state = ngx_http_proxy_v2_st_stream_id;
  1882.             break;

  1883.         case ngx_http_proxy_v2_st_stream_id:
  1884.             ctx->stream_id = (ch & 0x7f) << 24;
  1885.             state = ngx_http_proxy_v2_st_stream_id_2;
  1886.             break;

  1887.         case ngx_http_proxy_v2_st_stream_id_2:
  1888.             ctx->stream_id |= ch << 16;
  1889.             state = ngx_http_proxy_v2_st_stream_id_3;
  1890.             break;

  1891.         case ngx_http_proxy_v2_st_stream_id_3:
  1892.             ctx->stream_id |= ch << 8;
  1893.             state = ngx_http_proxy_v2_st_stream_id_4;
  1894.             break;

  1895.         case ngx_http_proxy_v2_st_stream_id_4:
  1896.             ctx->stream_id |= ch;

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

  1900.             b->pos = p + 1;

  1901.             ctx->state = ngx_http_proxy_v2_st_payload;
  1902.             ctx->frame_state = 0;

  1903.             return NGX_OK;

  1904.         /* suppress warning */
  1905.         case ngx_http_proxy_v2_st_payload:
  1906.         case ngx_http_proxy_v2_st_padding:
  1907.             break;
  1908.         }
  1909.     }

  1910.     b->pos = p;
  1911.     ctx->state = state;

  1912.     return NGX_AGAIN;
  1913. }


  1914. static ngx_int_t
  1915. ‌ngx_http_proxy_v2_parse_header(ngx_http_request_t *r,
  1916.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  1917. {
  1918.     u_char     ch, *p, *last;
  1919.     size_t     min;
  1920.     ngx_int_t  rc;
  1921. ‌    enum {
  1922.         sw_start = 0,
  1923.         sw_padding_length,
  1924.         sw_dependency,
  1925.         sw_dependency_2,
  1926.         sw_dependency_3,
  1927.         sw_dependency_4,
  1928.         sw_weight,
  1929.         sw_fragment,
  1930.         sw_padding
  1931.     } state;

  1932.     state = ctx->frame_state;

  1933.     if (state == sw_start) {

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

  1936.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
  1937.             ctx->parsing_headers = 1;
  1938.             ctx->fragment_state = 0;
  1939.             ctx->header_limit = r->upstream->conf->buffer_size;

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

  1942.             if (ctx->rest < min) {
  1943.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1944.                               "upstream sent headers frame "
  1945.                               "with invalid length: %uz",
  1946.                               ctx->rest);
  1947.                 return NGX_ERROR;
  1948.             }

  1949.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1950.                 ctx->end_stream = 1;
  1951.             }

  1952.             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
  1953.                 state = sw_padding_length;

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

  1956.             } else {
  1957.                 state = sw_fragment;
  1958.             }

  1959.         } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
  1960.             state = sw_fragment;
  1961.         }

  1962.         ctx->padding = 0;
  1963.         ctx->frame_state = state;
  1964.     }

  1965.     if (state < sw_fragment) {

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

  1968.         } else {
  1969.             last = b->pos + ctx->rest;
  1970.         }

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

  1973. #if 0
  1974.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1975.                            "http proxy header byte: %02Xd s:%d", ch, state);
  1976. #endif

  1977.             /*
  1978.              * headers frame:
  1979.              *
  1980.              * +---------------+
  1981.              * |Pad Length? (8)|
  1982.              * +-+-------------+----------------------------------------------+
  1983.              * |E|                 Stream Dependency? (31)                    |
  1984.              * +-+-------------+----------------------------------------------+
  1985.              * |  Weight? (8)  |
  1986.              * +-+-------------+----------------------------------------------+
  1987.              * |                   Header Block Fragment (*)                ...
  1988.              * +--------------------------------------------------------------+
  1989.              * |                           Padding (*)                      ...
  1990.              * +--------------------------------------------------------------+
  1991.              */

  1992.             switch (state) {

  1993.             case sw_padding_length:

  1994.                 ctx->padding = ch;

  1995.                 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
  1996.                     state = sw_dependency;
  1997.                     break;
  1998.                 }

  1999.                 goto fragment;

  2000.             case sw_dependency:
  2001.                 state = sw_dependency_2;
  2002.                 break;

  2003.             case sw_dependency_2:
  2004.                 state = sw_dependency_3;
  2005.                 break;

  2006.             case sw_dependency_3:
  2007.                 state = sw_dependency_4;
  2008.                 break;

  2009.             case sw_dependency_4:
  2010.                 state = sw_weight;
  2011.                 break;

  2012.             case sw_weight:
  2013.                 goto fragment;

  2014.             /* suppress warning */
  2015.             case sw_start:
  2016.             case sw_fragment:
  2017.             case sw_padding:
  2018.                 break;
  2019.             }
  2020.         }

  2021.         ctx->rest -= p - b->pos;
  2022.         b->pos = p;

  2023.         ctx->frame_state = state;
  2024.         return NGX_AGAIN;

  2025.     fragment:

  2026.         p++;
  2027.         ctx->rest -= p - b->pos;
  2028.         b->pos = p;

  2029.         if (ctx->padding > ctx->rest) {
  2030.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2031.                           "upstream sent http2 frame with too long "
  2032.                           "padding: %d in frame %uz",
  2033.                           ctx->padding, ctx->rest);
  2034.             return NGX_ERROR;
  2035.         }

  2036.         state = sw_fragment;
  2037.         ctx->frame_state = state;
  2038.     }

  2039.     if (state == sw_fragment) {

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

  2041.         if (rc == NGX_AGAIN) {
  2042.             return NGX_AGAIN;
  2043.         }

  2044.         if (rc == NGX_ERROR) {
  2045.             return NGX_ERROR;
  2046.         }

  2047.         if (rc == NGX_OK) {
  2048.             return NGX_OK;
  2049.         }

  2050.         /* rc == NGX_DONE */

  2051.         state = sw_padding;
  2052.         ctx->frame_state = state;
  2053.     }

  2054.     if (state == sw_padding) {

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

  2056.             ctx->rest -= b->last - b->pos;
  2057.             b->pos = b->last;

  2058.             return NGX_AGAIN;
  2059.         }

  2060.         b->pos += ctx->rest;
  2061.         ctx->rest = 0;

  2062.         ctx->state = ngx_http_proxy_v2_st_start;

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

  2064.             if (ctx->fragment_state) {
  2065.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2066.                               "upstream sent truncated http2 header");
  2067.                 return NGX_ERROR;
  2068.             }

  2069.             ctx->parsing_headers = 0;

  2070.             return NGX_HTTP_PARSE_HEADER_DONE;
  2071.         }

  2072.         return NGX_AGAIN;
  2073.     }

  2074.     /* unreachable */

  2075.     return NGX_ERROR;
  2076. }


  2077. static ngx_int_t
  2078. ‌ngx_http_proxy_v2_parse_fragment(ngx_http_request_t *r,
  2079.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2080. {
  2081.     u_char      ch, *p, *last;
  2082.     size_t      len, size;
  2083.     ngx_uint_t  index, size_update;
  2084. ‌    enum {
  2085.         sw_start = 0,
  2086.         sw_index,
  2087.         sw_name_length,
  2088.         sw_name_length_2,
  2089.         sw_name_length_3,
  2090.         sw_name_length_4,
  2091.         sw_name,
  2092.         sw_name_bytes,
  2093.         sw_value_length,
  2094.         sw_value_length_2,
  2095.         sw_value_length_3,
  2096.         sw_value_length_4,
  2097.         sw_value,
  2098.         sw_value_bytes
  2099.     } state;

  2100.     /* header block fragment */

  2101. #if 0
  2102.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2103.                    "http proxy header fragment %p:%p rest:%uz",
  2104.                    b->pos, b->last, ctx->rest);
  2105. #endif

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

  2108.     } else {
  2109.         last = b->pos + ctx->rest - ctx->padding;
  2110.     }

  2111.     state = ctx->fragment_state;

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

  2114. #if 0
  2115.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2116.                        "http proxy header byte: %02Xd s:%d", ch, state);
  2117. #endif

  2118.         switch (state) {

  2119.         case sw_start:
  2120.             ctx->index = 0;

  2121.             if ((ch & 0x80) == 0x80) {
  2122.                 /*
  2123.                  * indexed header:
  2124.                  *
  2125.                  *   0   1   2   3   4   5   6   7
  2126.                  * +---+---+---+---+---+---+---+---+
  2127.                  * | 1 |        Index (7+)         |
  2128.                  * +---+---------------------------+
  2129.                  */

  2130.                 index = ch & ~0x80;

  2131.                 if (index == 0 || index > 61) {
  2132.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2133.                                   "upstream sent invalid http2 "
  2134.                                   "table index: %ui", index);
  2135.                     return NGX_ERROR;
  2136.                 }

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

  2139.                 ctx->index = index;
  2140.                 ctx->literal = 0;

  2141.                 goto done;

  2142.             } else if ((ch & 0xc0) == 0x40) {
  2143.                 /*
  2144.                  * literal header with incremental indexing:
  2145.                  *
  2146.                  *   0   1   2   3   4   5   6   7
  2147.                  * +---+---+---+---+---+---+---+---+
  2148.                  * | 0 | 1 |      Index (6+)       |
  2149.                  * +---+---+-----------------------+
  2150.                  * | H |     Value Length (7+)     |
  2151.                  * +---+---------------------------+
  2152.                  * | Value String (Length octets)  |
  2153.                  * +-------------------------------+
  2154.                  *
  2155.                  *   0   1   2   3   4   5   6   7
  2156.                  * +---+---+---+---+---+---+---+---+
  2157.                  * | 0 | 1 |           0           |
  2158.                  * +---+---+-----------------------+
  2159.                  * | H |     Name Length (7+)      |
  2160.                  * +---+---------------------------+
  2161.                  * |  Name String (Length octets)  |
  2162.                  * +---+---------------------------+
  2163.                  * | H |     Value Length (7+)     |
  2164.                  * +---+---------------------------+
  2165.                  * | Value String (Length octets)  |
  2166.                  * +-------------------------------+
  2167.                  */

  2168.                 index = ch & ~0xc0;

  2169.                 if (index > 61) {
  2170.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2171.                                   "upstream sent invalid http2 "
  2172.                                   "table index: %ui", index);
  2173.                     return NGX_ERROR;
  2174.                 }

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

  2177.                 if (index == 0) {
  2178.                     state = sw_name_length;
  2179.                     break;
  2180.                 }

  2181.                 ctx->index = index;
  2182.                 ctx->literal = 1;

  2183.                 state = sw_value_length;
  2184.                 break;

  2185.             } else if ((ch & 0xe0) == 0x20) {
  2186.                 /*
  2187.                  * dynamic table size update:
  2188.                  *
  2189.                  *   0   1   2   3   4   5   6   7
  2190.                  * +---+---+---+---+---+---+---+---+
  2191.                  * | 0 | 0 | 1 |   Max size (5+)   |
  2192.                  * +---+---------------------------+
  2193.                  */

  2194.                 size_update = ch & ~0xe0;

  2195.                 if (size_update > 0) {
  2196.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2197.                                   "upstream sent invalid http2 "
  2198.                                   "dynamic table size update: %ui",
  2199.                                   size_update);
  2200.                     return NGX_ERROR;
  2201.                 }

  2202.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2203.                                "http proxy table size update: %ui",
  2204.                                size_update);

  2205.                 break;

  2206.             } else if ((ch & 0xf0) == 0x10) {
  2207.                 /*
  2208.                  *  literal header field never indexed:
  2209.                  *
  2210.                  *   0   1   2   3   4   5   6   7
  2211.                  * +---+---+---+---+---+---+---+---+
  2212.                  * | 0 | 0 | 0 | 1 |  Index (4+)   |
  2213.                  * +---+---+-----------------------+
  2214.                  * | H |     Value Length (7+)     |
  2215.                  * +---+---------------------------+
  2216.                  * | Value String (Length octets)  |
  2217.                  * +-------------------------------+
  2218.                  *
  2219.                  *   0   1   2   3   4   5   6   7
  2220.                  * +---+---+---+---+---+---+---+---+
  2221.                  * | 0 | 0 | 0 | 1 |       0       |
  2222.                  * +---+---+-----------------------+
  2223.                  * | H |     Name Length (7+)      |
  2224.                  * +---+---------------------------+
  2225.                  * |  Name String (Length octets)  |
  2226.                  * +---+---------------------------+
  2227.                  * | H |     Value Length (7+)     |
  2228.                  * +---+---------------------------+
  2229.                  * | Value String (Length octets)  |
  2230.                  * +-------------------------------+
  2231.                  */

  2232.                 index = ch & ~0xf0;

  2233.                 if (index == 0x0f) {
  2234.                     ctx->index = index;
  2235.                     ctx->literal = 1;
  2236.                     state = sw_index;
  2237.                     break;
  2238.                 }

  2239.                 if (index == 0) {
  2240.                     state = sw_name_length;
  2241.                     break;
  2242.                 }

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

  2246.                 ctx->index = index;
  2247.                 ctx->literal = 1;

  2248.                 state = sw_value_length;
  2249.                 break;

  2250.             } else if ((ch & 0xf0) == 0x00) {
  2251.                 /*
  2252.                  * literal header field without indexing:
  2253.                  *
  2254.                  *   0   1   2   3   4   5   6   7
  2255.                  * +---+---+---+---+---+---+---+---+
  2256.                  * | 0 | 0 | 0 | 0 |  Index (4+)   |
  2257.                  * +---+---+-----------------------+
  2258.                  * | H |     Value Length (7+)     |
  2259.                  * +---+---------------------------+
  2260.                  * | Value String (Length octets)  |
  2261.                  * +-------------------------------+
  2262.                  *
  2263.                  *   0   1   2   3   4   5   6   7
  2264.                  * +---+---+---+---+---+---+---+---+
  2265.                  * | 0 | 0 | 0 | 0 |       0       |
  2266.                  * +---+---+-----------------------+
  2267.                  * | H |     Name Length (7+)      |
  2268.                  * +---+---------------------------+
  2269.                  * |  Name String (Length octets)  |
  2270.                  * +---+---------------------------+
  2271.                  * | H |     Value Length (7+)     |
  2272.                  * +---+---------------------------+
  2273.                  * | Value String (Length octets)  |
  2274.                  * +-------------------------------+
  2275.                  */

  2276.                 index = ch & ~0xf0;

  2277.                 if (index == 0x0f) {
  2278.                     ctx->index = index;
  2279.                     ctx->literal = 1;
  2280.                     state = sw_index;
  2281.                     break;
  2282.                 }

  2283.                 if (index == 0) {
  2284.                     state = sw_name_length;
  2285.                     break;
  2286.                 }

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

  2290.                 ctx->index = index;
  2291.                 ctx->literal = 1;

  2292.                 state = sw_value_length;
  2293.                 break;
  2294.             }

  2295.             /* not reached */

  2296.             return NGX_ERROR;

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

  2299.             if (ch & 0x80) {
  2300.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2301.                               "upstream sent http2 table index "
  2302.                               "with continuation flag");
  2303.                 return NGX_ERROR;
  2304.             }

  2305.             if (ctx->index > 61) {
  2306.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2307.                               "upstream sent invalid http2 "
  2308.                               "table index: %ui", ctx->index);
  2309.                 return NGX_ERROR;
  2310.             }

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

  2313.             state = sw_value_length;
  2314.             break;

  2315.         case sw_name_length:
  2316.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2317.             ctx->field_length = ch & ~0x80;

  2318.             if (ctx->field_length == 0x7f) {
  2319.                 state = sw_name_length_2;
  2320.                 break;
  2321.             }

  2322.             if (ctx->field_length == 0) {
  2323.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2324.                               "upstream sent zero http2 "
  2325.                               "header name length");
  2326.                 return NGX_ERROR;
  2327.             }

  2328.             state = sw_name;
  2329.             break;

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

  2332.             if (ch & 0x80) {
  2333.                 state = sw_name_length_3;
  2334.                 break;
  2335.             }

  2336.             state = sw_name;
  2337.             break;

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

  2340.             if (ch & 0x80) {
  2341.                 state = sw_name_length_4;
  2342.                 break;
  2343.             }

  2344.             state = sw_name;
  2345.             break;

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

  2348.             if (ch & 0x80) {
  2349.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2350.                               "upstream sent too large http2 "
  2351.                               "header name length");
  2352.                 return NGX_ERROR;
  2353.             }

  2354.             state = sw_name;
  2355.             break;

  2356.         case sw_name:
  2357.             ctx->name.len = ctx->field_huffman ?
  2358.                             ctx->field_length * 8 / 5 : ctx->field_length;

  2359.             if (ctx->name.len > ctx->header_limit) {
  2360.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2361.                               "upstream sent too large http2 "
  2362.                               "header name length: %uz",
  2363.                               ctx->name.len);
  2364.                 return NGX_ERROR;
  2365.             }

  2366.             ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
  2367.             if (ctx->name.data == NULL) {
  2368.                 return NGX_ERROR;
  2369.             }

  2370.             ctx->field_end = ctx->name.data;
  2371.             ctx->field_rest = ctx->field_length;
  2372.             ctx->field_state = 0;

  2373.             state = sw_name_bytes;

  2374.             /* fall through */

  2375.         case sw_name_bytes:

  2376.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2377.                            "http proxy name: len:%uz h:%d last:%uz, rest:%uz",
  2378.                            ctx->field_length,
  2379.                            ctx->field_huffman,
  2380.                            last - p,
  2381.                            ctx->rest - (p - b->pos));

  2382.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2383.             ctx->field_rest -= size;

  2384.             if (ctx->field_huffman) {
  2385.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2386.                                          &ctx->field_end,
  2387.                                          ctx->field_rest == 0,
  2388.                                          r->connection->log)
  2389.                     != NGX_OK)
  2390.                 {
  2391.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2392.                                   "upstream sent invalid encoded header");
  2393.                     return NGX_ERROR;
  2394.                 }

  2395.                 ctx->name.len = ctx->field_end - ctx->name.data;
  2396.                 ctx->name.data[ctx->name.len] = '\0';

  2397.             } else {
  2398.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2399.                 ctx->name.data[ctx->name.len] = '\0';
  2400.             }

  2401.             p += size - 1;

  2402.             if (ctx->field_rest == 0) {
  2403.                 state = sw_value_length;
  2404.             }

  2405.             break;

  2406.         case sw_value_length:
  2407.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2408.             ctx->field_length = ch & ~0x80;

  2409.             if (ctx->field_length == 0x7f) {
  2410.                 state = sw_value_length_2;
  2411.                 break;
  2412.             }

  2413.             if (ctx->field_length == 0) {
  2414.                 ngx_str_set(&ctx->value, "");
  2415.                 goto done;
  2416.             }

  2417.             state = sw_value;
  2418.             break;

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

  2421.             if (ch & 0x80) {
  2422.                 state = sw_value_length_3;
  2423.                 break;
  2424.             }

  2425.             state = sw_value;
  2426.             break;

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

  2429.             if (ch & 0x80) {
  2430.                 state = sw_value_length_4;
  2431.                 break;
  2432.             }

  2433.             state = sw_value;
  2434.             break;

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

  2437.             if (ch & 0x80) {
  2438.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2439.                               "upstream sent too large http2 "
  2440.                               "header value length");
  2441.                 return NGX_ERROR;
  2442.             }

  2443.             state = sw_value;
  2444.             break;

  2445.         case sw_value:
  2446.             ctx->value.len = ctx->field_huffman ?
  2447.                              ctx->field_length * 8 / 5 : ctx->field_length;

  2448.             if (ctx->value.len > ctx->header_limit) {
  2449.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2450.                               "upstream sent too large http2 "
  2451.                               "header value length: %uz",
  2452.                               ctx->value.len);
  2453.                 return NGX_ERROR;
  2454.             }

  2455.             ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
  2456.             if (ctx->value.data == NULL) {
  2457.                 return NGX_ERROR;
  2458.             }

  2459.             ctx->field_end = ctx->value.data;
  2460.             ctx->field_rest = ctx->field_length;
  2461.             ctx->field_state = 0;

  2462.             state = sw_value_bytes;

  2463.             /* fall through */

  2464.         case sw_value_bytes:

  2465.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2466.                            "http proxy value: len:%uz h:%d last:%uz, rest:%uz",
  2467.                            ctx->field_length,
  2468.                            ctx->field_huffman,
  2469.                            last - p,
  2470.                            ctx->rest - (p - b->pos));

  2471.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2472.             ctx->field_rest -= size;

  2473.             if (ctx->field_huffman) {
  2474.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2475.                                          &ctx->field_end,
  2476.                                          ctx->field_rest == 0,
  2477.                                          r->connection->log)
  2478.                     != NGX_OK)
  2479.                 {
  2480.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2481.                                   "upstream sent invalid encoded header");
  2482.                     return NGX_ERROR;
  2483.                 }

  2484.                 ctx->value.len = ctx->field_end - ctx->value.data;
  2485.                 ctx->value.data[ctx->value.len] = '\0';

  2486.             } else {
  2487.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2488.                 ctx->value.data[ctx->value.len] = '\0';
  2489.             }

  2490.             p += size - 1;

  2491.             if (ctx->field_rest == 0) {
  2492.                 goto done;
  2493.             }

  2494.             break;
  2495.         }

  2496.         continue;

  2497.     done:

  2498.         p++;
  2499.         ctx->rest -= p - b->pos;
  2500.         ctx->fragment_state = sw_start;
  2501.         b->pos = p;

  2502.         if (ctx->index) {
  2503.             ctx->name = *ngx_http_v2_get_static_name(ctx->index);
  2504.         }

  2505.         if (ctx->index && !ctx->literal) {
  2506.             ctx->value = *ngx_http_v2_get_static_value(ctx->index);
  2507.         }

  2508.         if (!ctx->index) {
  2509.             if (ngx_http_proxy_v2_validate_header_name(r, &ctx->name)
  2510.                 != NGX_OK)
  2511.             {
  2512.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2513.                               "upstream sent invalid header: \"%V: %V\"",
  2514.                               &ctx->name, &ctx->value);
  2515.                 return NGX_ERROR;
  2516.             }
  2517.         }

  2518.         if (!ctx->index || ctx->literal) {
  2519.             if (ngx_http_proxy_v2_validate_header_value(r, &ctx->value)
  2520.                 != NGX_OK)
  2521.             {
  2522.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2523.                               "upstream sent invalid header: \"%V: %V\"",
  2524.                               &ctx->name, &ctx->value);
  2525.                 return NGX_ERROR;
  2526.             }
  2527.         }

  2528.         len = ctx->name.len + ctx->value.len;

  2529.         if (len > ctx->header_limit) {
  2530.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2531.                           "upstream sent too large http2 header");
  2532.             return NGX_ERROR;
  2533.         }

  2534.         ctx->header_limit -= len;

  2535.         return NGX_OK;
  2536.     }

  2537.     ctx->rest -= p - b->pos;
  2538.     ctx->fragment_state = state;
  2539.     b->pos = p;

  2540.     if (ctx->rest > ctx->padding) {
  2541.         return NGX_AGAIN;
  2542.     }

  2543.     return NGX_DONE;
  2544. }


  2545. static ngx_int_t
  2546. ‌ngx_http_proxy_v2_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
  2547. {
  2548.     u_char      ch;
  2549.     ngx_uint_t  i;

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

  2552.         if (ch == ':' && i > 0) {
  2553.             return NGX_ERROR;
  2554.         }

  2555.         if (ch >= 'A' && ch <= 'Z') {
  2556.             return NGX_ERROR;
  2557.         }

  2558.         if (ch <= 0x20 || ch == 0x7f) {
  2559.             return NGX_ERROR;
  2560.         }
  2561.     }

  2562.     return NGX_OK;
  2563. }


  2564. static ngx_int_t
  2565. ‌ngx_http_proxy_v2_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
  2566. {
  2567.     u_char      ch;
  2568.     ngx_uint_t  i;

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

  2571.         if (ch == '\0' || ch == CR || ch == LF) {
  2572.             return NGX_ERROR;
  2573.         }
  2574.     }

  2575.     return NGX_OK;
  2576. }


  2577. static ngx_int_t
  2578. ‌ngx_http_proxy_v2_parse_rst_stream(ngx_http_request_t *r,
  2579.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2580. {
  2581.     u_char  ch, *p, *last;
  2582. ‌    enum {
  2583.         sw_start = 0,
  2584.         sw_error_2,
  2585.         sw_error_3,
  2586.         sw_error_4
  2587.     } state;

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

  2590.     } else {
  2591.         last = b->pos + ctx->rest;
  2592.     }

  2593.     state = ctx->frame_state;

  2594.     if (state == sw_start) {
  2595.         if (ctx->rest != 4) {
  2596.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2597.                           "upstream sent rst stream frame "
  2598.                           "with invalid length: %uz",
  2599.                           ctx->rest);
  2600.             return NGX_ERROR;
  2601.         }
  2602.     }

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

  2605. #if 0
  2606.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2607.                        "http proxy rst byte: %02Xd s:%d", ch, state);
  2608. #endif

  2609.         switch (state) {

  2610.         case sw_start:
  2611.             ctx->error = (ngx_uint_t) ch << 24;
  2612.             state = sw_error_2;
  2613.             break;

  2614.         case sw_error_2:
  2615.             ctx->error |= ch << 16;
  2616.             state = sw_error_3;
  2617.             break;

  2618.         case sw_error_3:
  2619.             ctx->error |= ch << 8;
  2620.             state = sw_error_4;
  2621.             break;

  2622.         case sw_error_4:
  2623.             ctx->error |= ch;
  2624.             state = sw_start;

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

  2627.             break;
  2628.         }
  2629.     }

  2630.     ctx->rest -= p - b->pos;
  2631.     ctx->frame_state = state;
  2632.     b->pos = p;

  2633.     if (ctx->rest > 0) {
  2634.         return NGX_AGAIN;
  2635.     }

  2636.     ctx->state = ngx_http_proxy_v2_st_start;

  2637.     return NGX_OK;
  2638. }


  2639. static ngx_int_t
  2640. ‌ngx_http_proxy_v2_parse_goaway(ngx_http_request_t *r,
  2641.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2642. {
  2643.     u_char  ch, *p, *last;
  2644. ‌    enum {
  2645.         sw_start = 0,
  2646.         sw_last_stream_id_2,
  2647.         sw_last_stream_id_3,
  2648.         sw_last_stream_id_4,
  2649.         sw_error,
  2650.         sw_error_2,
  2651.         sw_error_3,
  2652.         sw_error_4,
  2653.         sw_debug
  2654.     } state;

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

  2657.     } else {
  2658.         last = b->pos + ctx->rest;
  2659.     }

  2660.     state = ctx->frame_state;

  2661.     if (state == sw_start) {

  2662.         if (ctx->stream_id) {
  2663.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2664.                           "upstream sent goaway frame "
  2665.                           "with non-zero stream id: %ui",
  2666.                           ctx->stream_id);
  2667.             return NGX_ERROR;
  2668.         }

  2669.         if (ctx->rest < 8) {
  2670.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2671.                           "upstream sent goaway frame "
  2672.                           "with invalid length: %uz",
  2673.                           ctx->rest);
  2674.             return NGX_ERROR;
  2675.         }
  2676.     }

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

  2679. #if 0
  2680.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2681.                        "http proxy goaway byte: %02Xd s:%d", ch, state);
  2682. #endif

  2683.         switch (state) {

  2684.         case sw_start:
  2685.             ctx->stream_id = (ch & 0x7f) << 24;
  2686.             state = sw_last_stream_id_2;
  2687.             break;

  2688.         case sw_last_stream_id_2:
  2689.             ctx->stream_id |= ch << 16;
  2690.             state = sw_last_stream_id_3;
  2691.             break;

  2692.         case sw_last_stream_id_3:
  2693.             ctx->stream_id |= ch << 8;
  2694.             state = sw_last_stream_id_4;
  2695.             break;

  2696.         case sw_last_stream_id_4:
  2697.             ctx->stream_id |= ch;
  2698.             state = sw_error;
  2699.             break;

  2700.         case sw_error:
  2701.             ctx->error = (ngx_uint_t) ch << 24;
  2702.             state = sw_error_2;
  2703.             break;

  2704.         case sw_error_2:
  2705.             ctx->error |= ch << 16;
  2706.             state = sw_error_3;
  2707.             break;

  2708.         case sw_error_3:
  2709.             ctx->error |= ch << 8;
  2710.             state = sw_error_4;
  2711.             break;

  2712.         case sw_error_4:
  2713.             ctx->error |= ch;
  2714.             state = sw_debug;
  2715.             break;

  2716.         case sw_debug:
  2717.             break;
  2718.         }
  2719.     }

  2720.     ctx->rest -= p - b->pos;
  2721.     ctx->frame_state = state;
  2722.     b->pos = p;

  2723.     if (ctx->rest > 0) {
  2724.         return NGX_AGAIN;
  2725.     }

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

  2729.     ctx->state = ngx_http_proxy_v2_st_start;

  2730.     return NGX_OK;
  2731. }


  2732. static ngx_int_t
  2733. ‌ngx_http_proxy_v2_parse_window_update(ngx_http_request_t *r,
  2734.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2735. {
  2736.     u_char  ch, *p, *last;
  2737. ‌    enum {
  2738.         sw_start = 0,
  2739.         sw_size_2,
  2740.         sw_size_3,
  2741.         sw_size_4
  2742.     } state;

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

  2745.     } else {
  2746.         last = b->pos + ctx->rest;
  2747.     }

  2748.     state = ctx->frame_state;

  2749.     if (state == sw_start) {
  2750.         if (ctx->rest != 4) {
  2751.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2752.                           "upstream sent window update frame "
  2753.                           "with invalid length: %uz",
  2754.                           ctx->rest);
  2755.             return NGX_ERROR;
  2756.         }
  2757.     }

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

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

  2764.         switch (state) {

  2765.         case sw_start:
  2766.             ctx->window_update = (ch & 0x7f) << 24;
  2767.             state = sw_size_2;
  2768.             break;

  2769.         case sw_size_2:
  2770.             ctx->window_update |= ch << 16;
  2771.             state = sw_size_3;
  2772.             break;

  2773.         case sw_size_3:
  2774.             ctx->window_update |= ch << 8;
  2775.             state = sw_size_4;
  2776.             break;

  2777.         case sw_size_4:
  2778.             ctx->window_update |= ch;
  2779.             state = sw_start;
  2780.             break;
  2781.         }
  2782.     }

  2783.     ctx->rest -= p - b->pos;
  2784.     ctx->frame_state = state;
  2785.     b->pos = p;

  2786.     if (ctx->rest > 0) {
  2787.         return NGX_AGAIN;
  2788.     }

  2789.     ctx->state = ngx_http_proxy_v2_st_start;

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

  2792.     if (ctx->window_update == 0) {
  2793.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2794.                       "upstream sent zero window update");
  2795.         return NGX_ERROR;
  2796.     }

  2797.     if (ctx->stream_id) {

  2798.         if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
  2799.                                  - ctx->send_window)
  2800.         {
  2801.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2802.                           "upstream sent too large window update");
  2803.             return NGX_ERROR;
  2804.         }

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

  2806.     } else {

  2807.         if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
  2808.                                  - ctx->connection->send_window)
  2809.         {
  2810.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2811.                           "upstream sent too large window update");
  2812.             return NGX_ERROR;
  2813.         }

  2814.         ctx->connection->send_window += ctx->window_update;
  2815.     }

  2816.     return NGX_OK;
  2817. }


  2818. static ngx_int_t
  2819. ‌ngx_http_proxy_v2_parse_settings(ngx_http_request_t *r,
  2820.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2821. {
  2822.     u_char   ch, *p, *last;
  2823.     ssize_t  window_update;
  2824. ‌    enum {
  2825.         sw_start = 0,
  2826.         sw_id,
  2827.         sw_id_2,
  2828.         sw_value,
  2829.         sw_value_2,
  2830.         sw_value_3,
  2831.         sw_value_4
  2832.     } state;

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

  2835.     } else {
  2836.         last = b->pos + ctx->rest;
  2837.     }

  2838.     state = ctx->frame_state;

  2839.     if (state == sw_start) {

  2840.         if (ctx->stream_id) {
  2841.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2842.                           "upstream sent settings frame "
  2843.                           "with non-zero stream id: %ui",
  2844.                           ctx->stream_id);
  2845.             return NGX_ERROR;
  2846.         }

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

  2850.             if (ctx->rest != 0) {
  2851.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2852.                               "upstream sent settings frame "
  2853.                               "with ack flag and non-zero length: %uz",
  2854.                               ctx->rest);
  2855.                 return NGX_ERROR;
  2856.             }

  2857.             ctx->state = ngx_http_proxy_v2_st_start;

  2858.             return NGX_OK;
  2859.         }

  2860.         if (ctx->rest % 6 != 0) {
  2861.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2862.                           "upstream sent settings frame "
  2863.                           "with invalid length: %uz",
  2864.                           ctx->rest);
  2865.             return NGX_ERROR;
  2866.         }

  2867.         if (ctx->free == NULL && ctx->settings++ > 1000) {
  2868.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2869.                           "upstream sent too many settings frames");
  2870.             return NGX_ERROR;
  2871.         }
  2872.     }

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

  2875. #if 0
  2876.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2877.                        "http proxy settings byte: %02Xd s:%d", ch, state);
  2878. #endif

  2879.         switch (state) {

  2880.         case sw_start:
  2881.         case sw_id:
  2882.             ctx->setting_id = ch << 8;
  2883.             state = sw_id_2;
  2884.             break;

  2885.         case sw_id_2:
  2886.             ctx->setting_id |= ch;
  2887.             state = sw_value;
  2888.             break;

  2889.         case sw_value:
  2890.             ctx->setting_value = (ngx_uint_t) ch << 24;
  2891.             state = sw_value_2;
  2892.             break;

  2893.         case sw_value_2:
  2894.             ctx->setting_value |= ch << 16;
  2895.             state = sw_value_3;
  2896.             break;

  2897.         case sw_value_3:
  2898.             ctx->setting_value |= ch << 8;
  2899.             state = sw_value_4;
  2900.             break;

  2901.         case sw_value_4:
  2902.             ctx->setting_value |= ch;
  2903.             state = sw_id;

  2904.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2905.                            "http proxy setting: %ui %ui",
  2906.                            ctx->setting_id, ctx->setting_value);

  2907.             /*
  2908.              * The following settings are defined by the protocol:
  2909.              *
  2910.              * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
  2911.              * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
  2912.              * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
  2913.              *
  2914.              * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
  2915.              * a simple client.
  2916.              */

  2917.             if (ctx->setting_id == 0x04) {
  2918.                 /* SETTINGS_INITIAL_WINDOW_SIZE */

  2919.                 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
  2920.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2921.                                   "upstream sent settings frame "
  2922.                                   "with too large initial window size: %ui",
  2923.                                   ctx->setting_value);
  2924.                     return NGX_ERROR;
  2925.                 }

  2926.                 window_update = ctx->setting_value
  2927.                                 - ctx->connection->init_window;
  2928.                 ctx->connection->init_window = ctx->setting_value;

  2929.                 if (ctx->send_window > 0
  2930.                     && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
  2931.                                        - ctx->send_window)
  2932.                 {
  2933.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2934.                                   "upstream sent settings frame "
  2935.                                   "with too large initial window size: %ui",
  2936.                                   ctx->setting_value);
  2937.                     return NGX_ERROR;
  2938.                 }

  2939.                 ctx->send_window += window_update;
  2940.             }

  2941.             break;
  2942.         }
  2943.     }

  2944.     ctx->rest -= p - b->pos;
  2945.     ctx->frame_state = state;
  2946.     b->pos = p;

  2947.     if (ctx->rest > 0) {
  2948.         return NGX_AGAIN;
  2949.     }

  2950.     ctx->state = ngx_http_proxy_v2_st_start;

  2951.     return ngx_http_proxy_v2_send_settings_ack(r, ctx);
  2952. }


  2953. static ngx_int_t
  2954. ‌ngx_http_proxy_v2_parse_ping(ngx_http_request_t *r,
  2955.     ngx_http_proxy_v2_ctx_t *ctx, ngx_buf_t *b)
  2956. {
  2957.     u_char  ch, *p, *last;
  2958. ‌    enum {
  2959.         sw_start = 0,
  2960.         sw_data_2,
  2961.         sw_data_3,
  2962.         sw_data_4,
  2963.         sw_data_5,
  2964.         sw_data_6,
  2965.         sw_data_7,
  2966.         sw_data_8
  2967.     } state;

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

  2970.     } else {
  2971.         last = b->pos + ctx->rest;
  2972.     }

  2973.     state = ctx->frame_state;

  2974.     if (state == sw_start) {

  2975.         if (ctx->stream_id) {
  2976.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2977.                           "upstream sent ping frame "
  2978.                           "with non-zero stream id: %ui",
  2979.                           ctx->stream_id);
  2980.             return NGX_ERROR;
  2981.         }

  2982.         if (ctx->rest != 8) {
  2983.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2984.                           "upstream sent ping frame "
  2985.                           "with invalid length: %uz",
  2986.                           ctx->rest);
  2987.             return NGX_ERROR;
  2988.         }

  2989.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  2990.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2991.                           "upstream sent ping frame with ack flag");
  2992.             return NGX_ERROR;
  2993.         }

  2994.         if (ctx->free == NULL && ctx->pings++ > 1000) {
  2995.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2996.                           "upstream sent too many ping frames");
  2997.             return NGX_ERROR;
  2998.         }
  2999.     }

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

  3002. #if 0
  3003.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3004.                        "http proxy ping byte: %02Xd s:%d", ch, state);
  3005. #endif

  3006.         if (state < sw_data_8) {
  3007.             ctx->ping_data[state] = ch;
  3008.             state++;

  3009.         } else {
  3010.             ctx->ping_data[7] = ch;
  3011.             state = sw_start;

  3012.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3013.                            "http proxy ping");
  3014.         }
  3015.     }

  3016.     ctx->rest -= p - b->pos;
  3017.     ctx->frame_state = state;
  3018.     b->pos = p;

  3019.     if (ctx->rest > 0) {
  3020.         return NGX_AGAIN;
  3021.     }

  3022.     ctx->state = ngx_http_proxy_v2_st_start;

  3023.     return ngx_http_proxy_v2_send_ping_ack(r, ctx);
  3024. }


  3025. static ngx_int_t
  3026. ‌ngx_http_proxy_v2_send_settings_ack(ngx_http_request_t *r,
  3027.     ngx_http_proxy_v2_ctx_t *ctx)
  3028. {
  3029.     ngx_chain_t                *cl, **ll;
  3030.     ngx_http_proxy_v2_frame_t  *f;

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

  3033.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3034.         ll = &cl->next;
  3035.     }

  3036.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  3037.     if (cl == NULL) {
  3038.         return NGX_ERROR;
  3039.     }

  3040.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3041.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3042.     f->length_0 = 0;
  3043.     f->length_1 = 0;
  3044.     f->length_2 = 0;
  3045.     f->type = NGX_HTTP_V2_SETTINGS_FRAME;
  3046.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  3047.     f->stream_id_0 = 0;
  3048.     f->stream_id_1 = 0;
  3049.     f->stream_id_2 = 0;
  3050.     f->stream_id_3 = 0;

  3051.     *ll = cl;

  3052.     return NGX_OK;
  3053. }


  3054. static ngx_int_t
  3055. ‌ngx_http_proxy_v2_send_ping_ack(ngx_http_request_t *r,
  3056.     ngx_http_proxy_v2_ctx_t *ctx)
  3057. {
  3058.     ngx_chain_t                *cl, **ll;
  3059.     ngx_http_proxy_v2_frame_t  *f;

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

  3062.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3063.         ll = &cl->next;
  3064.     }

  3065.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  3066.     if (cl == NULL) {
  3067.         return NGX_ERROR;
  3068.     }

  3069.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3070.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3071.     f->length_0 = 0;
  3072.     f->length_1 = 0;
  3073.     f->length_2 = 8;
  3074.     f->type = NGX_HTTP_V2_PING_FRAME;
  3075.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  3076.     f->stream_id_0 = 0;
  3077.     f->stream_id_1 = 0;
  3078.     f->stream_id_2 = 0;
  3079.     f->stream_id_3 = 0;

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

  3081.     *ll = cl;

  3082.     return NGX_OK;
  3083. }


  3084. static ngx_int_t
  3085. ‌ngx_http_proxy_v2_send_window_update(ngx_http_request_t *r,
  3086.     ngx_http_proxy_v2_ctx_t *ctx)
  3087. {
  3088.     size_t                      n;
  3089.     ngx_chain_t                *cl, **ll;
  3090.     ngx_http_proxy_v2_frame_t  *f;

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

  3094.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3095.         ll = &cl->next;
  3096.     }

  3097.     cl = ngx_http_proxy_v2_get_buf(r, ctx);
  3098.     if (cl == NULL) {
  3099.         return NGX_ERROR;
  3100.     }

  3101.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3102.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3103.     f->length_0 = 0;
  3104.     f->length_1 = 0;
  3105.     f->length_2 = 4;
  3106.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3107.     f->flags = 0;
  3108.     f->stream_id_0 = 0;
  3109.     f->stream_id_1 = 0;
  3110.     f->stream_id_2 = 0;
  3111.     f->stream_id_3 = 0;

  3112.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
  3113.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3114.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3115.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3116.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3117.     *cl->buf->last++ = (u_char) (n & 0xff);

  3118.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3119.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

  3120.     f->length_0 = 0;
  3121.     f->length_1 = 0;
  3122.     f->length_2 = 4;
  3123.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3124.     f->flags = 0;
  3125.     f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  3126.     f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  3127.     f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  3128.     f->stream_id_3 = (u_char) (ctx->id & 0xff);

  3129.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
  3130.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3131.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3132.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3133.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3134.     *cl->buf->last++ = (u_char) (n & 0xff);

  3135.     *ll = cl;

  3136.     return NGX_OK;
  3137. }


  3138. static ngx_chain_t *
  3139. ‌ngx_http_proxy_v2_get_buf(ngx_http_request_t *r, ngx_http_proxy_v2_ctx_t *ctx)
  3140. {
  3141.     u_char       *start;
  3142.     ngx_buf_t    *b;
  3143.     ngx_chain_t  *cl;

  3144.     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  3145.     if (cl == NULL) {
  3146.         return NULL;
  3147.     }

  3148.     b = cl->buf;
  3149.     start = b->start;

  3150.     if (start == NULL) {

  3151.         /*
  3152.          * each buffer is large enough to hold two window update
  3153.          * frames in a row
  3154.          */

  3155.         start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8);
  3156.         if (start == NULL) {
  3157.             return NULL;
  3158.         }

  3159.     }

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

  3161.     b->start = start;
  3162.     b->pos = start;
  3163.     b->last = start;
  3164.     b->end = start + 2 * sizeof(ngx_http_proxy_v2_frame_t) + 8;

  3165.     b->tag = (ngx_buf_tag_t) &ngx_http_proxy_v2_body_output_filter;
  3166.     b->temporary = 1;
  3167.     b->flush = 1;

  3168.     return cl;
  3169. }


  3170. static ngx_http_proxy_v2_ctx_t *
  3171. ‌ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r)
  3172. {
  3173.     ngx_http_upstream_t      *u;
  3174.     ngx_http_proxy_v2_ctx_t  *ctx;

  3175.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  3176.     if (ctx->connection == NULL) {
  3177.         u = r->upstream;

  3178.         if (ngx_http_proxy_v2_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
  3179.             return NULL;
  3180.         }
  3181.     }

  3182.     return ctx;
  3183. }


  3184. static ngx_int_t
  3185. ‌ngx_http_proxy_v2_get_connection_data(ngx_http_request_t *r,
  3186.     ngx_http_proxy_v2_ctx_t *ctx, ngx_peer_connection_t *pc)
  3187. {
  3188.     ngx_connection_t    *c;
  3189.     ngx_pool_cleanup_t  *cln;

  3190.     if (ngx_http_proxy_v2_cached(r)) {
  3191.         ctx->connection = ngx_palloc(r->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3192.         if (ctx->connection == NULL) {
  3193.             return NGX_ERROR;
  3194.         }

  3195.         ctx->id = 0;

  3196.         goto done;
  3197.     }

  3198.     c = pc->connection;

  3199.     if (pc->cached) {

  3200.         /*
  3201.          * for cached connections, connection data can be found
  3202.          * in the cleanup handler
  3203.          */

  3204.         for (cln = c->pool->cleanup; cln; cln = cln->next) {
  3205.             if (cln->handler == ngx_http_proxy_v2_cleanup) {
  3206.                 ctx->connection = cln->data;
  3207.                 break;
  3208.             }
  3209.         }

  3210.         if (ctx->connection == NULL) {
  3211.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  3212.                           "no connection data found for "
  3213.                           "keepalive http2 connection");
  3214.             return NGX_ERROR;
  3215.         }

  3216.         ctx->send_window = ctx->connection->init_window;
  3217.         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3218.         ctx->connection->last_stream_id += 2;
  3219.         ctx->id = ctx->connection->last_stream_id;

  3220.         return NGX_OK;
  3221.     }

  3222.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_proxy_v2_conn_t));
  3223.     if (cln == NULL) {
  3224.         return NGX_ERROR;
  3225.     }

  3226.     cln->handler = ngx_http_proxy_v2_cleanup;
  3227.     ctx->connection = cln->data;

  3228.     ctx->id = 1;

  3229. done:

  3230.     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3231.     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3232.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3233.     ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3234.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

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

  3236.     return NGX_OK;
  3237. }


  3238. static ngx_inline ngx_int_t
  3239. ‌ngx_http_proxy_v2_cached(ngx_http_request_t *r)
  3240. {
  3241. #if (NGX_HTTP_CACHE)
  3242.     return r->cached;
  3243. #else
  3244.     return 0;
  3245. #endif
  3246. }


  3247. static void
  3248. ‌ngx_http_proxy_v2_cleanup(void *data)
  3249. {
  3250. #if 0
  3251.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  3252.                    "http proxy cleanup");
  3253. #endif
  3254.     return;
  3255. }


  3256. static void
  3257. ‌ngx_http_proxy_v2_abort_request(ngx_http_request_t *r)
  3258. {
  3259.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3260.                    "abort proxy http2 request");
  3261.     return;
  3262. }


  3263. static void
  3264. ‌ngx_http_proxy_v2_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  3265. {
  3266.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3267.                    "finalize proxy http2 request");
  3268.     return;
  3269. }