src/http/modules/ngx_http_proxy_v2_module.c - nginx-1.31.4 nginx/ @ 8d9666701

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 {
  384.         ctx->ctx.internal_body_length = r->headers_in.content_length_n;
  385.     }

  386.     le.ip = headers->lengths->elts;
  387.     le.request = r;
  388.     le.flushed = 1;

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

  390.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  391.         key_len = lcode(&le);

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

  396.         if (val_len == 0) {
  397.             continue;
  398.         }

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

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

  409.         headers_len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
  410.                          + NGX_HTTP_V2_INT_OCTETS + val_len;

  411.         if (tmp_len < key_len) {
  412.             tmp_len = key_len;
  413.         }

  414.         if (tmp_len < val_len) {
  415.             tmp_len = val_len;
  416.         }
  417.     }

  418.     len += headers_len;

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

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

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

  427.                 part = part->next;
  428.                 header = part->elts;
  429.                 i = 0;
  430.             }

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

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

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

  448.             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
  449.                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;

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

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

  458.     /* continuation frames */

  459.     len += sizeof(ngx_http_proxy_v2_frame_t)
  460.            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);


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

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

  469.     cl->buf = b;
  470.     cl->next = NULL;

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

  475.     key_tmp = tmp + tmp_len;
  476.     val_tmp = tmp + 2 * tmp_len;

  477.     /* connection preface */

  478.     b->last = ngx_copy(b->last, ngx_http_proxy_v2_connection_start,
  479.                        sizeof(ngx_http_proxy_v2_connection_start) - 1);

  480.     /* headers frame */

  481.     headers_frame = b->last;

  482.     f = (ngx_http_proxy_v2_frame_t *) b->last;
  483.     b->last += sizeof(ngx_http_proxy_v2_frame_t);

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

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

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

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

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

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

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

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

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

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

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

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

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

  526.     } else if (unparsed_uri) {

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

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

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

  536.     } else {
  537.         p = val_tmp;

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

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

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

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

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

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

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

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

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

  563.     e.ip = headers->values->elts;
  564.     e.request = r;
  565.     e.flushed = 1;

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

  567.     headers_end = b->last + headers_len;

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

  569.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  570.         key_len = lcode(&le);

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

  575.         if (val_len == 0) {
  576.             e.skip = 1;

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

  582.             e.skip = 0;

  583.             continue;
  584.         }

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

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

  591.         e.pos = key_tmp;
  592.         e.end = key_tmp + tmp_len;

  593.         code = *(ngx_http_script_code_pt *) e.ip;
  594.         code((ngx_http_script_engine_t *) &e);

  595.         if (e.status) {
  596.             return NGX_ERROR;
  597.         }

  598.         key_len = e.pos - key_tmp;

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

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

  607.         e.pos = val_tmp;
  608.         e.end = val_tmp + tmp_len;

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

  614.         if (e.status) {
  615.             return NGX_ERROR;
  616.         }

  617.         val_len = e.pos - val_tmp;

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

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

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

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

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

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

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

  643.                 part = part->next;
  644.                 header = part->elts;
  645.                 i = 0;
  646.             }

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

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

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

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

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

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

  667.     /* update headers frame length */

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

  669.     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  670.         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  671.         next = 1;

  672.     } else {
  673.         next = 0;
  674.     }

  675.     f = (ngx_http_proxy_v2_frame_t *) headers_frame;

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

  679.     /* create additional continuation frames */

  680.     p = headers_frame;

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

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

  686.         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  687.             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  688.             next = 1;

  689.         } else {
  690.             next = 0;
  691.         }

  692.         f = (ngx_http_proxy_v2_frame_t *) p;

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

  703.     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;

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

  709.     if (r->request_body_no_buffering) {

  710.         u->request_bufs = cl;

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

  712.         body = u->request_bufs;
  713.         u->request_bufs = cl;

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

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

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

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

  728.             cl = cl->next;
  729.             cl->buf = b;

  730.             body = body->next;
  731.         }

  732.         b->last_buf = 1;

  733.     } else if (body_len) {

  734.         u->request_bufs = cl;

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

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

  743.         cl = cl->next;
  744.         cl->buf = b;

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

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

  755.         if (e.status) {
  756.             return NGX_ERROR;
  757.         }

  758.         b->last = e.pos;
  759.         b->last_buf = 1;

  760.     } else {
  761.         u->request_bufs = cl;

  762.         f = (ngx_http_proxy_v2_frame_t *) headers_frame;
  763.         f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  764.         b->last_buf = 1;
  765.     }

  766.     u->output.output_filter = ngx_http_proxy_v2_body_output_filter;
  767.     u->output.filter_ctx = r;

  768.     b->flush = 1;
  769.     cl->next = NULL;

  770.     return NGX_OK;
  771. }


  772. static ngx_int_t
  773. ngx_http_proxy_v2_reinit_request(ngx_http_request_t *r)
  774. {
  775.     ngx_http_proxy_v2_ctx_t  *ctx;

  776.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  777.     if (ctx == NULL) {
  778.         return NGX_OK;
  779.     }

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

  794.     return NGX_OK;
  795. }


  796. static ngx_int_t
  797. ngx_http_proxy_v2_body_output_filter(void *data, ngx_chain_t *in)
  798. {
  799.     ngx_http_request_t  *r = data;

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

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

  812.     ctx = ngx_http_proxy_v2_get_ctx(r);

  813.     if (ctx == NULL) {
  814.         return NGX_ERROR;
  815.     }

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

  821.     out = NULL;
  822.     ll = &out;

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

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

  827.         ctx->header_sent = 1;

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

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

  835.             p = b->pos;

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

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

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

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

  849.         *ll = ctx->in;
  850.         ll = &ctx->in->next;

  851.         ctx->in = ctx->in->next;
  852.     }

  853.     if (ctx->out) {
  854.         /* queued control frames */

  855.         *ll = ctx->out;

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

  859.         ctx->out = NULL;
  860.     }

  861.     f = NULL;
  862.     last = 0;

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

  864.     if (limit > ctx->connection->send_window) {
  865.         limit = ctx->connection->send_window;
  866.     }

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

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

  875.     in = ctx->in;

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

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

  886.         if (ngx_buf_special(in->buf)) {
  887.             goto next;
  888.         }

  889.         if (in->buf->in_file) {
  890.             file_pos = in->buf->file_pos;

  891.         } else {
  892.             pos = in->buf->pos;
  893.         }

  894.         next = 0;

  895.         do {

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

  900.             b = cl->buf;

  901.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  902.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

  903.             *ll = cl;
  904.             ll = &cl->next;

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

  909.             b = cl->buf;
  910.             start = b->start;

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

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

  916.             b->start = start;

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

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

  924.                 b->file_last = file_pos;
  925.                 len = (ngx_uint_t) (file_pos - b->file_pos);

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

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

  933.                 b->last = pos;
  934.                 len = (ngx_uint_t) (pos - b->pos);
  935.             }

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

  939.             b->last_buf = 0;
  940.             b->last_in_chain = 0;

  941.             *ll = cl;
  942.             ll = &cl->next;

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

  952.             limit -= len;
  953.             ctx->send_window -= len;
  954.             ctx->connection->send_window -= len;

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

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

  961.             if (in->buf->in_file) {
  962.                 in->buf->file_pos = file_pos;

  963.             } else {
  964.                 in->buf->pos = pos;
  965.             }

  966.             break;
  967.         }

  968.     next:

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

  972.         ln = in;
  973.         in = in->next;

  974.         ngx_free_chain(r->pool, ln);
  975.     }

  976.     ctx->in = in;

  977.     if (last) {

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

  980.         ctx->output_closed = 1;

  981.         if (f) {
  982.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

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

  988.             b = cl->buf;

  989.             f = (ngx_http_proxy_v2_frame_t *) b->last;
  990.             b->last += sizeof(ngx_http_proxy_v2_frame_t);

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

  1000.             *ll = cl;
  1001.             ll = &cl->next;
  1002.         }

  1003.         cl->buf->last_buf = 1;
  1004.     }

  1005.     *ll = NULL;

  1006. #if (NGX_DEBUG)

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

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

  1021. #endif

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

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

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

  1026.         /* mark original buffers as sent */

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

  1032.             cl->buf->shadow = NULL;
  1033.         }
  1034.     }

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

  1038.     if (rc == NGX_AGAIN) {
  1039.         ctx->output_blocked = 1;

  1040.     } else {
  1041.         ctx->output_blocked = 0;
  1042.     }

  1043.     if (ctx->done) {

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

  1049.         u = r->upstream;
  1050.         u->length = 0;
  1051.         u->pipe->length = 0;

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

  1061.         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
  1062.     }

  1063.     return rc;
  1064. }


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

  1077.     u = r->upstream;
  1078.     b = &u->buffer;
  1079.     pos = b->pos;

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

  1085.     ctx = ngx_http_proxy_v2_get_ctx(r);

  1086.     if (ctx == NULL) {
  1087.         return NGX_ERROR;
  1088.     }

  1089.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1090.     for ( ;; ) {

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

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

  1093.             if (rc == NGX_AGAIN) {

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

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

  1103.                 return NGX_AGAIN;
  1104.             }

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

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

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

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

  1134.         /* frame payload */

  1135.         if (!ngx_http_proxy_v2_cached(r)) {

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

  1138.                 if (rc == NGX_AGAIN) {
  1139.                     return NGX_AGAIN;
  1140.                 }

  1141.                 if (rc == NGX_ERROR) {
  1142.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1143.                 }

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

  1147.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1148.             }

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

  1150.             if (rc == NGX_AGAIN) {
  1151.                 return NGX_AGAIN;
  1152.             }

  1153.             if (rc == NGX_ERROR) {
  1154.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1155.             }

  1156.             if (rc == NGX_OK) {
  1157.                 continue;
  1158.             }
  1159.         }

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

  1164.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1165.             if (rc == NGX_AGAIN) {
  1166.                 return NGX_AGAIN;
  1167.             }

  1168.             continue;
  1169.         }

  1170.         /* headers */

  1171.         for ( ;; ) {

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

  1173.             if (rc == NGX_AGAIN) {
  1174.                 break;
  1175.             }

  1176.             if (rc == NGX_OK) {

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

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

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

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

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

  1197.                     status_line = &ctx->value;

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

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

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

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

  1218.                     u->headers_in.status_n = status;

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

  1222.                     ctx->status = 1;

  1223.                     continue;

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

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

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

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

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

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

  1244.                     if (rc != NGX_OK) {
  1245.                         return rc;
  1246.                     }
  1247.                 }

  1248.                 continue;
  1249.             }

  1250.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

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

  1260.                     ctx->status = 0;
  1261.                     return NGX_HTTP_UPSTREAM_EARLY_HINTS;
  1262.                 }

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

  1273.                 return NGX_OK;
  1274.             }

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

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

  1278.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1279.         }

  1280.         /* rc == NGX_AGAIN */

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

  1285.         return NGX_AGAIN;
  1286.     }
  1287. }


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

  1294.     u = r->upstream;
  1295.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1296.     if (ctx == NULL) {
  1297.         return NGX_ERROR;
  1298.     }

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

  1304.     } else {
  1305.         ctx->length = u->headers_in.content_length_n;
  1306.     }

  1307.     if (ctx->end_stream) {

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

  1313.         u->length = 0;
  1314.         u->pipe->length = 0;
  1315.         ctx->done = 1;

  1316.     } else {
  1317.         u->length = 1;
  1318.         u->pipe->length = 1;
  1319.     }

  1320.     return NGX_OK;
  1321. }


  1322. static ngx_int_t
  1323. ngx_http_proxy_v2_non_buffered_filter(void *data, ssize_t bytes)
  1324. {
  1325.     ngx_http_request_t   *r = data;

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

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

  1333.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1334.     if (ctx == NULL) {
  1335.         return NGX_ERROR;
  1336.     }

  1337.     u = r->upstream;
  1338.     b = &u->buffer;

  1339.     b->pos = b->last;
  1340.     b->last += bytes;

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

  1344.     for ( ;; ) {

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

  1346.         if (rc == NGX_OK) {

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

  1351.             *ll = cl;
  1352.             ll = &cl->next;

  1353.             buf = cl->buf;

  1354.             buf->flush = 1;
  1355.             buf->memory = 1;

  1356.             buf->pos = b->pos;
  1357.             buf->tag = u->output.tag;

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

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

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

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

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

  1376.                 ctx->length -= buf->last - buf->pos;
  1377.             }

  1378.             continue;
  1379.         }

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

  1384.         if (rc == NGX_AGAIN) {
  1385.             return NGX_AGAIN;
  1386.         }

  1387.         /* invalid response */

  1388.         return NGX_ERROR;
  1389.     }

  1390.     return NGX_OK;
  1391. }


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

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

  1403.     r = p->input_ctx;
  1404.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  1405.     if (ctx == NULL) {
  1406.         return NGX_ERROR;
  1407.     }

  1408.     buf = NULL;
  1409.     prev = &b->shadow;

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

  1412.     for ( ;; ) {

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

  1414.         if (rc == NGX_OK) {

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

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

  1420.             buf = cl->buf;

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

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

  1428.             *prev = buf;
  1429.             prev = &buf->shadow;

  1430.             if (p->in) {
  1431.                 *p->last_in = cl;

  1432.             } else {
  1433.                 p->in = cl;
  1434.             }

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

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

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

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

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

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

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

  1455.                 ctx->length -= buf->last - buf->pos;
  1456.             }

  1457.             continue;
  1458.         }

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

  1463.         if (rc == NGX_AGAIN) {
  1464.             break;
  1465.         }

  1466.         /* invalid response */

  1467.         return NGX_ERROR;
  1468.     }

  1469.     if (buf) {
  1470.         buf->shadow = b;
  1471.         buf->last_shadow = 1;

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

  1474.         return NGX_OK;
  1475.     }

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

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

  1480.     return NGX_OK;
  1481. }


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

  1488.     u = r->upstream;

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

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

  1491.         if (rc == NGX_AGAIN) {
  1492.             return NGX_AGAIN;
  1493.         }

  1494.         if (rc == NGX_ERROR) {
  1495.             return NGX_ERROR;
  1496.         }

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

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

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

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

  1510.             return NGX_ERROR;
  1511.         }

  1512.         ctx->goaway = 1;

  1513.         return NGX_OK;
  1514.     }

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

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

  1517.         if (rc == NGX_AGAIN) {
  1518.             return NGX_AGAIN;
  1519.         }

  1520.         if (rc == NGX_ERROR) {
  1521.             return NGX_ERROR;
  1522.         }

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

  1526.         return NGX_OK;
  1527.     }

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

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

  1530.         if (rc == NGX_AGAIN) {
  1531.             return NGX_AGAIN;
  1532.         }

  1533.         if (rc == NGX_ERROR) {
  1534.             return NGX_ERROR;
  1535.         }

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

  1539.         return NGX_OK;
  1540.     }

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

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

  1543.         if (rc == NGX_AGAIN) {
  1544.             return NGX_AGAIN;
  1545.         }

  1546.         if (rc == NGX_ERROR) {
  1547.             return NGX_ERROR;
  1548.         }

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

  1550.         return NGX_OK;
  1551.     }

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

  1557.     return NGX_DECLINED;
  1558. }


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

  1567.     b->pos += ctx->rest;
  1568.     ctx->rest = 0;
  1569.     ctx->state = ngx_http_proxy_v2_st_start;

  1570.     return NGX_OK;
  1571. }


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

  1579.     u = r->upstream;

  1580.     for ( ;; ) {

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

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

  1583.             if (rc == NGX_AGAIN) {

  1584.                 if (ctx->done) {

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

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

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

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

  1608.                     return NGX_DONE;
  1609.                 }

  1610.                 return NGX_AGAIN;
  1611.             }

  1612.             if (rc == NGX_ERROR) {
  1613.                 return NGX_ERROR;
  1614.             }

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

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

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

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

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

  1647.                 ctx->recv_window -= ctx->rest;
  1648.                 ctx->connection->recv_window -= ctx->rest;

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

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

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

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

  1676.             ctx->padding = 0;
  1677.         }

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

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

  1684.             b->pos += ctx->rest;
  1685.             ctx->rest = 0;
  1686.             ctx->state = ngx_http_proxy_v2_st_start;

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

  1690.             continue;
  1691.         }

  1692.         /* frame payload */

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

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

  1695.             if (rc == NGX_AGAIN) {
  1696.                 return NGX_AGAIN;
  1697.             }

  1698.             if (rc == NGX_ERROR) {
  1699.                 return NGX_ERROR;
  1700.             }

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

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

  1713.             ctx->rst = 1;

  1714.             continue;
  1715.         }

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

  1717.         if (rc == NGX_AGAIN) {
  1718.             return NGX_AGAIN;
  1719.         }

  1720.         if (rc == NGX_ERROR) {
  1721.             return NGX_ERROR;
  1722.         }

  1723.         if (rc == NGX_OK) {
  1724.             continue;
  1725.         }

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

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

  1731.                 if (rc == NGX_AGAIN) {
  1732.                     break;
  1733.                 }

  1734.                 if (rc == NGX_OK) {

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

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

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

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

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

  1754.                     continue;
  1755.                 }

  1756.                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

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

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

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

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

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

  1772.                 return NGX_ERROR;
  1773.             }

  1774.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1775.                 continue;
  1776.             }

  1777.             /* rc == NGX_AGAIN */

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

  1782.             return NGX_AGAIN;
  1783.         }

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

  1785.             /* priority, unknown frames */

  1786.             rc = ngx_http_proxy_v2_skip_frame(ctx, b);

  1787.             if (rc == NGX_AGAIN) {
  1788.                 return NGX_AGAIN;
  1789.             }

  1790.             continue;
  1791.         }

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

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

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

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

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

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

  1822.             continue;
  1823.         }

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

  1825.             if (ctx->padding) {
  1826.                 ctx->state = ngx_http_proxy_v2_st_padding;

  1827.             } else {
  1828.                 ctx->state = ngx_http_proxy_v2_st_start;

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

  1833.             continue;
  1834.         }

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

  1838.         return NGX_OK;
  1839.     }
  1840. }


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

  1847.     state = ctx->state;

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

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

  1854.         switch (state) {

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

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

  1863.         case ngx_http_proxy_v2_st_length_3:
  1864.             ctx->rest |= ch;

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

  1871.             state = ngx_http_proxy_v2_st_type;
  1872.             break;

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

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

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

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

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

  1893.         case ngx_http_proxy_v2_st_stream_id_4:
  1894.             ctx->stream_id |= ch;

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

  1898.             b->pos = p + 1;

  1899.             ctx->state = ngx_http_proxy_v2_st_payload;
  1900.             ctx->frame_state = 0;

  1901.             return NGX_OK;

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

  1908.     b->pos = p;
  1909.     ctx->state = state;

  1910.     return NGX_AGAIN;
  1911. }


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

  1930.     state = ctx->frame_state;

  1931.     if (state == sw_start) {

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

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

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

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

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

  1950.             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
  1951.                 state = sw_padding_length;

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

  1954.             } else {
  1955.                 state = sw_fragment;
  1956.             }

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

  1960.         ctx->padding = 0;
  1961.         ctx->frame_state = state;
  1962.     }

  1963.     if (state < sw_fragment) {

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

  1966.         } else {
  1967.             last = b->pos + ctx->rest;
  1968.         }

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

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

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

  1990.             switch (state) {

  1991.             case sw_padding_length:

  1992.                 ctx->padding = ch;

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

  1997.                 goto fragment;

  1998.             case sw_dependency:
  1999.                 state = sw_dependency_2;
  2000.                 break;

  2001.             case sw_dependency_2:
  2002.                 state = sw_dependency_3;
  2003.                 break;

  2004.             case sw_dependency_3:
  2005.                 state = sw_dependency_4;
  2006.                 break;

  2007.             case sw_dependency_4:
  2008.                 state = sw_weight;
  2009.                 break;

  2010.             case sw_weight:
  2011.                 goto fragment;

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

  2019.         ctx->rest -= p - b->pos;
  2020.         b->pos = p;

  2021.         ctx->frame_state = state;
  2022.         return NGX_AGAIN;

  2023.     fragment:

  2024.         p++;
  2025.         ctx->rest -= p - b->pos;
  2026.         b->pos = p;

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

  2034.         state = sw_fragment;
  2035.         ctx->frame_state = state;
  2036.     }

  2037.     if (state == sw_fragment) {

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

  2039.         if (rc == NGX_AGAIN) {
  2040.             return NGX_AGAIN;
  2041.         }

  2042.         if (rc == NGX_ERROR) {
  2043.             return NGX_ERROR;
  2044.         }

  2045.         if (rc == NGX_OK) {
  2046.             return NGX_OK;
  2047.         }

  2048.         /* rc == NGX_DONE */

  2049.         state = sw_padding;
  2050.         ctx->frame_state = state;
  2051.     }

  2052.     if (state == sw_padding) {

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

  2054.             ctx->rest -= b->last - b->pos;
  2055.             b->pos = b->last;

  2056.             return NGX_AGAIN;
  2057.         }

  2058.         b->pos += ctx->rest;
  2059.         ctx->rest = 0;

  2060.         ctx->state = ngx_http_proxy_v2_st_start;

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

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

  2067.             ctx->parsing_headers = 0;

  2068.             return NGX_HTTP_PARSE_HEADER_DONE;
  2069.         }

  2070.         return NGX_AGAIN;
  2071.     }

  2072.     /* unreachable */

  2073.     return NGX_ERROR;
  2074. }


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

  2098.     /* header block fragment */

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

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

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

  2109.     state = ctx->fragment_state;

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

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

  2116.         switch (state) {

  2117.         case sw_start:
  2118.             ctx->index = 0;

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

  2128.                 index = ch & ~0x80;

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

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

  2137.                 ctx->index = index;
  2138.                 ctx->literal = 0;

  2139.                 goto done;

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

  2166.                 index = ch & ~0xc0;

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

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

  2175.                 if (index == 0) {
  2176.                     state = sw_name_length;
  2177.                     break;
  2178.                 }

  2179.                 ctx->index = index;
  2180.                 ctx->literal = 1;

  2181.                 state = sw_value_length;
  2182.                 break;

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

  2192.                 size_update = ch & ~0xe0;

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

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

  2203.                 break;

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

  2230.                 index = ch & ~0xf0;

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

  2237.                 if (index == 0) {
  2238.                     state = sw_name_length;
  2239.                     break;
  2240.                 }

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

  2244.                 ctx->index = index;
  2245.                 ctx->literal = 1;

  2246.                 state = sw_value_length;
  2247.                 break;

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

  2274.                 index = ch & ~0xf0;

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

  2281.                 if (index == 0) {
  2282.                     state = sw_name_length;
  2283.                     break;
  2284.                 }

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

  2288.                 ctx->index = index;
  2289.                 ctx->literal = 1;

  2290.                 state = sw_value_length;
  2291.                 break;
  2292.             }

  2293.             /* not reached */

  2294.             return NGX_ERROR;

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

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

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

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

  2311.             state = sw_value_length;
  2312.             break;

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

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

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

  2326.             state = sw_name;
  2327.             break;

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

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

  2334.             state = sw_name;
  2335.             break;

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

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

  2342.             state = sw_name;
  2343.             break;

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

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

  2352.             state = sw_name;
  2353.             break;

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

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

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

  2368.             ctx->field_end = ctx->name.data;
  2369.             ctx->field_rest = ctx->field_length;
  2370.             ctx->field_state = 0;

  2371.             state = sw_name_bytes;

  2372.             /* fall through */

  2373.         case sw_name_bytes:

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

  2380.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2381.             ctx->field_rest -= size;

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

  2393.                 ctx->name.len = ctx->field_end - ctx->name.data;
  2394.                 ctx->name.data[ctx->name.len] = '\0';

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

  2399.             p += size - 1;

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

  2403.             break;

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

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

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

  2415.             state = sw_value;
  2416.             break;

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

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

  2423.             state = sw_value;
  2424.             break;

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

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

  2431.             state = sw_value;
  2432.             break;

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

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

  2441.             state = sw_value;
  2442.             break;

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

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

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

  2457.             ctx->field_end = ctx->value.data;
  2458.             ctx->field_rest = ctx->field_length;
  2459.             ctx->field_state = 0;

  2460.             state = sw_value_bytes;

  2461.             /* fall through */

  2462.         case sw_value_bytes:

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

  2469.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2470.             ctx->field_rest -= size;

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

  2482.                 ctx->value.len = ctx->field_end - ctx->value.data;
  2483.                 ctx->value.data[ctx->value.len] = '\0';

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

  2488.             p += size - 1;

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

  2492.             break;
  2493.         }

  2494.         continue;

  2495.     done:

  2496.         p++;
  2497.         ctx->rest -= p - b->pos;
  2498.         ctx->fragment_state = sw_start;
  2499.         b->pos = p;

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

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

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

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

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

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

  2532.         ctx->header_limit -= len;

  2533.         return NGX_OK;
  2534.     }

  2535.     ctx->rest -= p - b->pos;
  2536.     ctx->fragment_state = state;
  2537.     b->pos = p;

  2538.     if (ctx->rest > ctx->padding) {
  2539.         return NGX_AGAIN;
  2540.     }

  2541.     return NGX_DONE;
  2542. }


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

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

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

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

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

  2560.     return NGX_OK;
  2561. }


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

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

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

  2573.     return NGX_OK;
  2574. }


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

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

  2588.     } else {
  2589.         last = b->pos + ctx->rest;
  2590.     }

  2591.     state = ctx->frame_state;

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

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

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

  2607.         switch (state) {

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

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

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

  2620.         case sw_error_4:
  2621.             ctx->error |= ch;
  2622.             state = sw_start;

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

  2625.             break;
  2626.         }
  2627.     }

  2628.     ctx->rest -= p - b->pos;
  2629.     ctx->frame_state = state;
  2630.     b->pos = p;

  2631.     if (ctx->rest > 0) {
  2632.         return NGX_AGAIN;
  2633.     }

  2634.     ctx->state = ngx_http_proxy_v2_st_start;

  2635.     return NGX_OK;
  2636. }


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

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

  2655.     } else {
  2656.         last = b->pos + ctx->rest;
  2657.     }

  2658.     state = ctx->frame_state;

  2659.     if (state == sw_start) {

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

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

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

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

  2681.         switch (state) {

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

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

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

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

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

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

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

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

  2714.         case sw_debug:
  2715.             break;
  2716.         }
  2717.     }

  2718.     ctx->rest -= p - b->pos;
  2719.     ctx->frame_state = state;
  2720.     b->pos = p;

  2721.     if (ctx->rest > 0) {
  2722.         return NGX_AGAIN;
  2723.     }

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

  2727.     ctx->state = ngx_http_proxy_v2_st_start;

  2728.     return NGX_OK;
  2729. }


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

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

  2743.     } else {
  2744.         last = b->pos + ctx->rest;
  2745.     }

  2746.     state = ctx->frame_state;

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

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

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

  2762.         switch (state) {

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

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

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

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

  2781.     ctx->rest -= p - b->pos;
  2782.     ctx->frame_state = state;
  2783.     b->pos = p;

  2784.     if (ctx->rest > 0) {
  2785.         return NGX_AGAIN;
  2786.     }

  2787.     ctx->state = ngx_http_proxy_v2_st_start;

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

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

  2795.     if (ctx->stream_id) {

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

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

  2804.     } else {

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

  2812.         ctx->connection->send_window += ctx->window_update;
  2813.     }

  2814.     return NGX_OK;
  2815. }


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

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

  2833.     } else {
  2834.         last = b->pos + ctx->rest;
  2835.     }

  2836.     state = ctx->frame_state;

  2837.     if (state == sw_start) {

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

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

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

  2855.             ctx->state = ngx_http_proxy_v2_st_start;

  2856.             return NGX_OK;
  2857.         }

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

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

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

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

  2877.         switch (state) {

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

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

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

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

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

  2899.         case sw_value_4:
  2900.             ctx->setting_value |= ch;
  2901.             state = sw_id;

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

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

  2915.             if (ctx->setting_id == 0x04) {
  2916.                 /* SETTINGS_INITIAL_WINDOW_SIZE */

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

  2924.                 window_update = ctx->setting_value
  2925.                                 - ctx->connection->init_window;
  2926.                 ctx->connection->init_window = ctx->setting_value;

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

  2937.                 ctx->send_window += window_update;
  2938.             }

  2939.             break;
  2940.         }
  2941.     }

  2942.     ctx->rest -= p - b->pos;
  2943.     ctx->frame_state = state;
  2944.     b->pos = p;

  2945.     if (ctx->rest > 0) {
  2946.         return NGX_AGAIN;
  2947.     }

  2948.     ctx->state = ngx_http_proxy_v2_st_start;

  2949.     return ngx_http_proxy_v2_send_settings_ack(r, ctx);
  2950. }


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

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

  2968.     } else {
  2969.         last = b->pos + ctx->rest;
  2970.     }

  2971.     state = ctx->frame_state;

  2972.     if (state == sw_start) {

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

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

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

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

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

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

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

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

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

  3014.     ctx->rest -= p - b->pos;
  3015.     ctx->frame_state = state;
  3016.     b->pos = p;

  3017.     if (ctx->rest > 0) {
  3018.         return NGX_AGAIN;
  3019.     }

  3020.     ctx->state = ngx_http_proxy_v2_st_start;

  3021.     return ngx_http_proxy_v2_send_ping_ack(r, ctx);
  3022. }


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

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

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

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

  3038.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3039.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

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

  3049.     *ll = cl;

  3050.     return NGX_OK;
  3051. }


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

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

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

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

  3067.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3068.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

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

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

  3079.     *ll = cl;

  3080.     return NGX_OK;
  3081. }


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

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

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

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

  3099.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3100.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

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

  3110.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
  3111.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

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

  3116.     f = (ngx_http_proxy_v2_frame_t *) cl->buf->last;
  3117.     cl->buf->last += sizeof(ngx_http_proxy_v2_frame_t);

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

  3127.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
  3128.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

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

  3133.     *ll = cl;

  3134.     return NGX_OK;
  3135. }


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

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

  3146.     b = cl->buf;
  3147.     start = b->start;

  3148.     if (start == NULL) {

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

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

  3157.     }

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

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

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

  3166.     return cl;
  3167. }


  3168. static ngx_http_proxy_v2_ctx_t *
  3169. ngx_http_proxy_v2_get_ctx(ngx_http_request_t *r)
  3170. {
  3171.     ngx_http_upstream_t      *u;
  3172.     ngx_http_proxy_v2_ctx_t  *ctx;

  3173.     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_v2_module);

  3174.     if (ctx->connection == NULL) {
  3175.         u = r->upstream;

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

  3180.     return ctx;
  3181. }


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

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

  3193.         ctx->id = 0;

  3194.         goto done;
  3195.     }

  3196.     c = pc->connection;

  3197.     if (pc->cached) {

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

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

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

  3214.         ctx->send_window = ctx->connection->init_window;
  3215.         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3216.         ctx->connection->last_stream_id += 2;
  3217.         ctx->id = ctx->connection->last_stream_id;

  3218.         return NGX_OK;
  3219.     }

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

  3224.     cln->handler = ngx_http_proxy_v2_cleanup;
  3225.     ctx->connection = cln->data;

  3226.     ctx->id = 1;

  3227. done:

  3228.     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3229.     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3230.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

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

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

  3234.     return NGX_OK;
  3235. }


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


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


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


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