src/http/modules/ngx_http_grpc_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. typedef struct {
  9.     ngx_array_t               *flushes;
  10.     ngx_array_t               *lengths;
  11.     ngx_array_t               *values;
  12.     ngx_hash_t                 hash;
  13. } ngx_http_grpc_headers_t;


  14. typedef struct {
  15.     ngx_http_upstream_conf_t   upstream;

  16.     ngx_http_grpc_headers_t    headers;
  17.     ngx_array_t               *headers_source;

  18.     ngx_str_t                  host;
  19.     ngx_http_complex_value_t  *host_value;

  20.     ngx_array_t               *grpc_lengths;
  21.     ngx_array_t               *grpc_values;

  22. #if (NGX_HTTP_SSL)
  23.     ngx_uint_t                 ssl;
  24.     ngx_uint_t                 ssl_protocols;
  25.     ngx_str_t                  ssl_ciphers;
  26.     ngx_uint_t                 ssl_verify_depth;
  27.     ngx_str_t                  ssl_trusted_certificate;
  28.     ngx_str_t                  ssl_crl;
  29.     ngx_array_t               *ssl_conf_commands;
  30. #endif
  31. } ngx_http_grpc_loc_conf_t;


  32. typedef enum {
  33.     ngx_http_grpc_st_start = 0,
  34.     ngx_http_grpc_st_length_2,
  35.     ngx_http_grpc_st_length_3,
  36.     ngx_http_grpc_st_type,
  37.     ngx_http_grpc_st_flags,
  38.     ngx_http_grpc_st_stream_id,
  39.     ngx_http_grpc_st_stream_id_2,
  40.     ngx_http_grpc_st_stream_id_3,
  41.     ngx_http_grpc_st_stream_id_4,
  42.     ngx_http_grpc_st_payload,
  43.     ngx_http_grpc_st_padding
  44. } ngx_http_grpc_state_e;


  45. typedef struct {
  46.     size_t                     init_window;
  47.     size_t                     send_window;
  48.     size_t                     recv_window;
  49.     ngx_uint_t                 last_stream_id;
  50. } ngx_http_grpc_conn_t;


  51. typedef struct {
  52.     ngx_http_grpc_state_e      state;
  53.     ngx_uint_t                 frame_state;
  54.     ngx_uint_t                 fragment_state;

  55.     ngx_chain_t               *in;
  56.     ngx_chain_t               *out;
  57.     ngx_chain_t               *free;
  58.     ngx_chain_t               *busy;

  59.     ngx_http_grpc_conn_t      *connection;

  60.     ngx_uint_t                 id;

  61.     ngx_uint_t                 pings;
  62.     ngx_uint_t                 settings;

  63.     off_t                      length;

  64.     ssize_t                    send_window;
  65.     size_t                     recv_window;

  66.     size_t                     rest;
  67.     ngx_uint_t                 stream_id;
  68.     u_char                     type;
  69.     u_char                     flags;
  70.     u_char                     padding;

  71.     ngx_uint_t                 error;
  72.     ngx_uint_t                 window_update;

  73.     ngx_uint_t                 setting_id;
  74.     ngx_uint_t                 setting_value;

  75.     u_char                     ping_data[8];

  76.     ngx_uint_t                 index;
  77.     ngx_str_t                  name;
  78.     ngx_str_t                  value;

  79.     u_char                    *field_end;
  80.     size_t                     header_limit;
  81.     size_t                     field_length;
  82.     size_t                     field_rest;
  83.     u_char                     field_state;

  84.     unsigned                   literal:1;
  85.     unsigned                   field_huffman:1;

  86.     unsigned                   header_sent:1;
  87.     unsigned                   output_closed:1;
  88.     unsigned                   output_blocked:1;
  89.     unsigned                   parsing_headers:1;
  90.     unsigned                   end_stream:1;
  91.     unsigned                   done:1;
  92.     unsigned                   status:1;
  93.     unsigned                   rst:1;
  94.     unsigned                   goaway:1;

  95.     ngx_http_request_t        *request;

  96.     ngx_str_t                  host;
  97. } ngx_http_grpc_ctx_t;


  98. typedef struct {
  99.     u_char                     length_0;
  100.     u_char                     length_1;
  101.     u_char                     length_2;
  102.     u_char                     type;
  103.     u_char                     flags;
  104.     u_char                     stream_id_0;
  105.     u_char                     stream_id_1;
  106.     u_char                     stream_id_2;
  107.     u_char                     stream_id_3;
  108. } ngx_http_grpc_frame_t;


  109. static ngx_int_t ngx_http_grpc_eval(ngx_http_request_t *r,
  110.     ngx_http_grpc_ctx_t *ctx, ngx_http_grpc_loc_conf_t *glcf);
  111. static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r);
  112. static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r);
  113. static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in);
  114. static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r);
  115. static ngx_int_t ngx_http_grpc_filter_init(void *data);
  116. static ngx_int_t ngx_http_grpc_filter(void *data, ssize_t bytes);

  117. static ngx_int_t ngx_http_grpc_parse_frame(ngx_http_request_t *r,
  118.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  119. static ngx_int_t ngx_http_grpc_parse_header(ngx_http_request_t *r,
  120.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  121. static ngx_int_t ngx_http_grpc_parse_fragment(ngx_http_request_t *r,
  122.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  123. static ngx_int_t ngx_http_grpc_validate_header_name(ngx_http_request_t *r,
  124.     ngx_str_t *s);
  125. static ngx_int_t ngx_http_grpc_validate_header_value(ngx_http_request_t *r,
  126.     ngx_str_t *s);
  127. static ngx_int_t ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r,
  128.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  129. static ngx_int_t ngx_http_grpc_parse_goaway(ngx_http_request_t *r,
  130.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  131. static ngx_int_t ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
  132.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  133. static ngx_int_t ngx_http_grpc_parse_settings(ngx_http_request_t *r,
  134.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
  135. static ngx_int_t ngx_http_grpc_parse_ping(ngx_http_request_t *r,
  136.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);

  137. static ngx_int_t ngx_http_grpc_send_settings_ack(ngx_http_request_t *r,
  138.     ngx_http_grpc_ctx_t *ctx);
  139. static ngx_int_t ngx_http_grpc_send_ping_ack(ngx_http_request_t *r,
  140.     ngx_http_grpc_ctx_t *ctx);
  141. static ngx_int_t ngx_http_grpc_send_window_update(ngx_http_request_t *r,
  142.     ngx_http_grpc_ctx_t *ctx);

  143. static ngx_chain_t *ngx_http_grpc_get_buf(ngx_http_request_t *r,
  144.     ngx_http_grpc_ctx_t *ctx);
  145. static ngx_http_grpc_ctx_t *ngx_http_grpc_get_ctx(ngx_http_request_t *r);
  146. static ngx_int_t ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
  147.     ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc);
  148. static void ngx_http_grpc_cleanup(void *data);

  149. static void ngx_http_grpc_abort_request(ngx_http_request_t *r);
  150. static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
  151.     ngx_int_t rc);

  152. static ngx_int_t ngx_http_grpc_internal_trailers_variable(
  153.     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);

  154. static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf);
  155. static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
  156. static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
  157.     void *parent, void *child);
  158. static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
  159.     ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers,
  160.     ngx_keyval_t *default_headers);

  161. static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
  162.     void *conf);

  163. #if (NGX_HTTP_SSL)
  164. static char *ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf,
  165.     ngx_command_t *cmd, void *conf);
  166. static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf,
  167.     ngx_command_t *cmd, void *conf);
  168. static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post,
  169.     void *data);
  170. static ngx_int_t ngx_http_grpc_merge_ssl(ngx_conf_t *cf,
  171.     ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_loc_conf_t *prev);
  172. static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf,
  173.     ngx_http_grpc_loc_conf_t *glcf);
  174. #endif


  175. static ngx_conf_bitmask_t  ngx_http_grpc_next_upstream_masks[] = {
  176.     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
  177.     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
  178.     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
  179.     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
  180.     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
  181.     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
  182.     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
  183.     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
  184.     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
  185.     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
  186.     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
  187.     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
  188.     { ngx_null_string, 0 }
  189. };


  190. #if (NGX_HTTP_SSL)

  191. static ngx_conf_bitmask_t  ngx_http_grpc_ssl_protocols[] = {
  192.     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
  193.     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
  194.     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
  195.     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
  196.     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
  197.     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
  198.     { ngx_null_string, 0 }
  199. };

  200. static ngx_conf_post_t  ngx_http_grpc_ssl_conf_command_post =
  201.     { ngx_http_grpc_ssl_conf_command_check };

  202. #endif


  203. static ngx_command_t  ngx_http_grpc_commands[] = {

  204.     { ngx_string("grpc_pass"),
  205.       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
  206.       ngx_http_grpc_pass,
  207.       NGX_HTTP_LOC_CONF_OFFSET,
  208.       0,
  209.       NULL },

  210.     { ngx_string("grpc_bind"),
  211.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
  212.       ngx_http_upstream_bind_set_slot,
  213.       NGX_HTTP_LOC_CONF_OFFSET,
  214.       offsetof(ngx_http_grpc_loc_conf_t, upstream.local),
  215.       NULL },

  216.     { ngx_string("grpc_socket_keepalive"),
  217.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  218.       ngx_conf_set_flag_slot,
  219.       NGX_HTTP_LOC_CONF_OFFSET,
  220.       offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive),
  221.       NULL },

  222.     { ngx_string("grpc_socket_rcvbuf"),
  223.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  224.       ngx_conf_set_size_slot,
  225.       NGX_HTTP_LOC_CONF_OFFSET,
  226.       offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_rcvbuf),
  227.       NULL },

  228.     { ngx_string("grpc_socket_sndbuf"),
  229.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  230.       ngx_conf_set_size_slot,
  231.       NGX_HTTP_LOC_CONF_OFFSET,
  232.       offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_sndbuf),
  233.       NULL },

  234.     { ngx_string("grpc_connect_timeout"),
  235.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  236.       ngx_conf_set_msec_slot,
  237.       NGX_HTTP_LOC_CONF_OFFSET,
  238.       offsetof(ngx_http_grpc_loc_conf_t, upstream.connect_timeout),
  239.       NULL },

  240.     { ngx_string("grpc_send_timeout"),
  241.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  242.       ngx_conf_set_msec_slot,
  243.       NGX_HTTP_LOC_CONF_OFFSET,
  244.       offsetof(ngx_http_grpc_loc_conf_t, upstream.send_timeout),
  245.       NULL },

  246.     { ngx_string("grpc_intercept_errors"),
  247.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  248.       ngx_conf_set_flag_slot,
  249.       NGX_HTTP_LOC_CONF_OFFSET,
  250.       offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors),
  251.       NULL },

  252.     { ngx_string("grpc_buffer_size"),
  253.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  254.       ngx_conf_set_size_slot,
  255.       NGX_HTTP_LOC_CONF_OFFSET,
  256.       offsetof(ngx_http_grpc_loc_conf_t, upstream.buffer_size),
  257.       NULL },

  258.     { ngx_string("grpc_read_timeout"),
  259.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  260.       ngx_conf_set_msec_slot,
  261.       NGX_HTTP_LOC_CONF_OFFSET,
  262.       offsetof(ngx_http_grpc_loc_conf_t, upstream.read_timeout),
  263.       NULL },

  264.     { ngx_string("grpc_next_upstream"),
  265.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  266.       ngx_conf_set_bitmask_slot,
  267.       NGX_HTTP_LOC_CONF_OFFSET,
  268.       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream),
  269.       &ngx_http_grpc_next_upstream_masks },

  270.     { ngx_string("grpc_next_upstream_tries"),
  271.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  272.       ngx_conf_set_num_slot,
  273.       NGX_HTTP_LOC_CONF_OFFSET,
  274.       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_tries),
  275.       NULL },

  276.     { ngx_string("grpc_next_upstream_timeout"),
  277.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  278.       ngx_conf_set_msec_slot,
  279.       NGX_HTTP_LOC_CONF_OFFSET,
  280.       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_timeout),
  281.       NULL },

  282.     { ngx_string("grpc_set_header"),
  283.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  284.       ngx_conf_set_keyval_slot,
  285.       NGX_HTTP_LOC_CONF_OFFSET,
  286.       offsetof(ngx_http_grpc_loc_conf_t, headers_source),
  287.       NULL },

  288.     { ngx_string("grpc_pass_header"),
  289.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  290.       ngx_conf_set_str_array_slot,
  291.       NGX_HTTP_LOC_CONF_OFFSET,
  292.       offsetof(ngx_http_grpc_loc_conf_t, upstream.pass_headers),
  293.       NULL },

  294.     { ngx_string("grpc_hide_header"),
  295.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  296.       ngx_conf_set_str_array_slot,
  297.       NGX_HTTP_LOC_CONF_OFFSET,
  298.       offsetof(ngx_http_grpc_loc_conf_t, upstream.hide_headers),
  299.       NULL },

  300.     { ngx_string("grpc_ignore_headers"),
  301.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  302.       ngx_conf_set_bitmask_slot,
  303.       NGX_HTTP_LOC_CONF_OFFSET,
  304.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ignore_headers),
  305.       &ngx_http_upstream_ignore_headers_masks },

  306. #if (NGX_HTTP_SSL)

  307.     { ngx_string("grpc_ssl_session_reuse"),
  308.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  309.       ngx_conf_set_flag_slot,
  310.       NGX_HTTP_LOC_CONF_OFFSET,
  311.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_session_reuse),
  312.       NULL },

  313.     { ngx_string("grpc_ssl_protocols"),
  314.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
  315.       ngx_conf_set_bitmask_slot,
  316.       NGX_HTTP_LOC_CONF_OFFSET,
  317.       offsetof(ngx_http_grpc_loc_conf_t, ssl_protocols),
  318.       &ngx_http_grpc_ssl_protocols },

  319.     { ngx_string("grpc_ssl_ciphers"),
  320.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  321.       ngx_conf_set_str_slot,
  322.       NGX_HTTP_LOC_CONF_OFFSET,
  323.       offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers),
  324.       NULL },

  325.     { ngx_string("grpc_ssl_name"),
  326.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  327.       ngx_http_set_complex_value_slot,
  328.       NGX_HTTP_LOC_CONF_OFFSET,
  329.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_name),
  330.       NULL },

  331.     { ngx_string("grpc_ssl_server_name"),
  332.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  333.       ngx_conf_set_flag_slot,
  334.       NGX_HTTP_LOC_CONF_OFFSET,
  335.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_server_name),
  336.       NULL },

  337.     { ngx_string("grpc_ssl_verify"),
  338.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  339.       ngx_conf_set_flag_slot,
  340.       NGX_HTTP_LOC_CONF_OFFSET,
  341.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_verify),
  342.       NULL },

  343.     { ngx_string("grpc_ssl_verify_depth"),
  344.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  345.       ngx_conf_set_num_slot,
  346.       NGX_HTTP_LOC_CONF_OFFSET,
  347.       offsetof(ngx_http_grpc_loc_conf_t, ssl_verify_depth),
  348.       NULL },

  349.     { ngx_string("grpc_ssl_trusted_certificate"),
  350.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  351.       ngx_conf_set_str_slot,
  352.       NGX_HTTP_LOC_CONF_OFFSET,
  353.       offsetof(ngx_http_grpc_loc_conf_t, ssl_trusted_certificate),
  354.       NULL },

  355.     { ngx_string("grpc_ssl_crl"),
  356.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  357.       ngx_conf_set_str_slot,
  358.       NGX_HTTP_LOC_CONF_OFFSET,
  359.       offsetof(ngx_http_grpc_loc_conf_t, ssl_crl),
  360.       NULL },

  361.     { ngx_string("grpc_ssl_certificate"),
  362.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  363.       ngx_http_set_complex_value_zero_slot,
  364.       NGX_HTTP_LOC_CONF_OFFSET,
  365.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate),
  366.       NULL },

  367.     { ngx_string("grpc_ssl_certificate_key"),
  368.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  369.       ngx_http_set_complex_value_zero_slot,
  370.       NGX_HTTP_LOC_CONF_OFFSET,
  371.       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key),
  372.       NULL },

  373.     { ngx_string("grpc_ssl_certificate_cache"),
  374.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
  375.       ngx_http_grpc_ssl_certificate_cache,
  376.       NGX_HTTP_LOC_CONF_OFFSET,
  377.       0,
  378.       NULL },

  379.     { ngx_string("grpc_ssl_password_file"),
  380.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  381.       ngx_http_grpc_ssl_password_file,
  382.       NGX_HTTP_LOC_CONF_OFFSET,
  383.       0,
  384.       NULL },

  385.     { ngx_string("grpc_ssl_conf_command"),
  386.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
  387.       ngx_conf_set_keyval_slot,
  388.       NGX_HTTP_LOC_CONF_OFFSET,
  389.       offsetof(ngx_http_grpc_loc_conf_t, ssl_conf_commands),
  390.       &ngx_http_grpc_ssl_conf_command_post },

  391. #endif

  392.       ngx_null_command
  393. };


  394. static ngx_http_module_t  ngx_http_grpc_module_ctx = {
  395.     ngx_http_grpc_add_variables,           /* preconfiguration */
  396.     NULL,                                  /* postconfiguration */

  397.     NULL,                                  /* create main configuration */
  398.     NULL,                                  /* init main configuration */

  399.     NULL,                                  /* create server configuration */
  400.     NULL,                                  /* merge server configuration */

  401.     ngx_http_grpc_create_loc_conf,         /* create location configuration */
  402.     ngx_http_grpc_merge_loc_conf           /* merge location configuration */
  403. };


  404. ngx_module_t  ngx_http_grpc_module = {
  405.     NGX_MODULE_V1,
  406.     &ngx_http_grpc_module_ctx,             /* module context */
  407.     ngx_http_grpc_commands,                /* module directives */
  408.     NGX_HTTP_MODULE,                       /* module type */
  409.     NULL,                                  /* init master */
  410.     NULL,                                  /* init module */
  411.     NULL,                                  /* init process */
  412.     NULL,                                  /* init thread */
  413.     NULL,                                  /* exit thread */
  414.     NULL,                                  /* exit process */
  415.     NULL,                                  /* exit master */
  416.     NGX_MODULE_V1_PADDING
  417. };


  418. static u_char  ngx_http_grpc_connection_start[] =
  419.     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"         /* connection preface */

  420.     "\x00\x00\x12\x04\x00\x00\x00\x00\x00"     /* settings frame */
  421.     "\x00\x01\x00\x00\x00\x00"                 /* header table size */
  422.     "\x00\x02\x00\x00\x00\x00"                 /* disable push */
  423.     "\x00\x04\x7f\xff\xff\xff"                 /* initial window */

  424.     "\x00\x00\x04\x08\x00\x00\x00\x00\x00"     /* window update frame */
  425.     "\x7f\xff\x00\x00";


  426. static ngx_keyval_t  ngx_http_grpc_headers[] = {
  427.     { ngx_string("Content-Length"), ngx_string("$content_length") },
  428.     { ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
  429.     { ngx_string("Host"), ngx_string("") },
  430.     { ngx_string("Connection"), ngx_string("") },
  431.     { ngx_string("Proxy-Connection"), ngx_string("") },
  432.     { ngx_string("Transfer-Encoding"), ngx_string("") },
  433.     { ngx_string("Keep-Alive"), ngx_string("") },
  434.     { ngx_string("Expect"), ngx_string("") },
  435.     { ngx_string("Upgrade"), ngx_string("") },
  436.     { ngx_null_string, ngx_null_string }
  437. };


  438. static ngx_str_t  ngx_http_grpc_hide_headers[] = {
  439.     ngx_string("Date"),
  440.     ngx_string("Server"),
  441.     ngx_string("X-Accel-Expires"),
  442.     ngx_string("X-Accel-Redirect"),
  443.     ngx_string("X-Accel-Limit-Rate"),
  444.     ngx_string("X-Accel-Buffering"),
  445.     ngx_string("X-Accel-Charset"),
  446.     ngx_null_string
  447. };


  448. static ngx_http_variable_t  ngx_http_grpc_vars[] = {

  449.     { ngx_string("grpc_internal_trailers"), NULL,
  450.       ngx_http_grpc_internal_trailers_variable, 0,
  451.       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },

  452.       ngx_http_null_variable
  453. };


  454. static ngx_int_t
  455. ngx_http_grpc_handler(ngx_http_request_t *r)
  456. {
  457.     ngx_int_t                  rc;
  458.     ngx_http_upstream_t       *u;
  459.     ngx_http_grpc_ctx_t       *ctx;
  460.     ngx_http_grpc_loc_conf_t  *glcf;

  461.     if (ngx_http_upstream_create(r) != NGX_OK) {
  462.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  463.     }

  464.     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
  465.     if (ctx == NULL) {
  466.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  467.     }

  468.     ctx->request = r;

  469.     ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);

  470.     glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);

  471.     u = r->upstream;

  472.     if (glcf->grpc_lengths == NULL) {
  473.         ctx->host = glcf->host;

  474. #if (NGX_HTTP_SSL)
  475.         u->ssl = glcf->ssl;

  476.         if (u->ssl) {
  477.             ngx_str_set(&u->schema, "grpcs://");

  478.         } else {
  479.             ngx_str_set(&u->schema, "grpc://");
  480.         }
  481. #else
  482.         ngx_str_set(&u->schema, "grpc://");
  483. #endif

  484.     } else {
  485.         if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) {
  486.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  487.         }
  488.     }

  489.     u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;

  490.     u->conf = &glcf->upstream;

  491.     u->create_request = ngx_http_grpc_create_request;
  492.     u->reinit_request = ngx_http_grpc_reinit_request;
  493.     u->process_header = ngx_http_grpc_process_header;
  494.     u->abort_request = ngx_http_grpc_abort_request;
  495.     u->finalize_request = ngx_http_grpc_finalize_request;

  496.     u->input_filter_init = ngx_http_grpc_filter_init;
  497.     u->input_filter = ngx_http_grpc_filter;
  498.     u->input_filter_ctx = ctx;

  499.     r->request_body_no_buffering = 1;

  500.     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);

  501.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  502.         return rc;
  503.     }

  504.     return NGX_DONE;
  505. }


  506. static ngx_int_t
  507. ngx_http_grpc_eval(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  508.     ngx_http_grpc_loc_conf_t *glcf)
  509. {
  510.     size_t                add;
  511.     ngx_url_t             url;
  512.     ngx_http_upstream_t  *u;

  513.     ngx_memzero(&url, sizeof(ngx_url_t));

  514.     if (ngx_http_script_run(r, &url.url, glcf->grpc_lengths->elts, 0,
  515.                             glcf->grpc_values->elts)
  516.         == NULL)
  517.     {
  518.         return NGX_ERROR;
  519.     }

  520.     if (url.url.len > 7
  521.         && ngx_strncasecmp(url.url.data, (u_char *) "grpc://", 7) == 0)
  522.     {
  523.         add = 7;

  524.     } else if (url.url.len > 8
  525.                && ngx_strncasecmp(url.url.data, (u_char *) "grpcs://", 8) == 0)
  526.     {

  527. #if (NGX_HTTP_SSL)
  528.         add = 8;
  529.         r->upstream->ssl = 1;
  530. #else
  531.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  532.                       "grpcs protocol requires SSL support");
  533.         return NGX_ERROR;
  534. #endif

  535.     } else {
  536.         add = 0;
  537.     }

  538.     u = r->upstream;

  539.     if (add) {
  540.         u->schema.len = add;
  541.         u->schema.data = url.url.data;

  542.         url.url.data += add;
  543.         url.url.len -= add;

  544.     } else {
  545.         ngx_str_set(&u->schema, "grpc://");
  546.     }

  547.     url.no_resolve = 1;

  548.     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
  549.         if (url.err) {
  550.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  551.                           "%s in upstream \"%V\"", url.err, &url.url);
  552.         }

  553.         return NGX_ERROR;
  554.     }

  555.     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
  556.     if (u->resolved == NULL) {
  557.         return NGX_ERROR;
  558.     }

  559.     if (url.addrs) {
  560.         u->resolved->sockaddr = url.addrs[0].sockaddr;
  561.         u->resolved->socklen = url.addrs[0].socklen;
  562.         u->resolved->name = url.addrs[0].name;
  563.         u->resolved->naddrs = 1;
  564.     }

  565.     u->resolved->host = url.host;
  566.     u->resolved->port = url.port;
  567.     u->resolved->no_port = url.no_port;

  568.     if (url.family != AF_UNIX) {

  569.         if (url.no_port) {
  570.             ctx->host = url.host;

  571.         } else {
  572.             ctx->host.len = url.host.len + 1 + url.port_text.len;
  573.             ctx->host.data = url.host.data;
  574.         }

  575.     } else {
  576.         ngx_str_set(&ctx->host, "localhost");
  577.     }

  578.     return NGX_OK;
  579. }


  580. static ngx_int_t
  581. ngx_http_grpc_create_request(ngx_http_request_t *r)
  582. {
  583.     u_char                       *p, *tmp, *key_tmp, *val_tmp, *headers_frame,
  584.                                  *headers_end;
  585.     size_t                        len, headers_len, tmp_len,
  586.                                   key_len, val_len, uri_len;
  587.     uintptr_t                     escape;
  588.     ngx_buf_t                    *b;
  589.     ngx_str_t                     host;
  590.     ngx_uint_t                    i, next;
  591.     ngx_chain_t                  *cl, *body;
  592.     ngx_list_part_t              *part;
  593.     ngx_table_elt_t              *header;
  594.     ngx_http_grpc_ctx_t          *ctx;
  595.     ngx_http_upstream_t          *u;
  596.     ngx_http_grpc_frame_t        *f;
  597.     ngx_http_script_code_pt       code;
  598.     ngx_http_grpc_loc_conf_t     *glcf;
  599.     ngx_http_script_engine_t      e, le;
  600.     ngx_http_script_len_code_pt   lcode;

  601.     u = r->upstream;

  602.     glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);

  603.     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);

  604.     len = sizeof(ngx_http_grpc_connection_start) - 1
  605.           + sizeof(ngx_http_grpc_frame_t);             /* headers frame */

  606.     headers_len = 0;

  607.     /* :method header */

  608.     if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) {
  609.         len += 1;
  610.         tmp_len = 0;

  611.     } else {
  612.         if (r->method_name.len > NGX_HTTP_V2_MAX_FIELD) {
  613.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  614.                           "too long http2 method: \"%V\"", &r->method_name);
  615.             return NGX_ERROR;
  616.         }

  617.         len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len;
  618.         tmp_len = r->method_name.len;
  619.     }

  620.     /* :scheme header */

  621.     len += 1;

  622.     /* :path header */

  623.     if (r->valid_unparsed_uri) {
  624.         escape = 0;
  625.         uri_len = r->unparsed_uri.len;

  626.     } else {
  627.         escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
  628.                                     NGX_ESCAPE_URI);
  629.         uri_len = r->uri.len + escape + sizeof("?") - 1 + r->args.len;
  630.     }

  631.     if (uri_len > NGX_HTTP_V2_MAX_FIELD) {
  632.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  633.                       "too long http2 URI");
  634.         return NGX_ERROR;
  635.     }

  636.     len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;

  637.     if (tmp_len < uri_len) {
  638.         tmp_len = uri_len;
  639.     }

  640.     /* :authority header */

  641.     host.len = 0;
  642. #if (NGX_SUPPRESS_WARN)
  643.     host.data = NULL;
  644. #endif

  645.     if (glcf->host_value
  646.         && ngx_http_complex_value(r, glcf->host_value, &host) != NGX_OK)
  647.     {
  648.         return NGX_ERROR;
  649.     }

  650.     if (host.len == 0) {
  651.         host = ctx->host;
  652.     }

  653.     if (host.len > NGX_HTTP_V2_MAX_FIELD) {
  654.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  655.                       "too long http2 host: \"%V\"", &host);
  656.         return NGX_ERROR;
  657.     }

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

  659.     if (tmp_len < host.len) {
  660.         tmp_len = host.len;
  661.     }

  662.     /* other headers */

  663.     ngx_http_script_flush_no_cacheable_variables(r, glcf->headers.flushes);
  664.     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));

  665.     le.ip = glcf->headers.lengths->elts;
  666.     le.request = r;
  667.     le.flushed = 1;

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

  669.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  670.         key_len = lcode(&le);

  671.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  672.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  673.         }
  674.         le.ip += sizeof(uintptr_t);

  675.         if (val_len == 0) {
  676.             continue;
  677.         }

  678.         if (key_len > NGX_HTTP_V2_MAX_FIELD) {
  679.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  680.                           "too long http2 header name");
  681.             return NGX_ERROR;
  682.         }

  683.         if (val_len > NGX_HTTP_V2_MAX_FIELD) {
  684.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  685.                           "too long http2 header value");
  686.             return NGX_ERROR;
  687.         }

  688.         headers_len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
  689.                          + NGX_HTTP_V2_INT_OCTETS + val_len;

  690.         if (tmp_len < key_len) {
  691.             tmp_len = key_len;
  692.         }

  693.         if (tmp_len < val_len) {
  694.             tmp_len = val_len;
  695.         }
  696.     }

  697.     len += headers_len;

  698.     if (glcf->upstream.pass_request_headers) {
  699.         part = &r->headers_in.headers.part;
  700.         header = part->elts;

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

  702.             if (i >= part->nelts) {
  703.                 if (part->next == NULL) {
  704.                     break;
  705.                 }

  706.                 part = part->next;
  707.                 header = part->elts;
  708.                 i = 0;
  709.             }

  710.             if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
  711.                               header[i].lowcase_key, header[i].key.len))
  712.             {
  713.                 continue;
  714.             }

  715.             if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) {
  716.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  717.                               "too long http2 header name: \"%V\"",
  718.                               &header[i].key);
  719.                 return NGX_ERROR;
  720.             }

  721.             if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) {
  722.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  723.                               "too long http2 header value: \"%V: %V\"",
  724.                               &header[i].key, &header[i].value);
  725.                 return NGX_ERROR;
  726.             }

  727.             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
  728.                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;

  729.             if (tmp_len < header[i].key.len) {
  730.                 tmp_len = header[i].key.len;
  731.             }

  732.             if (tmp_len < header[i].value.len) {
  733.                 tmp_len = header[i].value.len;
  734.             }
  735.         }
  736.     }

  737.     /* continuation frames */

  738.     len += sizeof(ngx_http_grpc_frame_t)
  739.            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);


  740.     b = ngx_create_temp_buf(r->pool, len);
  741.     if (b == NULL) {
  742.         return NGX_ERROR;
  743.     }

  744.     cl = ngx_alloc_chain_link(r->pool);
  745.     if (cl == NULL) {
  746.         return NGX_ERROR;
  747.     }

  748.     cl->buf = b;
  749.     cl->next = NULL;

  750.     tmp = ngx_palloc(r->pool, tmp_len * 3);
  751.     if (tmp == NULL) {
  752.         return NGX_ERROR;
  753.     }

  754.     key_tmp = tmp + tmp_len;
  755.     val_tmp = tmp + 2 * tmp_len;

  756.     /* connection preface */

  757.     b->last = ngx_copy(b->last, ngx_http_grpc_connection_start,
  758.                        sizeof(ngx_http_grpc_connection_start) - 1);

  759.     /* headers frame */

  760.     headers_frame = b->last;

  761.     f = (ngx_http_grpc_frame_t *) b->last;
  762.     b->last += sizeof(ngx_http_grpc_frame_t);

  763.     f->length_0 = 0;
  764.     f->length_1 = 0;
  765.     f->length_2 = 0;
  766.     f->type = NGX_HTTP_V2_HEADERS_FRAME;
  767.     f->flags = 0;
  768.     f->stream_id_0 = 0;
  769.     f->stream_id_1 = 0;
  770.     f->stream_id_2 = 0;
  771.     f->stream_id_3 = 1;

  772.     if (r->method == NGX_HTTP_GET) {
  773.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);

  774.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  775.                        "grpc header: \":method: GET\"");

  776.     } else if (r->method == NGX_HTTP_POST) {
  777.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);

  778.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  779.                        "grpc header: \":method: POST\"");

  780.     } else {
  781.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
  782.         b->last = ngx_http_v2_write_value(b->last, r->method_name.data,
  783.                                           r->method_name.len, tmp);

  784.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  785.                        "grpc header: \":method: %V\"", &r->method_name);
  786.     }

  787. #if (NGX_HTTP_SSL)
  788.     if (u->ssl) {
  789.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);

  790.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  791.                        "grpc header: \":scheme: https\"");
  792.     } else
  793. #endif
  794.     {
  795.         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);

  796.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  797.                        "grpc header: \":scheme: http\"");
  798.     }

  799.     if (r->valid_unparsed_uri) {

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

  802.         } else {
  803.             *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  804.             b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
  805.                                               r->unparsed_uri.len, tmp);
  806.         }

  807.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  808.                        "grpc header: \":path: %V\"", &r->unparsed_uri);

  809.     } else if (escape || r->args.len > 0) {
  810.         p = val_tmp;

  811.         if (escape) {
  812.             p = (u_char *) ngx_escape_uri(p, r->uri.data, r->uri.len,
  813.                                           NGX_ESCAPE_URI);

  814.         } else {
  815.             p = ngx_copy(p, r->uri.data, r->uri.len);
  816.         }

  817.         if (r->args.len > 0) {
  818.             *p++ = '?';
  819.             p = ngx_copy(p, r->args.data, r->args.len);
  820.         }

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

  823.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  824.                        "grpc header: \":path: %*s\"", p - val_tmp, val_tmp);

  825.     } else {
  826.         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
  827.         b->last = ngx_http_v2_write_value(b->last, r->uri.data,
  828.                                           r->uri.len, tmp);

  829.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  830.                        "grpc header: \":path: %V\"", &r->uri);
  831.     }

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

  834.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  835.                    "grpc header: \":authority: %V\"", &host);

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

  837.     e.ip = glcf->headers.values->elts;
  838.     e.request = r;
  839.     e.flushed = 1;

  840.     le.ip = glcf->headers.lengths->elts;

  841.     headers_end = b->last + headers_len;

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

  843.         lcode = *(ngx_http_script_len_code_pt *) le.ip;
  844.         key_len = lcode(&le);

  845.         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
  846.             lcode = *(ngx_http_script_len_code_pt *) le.ip;
  847.         }
  848.         le.ip += sizeof(uintptr_t);

  849.         if (val_len == 0) {
  850.             e.skip = 1;

  851.             while (*(uintptr_t *) e.ip) {
  852.                 code = *(ngx_http_script_code_pt *) e.ip;
  853.                 code((ngx_http_script_engine_t *) &e);
  854.             }
  855.             e.ip += sizeof(uintptr_t);

  856.             e.skip = 0;

  857.             continue;
  858.         }

  859.         if (headers_end - b->last < 1) {
  860.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  861.                           "no buffer space in grpc create request");
  862.             return NGX_ERROR;
  863.         }

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

  865.         e.pos = key_tmp;
  866.         e.end = key_tmp + tmp_len;

  867.         code = *(ngx_http_script_code_pt *) e.ip;
  868.         code((ngx_http_script_engine_t *) &e);

  869.         if (e.status) {
  870.             return NGX_ERROR;
  871.         }

  872.         key_len = e.pos - key_tmp;

  873.         if (headers_end - b->last
  874.             < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + key_len))
  875.         {
  876.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  877.                           "no buffer space in grpc create request");
  878.             return NGX_ERROR;
  879.         }

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

  881.         e.pos = val_tmp;
  882.         e.end = val_tmp + tmp_len;

  883.         while (*(uintptr_t *) e.ip) {
  884.             code = *(ngx_http_script_code_pt *) e.ip;
  885.             code((ngx_http_script_engine_t *) &e);
  886.         }
  887.         e.ip += sizeof(uintptr_t);

  888.         if (e.status) {
  889.             return NGX_ERROR;
  890.         }

  891.         val_len = e.pos - val_tmp;

  892.         if (headers_end - b->last
  893.             < (ssize_t) (NGX_HTTP_V2_INT_OCTETS + val_len))
  894.         {
  895.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  896.                           "no buffer space in grpc create request");
  897.             return NGX_ERROR;
  898.         }

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

  900. #if (NGX_DEBUG)
  901.         if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
  902.             ngx_strlow(key_tmp, key_tmp, key_len);

  903.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  904.                            "grpc header: \"%*s: %*s\"",
  905.                            key_len, key_tmp, val_len, val_tmp);
  906.         }
  907. #endif
  908.     }

  909.     if (glcf->upstream.pass_request_headers) {
  910.         part = &r->headers_in.headers.part;
  911.         header = part->elts;

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

  913.             if (i >= part->nelts) {
  914.                 if (part->next == NULL) {
  915.                     break;
  916.                 }

  917.                 part = part->next;
  918.                 header = part->elts;
  919.                 i = 0;
  920.             }

  921.             if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
  922.                               header[i].lowcase_key, header[i].key.len))
  923.             {
  924.                 continue;
  925.             }

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

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

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

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

  934.                 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  935.                                "grpc header: \"%*s: %V\"",
  936.                                header[i].key.len, tmp, &header[i].value);
  937.             }
  938. #endif
  939.         }
  940.     }

  941.     /* update headers frame length */

  942.     len = b->last - headers_frame - sizeof(ngx_http_grpc_frame_t);

  943.     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  944.         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  945.         next = 1;

  946.     } else {
  947.         next = 0;
  948.     }

  949.     f = (ngx_http_grpc_frame_t *) headers_frame;

  950.     f->length_0 = (u_char) ((len >> 16) & 0xff);
  951.     f->length_1 = (u_char) ((len >> 8) & 0xff);
  952.     f->length_2 = (u_char) (len & 0xff);

  953.     /* create additional continuation frames */

  954.     p = headers_frame;

  955.     while (next) {
  956.         p += sizeof(ngx_http_grpc_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  957.         len = b->last - p;

  958.         ngx_memmove(p + sizeof(ngx_http_grpc_frame_t), p, len);
  959.         b->last += sizeof(ngx_http_grpc_frame_t);

  960.         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
  961.             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
  962.             next = 1;

  963.         } else {
  964.             next = 0;
  965.         }

  966.         f = (ngx_http_grpc_frame_t *) p;

  967.         f->length_0 = (u_char) ((len >> 16) & 0xff);
  968.         f->length_1 = (u_char) ((len >> 8) & 0xff);
  969.         f->length_2 = (u_char) (len & 0xff);
  970.         f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
  971.         f->flags = 0;
  972.         f->stream_id_0 = 0;
  973.         f->stream_id_1 = 0;
  974.         f->stream_id_2 = 0;
  975.         f->stream_id_3 = 1;
  976.     }

  977.     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;

  978.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  979.                    "grpc header: %*xs%s, len: %uz",
  980.                    (size_t) ngx_min(b->last - b->pos, 256), b->pos,
  981.                    b->last - b->pos > 256 ? "..." : "",
  982.                    b->last - b->pos);

  983.     if (r->request_body_no_buffering) {

  984.         u->request_bufs = cl;

  985.     } else {

  986.         body = u->request_bufs;
  987.         u->request_bufs = cl;

  988.         if (body == NULL) {
  989.             f = (ngx_http_grpc_frame_t *) headers_frame;
  990.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
  991.         }

  992.         while (body) {
  993.             b = ngx_alloc_buf(r->pool);
  994.             if (b == NULL) {
  995.                 return NGX_ERROR;
  996.             }

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

  998.             cl->next = ngx_alloc_chain_link(r->pool);
  999.             if (cl->next == NULL) {
  1000.                 return NGX_ERROR;
  1001.             }

  1002.             cl = cl->next;
  1003.             cl->buf = b;

  1004.             body = body->next;
  1005.         }

  1006.         b->last_buf = 1;
  1007.     }

  1008.     u->output.output_filter = ngx_http_grpc_body_output_filter;
  1009.     u->output.filter_ctx = r;

  1010.     b->flush = 1;
  1011.     cl->next = NULL;

  1012.     return NGX_OK;
  1013. }


  1014. static ngx_int_t
  1015. ngx_http_grpc_reinit_request(ngx_http_request_t *r)
  1016. {
  1017.     ngx_http_grpc_ctx_t  *ctx;

  1018.     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);

  1019.     if (ctx == NULL) {
  1020.         return NGX_OK;
  1021.     }

  1022.     ctx->state = 0;
  1023.     ctx->header_sent = 0;
  1024.     ctx->output_closed = 0;
  1025.     ctx->output_blocked = 0;
  1026.     ctx->parsing_headers = 0;
  1027.     ctx->end_stream = 0;
  1028.     ctx->done = 0;
  1029.     ctx->status = 0;
  1030.     ctx->rst = 0;
  1031.     ctx->goaway = 0;
  1032.     ctx->connection = NULL;
  1033.     ctx->in = NULL;
  1034.     ctx->busy = NULL;
  1035.     ctx->out = NULL;

  1036.     return NGX_OK;
  1037. }


  1038. static ngx_int_t
  1039. ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
  1040. {
  1041.     ngx_http_request_t  *r = data;

  1042.     off_t                   file_pos;
  1043.     u_char                 *p, *pos, *start;
  1044.     size_t                  len, limit;
  1045.     ngx_buf_t              *b;
  1046.     ngx_int_t               rc;
  1047.     ngx_uint_t              next, last;
  1048.     ngx_chain_t            *cl, *out, *ln, **ll;
  1049.     ngx_http_upstream_t    *u;
  1050.     ngx_http_grpc_ctx_t    *ctx;
  1051.     ngx_http_grpc_frame_t  *f;

  1052.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1053.                    "grpc output filter");

  1054.     ctx = ngx_http_grpc_get_ctx(r);

  1055.     if (ctx == NULL) {
  1056.         return NGX_ERROR;
  1057.     }

  1058.     if (in) {
  1059.         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
  1060.             return NGX_ERROR;
  1061.         }
  1062.     }

  1063.     out = NULL;
  1064.     ll = &out;

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

  1067.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1068.                        "grpc output header");

  1069.         ctx->header_sent = 1;

  1070.         if (ctx->id != 1) {
  1071.             /*
  1072.              * keepalive connection: skip connection preface,
  1073.              * update stream identifiers
  1074.              */

  1075.             b = ctx->in->buf;
  1076.             b->pos += sizeof(ngx_http_grpc_connection_start) - 1;

  1077.             p = b->pos;

  1078.             while (p < b->last) {
  1079.                 f = (ngx_http_grpc_frame_t *) p;
  1080.                 p += sizeof(ngx_http_grpc_frame_t);

  1081.                 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  1082.                 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  1083.                 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  1084.                 f->stream_id_3 = (u_char) (ctx->id & 0xff);

  1085.                 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
  1086.             }
  1087.         }

  1088.         if (ctx->in->buf->last_buf) {
  1089.             ctx->output_closed = 1;
  1090.         }

  1091.         *ll = ctx->in;
  1092.         ll = &ctx->in->next;

  1093.         ctx->in = ctx->in->next;
  1094.     }

  1095.     if (ctx->out) {
  1096.         /* queued control frames */

  1097.         *ll = ctx->out;

  1098.         for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
  1099.             ll = &cl->next;
  1100.         }

  1101.         ctx->out = NULL;
  1102.     }

  1103.     f = NULL;
  1104.     last = 0;

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

  1106.     if (limit > ctx->connection->send_window) {
  1107.         limit = ctx->connection->send_window;
  1108.     }

  1109.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1110.                    "grpc output limit: %uz w:%z:%uz",
  1111.                    limit, ctx->send_window, ctx->connection->send_window);

  1112. #if (NGX_SUPPRESS_WARN)
  1113.     file_pos = 0;
  1114.     pos = NULL;
  1115.     cl = NULL;
  1116. #endif

  1117.     in = ctx->in;

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

  1119.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1120.                        "grpc output in  l:%d f:%d %p, pos %p, size: %z "
  1121.                        "file: %O, size: %O",
  1122.                        in->buf->last_buf,
  1123.                        in->buf->in_file,
  1124.                        in->buf->start, in->buf->pos,
  1125.                        in->buf->last - in->buf->pos,
  1126.                        in->buf->file_pos,
  1127.                        in->buf->file_last - in->buf->file_pos);

  1128.         if (ngx_buf_special(in->buf)) {
  1129.             goto next;
  1130.         }

  1131.         if (in->buf->in_file) {
  1132.             file_pos = in->buf->file_pos;

  1133.         } else {
  1134.             pos = in->buf->pos;
  1135.         }

  1136.         next = 0;

  1137.         do {

  1138.             cl = ngx_http_grpc_get_buf(r, ctx);
  1139.             if (cl == NULL) {
  1140.                 return NGX_ERROR;
  1141.             }

  1142.             b = cl->buf;

  1143.             f = (ngx_http_grpc_frame_t *) b->last;
  1144.             b->last += sizeof(ngx_http_grpc_frame_t);

  1145.             *ll = cl;
  1146.             ll = &cl->next;

  1147.             cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  1148.             if (cl == NULL) {
  1149.                 return NGX_ERROR;
  1150.             }

  1151.             b = cl->buf;
  1152.             start = b->start;

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

  1154.             /*
  1155.              * restore b->start to preserve memory allocated in the buffer,
  1156.              * to reuse it later for headers and control frames
  1157.              */

  1158.             b->start = start;

  1159.             if (in->buf->in_file) {
  1160.                 b->file_pos = file_pos;
  1161.                 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  1162.                 if (file_pos >= in->buf->file_last) {
  1163.                     file_pos = in->buf->file_last;
  1164.                     next = 1;
  1165.                 }

  1166.                 b->file_last = file_pos;
  1167.                 len = (ngx_uint_t) (file_pos - b->file_pos);

  1168.             } else {
  1169.                 b->pos = pos;
  1170.                 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);

  1171.                 if (pos >= in->buf->last) {
  1172.                     pos = in->buf->last;
  1173.                     next = 1;
  1174.                 }

  1175.                 b->last = pos;
  1176.                 len = (ngx_uint_t) (pos - b->pos);
  1177.             }

  1178.             b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
  1179.             b->shadow = in->buf;
  1180.             b->last_shadow = next;

  1181.             b->last_buf = 0;
  1182.             b->last_in_chain = 0;

  1183.             *ll = cl;
  1184.             ll = &cl->next;

  1185.             f->length_0 = (u_char) ((len >> 16) & 0xff);
  1186.             f->length_1 = (u_char) ((len >> 8) & 0xff);
  1187.             f->length_2 = (u_char) (len & 0xff);
  1188.             f->type = NGX_HTTP_V2_DATA_FRAME;
  1189.             f->flags = 0;
  1190.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  1191.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  1192.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  1193.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  1194.             limit -= len;
  1195.             ctx->send_window -= len;
  1196.             ctx->connection->send_window -= len;

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

  1198.         if (!next) {
  1199.             /*
  1200.              * if the buffer wasn't fully sent due to flow control limits,
  1201.              * preserve position for future use
  1202.              */

  1203.             if (in->buf->in_file) {
  1204.                 in->buf->file_pos = file_pos;

  1205.             } else {
  1206.                 in->buf->pos = pos;
  1207.             }

  1208.             break;
  1209.         }

  1210.     next:

  1211.         if (in->buf->last_buf) {
  1212.             last = 1;
  1213.         }

  1214.         ln = in;
  1215.         in = in->next;

  1216.         ngx_free_chain(r->pool, ln);
  1217.     }

  1218.     ctx->in = in;

  1219.     if (last) {

  1220.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1221.                        "grpc output last");

  1222.         ctx->output_closed = 1;

  1223.         if (f) {
  1224.             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;

  1225.         } else {
  1226.             cl = ngx_http_grpc_get_buf(r, ctx);
  1227.             if (cl == NULL) {
  1228.                 return NGX_ERROR;
  1229.             }

  1230.             b = cl->buf;

  1231.             f = (ngx_http_grpc_frame_t *) b->last;
  1232.             b->last += sizeof(ngx_http_grpc_frame_t);

  1233.             f->length_0 = 0;
  1234.             f->length_1 = 0;
  1235.             f->length_2 = 0;
  1236.             f->type = NGX_HTTP_V2_DATA_FRAME;
  1237.             f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
  1238.             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  1239.             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  1240.             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  1241.             f->stream_id_3 = (u_char) (ctx->id & 0xff);

  1242.             *ll = cl;
  1243.             ll = &cl->next;
  1244.         }

  1245.         cl->buf->last_buf = 1;
  1246.     }

  1247.     *ll = NULL;

  1248. #if (NGX_DEBUG)

  1249.     for (cl = out; cl; cl = cl->next) {
  1250.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  1251.                        "grpc output out l:%d f:%d %p, pos %p, size: %z "
  1252.                        "file: %O, size: %O",
  1253.                        cl->buf->last_buf,
  1254.                        cl->buf->in_file,
  1255.                        cl->buf->start, cl->buf->pos,
  1256.                        cl->buf->last - cl->buf->pos,
  1257.                        cl->buf->file_pos,
  1258.                        cl->buf->file_last - cl->buf->file_pos);
  1259.     }

  1260.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1261.                    "grpc output limit: %uz w:%z:%uz",
  1262.                    limit, ctx->send_window, ctx->connection->send_window);

  1263. #endif

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

  1265.     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
  1266.                             (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter);

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

  1268.         /* mark original buffers as sent */

  1269.         if (cl->buf->shadow) {
  1270.             if (cl->buf->last_shadow) {
  1271.                 b = cl->buf->shadow;
  1272.                 b->pos = b->last;
  1273.             }

  1274.             cl->buf->shadow = NULL;
  1275.         }
  1276.     }

  1277.     if (rc == NGX_OK && ctx->in) {
  1278.         rc = NGX_AGAIN;
  1279.     }

  1280.     if (rc == NGX_AGAIN) {
  1281.         ctx->output_blocked = 1;

  1282.     } else {
  1283.         ctx->output_blocked = 0;
  1284.     }

  1285.     if (ctx->done) {

  1286.         /*
  1287.          * We have already got the response and were sending some additional
  1288.          * control frames.  Even if there is still something unsent, stop
  1289.          * here anyway.
  1290.          */

  1291.         u = r->upstream;
  1292.         u->length = 0;

  1293.         if (ctx->in == NULL
  1294.             && ctx->out == NULL
  1295.             && ctx->output_closed
  1296.             && !ctx->output_blocked
  1297.             && !ctx->goaway
  1298.             && ctx->state == ngx_http_grpc_st_start)
  1299.         {
  1300.             u->keepalive = 1;
  1301.         }

  1302.         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
  1303.     }

  1304.     return rc;
  1305. }


  1306. static ngx_int_t
  1307. ngx_http_grpc_process_header(ngx_http_request_t *r)
  1308. {
  1309.     ngx_str_t                      *status_line;
  1310.     ngx_int_t                       rc, status;
  1311.     ngx_buf_t                      *b;
  1312.     ngx_table_elt_t                *h;
  1313.     ngx_http_upstream_t            *u;
  1314.     ngx_http_grpc_ctx_t            *ctx;
  1315.     ngx_http_upstream_header_t     *hh;
  1316.     ngx_http_upstream_main_conf_t  *umcf;

  1317.     u = r->upstream;
  1318.     b = &u->buffer;

  1319.     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1320.                    "grpc response: %*xs%s, len: %uz",
  1321.                    (size_t) ngx_min(b->last - b->pos, 256),
  1322.                    b->pos, b->last - b->pos > 256 ? "..." : "",
  1323.                    b->last - b->pos);

  1324.     ctx = ngx_http_grpc_get_ctx(r);

  1325.     if (ctx == NULL) {
  1326.         return NGX_ERROR;
  1327.     }

  1328.     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

  1329.     for ( ;; ) {

  1330.         if (ctx->state < ngx_http_grpc_st_payload) {

  1331.             rc = ngx_http_grpc_parse_frame(r, ctx, b);

  1332.             if (rc == NGX_AGAIN) {

  1333.                 /*
  1334.                  * there can be a lot of window update frames,
  1335.                  * so we reset buffer if it is empty and we haven't
  1336.                  * started parsing headers yet
  1337.                  */

  1338.                 if (!ctx->parsing_headers) {
  1339.                     b->pos = b->start;
  1340.                     b->last = b->pos;
  1341.                 }

  1342.                 return NGX_AGAIN;
  1343.             }

  1344.             if (rc == NGX_ERROR) {
  1345.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1346.             }

  1347.             /*
  1348.              * RFC 7540 says that implementations MUST discard frames
  1349.              * that have unknown or unsupported types.  However, extension
  1350.              * frames that appear in the middle of a header block are
  1351.              * not permitted.  Also, for obvious reasons CONTINUATION frames
  1352.              * cannot appear before headers, and DATA frames are not expected
  1353.              * to appear before all headers are parsed.
  1354.              */

  1355.             if (ctx->type == NGX_HTTP_V2_DATA_FRAME
  1356.                 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1357.                     && !ctx->parsing_headers)
  1358.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1359.                     && ctx->parsing_headers))
  1360.             {
  1361.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1362.                               "upstream sent unexpected http2 frame: %d",
  1363.                               ctx->type);
  1364.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1365.             }

  1366.             if (ctx->stream_id && ctx->stream_id != ctx->id) {
  1367.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1368.                               "upstream sent frame for unknown stream %ui",
  1369.                               ctx->stream_id);
  1370.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1371.             }
  1372.         }

  1373.         /* frame payload */

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

  1375.             rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);

  1376.             if (rc == NGX_AGAIN) {
  1377.                 return NGX_AGAIN;
  1378.             }

  1379.             if (rc == NGX_ERROR) {
  1380.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1381.             }

  1382.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1383.                           "upstream rejected request with error %ui",
  1384.                           ctx->error);

  1385.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1386.         }

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

  1388.             rc = ngx_http_grpc_parse_goaway(r, ctx, b);

  1389.             if (rc == NGX_AGAIN) {
  1390.                 return NGX_AGAIN;
  1391.             }

  1392.             if (rc == NGX_ERROR) {
  1393.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1394.             }

  1395.             /*
  1396.              * If stream_id is lower than one we use, our
  1397.              * request won't be processed and needs to be retried.
  1398.              * If stream_id is greater or equal to the one we use,
  1399.              * we can continue normally (except we can't use this
  1400.              * connection for additional requests).  If there is
  1401.              * a real error, the connection will be closed.
  1402.              */

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

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

  1405.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1406.                               "upstream sent goaway with error %ui",
  1407.                               ctx->error);

  1408.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1409.             }

  1410.             ctx->goaway = 1;

  1411.             continue;
  1412.         }

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

  1414.             rc = ngx_http_grpc_parse_window_update(r, ctx, b);

  1415.             if (rc == NGX_AGAIN) {
  1416.                 return NGX_AGAIN;
  1417.             }

  1418.             if (rc == NGX_ERROR) {
  1419.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1420.             }

  1421.             if (ctx->in) {
  1422.                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1423.             }

  1424.             continue;
  1425.         }

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

  1427.             rc = ngx_http_grpc_parse_settings(r, ctx, b);

  1428.             if (rc == NGX_AGAIN) {
  1429.                 return NGX_AGAIN;
  1430.             }

  1431.             if (rc == NGX_ERROR) {
  1432.                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1433.             }

  1434.             if (ctx->in) {
  1435.                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1436.             }

  1437.             continue;
  1438.         }

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

  1440.             rc = ngx_http_grpc_parse_ping(r, ctx, b);

  1441.             if (rc == NGX_AGAIN) {
  1442.                 return NGX_AGAIN;
  1443.             }

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

  1447.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1448.             continue;
  1449.         }

  1450.         if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
  1451.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1452.                           "upstream sent unexpected push promise frame");
  1453.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1454.         }

  1455.         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
  1456.             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
  1457.         {
  1458.             /* priority, unknown frames */

  1459.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1460.                 ctx->rest -= b->last - b->pos;
  1461.                 b->pos = b->last;
  1462.                 return NGX_AGAIN;
  1463.             }

  1464.             b->pos += ctx->rest;
  1465.             ctx->rest = 0;
  1466.             ctx->state = ngx_http_grpc_st_start;

  1467.             continue;
  1468.         }

  1469.         /* headers */

  1470.         for ( ;; ) {

  1471.             rc = ngx_http_grpc_parse_header(r, ctx, b);

  1472.             if (rc == NGX_AGAIN) {
  1473.                 break;
  1474.             }

  1475.             if (rc == NGX_OK) {

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

  1477.                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1478.                                "grpc header: \"%V: %V\"",
  1479.                                &ctx->name, &ctx->value);

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

  1481.                     if (ctx->name.len != sizeof(":status") - 1
  1482.                         || ngx_strncmp(ctx->name.data, ":status",
  1483.                                        sizeof(":status") - 1)
  1484.                            != 0)
  1485.                     {
  1486.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1487.                                       "upstream sent invalid header \"%V: %V\"",
  1488.                                       &ctx->name, &ctx->value);
  1489.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1490.                     }

  1491.                     if (ctx->status) {
  1492.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1493.                                       "upstream sent duplicate :status header");
  1494.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1495.                     }

  1496.                     status_line = &ctx->value;

  1497.                     if (status_line->len != 3) {
  1498.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1499.                                       "upstream sent invalid :status \"%V\"",
  1500.                                       status_line);
  1501.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1502.                     }

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

  1504.                     if (status == NGX_ERROR) {
  1505.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1506.                                       "upstream sent invalid :status \"%V\"",
  1507.                                       status_line);
  1508.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1509.                     }

  1510.                     if (status < NGX_HTTP_OK && status != NGX_HTTP_EARLY_HINTS)
  1511.                     {
  1512.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1513.                                       "upstream sent unexpected :status \"%V\"",
  1514.                                       status_line);
  1515.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1516.                     }

  1517.                     u->headers_in.status_n = status;

  1518.                     if (u->state && u->state->status == 0) {
  1519.                         u->state->status = status;
  1520.                     }

  1521.                     ctx->status = 1;

  1522.                     continue;

  1523.                 } else if (!ctx->status) {
  1524.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1525.                                   "upstream sent no :status header");
  1526.                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1527.                 }

  1528.                 h = ngx_list_push(&u->headers_in.headers);
  1529.                 if (h == NULL) {
  1530.                     return NGX_ERROR;
  1531.                 }

  1532.                 h->key = ctx->name;
  1533.                 h->value = ctx->value;
  1534.                 h->lowcase_key = h->key.data;
  1535.                 h->hash = ngx_hash_key(h->key.data, h->key.len);

  1536.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1537.                     continue;
  1538.                 }

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

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

  1543.                     if (rc != NGX_OK) {
  1544.                         return rc;
  1545.                     }
  1546.                 }

  1547.                 continue;
  1548.             }

  1549.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

  1551.                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1552.                                "grpc header done");

  1553.                 if (u->headers_in.status_n == NGX_HTTP_EARLY_HINTS) {
  1554.                     if (ctx->end_stream) {
  1555.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1556.                                       "upstream prematurely closed stream");
  1557.                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1558.                     }

  1559.                     ctx->status = 0;
  1560.                     return NGX_HTTP_UPSTREAM_EARLY_HINTS;
  1561.                 }

  1562.                 if (ctx->end_stream) {

  1563.                     if (u->headers_in.content_length_n == -1) {
  1564.                         u->headers_in.content_length_n = 0;
  1565.                     }

  1566.                     if (ctx->in == NULL
  1567.                         && ctx->out == NULL
  1568.                         && ctx->output_closed
  1569.                         && !ctx->output_blocked
  1570.                         && !ctx->goaway
  1571.                         && b->last == b->pos)
  1572.                     {
  1573.                         u->keepalive = 1;
  1574.                     }
  1575.                 }

  1576.                 return NGX_OK;
  1577.             }

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

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

  1581.             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  1582.         }

  1583.         /* rc == NGX_AGAIN */

  1584.         if (ctx->rest == 0) {
  1585.             ctx->state = ngx_http_grpc_st_start;
  1586.             continue;
  1587.         }

  1588.         return NGX_AGAIN;
  1589.     }
  1590. }


  1591. static ngx_int_t
  1592. ngx_http_grpc_filter_init(void *data)
  1593. {
  1594.     ngx_http_grpc_ctx_t  *ctx = data;

  1595.     ngx_http_request_t   *r;
  1596.     ngx_http_upstream_t  *u;

  1597.     r = ctx->request;
  1598.     u = r->upstream;

  1599.     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
  1600.         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
  1601.         || r->method == NGX_HTTP_HEAD)
  1602.     {
  1603.         ctx->length = 0;

  1604.     } else {
  1605.         ctx->length = u->headers_in.content_length_n;
  1606.     }

  1607.     if (ctx->end_stream) {

  1608.         if (ctx->length > 0) {
  1609.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1610.                           "upstream prematurely closed stream");
  1611.             return NGX_ERROR;
  1612.         }

  1613.         u->length = 0;
  1614.         ctx->done = 1;

  1615.     } else {
  1616.         u->length = 1;
  1617.     }

  1618.     return NGX_OK;
  1619. }


  1620. static ngx_int_t
  1621. ngx_http_grpc_filter(void *data, ssize_t bytes)
  1622. {
  1623.     ngx_http_grpc_ctx_t  *ctx = data;

  1624.     ngx_int_t             rc;
  1625.     ngx_buf_t            *b, *buf;
  1626.     ngx_chain_t          *cl, **ll;
  1627.     ngx_table_elt_t      *h;
  1628.     ngx_http_request_t   *r;
  1629.     ngx_http_upstream_t  *u;

  1630.     r = ctx->request;
  1631.     u = r->upstream;
  1632.     b = &u->buffer;

  1633.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1634.                    "grpc filter bytes:%z", bytes);

  1635.     b->pos = b->last;
  1636.     b->last += bytes;

  1637.     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
  1638.         ll = &cl->next;
  1639.     }

  1640.     for ( ;; ) {

  1641.         if (ctx->state < ngx_http_grpc_st_payload) {

  1642.             rc = ngx_http_grpc_parse_frame(r, ctx, b);

  1643.             if (rc == NGX_AGAIN) {

  1644.                 if (ctx->done) {

  1645.                     if (ctx->length > 0) {
  1646.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1647.                                       "upstream prematurely closed stream");
  1648.                         return NGX_ERROR;
  1649.                     }

  1650.                     /*
  1651.                      * We have finished parsing the response and the
  1652.                      * remaining control frames.  If there are unsent
  1653.                      * control frames, post a write event to send them.
  1654.                      */

  1655.                     if (ctx->out) {
  1656.                         ngx_post_event(u->peer.connection->write,
  1657.                                        &ngx_posted_events);
  1658.                         return NGX_AGAIN;
  1659.                     }

  1660.                     u->length = 0;

  1661.                     if (ctx->in == NULL
  1662.                         && ctx->output_closed
  1663.                         && !ctx->output_blocked
  1664.                         && !ctx->goaway
  1665.                         && ctx->state == ngx_http_grpc_st_start)
  1666.                     {
  1667.                         u->keepalive = 1;
  1668.                     }

  1669.                     break;
  1670.                 }

  1671.                 return NGX_AGAIN;
  1672.             }

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

  1676.             if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
  1677.                  && !ctx->parsing_headers)
  1678.                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
  1679.                     && ctx->parsing_headers))
  1680.             {
  1681.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1682.                               "upstream sent unexpected http2 frame: %d",
  1683.                               ctx->type);
  1684.                 return NGX_ERROR;
  1685.             }

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

  1687.                 if (ctx->stream_id != ctx->id) {
  1688.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1689.                                   "upstream sent data frame "
  1690.                                   "for unknown stream %ui",
  1691.                                   ctx->stream_id);
  1692.                     return NGX_ERROR;
  1693.                 }

  1694.                 if (ctx->rest > ctx->recv_window) {
  1695.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1696.                                   "upstream violated stream flow control, "
  1697.                                   "received %uz data frame with window %uz",
  1698.                                   ctx->rest, ctx->recv_window);
  1699.                     return NGX_ERROR;
  1700.                 }

  1701.                 if (ctx->rest > ctx->connection->recv_window) {
  1702.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1703.                                   "upstream violated connection flow control, "
  1704.                                   "received %uz data frame with window %uz",
  1705.                                   ctx->rest, ctx->connection->recv_window);
  1706.                     return NGX_ERROR;
  1707.                 }

  1708.                 ctx->recv_window -= ctx->rest;
  1709.                 ctx->connection->recv_window -= ctx->rest;

  1710.                 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
  1711.                     || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
  1712.                 {
  1713.                     if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) {
  1714.                         return NGX_ERROR;
  1715.                     }

  1716.                     ngx_post_event(u->peer.connection->write,
  1717.                                    &ngx_posted_events);
  1718.                 }
  1719.             }

  1720.             if (ctx->stream_id && ctx->stream_id != ctx->id) {
  1721.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1722.                               "upstream sent frame for unknown stream %ui",
  1723.                               ctx->stream_id);
  1724.                 return NGX_ERROR;
  1725.             }

  1726.             if (ctx->stream_id && ctx->done
  1727.                 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
  1728.                 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
  1729.             {
  1730.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1731.                               "upstream sent frame for closed stream %ui",
  1732.                               ctx->stream_id);
  1733.                 return NGX_ERROR;
  1734.             }

  1735.             ctx->padding = 0;
  1736.         }

  1737.         if (ctx->state == ngx_http_grpc_st_padding) {

  1738.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1739.                 ctx->rest -= b->last - b->pos;
  1740.                 b->pos = b->last;
  1741.                 return NGX_AGAIN;
  1742.             }

  1743.             b->pos += ctx->rest;
  1744.             ctx->rest = 0;
  1745.             ctx->state = ngx_http_grpc_st_start;

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

  1749.             continue;
  1750.         }

  1751.         /* frame payload */

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

  1753.             rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);

  1754.             if (rc == NGX_AGAIN) {
  1755.                 return NGX_AGAIN;
  1756.             }

  1757.             if (rc == NGX_ERROR) {
  1758.                 return NGX_ERROR;
  1759.             }

  1760.             if (ctx->error || !ctx->done) {
  1761.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1762.                               "upstream rejected request with error %ui",
  1763.                               ctx->error);
  1764.                 return NGX_ERROR;
  1765.             }

  1766.             if (ctx->rst) {
  1767.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1768.                               "upstream sent frame for closed stream %ui",
  1769.                               ctx->stream_id);
  1770.                 return NGX_ERROR;
  1771.             }

  1772.             ctx->rst = 1;

  1773.             continue;
  1774.         }

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

  1776.             rc = ngx_http_grpc_parse_goaway(r, ctx, b);

  1777.             if (rc == NGX_AGAIN) {
  1778.                 return NGX_AGAIN;
  1779.             }

  1780.             if (rc == NGX_ERROR) {
  1781.                 return NGX_ERROR;
  1782.             }

  1783.             /*
  1784.              * If stream_id is lower than one we use, our
  1785.              * request won't be processed and needs to be retried.
  1786.              * If stream_id is greater or equal to the one we use,
  1787.              * we can continue normally (except we can't use this
  1788.              * connection for additional requests).  If there is
  1789.              * a real error, the connection will be closed.
  1790.              */

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

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

  1793.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1794.                               "upstream sent goaway with error %ui",
  1795.                               ctx->error);

  1796.                 return NGX_ERROR;
  1797.             }

  1798.             ctx->goaway = 1;

  1799.             continue;
  1800.         }

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

  1802.             rc = ngx_http_grpc_parse_window_update(r, ctx, b);

  1803.             if (rc == NGX_AGAIN) {
  1804.                 return NGX_AGAIN;
  1805.             }

  1806.             if (rc == NGX_ERROR) {
  1807.                 return NGX_ERROR;
  1808.             }

  1809.             if (ctx->in) {
  1810.                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1811.             }

  1812.             continue;
  1813.         }

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

  1815.             rc = ngx_http_grpc_parse_settings(r, ctx, b);

  1816.             if (rc == NGX_AGAIN) {
  1817.                 return NGX_AGAIN;
  1818.             }

  1819.             if (rc == NGX_ERROR) {
  1820.                 return NGX_ERROR;
  1821.             }

  1822.             if (ctx->in) {
  1823.                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1824.             }

  1825.             continue;
  1826.         }

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

  1828.             rc = ngx_http_grpc_parse_ping(r, ctx, b);

  1829.             if (rc == NGX_AGAIN) {
  1830.                 return NGX_AGAIN;
  1831.             }

  1832.             if (rc == NGX_ERROR) {
  1833.                 return NGX_ERROR;
  1834.             }

  1835.             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
  1836.             continue;
  1837.         }

  1838.         if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
  1839.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1840.                           "upstream sent unexpected push promise frame");
  1841.             return NGX_ERROR;
  1842.         }

  1843.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
  1844.             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
  1845.         {
  1846.             for ( ;; ) {

  1847.                 rc = ngx_http_grpc_parse_header(r, ctx, b);

  1848.                 if (rc == NGX_AGAIN) {
  1849.                     break;
  1850.                 }

  1851.                 if (rc == NGX_OK) {

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

  1853.                     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1854.                                    "grpc trailer: \"%V: %V\"",
  1855.                                    &ctx->name, &ctx->value);

  1856.                     if (ctx->name.len && ctx->name.data[0] == ':') {
  1857.                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1858.                                       "upstream sent invalid "
  1859.                                       "trailer \"%V: %V\"",
  1860.                                       &ctx->name, &ctx->value);
  1861.                         return NGX_ERROR;
  1862.                     }

  1863.                     h = ngx_list_push(&u->headers_in.trailers);
  1864.                     if (h == NULL) {
  1865.                         return NGX_ERROR;
  1866.                     }

  1867.                     h->key = ctx->name;
  1868.                     h->value = ctx->value;
  1869.                     h->lowcase_key = h->key.data;
  1870.                     h->hash = ngx_hash_key(h->key.data, h->key.len);

  1871.                     continue;
  1872.                 }

  1873.                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

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

  1875.                     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1876.                                    "grpc trailer done");

  1877.                     if (ctx->end_stream) {
  1878.                         ctx->done = 1;
  1879.                         break;
  1880.                     }

  1881.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1882.                                   "upstream sent trailer without "
  1883.                                   "end stream flag");
  1884.                     return NGX_ERROR;
  1885.                 }

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

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

  1889.                 return NGX_ERROR;
  1890.             }

  1891.             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
  1892.                 continue;
  1893.             }

  1894.             /* rc == NGX_AGAIN */

  1895.             if (ctx->rest == 0) {
  1896.                 ctx->state = ngx_http_grpc_st_start;
  1897.                 continue;
  1898.             }

  1899.             return NGX_AGAIN;
  1900.         }

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

  1902.             /* priority, unknown frames */

  1903.             if (b->last - b->pos < (ssize_t) ctx->rest) {
  1904.                 ctx->rest -= b->last - b->pos;
  1905.                 b->pos = b->last;
  1906.                 return NGX_AGAIN;
  1907.             }

  1908.             b->pos += ctx->rest;
  1909.             ctx->rest = 0;
  1910.             ctx->state = ngx_http_grpc_st_start;

  1911.             continue;
  1912.         }

  1913.         /*
  1914.          * data frame:
  1915.          *
  1916.          * +---------------+
  1917.          * |Pad Length? (8)|
  1918.          * +---------------+-----------------------------------------------+
  1919.          * |                            Data (*)                         ...
  1920.          * +---------------------------------------------------------------+
  1921.          * |                           Padding (*)                       ...
  1922.          * +---------------------------------------------------------------+
  1923.          */

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

  1925.             if (ctx->rest == 0) {
  1926.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1927.                               "upstream sent too short http2 frame");
  1928.                 return NGX_ERROR;
  1929.             }

  1930.             if (b->pos == b->last) {
  1931.                 return NGX_AGAIN;
  1932.             }

  1933.             ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
  1934.             ctx->padding = *b->pos++;
  1935.             ctx->rest -= 1;

  1936.             if (ctx->padding > ctx->rest) {
  1937.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1938.                               "upstream sent http2 frame with too long "
  1939.                               "padding: %d in frame %uz",
  1940.                               ctx->padding, ctx->rest);
  1941.                 return NGX_ERROR;
  1942.             }

  1943.             continue;
  1944.         }

  1945.         if (ctx->rest == ctx->padding) {
  1946.             goto done;
  1947.         }

  1948.         if (b->pos == b->last) {
  1949.             return NGX_AGAIN;
  1950.         }

  1951.         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
  1952.         if (cl == NULL) {
  1953.             return NGX_ERROR;
  1954.         }

  1955.         *ll = cl;
  1956.         ll = &cl->next;

  1957.         buf = cl->buf;

  1958.         buf->flush = 1;
  1959.         buf->memory = 1;

  1960.         buf->pos = b->pos;
  1961.         buf->tag = u->output.tag;

  1962.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  1963.                        "grpc output buf %p", buf->pos);

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

  1965.             ctx->rest -= b->last - b->pos;
  1966.             b->pos = b->last;
  1967.             buf->last = b->pos;

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

  1969.                 if (buf->last - buf->pos > ctx->length) {
  1970.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1971.                                   "upstream sent response body larger "
  1972.                                   "than indicated content length");
  1973.                     return NGX_ERROR;
  1974.                 }

  1975.                 ctx->length -= buf->last - buf->pos;
  1976.             }

  1977.             return NGX_AGAIN;
  1978.         }

  1979.         b->pos += ctx->rest - ctx->padding;
  1980.         buf->last = b->pos;
  1981.         ctx->rest = ctx->padding;

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

  1983.             if (buf->last - buf->pos > ctx->length) {
  1984.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  1985.                               "upstream sent response body larger "
  1986.                               "than indicated content length");
  1987.                 return NGX_ERROR;
  1988.             }

  1989.             ctx->length -= buf->last - buf->pos;
  1990.         }

  1991.     done:

  1992.         if (ctx->padding) {
  1993.             ctx->state = ngx_http_grpc_st_padding;
  1994.             continue;
  1995.         }

  1996.         ctx->state = ngx_http_grpc_st_start;

  1997.         if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  1998.             ctx->done = 1;
  1999.         }
  2000.     }

  2001.     return NGX_OK;
  2002. }


  2003. static ngx_int_t
  2004. ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2005.     ngx_buf_t *b)
  2006. {
  2007.     u_char                 ch, *p;
  2008.     ngx_http_grpc_state_e  state;

  2009.     state = ctx->state;

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

  2012. #if 0
  2013.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2014.                        "grpc frame byte: %02Xd, s:%d", ch, state);
  2015. #endif

  2016.         switch (state) {

  2017.         case ngx_http_grpc_st_start:
  2018.             ctx->rest = ch << 16;
  2019.             state = ngx_http_grpc_st_length_2;
  2020.             break;

  2021.         case ngx_http_grpc_st_length_2:
  2022.             ctx->rest |= ch << 8;
  2023.             state = ngx_http_grpc_st_length_3;
  2024.             break;

  2025.         case ngx_http_grpc_st_length_3:
  2026.             ctx->rest |= ch;

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

  2033.             state = ngx_http_grpc_st_type;
  2034.             break;

  2035.         case ngx_http_grpc_st_type:
  2036.             ctx->type = ch;
  2037.             state = ngx_http_grpc_st_flags;
  2038.             break;

  2039.         case ngx_http_grpc_st_flags:
  2040.             ctx->flags = ch;
  2041.             state = ngx_http_grpc_st_stream_id;
  2042.             break;

  2043.         case ngx_http_grpc_st_stream_id:
  2044.             ctx->stream_id = (ch & 0x7f) << 24;
  2045.             state = ngx_http_grpc_st_stream_id_2;
  2046.             break;

  2047.         case ngx_http_grpc_st_stream_id_2:
  2048.             ctx->stream_id |= ch << 16;
  2049.             state = ngx_http_grpc_st_stream_id_3;
  2050.             break;

  2051.         case ngx_http_grpc_st_stream_id_3:
  2052.             ctx->stream_id |= ch << 8;
  2053.             state = ngx_http_grpc_st_stream_id_4;
  2054.             break;

  2055.         case ngx_http_grpc_st_stream_id_4:
  2056.             ctx->stream_id |= ch;

  2057.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2058.                            "grpc frame: %d, len: %uz, f:%d, i:%ui",
  2059.                            ctx->type, ctx->rest, ctx->flags, ctx->stream_id);

  2060.             b->pos = p + 1;

  2061.             ctx->state = ngx_http_grpc_st_payload;
  2062.             ctx->frame_state = 0;

  2063.             return NGX_OK;

  2064.         /* suppress warning */
  2065.         case ngx_http_grpc_st_payload:
  2066.         case ngx_http_grpc_st_padding:
  2067.             break;
  2068.         }
  2069.     }

  2070.     b->pos = p;
  2071.     ctx->state = state;

  2072.     return NGX_AGAIN;
  2073. }


  2074. static ngx_int_t
  2075. ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2076.     ngx_buf_t *b)
  2077. {
  2078.     u_char     ch, *p, *last;
  2079.     size_t     min;
  2080.     ngx_int_t  rc;
  2081.     enum {
  2082.         sw_start = 0,
  2083.         sw_padding_length,
  2084.         sw_dependency,
  2085.         sw_dependency_2,
  2086.         sw_dependency_3,
  2087.         sw_dependency_4,
  2088.         sw_weight,
  2089.         sw_fragment,
  2090.         sw_padding
  2091.     } state;

  2092.     state = ctx->frame_state;

  2093.     if (state == sw_start) {

  2094.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2095.                        "grpc parse header: start");

  2096.         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
  2097.             ctx->parsing_headers = 1;
  2098.             ctx->fragment_state = 0;
  2099.             ctx->header_limit = r->upstream->conf->buffer_size;

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

  2102.             if (ctx->rest < min) {
  2103.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2104.                               "upstream sent headers frame "
  2105.                               "with invalid length: %uz",
  2106.                               ctx->rest);
  2107.                 return NGX_ERROR;
  2108.             }

  2109.             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
  2110.                 ctx->end_stream = 1;
  2111.             }

  2112.             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
  2113.                 state = sw_padding_length;

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

  2116.             } else {
  2117.                 state = sw_fragment;
  2118.             }

  2119.         } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
  2120.             state = sw_fragment;
  2121.         }

  2122.         ctx->padding = 0;
  2123.         ctx->frame_state = state;
  2124.     }

  2125.     if (state < sw_fragment) {

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

  2128.         } else {
  2129.             last = b->pos + ctx->rest;
  2130.         }

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

  2133. #if 0
  2134.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2135.                            "grpc header byte: %02Xd s:%d", ch, state);
  2136. #endif

  2137.             /*
  2138.              * headers frame:
  2139.              *
  2140.              * +---------------+
  2141.              * |Pad Length? (8)|
  2142.              * +-+-------------+----------------------------------------------+
  2143.              * |E|                 Stream Dependency? (31)                    |
  2144.              * +-+-------------+----------------------------------------------+
  2145.              * |  Weight? (8)  |
  2146.              * +-+-------------+----------------------------------------------+
  2147.              * |                   Header Block Fragment (*)                ...
  2148.              * +--------------------------------------------------------------+
  2149.              * |                           Padding (*)                      ...
  2150.              * +--------------------------------------------------------------+
  2151.              */

  2152.             switch (state) {

  2153.             case sw_padding_length:

  2154.                 ctx->padding = ch;

  2155.                 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
  2156.                     state = sw_dependency;
  2157.                     break;
  2158.                 }

  2159.                 goto fragment;

  2160.             case sw_dependency:
  2161.                 state = sw_dependency_2;
  2162.                 break;

  2163.             case sw_dependency_2:
  2164.                 state = sw_dependency_3;
  2165.                 break;

  2166.             case sw_dependency_3:
  2167.                 state = sw_dependency_4;
  2168.                 break;

  2169.             case sw_dependency_4:
  2170.                 state = sw_weight;
  2171.                 break;

  2172.             case sw_weight:
  2173.                 goto fragment;

  2174.             /* suppress warning */
  2175.             case sw_start:
  2176.             case sw_fragment:
  2177.             case sw_padding:
  2178.                 break;
  2179.             }
  2180.         }

  2181.         ctx->rest -= p - b->pos;
  2182.         b->pos = p;

  2183.         ctx->frame_state = state;
  2184.         return NGX_AGAIN;

  2185.     fragment:

  2186.         p++;
  2187.         ctx->rest -= p - b->pos;
  2188.         b->pos = p;

  2189.         if (ctx->padding > ctx->rest) {
  2190.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2191.                           "upstream sent http2 frame with too long "
  2192.                           "padding: %d in frame %uz",
  2193.                           ctx->padding, ctx->rest);
  2194.             return NGX_ERROR;
  2195.         }

  2196.         state = sw_fragment;
  2197.         ctx->frame_state = state;
  2198.     }

  2199.     if (state == sw_fragment) {

  2200.         rc = ngx_http_grpc_parse_fragment(r, ctx, b);

  2201.         if (rc == NGX_AGAIN) {
  2202.             return NGX_AGAIN;
  2203.         }

  2204.         if (rc == NGX_ERROR) {
  2205.             return NGX_ERROR;
  2206.         }

  2207.         if (rc == NGX_OK) {
  2208.             return NGX_OK;
  2209.         }

  2210.         /* rc == NGX_DONE */

  2211.         state = sw_padding;
  2212.         ctx->frame_state = state;
  2213.     }

  2214.     if (state == sw_padding) {

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

  2216.             ctx->rest -= b->last - b->pos;
  2217.             b->pos = b->last;

  2218.             return NGX_AGAIN;
  2219.         }

  2220.         b->pos += ctx->rest;
  2221.         ctx->rest = 0;

  2222.         ctx->state = ngx_http_grpc_st_start;

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

  2224.             if (ctx->fragment_state) {
  2225.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2226.                               "upstream sent truncated http2 header");
  2227.                 return NGX_ERROR;
  2228.             }

  2229.             ctx->parsing_headers = 0;

  2230.             return NGX_HTTP_PARSE_HEADER_DONE;
  2231.         }

  2232.         return NGX_AGAIN;
  2233.     }

  2234.     /* unreachable */

  2235.     return NGX_ERROR;
  2236. }


  2237. static ngx_int_t
  2238. ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2239.     ngx_buf_t *b)
  2240. {
  2241.     u_char      ch, *p, *last;
  2242.     size_t      len, size;
  2243.     ngx_uint_t  index, size_update;
  2244.     enum {
  2245.         sw_start = 0,
  2246.         sw_index,
  2247.         sw_name_length,
  2248.         sw_name_length_2,
  2249.         sw_name_length_3,
  2250.         sw_name_length_4,
  2251.         sw_name,
  2252.         sw_name_bytes,
  2253.         sw_value_length,
  2254.         sw_value_length_2,
  2255.         sw_value_length_3,
  2256.         sw_value_length_4,
  2257.         sw_value,
  2258.         sw_value_bytes
  2259.     } state;

  2260.     /* header block fragment */

  2261. #if 0
  2262.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2263.                    "grpc header fragment %p:%p rest:%uz",
  2264.                    b->pos, b->last, ctx->rest);
  2265. #endif

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

  2268.     } else {
  2269.         last = b->pos + ctx->rest - ctx->padding;
  2270.     }

  2271.     state = ctx->fragment_state;

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

  2274. #if 0
  2275.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2276.                        "grpc header byte: %02Xd s:%d", ch, state);
  2277. #endif

  2278.         switch (state) {

  2279.         case sw_start:
  2280.             ctx->index = 0;

  2281.             if ((ch & 0x80) == 0x80) {
  2282.                 /*
  2283.                  * indexed header:
  2284.                  *
  2285.                  *   0   1   2   3   4   5   6   7
  2286.                  * +---+---+---+---+---+---+---+---+
  2287.                  * | 1 |        Index (7+)         |
  2288.                  * +---+---------------------------+
  2289.                  */

  2290.                 index = ch & ~0x80;

  2291.                 if (index == 0 || index > 61) {
  2292.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2293.                                   "upstream sent invalid http2 "
  2294.                                   "table index: %ui", index);
  2295.                     return NGX_ERROR;
  2296.                 }

  2297.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2298.                                "grpc indexed header: %ui", index);

  2299.                 ctx->index = index;
  2300.                 ctx->literal = 0;

  2301.                 goto done;

  2302.             } else if ((ch & 0xc0) == 0x40) {
  2303.                 /*
  2304.                  * literal header with incremental indexing:
  2305.                  *
  2306.                  *   0   1   2   3   4   5   6   7
  2307.                  * +---+---+---+---+---+---+---+---+
  2308.                  * | 0 | 1 |      Index (6+)       |
  2309.                  * +---+---+-----------------------+
  2310.                  * | H |     Value Length (7+)     |
  2311.                  * +---+---------------------------+
  2312.                  * | Value String (Length octets)  |
  2313.                  * +-------------------------------+
  2314.                  *
  2315.                  *   0   1   2   3   4   5   6   7
  2316.                  * +---+---+---+---+---+---+---+---+
  2317.                  * | 0 | 1 |           0           |
  2318.                  * +---+---+-----------------------+
  2319.                  * | H |     Name Length (7+)      |
  2320.                  * +---+---------------------------+
  2321.                  * |  Name String (Length octets)  |
  2322.                  * +---+---------------------------+
  2323.                  * | H |     Value Length (7+)     |
  2324.                  * +---+---------------------------+
  2325.                  * | Value String (Length octets)  |
  2326.                  * +-------------------------------+
  2327.                  */

  2328.                 index = ch & ~0xc0;

  2329.                 if (index > 61) {
  2330.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2331.                                   "upstream sent invalid http2 "
  2332.                                   "table index: %ui", index);
  2333.                     return NGX_ERROR;
  2334.                 }

  2335.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2336.                                "grpc literal header: %ui", index);

  2337.                 if (index == 0) {
  2338.                     state = sw_name_length;
  2339.                     break;
  2340.                 }

  2341.                 ctx->index = index;
  2342.                 ctx->literal = 1;

  2343.                 state = sw_value_length;
  2344.                 break;

  2345.             } else if ((ch & 0xe0) == 0x20) {
  2346.                 /*
  2347.                  * dynamic table size update:
  2348.                  *
  2349.                  *   0   1   2   3   4   5   6   7
  2350.                  * +---+---+---+---+---+---+---+---+
  2351.                  * | 0 | 0 | 1 |   Max size (5+)   |
  2352.                  * +---+---------------------------+
  2353.                  */

  2354.                 size_update = ch & ~0xe0;

  2355.                 if (size_update > 0) {
  2356.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2357.                                   "upstream sent invalid http2 "
  2358.                                   "dynamic table size update: %ui",
  2359.                                   size_update);
  2360.                     return NGX_ERROR;
  2361.                 }

  2362.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2363.                                "grpc table size update: %ui", size_update);

  2364.                 break;

  2365.             } else if ((ch & 0xf0) == 0x10) {
  2366.                 /*
  2367.                  *  literal header field never indexed:
  2368.                  *
  2369.                  *   0   1   2   3   4   5   6   7
  2370.                  * +---+---+---+---+---+---+---+---+
  2371.                  * | 0 | 0 | 0 | 1 |  Index (4+)   |
  2372.                  * +---+---+-----------------------+
  2373.                  * | H |     Value Length (7+)     |
  2374.                  * +---+---------------------------+
  2375.                  * | Value String (Length octets)  |
  2376.                  * +-------------------------------+
  2377.                  *
  2378.                  *   0   1   2   3   4   5   6   7
  2379.                  * +---+---+---+---+---+---+---+---+
  2380.                  * | 0 | 0 | 0 | 1 |       0       |
  2381.                  * +---+---+-----------------------+
  2382.                  * | H |     Name Length (7+)      |
  2383.                  * +---+---------------------------+
  2384.                  * |  Name String (Length octets)  |
  2385.                  * +---+---------------------------+
  2386.                  * | H |     Value Length (7+)     |
  2387.                  * +---+---------------------------+
  2388.                  * | Value String (Length octets)  |
  2389.                  * +-------------------------------+
  2390.                  */

  2391.                 index = ch & ~0xf0;

  2392.                 if (index == 0x0f) {
  2393.                     ctx->index = index;
  2394.                     ctx->literal = 1;
  2395.                     state = sw_index;
  2396.                     break;
  2397.                 }

  2398.                 if (index == 0) {
  2399.                     state = sw_name_length;
  2400.                     break;
  2401.                 }

  2402.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2403.                                "grpc literal header never indexed: %ui",
  2404.                                index);

  2405.                 ctx->index = index;
  2406.                 ctx->literal = 1;

  2407.                 state = sw_value_length;
  2408.                 break;

  2409.             } else if ((ch & 0xf0) == 0x00) {
  2410.                 /*
  2411.                  * literal header field without indexing:
  2412.                  *
  2413.                  *   0   1   2   3   4   5   6   7
  2414.                  * +---+---+---+---+---+---+---+---+
  2415.                  * | 0 | 0 | 0 | 0 |  Index (4+)   |
  2416.                  * +---+---+-----------------------+
  2417.                  * | H |     Value Length (7+)     |
  2418.                  * +---+---------------------------+
  2419.                  * | Value String (Length octets)  |
  2420.                  * +-------------------------------+
  2421.                  *
  2422.                  *   0   1   2   3   4   5   6   7
  2423.                  * +---+---+---+---+---+---+---+---+
  2424.                  * | 0 | 0 | 0 | 0 |       0       |
  2425.                  * +---+---+-----------------------+
  2426.                  * | H |     Name Length (7+)      |
  2427.                  * +---+---------------------------+
  2428.                  * |  Name String (Length octets)  |
  2429.                  * +---+---------------------------+
  2430.                  * | H |     Value Length (7+)     |
  2431.                  * +---+---------------------------+
  2432.                  * | Value String (Length octets)  |
  2433.                  * +-------------------------------+
  2434.                  */

  2435.                 index = ch & ~0xf0;

  2436.                 if (index == 0x0f) {
  2437.                     ctx->index = index;
  2438.                     ctx->literal = 1;
  2439.                     state = sw_index;
  2440.                     break;
  2441.                 }

  2442.                 if (index == 0) {
  2443.                     state = sw_name_length;
  2444.                     break;
  2445.                 }

  2446.                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2447.                                "grpc literal header without indexing: %ui",
  2448.                                index);

  2449.                 ctx->index = index;
  2450.                 ctx->literal = 1;

  2451.                 state = sw_value_length;
  2452.                 break;
  2453.             }

  2454.             /* not reached */

  2455.             return NGX_ERROR;

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

  2458.             if (ch & 0x80) {
  2459.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2460.                               "upstream sent http2 table index "
  2461.                               "with continuation flag");
  2462.                 return NGX_ERROR;
  2463.             }

  2464.             if (ctx->index > 61) {
  2465.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2466.                               "upstream sent invalid http2 "
  2467.                               "table index: %ui", ctx->index);
  2468.                 return NGX_ERROR;
  2469.             }

  2470.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2471.                            "grpc header index: %ui", ctx->index);

  2472.             state = sw_value_length;
  2473.             break;

  2474.         case sw_name_length:
  2475.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2476.             ctx->field_length = ch & ~0x80;

  2477.             if (ctx->field_length == 0x7f) {
  2478.                 state = sw_name_length_2;
  2479.                 break;
  2480.             }

  2481.             if (ctx->field_length == 0) {
  2482.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2483.                               "upstream sent zero http2 "
  2484.                               "header name length");
  2485.                 return NGX_ERROR;
  2486.             }

  2487.             state = sw_name;
  2488.             break;

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

  2491.             if (ch & 0x80) {
  2492.                 state = sw_name_length_3;
  2493.                 break;
  2494.             }

  2495.             state = sw_name;
  2496.             break;

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

  2499.             if (ch & 0x80) {
  2500.                 state = sw_name_length_4;
  2501.                 break;
  2502.             }

  2503.             state = sw_name;
  2504.             break;

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

  2507.             if (ch & 0x80) {
  2508.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2509.                               "upstream sent too large http2 "
  2510.                               "header name length");
  2511.                 return NGX_ERROR;
  2512.             }

  2513.             state = sw_name;
  2514.             break;

  2515.         case sw_name:
  2516.             ctx->name.len = ctx->field_huffman ?
  2517.                             ctx->field_length * 8 / 5 : ctx->field_length;

  2518.             if (ctx->name.len > ctx->header_limit) {
  2519.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2520.                               "upstream sent too large http2 "
  2521.                               "header name length: %uz",
  2522.                               ctx->name.len);
  2523.                 return NGX_ERROR;
  2524.             }

  2525.             ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
  2526.             if (ctx->name.data == NULL) {
  2527.                 return NGX_ERROR;
  2528.             }

  2529.             ctx->field_end = ctx->name.data;
  2530.             ctx->field_rest = ctx->field_length;
  2531.             ctx->field_state = 0;

  2532.             state = sw_name_bytes;

  2533.             /* fall through */

  2534.         case sw_name_bytes:

  2535.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2536.                            "grpc name: len:%uz h:%d last:%uz, rest:%uz",
  2537.                            ctx->field_length,
  2538.                            ctx->field_huffman,
  2539.                            last - p,
  2540.                            ctx->rest - (p - b->pos));

  2541.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2542.             ctx->field_rest -= size;

  2543.             if (ctx->field_huffman) {
  2544.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2545.                                          &ctx->field_end,
  2546.                                          ctx->field_rest == 0,
  2547.                                          r->connection->log)
  2548.                     != NGX_OK)
  2549.                 {
  2550.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2551.                                   "upstream sent invalid encoded header");
  2552.                     return NGX_ERROR;
  2553.                 }

  2554.                 ctx->name.len = ctx->field_end - ctx->name.data;
  2555.                 ctx->name.data[ctx->name.len] = '\0';

  2556.             } else {
  2557.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2558.                 ctx->name.data[ctx->name.len] = '\0';
  2559.             }

  2560.             p += size - 1;

  2561.             if (ctx->field_rest == 0) {
  2562.                 state = sw_value_length;
  2563.             }

  2564.             break;

  2565.         case sw_value_length:
  2566.             ctx->field_huffman = ch & 0x80 ? 1 : 0;
  2567.             ctx->field_length = ch & ~0x80;

  2568.             if (ctx->field_length == 0x7f) {
  2569.                 state = sw_value_length_2;
  2570.                 break;
  2571.             }

  2572.             if (ctx->field_length == 0) {
  2573.                 ngx_str_set(&ctx->value, "");
  2574.                 goto done;
  2575.             }

  2576.             state = sw_value;
  2577.             break;

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

  2580.             if (ch & 0x80) {
  2581.                 state = sw_value_length_3;
  2582.                 break;
  2583.             }

  2584.             state = sw_value;
  2585.             break;

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

  2588.             if (ch & 0x80) {
  2589.                 state = sw_value_length_4;
  2590.                 break;
  2591.             }

  2592.             state = sw_value;
  2593.             break;

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

  2596.             if (ch & 0x80) {
  2597.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2598.                               "upstream sent too large http2 "
  2599.                               "header value length");
  2600.                 return NGX_ERROR;
  2601.             }

  2602.             state = sw_value;
  2603.             break;

  2604.         case sw_value:
  2605.             ctx->value.len = ctx->field_huffman ?
  2606.                              ctx->field_length * 8 / 5 : ctx->field_length;

  2607.             if (ctx->value.len > ctx->header_limit) {
  2608.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2609.                               "upstream sent too large http2 "
  2610.                               "header value length: %uz",
  2611.                               ctx->value.len);
  2612.                 return NGX_ERROR;
  2613.             }

  2614.             ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
  2615.             if (ctx->value.data == NULL) {
  2616.                 return NGX_ERROR;
  2617.             }

  2618.             ctx->field_end = ctx->value.data;
  2619.             ctx->field_rest = ctx->field_length;
  2620.             ctx->field_state = 0;

  2621.             state = sw_value_bytes;

  2622.             /* fall through */

  2623.         case sw_value_bytes:

  2624.             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2625.                            "grpc value: len:%uz h:%d last:%uz, rest:%uz",
  2626.                            ctx->field_length,
  2627.                            ctx->field_huffman,
  2628.                            last - p,
  2629.                            ctx->rest - (p - b->pos));

  2630.             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
  2631.             ctx->field_rest -= size;

  2632.             if (ctx->field_huffman) {
  2633.                 if (ngx_http_huff_decode(&ctx->field_state, p, size,
  2634.                                          &ctx->field_end,
  2635.                                          ctx->field_rest == 0,
  2636.                                          r->connection->log)
  2637.                     != NGX_OK)
  2638.                 {
  2639.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2640.                                   "upstream sent invalid encoded header");
  2641.                     return NGX_ERROR;
  2642.                 }

  2643.                 ctx->value.len = ctx->field_end - ctx->value.data;
  2644.                 ctx->value.data[ctx->value.len] = '\0';

  2645.             } else {
  2646.                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
  2647.                 ctx->value.data[ctx->value.len] = '\0';
  2648.             }

  2649.             p += size - 1;

  2650.             if (ctx->field_rest == 0) {
  2651.                 goto done;
  2652.             }

  2653.             break;
  2654.         }

  2655.         continue;

  2656.     done:

  2657.         p++;
  2658.         ctx->rest -= p - b->pos;
  2659.         ctx->fragment_state = sw_start;
  2660.         b->pos = p;

  2661.         if (ctx->index) {
  2662.             ctx->name = *ngx_http_v2_get_static_name(ctx->index);
  2663.         }

  2664.         if (ctx->index && !ctx->literal) {
  2665.             ctx->value = *ngx_http_v2_get_static_value(ctx->index);
  2666.         }

  2667.         if (!ctx->index) {
  2668.             if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) {
  2669.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2670.                               "upstream sent invalid header: \"%V: %V\"",
  2671.                               &ctx->name, &ctx->value);
  2672.                 return NGX_ERROR;
  2673.             }
  2674.         }

  2675.         if (!ctx->index || ctx->literal) {
  2676.             if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) {
  2677.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2678.                               "upstream sent invalid header: \"%V: %V\"",
  2679.                               &ctx->name, &ctx->value);
  2680.                 return NGX_ERROR;
  2681.             }
  2682.         }

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

  2684.         if (len > ctx->header_limit) {
  2685.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2686.                           "upstream sent too large http2 header");
  2687.             return NGX_ERROR;
  2688.         }

  2689.         ctx->header_limit -= len;

  2690.         return NGX_OK;
  2691.     }

  2692.     ctx->rest -= p - b->pos;
  2693.     ctx->fragment_state = state;
  2694.     b->pos = p;

  2695.     if (ctx->rest > ctx->padding) {
  2696.         return NGX_AGAIN;
  2697.     }

  2698.     return NGX_DONE;
  2699. }


  2700. static ngx_int_t
  2701. ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
  2702. {
  2703.     u_char      ch;
  2704.     ngx_uint_t  i;

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

  2707.         if (ch == ':' && i > 0) {
  2708.             return NGX_ERROR;
  2709.         }

  2710.         if (ch >= 'A' && ch <= 'Z') {
  2711.             return NGX_ERROR;
  2712.         }

  2713.         if (ch <= 0x20 || ch == 0x7f) {
  2714.             return NGX_ERROR;
  2715.         }
  2716.     }

  2717.     return NGX_OK;
  2718. }


  2719. static ngx_int_t
  2720. ngx_http_grpc_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
  2721. {
  2722.     u_char      ch;
  2723.     ngx_uint_t  i;

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

  2726.         if (ch == '\0' || ch == CR || ch == LF) {
  2727.             return NGX_ERROR;
  2728.         }
  2729.     }

  2730.     return NGX_OK;
  2731. }


  2732. static ngx_int_t
  2733. ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2734.     ngx_buf_t *b)
  2735. {
  2736.     u_char  ch, *p, *last;
  2737.     enum {
  2738.         sw_start = 0,
  2739.         sw_error_2,
  2740.         sw_error_3,
  2741.         sw_error_4
  2742.     } state;

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

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

  2748.     state = ctx->frame_state;

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

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

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

  2764.         switch (state) {

  2765.         case sw_start:
  2766.             ctx->error = (ngx_uint_t) ch << 24;
  2767.             state = sw_error_2;
  2768.             break;

  2769.         case sw_error_2:
  2770.             ctx->error |= ch << 16;
  2771.             state = sw_error_3;
  2772.             break;

  2773.         case sw_error_3:
  2774.             ctx->error |= ch << 8;
  2775.             state = sw_error_4;
  2776.             break;

  2777.         case sw_error_4:
  2778.             ctx->error |= ch;
  2779.             state = sw_start;

  2780.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2781.                            "grpc error: %ui", ctx->error);

  2782.             break;
  2783.         }
  2784.     }

  2785.     ctx->rest -= p - b->pos;
  2786.     ctx->frame_state = state;
  2787.     b->pos = p;

  2788.     if (ctx->rest > 0) {
  2789.         return NGX_AGAIN;
  2790.     }

  2791.     ctx->state = ngx_http_grpc_st_start;

  2792.     return NGX_OK;
  2793. }


  2794. static ngx_int_t
  2795. ngx_http_grpc_parse_goaway(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2796.     ngx_buf_t *b)
  2797. {
  2798.     u_char  ch, *p, *last;
  2799.     enum {
  2800.         sw_start = 0,
  2801.         sw_last_stream_id_2,
  2802.         sw_last_stream_id_3,
  2803.         sw_last_stream_id_4,
  2804.         sw_error,
  2805.         sw_error_2,
  2806.         sw_error_3,
  2807.         sw_error_4,
  2808.         sw_debug
  2809.     } state;

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

  2812.     } else {
  2813.         last = b->pos + ctx->rest;
  2814.     }

  2815.     state = ctx->frame_state;

  2816.     if (state == sw_start) {

  2817.         if (ctx->stream_id) {
  2818.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2819.                           "upstream sent goaway frame "
  2820.                           "with non-zero stream id: %ui",
  2821.                           ctx->stream_id);
  2822.             return NGX_ERROR;
  2823.         }

  2824.         if (ctx->rest < 8) {
  2825.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2826.                           "upstream sent goaway frame "
  2827.                           "with invalid length: %uz",
  2828.                           ctx->rest);
  2829.             return NGX_ERROR;
  2830.         }
  2831.     }

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

  2834. #if 0
  2835.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2836.                        "grpc goaway byte: %02Xd s:%d", ch, state);
  2837. #endif

  2838.         switch (state) {

  2839.         case sw_start:
  2840.             ctx->stream_id = (ch & 0x7f) << 24;
  2841.             state = sw_last_stream_id_2;
  2842.             break;

  2843.         case sw_last_stream_id_2:
  2844.             ctx->stream_id |= ch << 16;
  2845.             state = sw_last_stream_id_3;
  2846.             break;

  2847.         case sw_last_stream_id_3:
  2848.             ctx->stream_id |= ch << 8;
  2849.             state = sw_last_stream_id_4;
  2850.             break;

  2851.         case sw_last_stream_id_4:
  2852.             ctx->stream_id |= ch;
  2853.             state = sw_error;
  2854.             break;

  2855.         case sw_error:
  2856.             ctx->error = (ngx_uint_t) ch << 24;
  2857.             state = sw_error_2;
  2858.             break;

  2859.         case sw_error_2:
  2860.             ctx->error |= ch << 16;
  2861.             state = sw_error_3;
  2862.             break;

  2863.         case sw_error_3:
  2864.             ctx->error |= ch << 8;
  2865.             state = sw_error_4;
  2866.             break;

  2867.         case sw_error_4:
  2868.             ctx->error |= ch;
  2869.             state = sw_debug;
  2870.             break;

  2871.         case sw_debug:
  2872.             break;
  2873.         }
  2874.     }

  2875.     ctx->rest -= p - b->pos;
  2876.     ctx->frame_state = state;
  2877.     b->pos = p;

  2878.     if (ctx->rest > 0) {
  2879.         return NGX_AGAIN;
  2880.     }

  2881.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2882.                    "grpc goaway: %ui, stream %ui",
  2883.                    ctx->error, ctx->stream_id);

  2884.     ctx->state = ngx_http_grpc_st_start;

  2885.     return NGX_OK;
  2886. }


  2887. static ngx_int_t
  2888. ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
  2889.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
  2890. {
  2891.     u_char  ch, *p, *last;
  2892.     enum {
  2893.         sw_start = 0,
  2894.         sw_size_2,
  2895.         sw_size_3,
  2896.         sw_size_4
  2897.     } state;

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

  2900.     } else {
  2901.         last = b->pos + ctx->rest;
  2902.     }

  2903.     state = ctx->frame_state;

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

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

  2915. #if 0
  2916.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2917.                        "grpc window update byte: %02Xd s:%d", ch, state);
  2918. #endif

  2919.         switch (state) {

  2920.         case sw_start:
  2921.             ctx->window_update = (ch & 0x7f) << 24;
  2922.             state = sw_size_2;
  2923.             break;

  2924.         case sw_size_2:
  2925.             ctx->window_update |= ch << 16;
  2926.             state = sw_size_3;
  2927.             break;

  2928.         case sw_size_3:
  2929.             ctx->window_update |= ch << 8;
  2930.             state = sw_size_4;
  2931.             break;

  2932.         case sw_size_4:
  2933.             ctx->window_update |= ch;
  2934.             state = sw_start;
  2935.             break;
  2936.         }
  2937.     }

  2938.     ctx->rest -= p - b->pos;
  2939.     ctx->frame_state = state;
  2940.     b->pos = p;

  2941.     if (ctx->rest > 0) {
  2942.         return NGX_AGAIN;
  2943.     }

  2944.     ctx->state = ngx_http_grpc_st_start;

  2945.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  2946.                    "grpc window update: %ui", ctx->window_update);

  2947.     if (ctx->window_update == 0) {
  2948.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2949.                       "upstream sent zero window update");
  2950.         return NGX_ERROR;
  2951.     }

  2952.     if (ctx->stream_id) {

  2953.         if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
  2954.                                  - ctx->send_window)
  2955.         {
  2956.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2957.                           "upstream sent too large window update");
  2958.             return NGX_ERROR;
  2959.         }

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

  2961.     } else {

  2962.         if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
  2963.                                  - ctx->connection->send_window)
  2964.         {
  2965.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2966.                           "upstream sent too large window update");
  2967.             return NGX_ERROR;
  2968.         }

  2969.         ctx->connection->send_window += ctx->window_update;
  2970.     }

  2971.     return NGX_OK;
  2972. }


  2973. static ngx_int_t
  2974. ngx_http_grpc_parse_settings(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
  2975.     ngx_buf_t *b)
  2976. {
  2977.     u_char   ch, *p, *last;
  2978.     ssize_t  window_update;
  2979.     enum {
  2980.         sw_start = 0,
  2981.         sw_id,
  2982.         sw_id_2,
  2983.         sw_value,
  2984.         sw_value_2,
  2985.         sw_value_3,
  2986.         sw_value_4
  2987.     } state;

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

  2990.     } else {
  2991.         last = b->pos + ctx->rest;
  2992.     }

  2993.     state = ctx->frame_state;

  2994.     if (state == sw_start) {

  2995.         if (ctx->stream_id) {
  2996.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  2997.                           "upstream sent settings frame "
  2998.                           "with non-zero stream id: %ui",
  2999.                           ctx->stream_id);
  3000.             return NGX_ERROR;
  3001.         }

  3002.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  3003.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3004.                            "grpc settings ack");

  3005.             if (ctx->rest != 0) {
  3006.                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3007.                               "upstream sent settings frame "
  3008.                               "with ack flag and non-zero length: %uz",
  3009.                               ctx->rest);
  3010.                 return NGX_ERROR;
  3011.             }

  3012.             ctx->state = ngx_http_grpc_st_start;

  3013.             return NGX_OK;
  3014.         }

  3015.         if (ctx->rest % 6 != 0) {
  3016.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3017.                           "upstream sent settings frame "
  3018.                           "with invalid length: %uz",
  3019.                           ctx->rest);
  3020.             return NGX_ERROR;
  3021.         }

  3022.         if (ctx->free == NULL && ctx->settings++ > 1000) {
  3023.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3024.                           "upstream sent too many settings frames");
  3025.             return NGX_ERROR;
  3026.         }
  3027.     }

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

  3030. #if 0
  3031.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3032.                        "grpc settings byte: %02Xd s:%d", ch, state);
  3033. #endif

  3034.         switch (state) {

  3035.         case sw_start:
  3036.         case sw_id:
  3037.             ctx->setting_id = ch << 8;
  3038.             state = sw_id_2;
  3039.             break;

  3040.         case sw_id_2:
  3041.             ctx->setting_id |= ch;
  3042.             state = sw_value;
  3043.             break;

  3044.         case sw_value:
  3045.             ctx->setting_value = (ngx_uint_t) ch << 24;
  3046.             state = sw_value_2;
  3047.             break;

  3048.         case sw_value_2:
  3049.             ctx->setting_value |= ch << 16;
  3050.             state = sw_value_3;
  3051.             break;

  3052.         case sw_value_3:
  3053.             ctx->setting_value |= ch << 8;
  3054.             state = sw_value_4;
  3055.             break;

  3056.         case sw_value_4:
  3057.             ctx->setting_value |= ch;
  3058.             state = sw_id;

  3059.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3060.                            "grpc setting: %ui %ui",
  3061.                            ctx->setting_id, ctx->setting_value);

  3062.             /*
  3063.              * The following settings are defined by the protocol:
  3064.              *
  3065.              * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
  3066.              * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
  3067.              * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
  3068.              *
  3069.              * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
  3070.              * a simple client.
  3071.              */

  3072.             if (ctx->setting_id == 0x04) {
  3073.                 /* SETTINGS_INITIAL_WINDOW_SIZE */

  3074.                 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
  3075.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3076.                                   "upstream sent settings frame "
  3077.                                   "with too large initial window size: %ui",
  3078.                                   ctx->setting_value);
  3079.                     return NGX_ERROR;
  3080.                 }

  3081.                 window_update = ctx->setting_value
  3082.                                 - ctx->connection->init_window;
  3083.                 ctx->connection->init_window = ctx->setting_value;

  3084.                 if (ctx->send_window > 0
  3085.                     && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
  3086.                                        - ctx->send_window)
  3087.                 {
  3088.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3089.                                   "upstream sent settings frame "
  3090.                                   "with too large initial window size: %ui",
  3091.                                   ctx->setting_value);
  3092.                     return NGX_ERROR;
  3093.                 }

  3094.                 ctx->send_window += window_update;
  3095.             }

  3096.             break;
  3097.         }
  3098.     }

  3099.     ctx->rest -= p - b->pos;
  3100.     ctx->frame_state = state;
  3101.     b->pos = p;

  3102.     if (ctx->rest > 0) {
  3103.         return NGX_AGAIN;
  3104.     }

  3105.     ctx->state = ngx_http_grpc_st_start;

  3106.     return ngx_http_grpc_send_settings_ack(r, ctx);
  3107. }


  3108. static ngx_int_t
  3109. ngx_http_grpc_parse_ping(ngx_http_request_t *r,
  3110.     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
  3111. {
  3112.     u_char  ch, *p, *last;
  3113.     enum {
  3114.         sw_start = 0,
  3115.         sw_data_2,
  3116.         sw_data_3,
  3117.         sw_data_4,
  3118.         sw_data_5,
  3119.         sw_data_6,
  3120.         sw_data_7,
  3121.         sw_data_8
  3122.     } state;

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

  3125.     } else {
  3126.         last = b->pos + ctx->rest;
  3127.     }

  3128.     state = ctx->frame_state;

  3129.     if (state == sw_start) {

  3130.         if (ctx->stream_id) {
  3131.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3132.                           "upstream sent ping frame "
  3133.                           "with non-zero stream id: %ui",
  3134.                           ctx->stream_id);
  3135.             return NGX_ERROR;
  3136.         }

  3137.         if (ctx->rest != 8) {
  3138.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3139.                           "upstream sent ping frame "
  3140.                           "with invalid length: %uz",
  3141.                           ctx->rest);
  3142.             return NGX_ERROR;
  3143.         }

  3144.         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
  3145.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3146.                           "upstream sent ping frame with ack flag");
  3147.             return NGX_ERROR;
  3148.         }

  3149.         if (ctx->free == NULL && ctx->pings++ > 1000) {
  3150.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  3151.                           "upstream sent too many ping frames");
  3152.             return NGX_ERROR;
  3153.         }
  3154.     }

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

  3157. #if 0
  3158.         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3159.                        "grpc ping byte: %02Xd s:%d", ch, state);
  3160. #endif

  3161.         if (state < sw_data_8) {
  3162.             ctx->ping_data[state] = ch;
  3163.             state++;

  3164.         } else {
  3165.             ctx->ping_data[7] = ch;
  3166.             state = sw_start;

  3167.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3168.                            "grpc ping");
  3169.         }
  3170.     }

  3171.     ctx->rest -= p - b->pos;
  3172.     ctx->frame_state = state;
  3173.     b->pos = p;

  3174.     if (ctx->rest > 0) {
  3175.         return NGX_AGAIN;
  3176.     }

  3177.     ctx->state = ngx_http_grpc_st_start;

  3178.     return ngx_http_grpc_send_ping_ack(r, ctx);
  3179. }


  3180. static ngx_int_t
  3181. ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
  3182. {
  3183.     ngx_chain_t            *cl, **ll;
  3184.     ngx_http_grpc_frame_t  *f;

  3185.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3186.                    "grpc send settings ack");

  3187.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3188.         ll = &cl->next;
  3189.     }

  3190.     cl = ngx_http_grpc_get_buf(r, ctx);
  3191.     if (cl == NULL) {
  3192.         return NGX_ERROR;
  3193.     }

  3194.     f = (ngx_http_grpc_frame_t *) cl->buf->last;
  3195.     cl->buf->last += sizeof(ngx_http_grpc_frame_t);

  3196.     f->length_0 = 0;
  3197.     f->length_1 = 0;
  3198.     f->length_2 = 0;
  3199.     f->type = NGX_HTTP_V2_SETTINGS_FRAME;
  3200.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  3201.     f->stream_id_0 = 0;
  3202.     f->stream_id_1 = 0;
  3203.     f->stream_id_2 = 0;
  3204.     f->stream_id_3 = 0;

  3205.     *ll = cl;

  3206.     return NGX_OK;
  3207. }


  3208. static ngx_int_t
  3209. ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
  3210. {
  3211.     ngx_chain_t            *cl, **ll;
  3212.     ngx_http_grpc_frame_t  *f;

  3213.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3214.                    "grpc send ping ack");

  3215.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3216.         ll = &cl->next;
  3217.     }

  3218.     cl = ngx_http_grpc_get_buf(r, ctx);
  3219.     if (cl == NULL) {
  3220.         return NGX_ERROR;
  3221.     }

  3222.     f = (ngx_http_grpc_frame_t *) cl->buf->last;
  3223.     cl->buf->last += sizeof(ngx_http_grpc_frame_t);

  3224.     f->length_0 = 0;
  3225.     f->length_1 = 0;
  3226.     f->length_2 = 8;
  3227.     f->type = NGX_HTTP_V2_PING_FRAME;
  3228.     f->flags = NGX_HTTP_V2_ACK_FLAG;
  3229.     f->stream_id_0 = 0;
  3230.     f->stream_id_1 = 0;
  3231.     f->stream_id_2 = 0;
  3232.     f->stream_id_3 = 0;

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

  3234.     *ll = cl;

  3235.     return NGX_OK;
  3236. }


  3237. static ngx_int_t
  3238. ngx_http_grpc_send_window_update(ngx_http_request_t *r,
  3239.     ngx_http_grpc_ctx_t *ctx)
  3240. {
  3241.     size_t                  n;
  3242.     ngx_chain_t            *cl, **ll;
  3243.     ngx_http_grpc_frame_t  *f;

  3244.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3245.                    "grpc send window update: %uz %uz",
  3246.                    ctx->connection->recv_window, ctx->recv_window);

  3247.     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
  3248.         ll = &cl->next;
  3249.     }

  3250.     cl = ngx_http_grpc_get_buf(r, ctx);
  3251.     if (cl == NULL) {
  3252.         return NGX_ERROR;
  3253.     }

  3254.     f = (ngx_http_grpc_frame_t *) cl->buf->last;
  3255.     cl->buf->last += sizeof(ngx_http_grpc_frame_t);

  3256.     f->length_0 = 0;
  3257.     f->length_1 = 0;
  3258.     f->length_2 = 4;
  3259.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3260.     f->flags = 0;
  3261.     f->stream_id_0 = 0;
  3262.     f->stream_id_1 = 0;
  3263.     f->stream_id_2 = 0;
  3264.     f->stream_id_3 = 0;

  3265.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
  3266.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3267.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3268.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3269.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3270.     *cl->buf->last++ = (u_char) (n & 0xff);

  3271.     f = (ngx_http_grpc_frame_t *) cl->buf->last;
  3272.     cl->buf->last += sizeof(ngx_http_grpc_frame_t);

  3273.     f->length_0 = 0;
  3274.     f->length_1 = 0;
  3275.     f->length_2 = 4;
  3276.     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
  3277.     f->flags = 0;
  3278.     f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
  3279.     f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
  3280.     f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
  3281.     f->stream_id_3 = (u_char) (ctx->id & 0xff);

  3282.     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
  3283.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3284.     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
  3285.     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
  3286.     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
  3287.     *cl->buf->last++ = (u_char) (n & 0xff);

  3288.     *ll = cl;

  3289.     return NGX_OK;
  3290. }


  3291. static ngx_chain_t *
  3292. ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
  3293. {
  3294.     u_char       *start;
  3295.     ngx_buf_t    *b;
  3296.     ngx_chain_t  *cl;

  3297.     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
  3298.     if (cl == NULL) {
  3299.         return NULL;
  3300.     }

  3301.     b = cl->buf;
  3302.     start = b->start;

  3303.     if (start == NULL) {

  3304.         /*
  3305.          * each buffer is large enough to hold two window update
  3306.          * frames in a row
  3307.          */

  3308.         start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8);
  3309.         if (start == NULL) {
  3310.             return NULL;
  3311.         }

  3312.     }

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

  3314.     b->start = start;
  3315.     b->pos = start;
  3316.     b->last = start;
  3317.     b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8;

  3318.     b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
  3319.     b->temporary = 1;
  3320.     b->flush = 1;

  3321.     return cl;
  3322. }


  3323. static ngx_http_grpc_ctx_t *
  3324. ngx_http_grpc_get_ctx(ngx_http_request_t *r)
  3325. {
  3326.     ngx_http_grpc_ctx_t  *ctx;
  3327.     ngx_http_upstream_t  *u;

  3328.     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);

  3329.     if (ctx->connection == NULL) {
  3330.         u = r->upstream;

  3331.         if (ngx_http_grpc_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
  3332.             return NULL;
  3333.         }
  3334.     }

  3335.     return ctx;
  3336. }


  3337. static ngx_int_t
  3338. ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
  3339.     ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc)
  3340. {
  3341.     ngx_connection_t    *c;
  3342.     ngx_pool_cleanup_t  *cln;

  3343.     c = pc->connection;

  3344.     if (pc->cached) {

  3345.         /*
  3346.          * for cached connections, connection data can be found
  3347.          * in the cleanup handler
  3348.          */

  3349.         for (cln = c->pool->cleanup; cln; cln = cln->next) {
  3350.             if (cln->handler == ngx_http_grpc_cleanup) {
  3351.                 ctx->connection = cln->data;
  3352.                 break;
  3353.             }
  3354.         }

  3355.         if (ctx->connection == NULL) {
  3356.             ngx_log_error(NGX_LOG_ERR, c->log, 0,
  3357.                           "no connection data found for "
  3358.                           "keepalive http2 connection");
  3359.             return NGX_ERROR;
  3360.         }

  3361.         ctx->send_window = ctx->connection->init_window;
  3362.         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3363.         ctx->connection->last_stream_id += 2;
  3364.         ctx->id = ctx->connection->last_stream_id;

  3365.         return NGX_OK;
  3366.     }

  3367.     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_grpc_conn_t));
  3368.     if (cln == NULL) {
  3369.         return NGX_ERROR;
  3370.     }

  3371.     cln->handler = ngx_http_grpc_cleanup;
  3372.     ctx->connection = cln->data;

  3373.     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3374.     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3375.     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3376.     ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
  3377.     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;

  3378.     ctx->id = 1;
  3379.     ctx->connection->last_stream_id = 1;

  3380.     return NGX_OK;
  3381. }


  3382. static void
  3383. ngx_http_grpc_cleanup(void *data)
  3384. {
  3385. #if 0
  3386.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  3387.                    "grpc cleanup");
  3388. #endif
  3389.     return;
  3390. }


  3391. static void
  3392. ngx_http_grpc_abort_request(ngx_http_request_t *r)
  3393. {
  3394.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3395.                    "abort grpc request");
  3396.     return;
  3397. }


  3398. static void
  3399. ngx_http_grpc_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
  3400. {
  3401.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  3402.                    "finalize grpc request");
  3403.     return;
  3404. }


  3405. static ngx_int_t
  3406. ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r,
  3407.     ngx_http_variable_value_t *v, uintptr_t data)
  3408. {
  3409.     ngx_table_elt_t  *te;

  3410.     te = r->headers_in.te;

  3411.     if (te == NULL) {
  3412.         v->not_found = 1;
  3413.         return NGX_OK;
  3414.     }

  3415.     if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len,
  3416.                          (u_char *) "trailers", 8 - 1)
  3417.         == NULL)
  3418.     {
  3419.         v->not_found = 1;
  3420.         return NGX_OK;
  3421.     }

  3422.     v->valid = 1;
  3423.     v->no_cacheable = 0;
  3424.     v->not_found = 0;

  3425.     v->data = (u_char *) "trailers";
  3426.     v->len = sizeof("trailers") - 1;

  3427.     return NGX_OK;
  3428. }


  3429. static ngx_int_t
  3430. ngx_http_grpc_add_variables(ngx_conf_t *cf)
  3431. {
  3432.     ngx_http_variable_t  *var, *v;

  3433.     for (v = ngx_http_grpc_vars; v->name.len; v++) {
  3434.         var = ngx_http_add_variable(cf, &v->name, v->flags);
  3435.         if (var == NULL) {
  3436.             return NGX_ERROR;
  3437.         }

  3438.         var->get_handler = v->get_handler;
  3439.         var->data = v->data;
  3440.     }

  3441.     return NGX_OK;
  3442. }


  3443. static void *
  3444. ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
  3445. {
  3446.     ngx_http_grpc_loc_conf_t  *conf;

  3447.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_grpc_loc_conf_t));
  3448.     if (conf == NULL) {
  3449.         return NULL;
  3450.     }

  3451.     /*
  3452.      * set by ngx_pcalloc():
  3453.      *
  3454.      *     conf->upstream.ignore_headers = 0;
  3455.      *     conf->upstream.next_upstream = 0;
  3456.      *     conf->upstream.hide_headers_hash = { NULL, 0 };
  3457.      *
  3458.      *     conf->headers.lengths = NULL;
  3459.      *     conf->headers.values = NULL;
  3460.      *     conf->headers.hash = { NULL, 0 };
  3461.      *     conf->host = { 0, NULL };
  3462.      *     conf->host_value = NULL;
  3463.      *     conf->ssl = 0;
  3464.      *     conf->ssl_protocols = 0;
  3465.      *     conf->ssl_ciphers = { 0, NULL };
  3466.      *     conf->ssl_trusted_certificate = { 0, NULL };
  3467.      *     conf->ssl_crl = { 0, NULL };
  3468.      */

  3469.     conf->upstream.local = NGX_CONF_UNSET_PTR;
  3470.     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
  3471.     conf->upstream.socket_rcvbuf = NGX_CONF_UNSET_SIZE;
  3472.     conf->upstream.socket_sndbuf = NGX_CONF_UNSET_SIZE;
  3473.     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
  3474.     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
  3475.     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
  3476.     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
  3477.     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;

  3478.     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;

  3479.     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
  3480.     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;

  3481.     conf->upstream.intercept_errors = NGX_CONF_UNSET;

  3482. #if (NGX_HTTP_SSL)
  3483.     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
  3484.     conf->upstream.ssl_name = NGX_CONF_UNSET_PTR;
  3485.     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
  3486.     conf->upstream.ssl_verify = NGX_CONF_UNSET;
  3487.     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
  3488.     conf->upstream.ssl_certificate = NGX_CONF_UNSET_PTR;
  3489.     conf->upstream.ssl_certificate_key = NGX_CONF_UNSET_PTR;
  3490.     conf->upstream.ssl_certificate_cache = NGX_CONF_UNSET_PTR;
  3491.     conf->upstream.ssl_passwords = NGX_CONF_UNSET_PTR;
  3492.     conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
  3493. #endif

  3494.     /* the hardcoded values */
  3495.     conf->upstream.cyclic_temp_file = 0;
  3496.     conf->upstream.buffering = 0;
  3497.     conf->upstream.ignore_client_abort = 0;
  3498.     conf->upstream.send_lowat = 0;
  3499.     conf->upstream.bufs.num = 0;
  3500.     conf->upstream.busy_buffers_size = 0;
  3501.     conf->upstream.max_temp_file_size = 0;
  3502.     conf->upstream.temp_file_write_size = 0;
  3503.     conf->upstream.pass_request_headers = 1;
  3504.     conf->upstream.pass_request_body = 1;
  3505.     conf->upstream.force_ranges = 0;
  3506.     conf->upstream.pass_trailers = 1;
  3507.     conf->upstream.pass_early_hints = 1;
  3508.     conf->upstream.preserve_output = 1;

  3509.     conf->headers_source = NGX_CONF_UNSET_PTR;

  3510.     ngx_str_set(&conf->upstream.module, "grpc");

  3511.     return conf;
  3512. }


  3513. static char *
  3514. ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  3515. {
  3516.     ngx_http_grpc_loc_conf_t *prev = parent;
  3517.     ngx_http_grpc_loc_conf_t *conf = child;

  3518.     ngx_int_t                  rc;
  3519.     ngx_hash_init_t            hash;
  3520.     ngx_http_core_loc_conf_t  *clcf;

  3521.     ngx_conf_merge_ptr_value(conf->upstream.local,
  3522.                               prev->upstream.local, NULL);

  3523.     ngx_conf_merge_value(conf->upstream.socket_keepalive,
  3524.                               prev->upstream.socket_keepalive, 0);

  3525.     ngx_conf_merge_size_value(conf->upstream.socket_rcvbuf,
  3526.                               prev->upstream.socket_rcvbuf, 0);

  3527.     ngx_conf_merge_size_value(conf->upstream.socket_sndbuf,
  3528.                               prev->upstream.socket_sndbuf, 0);

  3529.     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
  3530.                               prev->upstream.next_upstream_tries, 0);

  3531.     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
  3532.                               prev->upstream.connect_timeout, 60000);

  3533.     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
  3534.                               prev->upstream.send_timeout, 60000);

  3535.     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
  3536.                               prev->upstream.read_timeout, 60000);

  3537.     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
  3538.                               prev->upstream.next_upstream_timeout, 0);

  3539.     ngx_conf_merge_size_value(conf->upstream.buffer_size,
  3540.                               prev->upstream.buffer_size,
  3541.                               (size_t) ngx_pagesize);

  3542.     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
  3543.                               prev->upstream.ignore_headers,
  3544.                               NGX_CONF_BITMASK_SET);

  3545.     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
  3546.                               prev->upstream.next_upstream,
  3547.                               (NGX_CONF_BITMASK_SET
  3548.                                |NGX_HTTP_UPSTREAM_FT_ERROR
  3549.                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));

  3550.     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
  3551.         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
  3552.                                        |NGX_HTTP_UPSTREAM_FT_OFF;
  3553.     }

  3554.     ngx_conf_merge_value(conf->upstream.intercept_errors,
  3555.                               prev->upstream.intercept_errors, 0);

  3556. #if (NGX_HTTP_SSL)

  3557.     if (ngx_http_grpc_merge_ssl(cf, conf, prev) != NGX_OK) {
  3558.         return NGX_CONF_ERROR;
  3559.     }

  3560.     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
  3561.                               prev->upstream.ssl_session_reuse, 1);

  3562.     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
  3563.                               (NGX_CONF_BITMASK_SET|NGX_SSL_DEFAULT_PROTOCOLS));

  3564.     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
  3565.                              "DEFAULT");

  3566.     ngx_conf_merge_ptr_value(conf->upstream.ssl_name,
  3567.                               prev->upstream.ssl_name, NULL);
  3568.     ngx_conf_merge_value(conf->upstream.ssl_server_name,
  3569.                               prev->upstream.ssl_server_name, 0);
  3570.     ngx_conf_merge_value(conf->upstream.ssl_verify,
  3571.                               prev->upstream.ssl_verify, 0);
  3572.     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
  3573.                               prev->ssl_verify_depth, 1);
  3574.     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
  3575.                               prev->ssl_trusted_certificate, "");
  3576.     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");

  3577.     ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate,
  3578.                               prev->upstream.ssl_certificate, NULL);
  3579.     ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key,
  3580.                               prev->upstream.ssl_certificate_key, NULL);
  3581.     ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_cache,
  3582.                               prev->upstream.ssl_certificate_cache, NULL);

  3583.     if (ngx_http_upstream_merge_ssl_passwords(cf, &conf->upstream,
  3584.                                               &prev->upstream)
  3585.         != NGX_OK)
  3586.     {
  3587.         return NGX_CONF_ERROR;
  3588.     }

  3589.     ngx_conf_merge_ptr_value(conf->ssl_conf_commands,
  3590.                               prev->ssl_conf_commands, NULL);

  3591.     if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) {
  3592.         return NGX_CONF_ERROR;
  3593.     }

  3594. #endif

  3595.     hash.max_size = 512;
  3596.     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
  3597.     hash.name = "grpc_headers_hash";

  3598.     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
  3599.             &prev->upstream, ngx_http_grpc_hide_headers, &hash)
  3600.         != NGX_OK)
  3601.     {
  3602.         return NGX_CONF_ERROR;
  3603.     }

  3604.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  3605.     if (clcf->noname
  3606.         && conf->upstream.upstream == NULL && conf->grpc_lengths == NULL)
  3607.     {
  3608.         conf->upstream.upstream = prev->upstream.upstream;
  3609.         conf->host = prev->host;

  3610.         conf->grpc_lengths = prev->grpc_lengths;
  3611.         conf->grpc_values = prev->grpc_values;

  3612. #if (NGX_HTTP_SSL)
  3613.         conf->ssl = prev->ssl;
  3614. #endif
  3615.     }

  3616.     if (clcf->lmt_excpt && clcf->handler == NULL
  3617.         && (conf->upstream.upstream || conf->grpc_lengths))
  3618.     {
  3619.         clcf->handler = ngx_http_grpc_handler;
  3620.     }

  3621.     ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL);

  3622.     if (conf->headers_source == prev->headers_source) {
  3623.         conf->headers = prev->headers;
  3624.         conf->host_value = prev->host_value;
  3625.     }

  3626.     rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers,
  3627.                                     ngx_http_grpc_headers);
  3628.     if (rc != NGX_OK) {
  3629.         return NGX_CONF_ERROR;
  3630.     }

  3631.     /*
  3632.      * special handling to preserve conf->headers in the "http" section
  3633.      * to inherit it to all servers
  3634.      */

  3635.     if (prev->headers.hash.buckets == NULL
  3636.         && conf->headers_source == prev->headers_source)
  3637.     {
  3638.         prev->headers = conf->headers;
  3639.         prev->host_value = conf->host_value;
  3640.     }

  3641.     return NGX_CONF_OK;
  3642. }


  3643. static ngx_int_t
  3644. ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
  3645.     ngx_http_grpc_headers_t *headers, ngx_keyval_t *default_headers)
  3646. {
  3647.     u_char                            *p;
  3648.     size_t                             size;
  3649.     uintptr_t                         *code;
  3650.     ngx_uint_t                         i;
  3651.     ngx_array_t                        headers_names, headers_merged;
  3652.     ngx_keyval_t                      *src, *s, *h;
  3653.     ngx_hash_key_t                    *hk;
  3654.     ngx_hash_init_t                    hash;
  3655.     ngx_http_script_compile_t          sc;
  3656.     ngx_http_script_copy_code_t       *copy;
  3657.     ngx_http_compile_complex_value_t   ccv;

  3658.     if (headers->hash.buckets) {
  3659.         return NGX_OK;
  3660.     }

  3661.     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
  3662.         != NGX_OK)
  3663.     {
  3664.         return NGX_ERROR;
  3665.     }

  3666.     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
  3667.         != NGX_OK)
  3668.     {
  3669.         return NGX_ERROR;
  3670.     }

  3671.     headers->lengths = ngx_array_create(cf->pool, 64, 1);
  3672.     if (headers->lengths == NULL) {
  3673.         return NGX_ERROR;
  3674.     }

  3675.     headers->values = ngx_array_create(cf->pool, 512, 1);
  3676.     if (headers->values == NULL) {
  3677.         return NGX_ERROR;
  3678.     }

  3679.     if (conf->headers_source) {

  3680.         src = conf->headers_source->elts;
  3681.         for (i = 0; i < conf->headers_source->nelts; i++) {

  3682.             if (src[i].key.len == 4
  3683.                 && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0)
  3684.             {
  3685.                 conf->host_value = ngx_pcalloc(cf->pool,
  3686.                                              sizeof(ngx_http_complex_value_t));
  3687.                 if (conf->host_value == NULL) {
  3688.                     return NGX_ERROR;
  3689.                 }

  3690.                 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

  3691.                 ccv.cf = cf;
  3692.                 ccv.value = &src[i].value;
  3693.                 ccv.complex_value = conf->host_value;

  3694.                 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
  3695.                     return NGX_ERROR;
  3696.                 }

  3697.                 continue;
  3698.             }

  3699.             s = ngx_array_push(&headers_merged);
  3700.             if (s == NULL) {
  3701.                 return NGX_ERROR;
  3702.             }

  3703.             *s = src[i];
  3704.         }
  3705.     }

  3706.     h = default_headers;

  3707.     while (h->key.len) {

  3708.         src = headers_merged.elts;
  3709.         for (i = 0; i < headers_merged.nelts; i++) {
  3710.             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
  3711.                 goto next;
  3712.             }
  3713.         }

  3714.         s = ngx_array_push(&headers_merged);
  3715.         if (s == NULL) {
  3716.             return NGX_ERROR;
  3717.         }

  3718.         *s = *h;

  3719.     next:

  3720.         h++;
  3721.     }


  3722.     src = headers_merged.elts;
  3723.     for (i = 0; i < headers_merged.nelts; i++) {

  3724.         hk = ngx_array_push(&headers_names);
  3725.         if (hk == NULL) {
  3726.             return NGX_ERROR;
  3727.         }

  3728.         hk->key = src[i].key;
  3729.         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
  3730.         hk->value = (void *) 1;

  3731.         if (src[i].value.len == 0) {
  3732.             continue;
  3733.         }

  3734.         copy = ngx_array_push_n(headers->lengths,
  3735.                                 sizeof(ngx_http_script_copy_code_t));
  3736.         if (copy == NULL) {
  3737.             return NGX_ERROR;
  3738.         }

  3739.         copy->code = (ngx_http_script_code_pt) (void *)
  3740.                                                  ngx_http_script_copy_len_code;
  3741.         copy->len = src[i].key.len;

  3742.         size = (sizeof(ngx_http_script_copy_code_t)
  3743.                 + src[i].key.len + sizeof(uintptr_t) - 1)
  3744.                & ~(sizeof(uintptr_t) - 1);

  3745.         copy = ngx_array_push_n(headers->values, size);
  3746.         if (copy == NULL) {
  3747.             return NGX_ERROR;
  3748.         }

  3749.         copy->code = ngx_http_script_copy_code;
  3750.         copy->len = src[i].key.len;

  3751.         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
  3752.         ngx_memcpy(p, src[i].key.data, src[i].key.len);

  3753.         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  3754.         sc.cf = cf;
  3755.         sc.source = &src[i].value;
  3756.         sc.flushes = &headers->flushes;
  3757.         sc.lengths = &headers->lengths;
  3758.         sc.values = &headers->values;

  3759.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  3760.             return NGX_ERROR;
  3761.         }

  3762.         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  3763.         if (code == NULL) {
  3764.             return NGX_ERROR;
  3765.         }

  3766.         *code = (uintptr_t) NULL;

  3767.         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
  3768.         if (code == NULL) {
  3769.             return NGX_ERROR;
  3770.         }

  3771.         *code = (uintptr_t) NULL;
  3772.     }

  3773.     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
  3774.     if (code == NULL) {
  3775.         return NGX_ERROR;
  3776.     }

  3777.     *code = (uintptr_t) NULL;


  3778.     hash.hash = &headers->hash;
  3779.     hash.key = ngx_hash_key_lc;
  3780.     hash.max_size = 512;
  3781.     hash.bucket_size = 64;
  3782.     hash.name = "grpc_headers_hash";
  3783.     hash.pool = cf->pool;
  3784.     hash.temp_pool = NULL;

  3785.     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
  3786. }


  3787. static char *
  3788. ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3789. {
  3790.     ngx_http_grpc_loc_conf_t *glcf = conf;

  3791.     size_t                      add;
  3792.     ngx_str_t                  *value, *url;
  3793.     ngx_url_t                   u;
  3794.     ngx_uint_t                  n;
  3795.     ngx_http_core_loc_conf_t   *clcf;
  3796.     ngx_http_script_compile_t   sc;

  3797.     if (glcf->upstream.upstream || glcf->grpc_lengths) {
  3798.         return "is duplicate";
  3799.     }

  3800.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

  3801.     clcf->handler = ngx_http_grpc_handler;

  3802.     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
  3803.         clcf->auto_redirect = 1;
  3804.     }

  3805.     value = cf->args->elts;

  3806.     url = &value[1];

  3807.     n = ngx_http_script_variables_count(url);

  3808.     if (n) {

  3809.         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));

  3810.         sc.cf = cf;
  3811.         sc.source = url;
  3812.         sc.lengths = &glcf->grpc_lengths;
  3813.         sc.values = &glcf->grpc_values;
  3814.         sc.variables = n;
  3815.         sc.complete_lengths = 1;
  3816.         sc.complete_values = 1;

  3817.         if (ngx_http_script_compile(&sc) != NGX_OK) {
  3818.             return NGX_CONF_ERROR;
  3819.         }

  3820. #if (NGX_HTTP_SSL)
  3821.         glcf->ssl = 1;
  3822. #endif

  3823.         return NGX_CONF_OK;
  3824.     }

  3825.     if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) {
  3826.         add = 7;

  3827.     } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) {

  3828. #if (NGX_HTTP_SSL)
  3829.         glcf->ssl = 1;

  3830.         add = 8;
  3831. #else
  3832.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3833.                            "grpcs protocol requires SSL support");
  3834.         return NGX_CONF_ERROR;
  3835. #endif

  3836.     } else {
  3837.         add = 0;
  3838.     }

  3839.     ngx_memzero(&u, sizeof(ngx_url_t));

  3840.     u.url.len = url->len - add;
  3841.     u.url.data = url->data + add;
  3842.     u.no_resolve = 1;

  3843.     glcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
  3844.     if (glcf->upstream.upstream == NULL) {
  3845.         return NGX_CONF_ERROR;
  3846.     }

  3847.     if (u.family != AF_UNIX) {

  3848.         if (u.no_port) {
  3849.             glcf->host = u.host;

  3850.         } else {
  3851.             glcf->host.len = u.host.len + 1 + u.port_text.len;
  3852.             glcf->host.data = u.host.data;
  3853.         }

  3854.     } else {
  3855.         ngx_str_set(&glcf->host, "localhost");
  3856.     }

  3857.     return NGX_CONF_OK;
  3858. }


  3859. #if (NGX_HTTP_SSL)

  3860. static char *
  3861. ngx_http_grpc_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
  3862.     void *conf)
  3863. {
  3864.     ngx_http_grpc_loc_conf_t *plcf = conf;

  3865.     time_t       inactive, valid;
  3866.     ngx_str_t   *value, s;
  3867.     ngx_int_t    max;
  3868.     ngx_uint_t   i;

  3869.     if (plcf->upstream.ssl_certificate_cache != NGX_CONF_UNSET_PTR) {
  3870.         return "is duplicate";
  3871.     }

  3872.     value = cf->args->elts;

  3873.     max = 0;
  3874.     inactive = 10;
  3875.     valid = 60;

  3876.     for (i = 1; i < cf->args->nelts; i++) {

  3877.         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {

  3878.             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
  3879.             if (max <= 0) {
  3880.                 goto failed;
  3881.             }

  3882.             continue;
  3883.         }

  3884.         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

  3885.             s.len = value[i].len - 9;
  3886.             s.data = value[i].data + 9;

  3887.             inactive = ngx_parse_time(&s, 1);
  3888.             if (inactive == (time_t) NGX_ERROR) {
  3889.                 goto failed;
  3890.             }

  3891.             continue;
  3892.         }

  3893.         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {

  3894.             s.len = value[i].len - 6;
  3895.             s.data = value[i].data + 6;

  3896.             valid = ngx_parse_time(&s, 1);
  3897.             if (valid == (time_t) NGX_ERROR) {
  3898.                 goto failed;
  3899.             }

  3900.             continue;
  3901.         }

  3902.         if (ngx_strcmp(value[i].data, "off") == 0) {

  3903.             plcf->upstream.ssl_certificate_cache = NULL;

  3904.             continue;
  3905.         }

  3906.     failed:

  3907.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3908.                            "invalid parameter \"%V\"", &value[i]);
  3909.         return NGX_CONF_ERROR;
  3910.     }

  3911.     if (plcf->upstream.ssl_certificate_cache == NULL) {
  3912.         return NGX_CONF_OK;
  3913.     }

  3914.     if (max == 0) {
  3915.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  3916.                            "\"grpc_ssl_certificate_cache\" must have "
  3917.                            "the \"max\" parameter");
  3918.         return NGX_CONF_ERROR;
  3919.     }

  3920.     plcf->upstream.ssl_certificate_cache = ngx_ssl_cache_init(cf->pool, max,
  3921.                                                               valid, inactive);
  3922.     if (plcf->upstream.ssl_certificate_cache == NULL) {
  3923.         return NGX_CONF_ERROR;
  3924.     }

  3925.     return NGX_CONF_OK;
  3926. }


  3927. static char *
  3928. ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  3929. {
  3930.     ngx_http_grpc_loc_conf_t *glcf = conf;

  3931.     ngx_str_t  *value;

  3932.     if (glcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) {
  3933.         return "is duplicate";
  3934.     }

  3935.     value = cf->args->elts;

  3936.     glcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);

  3937.     if (glcf->upstream.ssl_passwords == NULL) {
  3938.         return NGX_CONF_ERROR;
  3939.     }

  3940.     return NGX_CONF_OK;
  3941. }


  3942. static char *
  3943. ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
  3944. {
  3945. #ifndef SSL_CONF_FLAG_FILE
  3946.     return "is not supported on this platform";
  3947. #else
  3948.     return NGX_CONF_OK;
  3949. #endif
  3950. }


  3951. static ngx_int_t
  3952. ngx_http_grpc_merge_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
  3953.     ngx_http_grpc_loc_conf_t *prev)
  3954. {
  3955.     ngx_uint_t  preserve;

  3956.     if (conf->ssl_protocols == 0
  3957.         && conf->ssl_ciphers.data == NULL
  3958.         && conf->upstream.ssl_certificate == NGX_CONF_UNSET_PTR
  3959.         && conf->upstream.ssl_certificate_key == NGX_CONF_UNSET_PTR
  3960.         && conf->upstream.ssl_passwords == NGX_CONF_UNSET_PTR
  3961.         && conf->upstream.ssl_verify == NGX_CONF_UNSET
  3962.         && conf->ssl_verify_depth == NGX_CONF_UNSET_UINT
  3963.         && conf->ssl_trusted_certificate.data == NULL
  3964.         && conf->ssl_crl.data == NULL
  3965.         && conf->upstream.ssl_session_reuse == NGX_CONF_UNSET
  3966.         && conf->ssl_conf_commands == NGX_CONF_UNSET_PTR)
  3967.     {
  3968.         if (prev->upstream.ssl) {
  3969.             conf->upstream.ssl = prev->upstream.ssl;
  3970.             return NGX_OK;
  3971.         }

  3972.         preserve = 1;

  3973.     } else {
  3974.         preserve = 0;
  3975.     }

  3976.     conf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
  3977.     if (conf->upstream.ssl == NULL) {
  3978.         return NGX_ERROR;
  3979.     }

  3980.     conf->upstream.ssl->log = cf->log;

  3981.     /*
  3982.      * special handling to preserve conf->upstream.ssl
  3983.      * in the "http" section to inherit it to all servers
  3984.      */

  3985.     if (preserve) {
  3986.         prev->upstream.ssl = conf->upstream.ssl;
  3987.     }

  3988.     return NGX_OK;
  3989. }


  3990. static ngx_int_t
  3991. ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf)
  3992. {
  3993.     ngx_pool_cleanup_t  *cln;

  3994.     if (glcf->upstream.ssl->ctx) {
  3995.         return NGX_OK;
  3996.     }

  3997.     if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL)
  3998.         != NGX_OK)
  3999.     {
  4000.         return NGX_ERROR;
  4001.     }

  4002.     cln = ngx_pool_cleanup_add(cf->pool, 0);
  4003.     if (cln == NULL) {
  4004.         ngx_ssl_cleanup_ctx(glcf->upstream.ssl);
  4005.         return NGX_ERROR;
  4006.     }

  4007.     cln->handler = ngx_ssl_cleanup_ctx;
  4008.     cln->data = glcf->upstream.ssl;

  4009.     if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0)
  4010.         != NGX_OK)
  4011.     {
  4012.         return NGX_ERROR;
  4013.     }

  4014.     if (glcf->upstream.ssl_certificate
  4015.         && glcf->upstream.ssl_certificate->value.len)
  4016.     {
  4017.         if (glcf->upstream.ssl_certificate_key == NULL) {
  4018.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  4019.                           "no \"grpc_ssl_certificate_key\" is defined "
  4020.                           "for certificate \"%V\"",
  4021.                           &glcf->upstream.ssl_certificate->value);
  4022.             return NGX_ERROR;
  4023.         }

  4024.         if (glcf->upstream.ssl_certificate->lengths == NULL
  4025.             && glcf->upstream.ssl_certificate_key->lengths == NULL)
  4026.         {
  4027.             if (ngx_ssl_certificate(cf, glcf->upstream.ssl,
  4028.                                     &glcf->upstream.ssl_certificate->value,
  4029.                                     &glcf->upstream.ssl_certificate_key->value,
  4030.                                     glcf->upstream.ssl_passwords)
  4031.                 != NGX_OK)
  4032.             {
  4033.                 return NGX_ERROR;
  4034.             }
  4035.         }
  4036.     }

  4037.     if (glcf->upstream.ssl_verify) {
  4038.         if (glcf->ssl_trusted_certificate.len == 0) {
  4039.             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  4040.                       "no grpc_ssl_trusted_certificate for grpc_ssl_verify");
  4041.             return NGX_ERROR;
  4042.         }

  4043.         if (ngx_ssl_trusted_certificate(cf, glcf->upstream.ssl,
  4044.                                         &glcf->ssl_trusted_certificate,
  4045.                                         glcf->ssl_verify_depth)
  4046.             != NGX_OK)
  4047.         {
  4048.             return NGX_ERROR;
  4049.         }

  4050.         if (ngx_ssl_crl(cf, glcf->upstream.ssl, &glcf->ssl_crl) != NGX_OK) {
  4051.             return NGX_ERROR;
  4052.         }
  4053.     }

  4054.     if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl,
  4055.                                      glcf->upstream.ssl_session_reuse)
  4056.         != NGX_OK)
  4057.     {
  4058.         return NGX_ERROR;
  4059.     }

  4060. #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation

  4061.     if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx,
  4062.                                 (u_char *) "\x02h2", 3)
  4063.         != 0)
  4064.     {
  4065.         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
  4066.                       "SSL_CTX_set_alpn_protos() failed");
  4067.         return NGX_ERROR;
  4068.     }

  4069. #endif

  4070.     if (ngx_ssl_conf_commands(cf, glcf->upstream.ssl, glcf->ssl_conf_commands)
  4071.         != NGX_OK)
  4072.     {
  4073.         return NGX_ERROR;
  4074.     }

  4075.     return NGX_OK;
  4076. }

  4077. #endif