Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.19.2 ]​[ nginx-1.18.0 ]​

0001 
0002 /*
0003  * Copyright (C) Maxim Dounin
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_array_t               *flushes;
0015     ngx_array_t               *lengths;
0016     ngx_array_t               *values;
0017     ngx_hash_t                 hash;
0018 } ngx_http_grpc_headers_t;
0019 
0020 
0021 typedef struct {
0022     ngx_http_upstream_conf_t   upstream;
0023 
0024     ngx_http_grpc_headers_t    headers;
0025     ngx_array_t               *headers_source;
0026 
0027     ngx_str_t                  host;
0028     ngx_uint_t                 host_set;
0029 
0030     ngx_array_t               *grpc_lengths;
0031     ngx_array_t               *grpc_values;
0032 
0033 #if (NGX_HTTP_SSL)
0034     ngx_uint_t                 ssl;
0035     ngx_uint_t                 ssl_protocols;
0036     ngx_str_t                  ssl_ciphers;
0037     ngx_uint_t                 ssl_verify_depth;
0038     ngx_str_t                  ssl_trusted_certificate;
0039     ngx_str_t                  ssl_crl;
0040     ngx_str_t                  ssl_certificate;
0041     ngx_str_t                  ssl_certificate_key;
0042     ngx_array_t               *ssl_passwords;
0043 #endif
0044 } ngx_http_grpc_loc_conf_t;
0045 
0046 
0047 typedef enum {
0048     ngx_http_grpc_st_start = 0,
0049     ngx_http_grpc_st_length_2,
0050     ngx_http_grpc_st_length_3,
0051     ngx_http_grpc_st_type,
0052     ngx_http_grpc_st_flags,
0053     ngx_http_grpc_st_stream_id,
0054     ngx_http_grpc_st_stream_id_2,
0055     ngx_http_grpc_st_stream_id_3,
0056     ngx_http_grpc_st_stream_id_4,
0057     ngx_http_grpc_st_payload,
0058     ngx_http_grpc_st_padding
0059 } ngx_http_grpc_state_e;
0060 
0061 
0062 typedef struct {
0063     size_t                     init_window;
0064     size_t                     send_window;
0065     size_t                     recv_window;
0066     ngx_uint_t                 last_stream_id;
0067 } ngx_http_grpc_conn_t;
0068 
0069 
0070 typedef struct {
0071     ngx_http_grpc_state_e      state;
0072     ngx_uint_t                 frame_state;
0073     ngx_uint_t                 fragment_state;
0074 
0075     ngx_chain_t               *in;
0076     ngx_chain_t               *out;
0077     ngx_chain_t               *free;
0078     ngx_chain_t               *busy;
0079 
0080     ngx_http_grpc_conn_t      *connection;
0081 
0082     ngx_uint_t                 id;
0083 
0084     ngx_uint_t                 pings;
0085     ngx_uint_t                 settings;
0086 
0087     off_t                      length;
0088 
0089     ssize_t                    send_window;
0090     size_t                     recv_window;
0091 
0092     size_t                     rest;
0093     ngx_uint_t                 stream_id;
0094     u_char                     type;
0095     u_char                     flags;
0096     u_char                     padding;
0097 
0098     ngx_uint_t                 error;
0099     ngx_uint_t                 window_update;
0100 
0101     ngx_uint_t                 setting_id;
0102     ngx_uint_t                 setting_value;
0103 
0104     u_char                     ping_data[8];
0105 
0106     ngx_uint_t                 index;
0107     ngx_str_t                  name;
0108     ngx_str_t                  value;
0109 
0110     u_char                    *field_end;
0111     size_t                     field_length;
0112     size_t                     field_rest;
0113     u_char                     field_state;
0114 
0115     unsigned                   literal:1;
0116     unsigned                   field_huffman:1;
0117 
0118     unsigned                   header_sent:1;
0119     unsigned                   output_closed:1;
0120     unsigned                   output_blocked:1;
0121     unsigned                   parsing_headers:1;
0122     unsigned                   end_stream:1;
0123     unsigned                   done:1;
0124     unsigned                   status:1;
0125     unsigned                   rst:1;
0126 
0127     ngx_http_request_t        *request;
0128 
0129     ngx_str_t                  host;
0130 } ngx_http_grpc_ctx_t;
0131 
0132 
0133 typedef struct {
0134     u_char                     length_0;
0135     u_char                     length_1;
0136     u_char                     length_2;
0137     u_char                     type;
0138     u_char                     flags;
0139     u_char                     stream_id_0;
0140     u_char                     stream_id_1;
0141     u_char                     stream_id_2;
0142     u_char                     stream_id_3;
0143 } ngx_http_grpc_frame_t;
0144 
0145 
0146 static ngx_int_t ngx_http_grpc_eval(ngx_http_request_t *r,
0147     ngx_http_grpc_ctx_t *ctx, ngx_http_grpc_loc_conf_t *glcf);
0148 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r);
0149 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r);
0150 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in);
0151 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r);
0152 static ngx_int_t ngx_http_grpc_filter_init(void *data);
0153 static ngx_int_t ngx_http_grpc_filter(void *data, ssize_t bytes);
0154 
0155 static ngx_int_t ngx_http_grpc_parse_frame(ngx_http_request_t *r,
0156     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0157 static ngx_int_t ngx_http_grpc_parse_header(ngx_http_request_t *r,
0158     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0159 static ngx_int_t ngx_http_grpc_parse_fragment(ngx_http_request_t *r,
0160     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0161 static ngx_int_t ngx_http_grpc_validate_header_name(ngx_http_request_t *r,
0162     ngx_str_t *s);
0163 static ngx_int_t ngx_http_grpc_validate_header_value(ngx_http_request_t *r,
0164     ngx_str_t *s);
0165 static ngx_int_t ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r,
0166     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0167 static ngx_int_t ngx_http_grpc_parse_goaway(ngx_http_request_t *r,
0168     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0169 static ngx_int_t ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
0170     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0171 static ngx_int_t ngx_http_grpc_parse_settings(ngx_http_request_t *r,
0172     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0173 static ngx_int_t ngx_http_grpc_parse_ping(ngx_http_request_t *r,
0174     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b);
0175 
0176 static ngx_int_t ngx_http_grpc_send_settings_ack(ngx_http_request_t *r,
0177     ngx_http_grpc_ctx_t *ctx);
0178 static ngx_int_t ngx_http_grpc_send_ping_ack(ngx_http_request_t *r,
0179     ngx_http_grpc_ctx_t *ctx);
0180 static ngx_int_t ngx_http_grpc_send_window_update(ngx_http_request_t *r,
0181     ngx_http_grpc_ctx_t *ctx);
0182 
0183 static ngx_chain_t *ngx_http_grpc_get_buf(ngx_http_request_t *r,
0184     ngx_http_grpc_ctx_t *ctx);
0185 static ngx_http_grpc_ctx_t *ngx_http_grpc_get_ctx(ngx_http_request_t *r);
0186 static ngx_int_t ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
0187     ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc);
0188 static void ngx_http_grpc_cleanup(void *data);
0189 
0190 static void ngx_http_grpc_abort_request(ngx_http_request_t *r);
0191 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r,
0192     ngx_int_t rc);
0193 
0194 static ngx_int_t ngx_http_grpc_internal_trailers_variable(
0195     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
0196 
0197 static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf);
0198 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf);
0199 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf,
0200     void *parent, void *child);
0201 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf,
0202     ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers,
0203     ngx_keyval_t *default_headers);
0204 
0205 static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd,
0206     void *conf);
0207 
0208 #if (NGX_HTTP_SSL)
0209 static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf,
0210     ngx_command_t *cmd, void *conf);
0211 static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf,
0212     ngx_http_grpc_loc_conf_t *glcf);
0213 #endif
0214 
0215 
0216 static ngx_conf_bitmask_t  ngx_http_grpc_next_upstream_masks[] = {
0217     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
0218     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
0219     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
0220     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
0221     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
0222     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
0223     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
0224     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
0225     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
0226     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0227     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
0228     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
0229     { ngx_null_string, 0 }
0230 };
0231 
0232 
0233 #if (NGX_HTTP_SSL)
0234 
0235 static ngx_conf_bitmask_t  ngx_http_grpc_ssl_protocols[] = {
0236     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
0237     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
0238     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
0239     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
0240     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
0241     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
0242     { ngx_null_string, 0 }
0243 };
0244 
0245 #endif
0246 
0247 
0248 static ngx_command_t  ngx_http_grpc_commands[] = {
0249 
0250     { ngx_string("grpc_pass"),
0251       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
0252       ngx_http_grpc_pass,
0253       NGX_HTTP_LOC_CONF_OFFSET,
0254       0,
0255       NULL },
0256 
0257     { ngx_string("grpc_bind"),
0258       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0259       ngx_http_upstream_bind_set_slot,
0260       NGX_HTTP_LOC_CONF_OFFSET,
0261       offsetof(ngx_http_grpc_loc_conf_t, upstream.local),
0262       NULL },
0263 
0264     { ngx_string("grpc_socket_keepalive"),
0265       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0266       ngx_conf_set_flag_slot,
0267       NGX_HTTP_LOC_CONF_OFFSET,
0268       offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive),
0269       NULL },
0270 
0271     { ngx_string("grpc_connect_timeout"),
0272       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0273       ngx_conf_set_msec_slot,
0274       NGX_HTTP_LOC_CONF_OFFSET,
0275       offsetof(ngx_http_grpc_loc_conf_t, upstream.connect_timeout),
0276       NULL },
0277 
0278     { ngx_string("grpc_send_timeout"),
0279       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0280       ngx_conf_set_msec_slot,
0281       NGX_HTTP_LOC_CONF_OFFSET,
0282       offsetof(ngx_http_grpc_loc_conf_t, upstream.send_timeout),
0283       NULL },
0284 
0285     { ngx_string("grpc_intercept_errors"),
0286       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0287       ngx_conf_set_flag_slot,
0288       NGX_HTTP_LOC_CONF_OFFSET,
0289       offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors),
0290       NULL },
0291 
0292     { ngx_string("grpc_buffer_size"),
0293       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0294       ngx_conf_set_size_slot,
0295       NGX_HTTP_LOC_CONF_OFFSET,
0296       offsetof(ngx_http_grpc_loc_conf_t, upstream.buffer_size),
0297       NULL },
0298 
0299     { ngx_string("grpc_read_timeout"),
0300       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0301       ngx_conf_set_msec_slot,
0302       NGX_HTTP_LOC_CONF_OFFSET,
0303       offsetof(ngx_http_grpc_loc_conf_t, upstream.read_timeout),
0304       NULL },
0305 
0306     { ngx_string("grpc_next_upstream"),
0307       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0308       ngx_conf_set_bitmask_slot,
0309       NGX_HTTP_LOC_CONF_OFFSET,
0310       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream),
0311       &ngx_http_grpc_next_upstream_masks },
0312 
0313     { ngx_string("grpc_next_upstream_tries"),
0314       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0315       ngx_conf_set_num_slot,
0316       NGX_HTTP_LOC_CONF_OFFSET,
0317       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_tries),
0318       NULL },
0319 
0320     { ngx_string("grpc_next_upstream_timeout"),
0321       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0322       ngx_conf_set_msec_slot,
0323       NGX_HTTP_LOC_CONF_OFFSET,
0324       offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_timeout),
0325       NULL },
0326 
0327     { ngx_string("grpc_set_header"),
0328       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0329       ngx_conf_set_keyval_slot,
0330       NGX_HTTP_LOC_CONF_OFFSET,
0331       offsetof(ngx_http_grpc_loc_conf_t, headers_source),
0332       NULL },
0333 
0334     { ngx_string("grpc_pass_header"),
0335       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0336       ngx_conf_set_str_array_slot,
0337       NGX_HTTP_LOC_CONF_OFFSET,
0338       offsetof(ngx_http_grpc_loc_conf_t, upstream.pass_headers),
0339       NULL },
0340 
0341     { ngx_string("grpc_hide_header"),
0342       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0343       ngx_conf_set_str_array_slot,
0344       NGX_HTTP_LOC_CONF_OFFSET,
0345       offsetof(ngx_http_grpc_loc_conf_t, upstream.hide_headers),
0346       NULL },
0347 
0348     { ngx_string("grpc_ignore_headers"),
0349       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0350       ngx_conf_set_bitmask_slot,
0351       NGX_HTTP_LOC_CONF_OFFSET,
0352       offsetof(ngx_http_grpc_loc_conf_t, upstream.ignore_headers),
0353       &ngx_http_upstream_ignore_headers_masks },
0354 
0355 #if (NGX_HTTP_SSL)
0356 
0357     { ngx_string("grpc_ssl_session_reuse"),
0358       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0359       ngx_conf_set_flag_slot,
0360       NGX_HTTP_LOC_CONF_OFFSET,
0361       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_session_reuse),
0362       NULL },
0363 
0364     { ngx_string("grpc_ssl_protocols"),
0365       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0366       ngx_conf_set_bitmask_slot,
0367       NGX_HTTP_LOC_CONF_OFFSET,
0368       offsetof(ngx_http_grpc_loc_conf_t, ssl_protocols),
0369       &ngx_http_grpc_ssl_protocols },
0370 
0371     { ngx_string("grpc_ssl_ciphers"),
0372       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0373       ngx_conf_set_str_slot,
0374       NGX_HTTP_LOC_CONF_OFFSET,
0375       offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers),
0376       NULL },
0377 
0378     { ngx_string("grpc_ssl_name"),
0379       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0380       ngx_http_set_complex_value_slot,
0381       NGX_HTTP_LOC_CONF_OFFSET,
0382       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_name),
0383       NULL },
0384 
0385     { ngx_string("grpc_ssl_server_name"),
0386       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0387       ngx_conf_set_flag_slot,
0388       NGX_HTTP_LOC_CONF_OFFSET,
0389       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_server_name),
0390       NULL },
0391 
0392     { ngx_string("grpc_ssl_verify"),
0393       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0394       ngx_conf_set_flag_slot,
0395       NGX_HTTP_LOC_CONF_OFFSET,
0396       offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_verify),
0397       NULL },
0398 
0399     { ngx_string("grpc_ssl_verify_depth"),
0400       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0401       ngx_conf_set_num_slot,
0402       NGX_HTTP_LOC_CONF_OFFSET,
0403       offsetof(ngx_http_grpc_loc_conf_t, ssl_verify_depth),
0404       NULL },
0405 
0406     { ngx_string("grpc_ssl_trusted_certificate"),
0407       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0408       ngx_conf_set_str_slot,
0409       NGX_HTTP_LOC_CONF_OFFSET,
0410       offsetof(ngx_http_grpc_loc_conf_t, ssl_trusted_certificate),
0411       NULL },
0412 
0413     { ngx_string("grpc_ssl_crl"),
0414       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0415       ngx_conf_set_str_slot,
0416       NGX_HTTP_LOC_CONF_OFFSET,
0417       offsetof(ngx_http_grpc_loc_conf_t, ssl_crl),
0418       NULL },
0419 
0420     { ngx_string("grpc_ssl_certificate"),
0421       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0422       ngx_conf_set_str_slot,
0423       NGX_HTTP_LOC_CONF_OFFSET,
0424       offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate),
0425       NULL },
0426 
0427     { ngx_string("grpc_ssl_certificate_key"),
0428       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0429       ngx_conf_set_str_slot,
0430       NGX_HTTP_LOC_CONF_OFFSET,
0431       offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key),
0432       NULL },
0433 
0434     { ngx_string("grpc_ssl_password_file"),
0435       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0436       ngx_http_grpc_ssl_password_file,
0437       NGX_HTTP_LOC_CONF_OFFSET,
0438       0,
0439       NULL },
0440 
0441 #endif
0442 
0443       ngx_null_command
0444 };
0445 
0446 
0447 static ngx_http_module_t  ngx_http_grpc_module_ctx = {
0448     ngx_http_grpc_add_variables,           /* preconfiguration */
0449     NULL,                                  /* postconfiguration */
0450 
0451     NULL,                                  /* create main configuration */
0452     NULL,                                  /* init main configuration */
0453 
0454     NULL,                                  /* create server configuration */
0455     NULL,                                  /* merge server configuration */
0456 
0457     ngx_http_grpc_create_loc_conf,         /* create location configuration */
0458     ngx_http_grpc_merge_loc_conf           /* merge location configuration */
0459 };
0460 
0461 
0462 ngx_module_t  ngx_http_grpc_module = {
0463     NGX_MODULE_V1,
0464     &ngx_http_grpc_module_ctx,             /* module context */
0465     ngx_http_grpc_commands,                /* module directives */
0466     NGX_HTTP_MODULE,                       /* module type */
0467     NULL,                                  /* init master */
0468     NULL,                                  /* init module */
0469     NULL,                                  /* init process */
0470     NULL,                                  /* init thread */
0471     NULL,                                  /* exit thread */
0472     NULL,                                  /* exit process */
0473     NULL,                                  /* exit master */
0474     NGX_MODULE_V1_PADDING
0475 };
0476 
0477 
0478 static u_char  ngx_http_grpc_connection_start[] =
0479     "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"         /* connection preface */
0480 
0481     "\x00\x00\x12\x04\x00\x00\x00\x00\x00"     /* settings frame */
0482     "\x00\x01\x00\x00\x00\x00"                 /* header table size */
0483     "\x00\x02\x00\x00\x00\x00"                 /* disable push */
0484     "\x00\x04\x7f\xff\xff\xff"                 /* initial window */
0485 
0486     "\x00\x00\x04\x08\x00\x00\x00\x00\x00"     /* window update frame */
0487     "\x7f\xff\x00\x00";
0488 
0489 
0490 static ngx_keyval_t  ngx_http_grpc_headers[] = {
0491     { ngx_string("Content-Length"), ngx_string("$content_length") },
0492     { ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
0493     { ngx_string("Host"), ngx_string("") },
0494     { ngx_string("Connection"), ngx_string("") },
0495     { ngx_string("Transfer-Encoding"), ngx_string("") },
0496     { ngx_string("Keep-Alive"), ngx_string("") },
0497     { ngx_string("Expect"), ngx_string("") },
0498     { ngx_string("Upgrade"), ngx_string("") },
0499     { ngx_null_string, ngx_null_string }
0500 };
0501 
0502 
0503 static ngx_str_t  ngx_http_grpc_hide_headers[] = {
0504     ngx_string("Date"),
0505     ngx_string("Server"),
0506     ngx_string("X-Accel-Expires"),
0507     ngx_string("X-Accel-Redirect"),
0508     ngx_string("X-Accel-Limit-Rate"),
0509     ngx_string("X-Accel-Buffering"),
0510     ngx_string("X-Accel-Charset"),
0511     ngx_null_string
0512 };
0513 
0514 
0515 static ngx_http_variable_t  ngx_http_grpc_vars[] = {
0516 
0517     { ngx_string("grpc_internal_trailers"), NULL,
0518       ngx_http_grpc_internal_trailers_variable, 0,
0519       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0520 
0521       ngx_http_null_variable
0522 };
0523 
0524 
0525 static ngx_int_t
0526 ngx_http_grpc_handler(ngx_http_request_t *r)
0527 {
0528     ngx_int_t                  rc;
0529     ngx_http_upstream_t       *u;
0530     ngx_http_grpc_ctx_t       *ctx;
0531     ngx_http_grpc_loc_conf_t  *glcf;
0532 
0533     if (ngx_http_upstream_create(r) != NGX_OK) {
0534         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0535     }
0536 
0537     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
0538     if (ctx == NULL) {
0539         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0540     }
0541 
0542     ctx->request = r;
0543 
0544     ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);
0545 
0546     glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
0547 
0548     u = r->upstream;
0549 
0550     if (glcf->grpc_lengths == NULL) {
0551         ctx->host = glcf->host;
0552 
0553 #if (NGX_HTTP_SSL)
0554         u->ssl = (glcf->upstream.ssl != NULL);
0555 
0556         if (u->ssl) {
0557             ngx_str_set(&u->schema, "grpcs://");
0558 
0559         } else {
0560             ngx_str_set(&u->schema, "grpc://");
0561         }
0562 #else
0563         ngx_str_set(&u->schema, "grpc://");
0564 #endif
0565 
0566     } else {
0567         if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) {
0568             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0569         }
0570     }
0571 
0572     u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;
0573 
0574     u->conf = &glcf->upstream;
0575 
0576     u->create_request = ngx_http_grpc_create_request;
0577     u->reinit_request = ngx_http_grpc_reinit_request;
0578     u->process_header = ngx_http_grpc_process_header;
0579     u->abort_request = ngx_http_grpc_abort_request;
0580     u->finalize_request = ngx_http_grpc_finalize_request;
0581 
0582     u->input_filter_init = ngx_http_grpc_filter_init;
0583     u->input_filter = ngx_http_grpc_filter;
0584     u->input_filter_ctx = ctx;
0585 
0586     r->request_body_no_buffering = 1;
0587 
0588     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
0589 
0590     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0591         return rc;
0592     }
0593 
0594     return NGX_DONE;
0595 }
0596 
0597 
0598 static ngx_int_t
0599 ngx_http_grpc_eval(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
0600     ngx_http_grpc_loc_conf_t *glcf)
0601 {
0602     size_t                add;
0603     ngx_url_t             url;
0604     ngx_http_upstream_t  *u;
0605 
0606     ngx_memzero(&url, sizeof(ngx_url_t));
0607 
0608     if (ngx_http_script_run(r, &url.url, glcf->grpc_lengths->elts, 0,
0609                             glcf->grpc_values->elts)
0610         == NULL)
0611     {
0612         return NGX_ERROR;
0613     }
0614 
0615     if (url.url.len > 7
0616         && ngx_strncasecmp(url.url.data, (u_char *) "grpc://", 7) == 0)
0617     {
0618         add = 7;
0619 
0620     } else if (url.url.len > 8
0621                && ngx_strncasecmp(url.url.data, (u_char *) "grpcs://", 8) == 0)
0622     {
0623 
0624 #if (NGX_HTTP_SSL)
0625         add = 8;
0626         r->upstream->ssl = 1;
0627 #else
0628         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0629                       "grpcs protocol requires SSL support");
0630         return NGX_ERROR;
0631 #endif
0632 
0633     } else {
0634         add = 0;
0635     }
0636 
0637     u = r->upstream;
0638 
0639     if (add) {
0640         u->schema.len = add;
0641         u->schema.data = url.url.data;
0642 
0643         url.url.data += add;
0644         url.url.len -= add;
0645 
0646     } else {
0647         ngx_str_set(&u->schema, "grpc://");
0648     }
0649 
0650     url.no_resolve = 1;
0651 
0652     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
0653         if (url.err) {
0654             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0655                           "%s in upstream \"%V\"", url.err, &url.url);
0656         }
0657 
0658         return NGX_ERROR;
0659     }
0660 
0661     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
0662     if (u->resolved == NULL) {
0663         return NGX_ERROR;
0664     }
0665 
0666     if (url.addrs) {
0667         u->resolved->sockaddr = url.addrs[0].sockaddr;
0668         u->resolved->socklen = url.addrs[0].socklen;
0669         u->resolved->name = url.addrs[0].name;
0670         u->resolved->naddrs = 1;
0671     }
0672 
0673     u->resolved->host = url.host;
0674     u->resolved->port = url.port;
0675     u->resolved->no_port = url.no_port;
0676 
0677     if (url.family != AF_UNIX) {
0678 
0679         if (url.no_port) {
0680             ctx->host = url.host;
0681 
0682         } else {
0683             ctx->host.len = url.host.len + 1 + url.port_text.len;
0684             ctx->host.data = url.host.data;
0685         }
0686 
0687     } else {
0688         ngx_str_set(&ctx->host, "localhost");
0689     }
0690 
0691     return NGX_OK;
0692 }
0693 
0694 
0695 static ngx_int_t
0696 ngx_http_grpc_create_request(ngx_http_request_t *r)
0697 {
0698     u_char                       *p, *tmp, *key_tmp, *val_tmp, *headers_frame;
0699     size_t                        len, tmp_len, key_len, val_len, uri_len;
0700     uintptr_t                     escape;
0701     ngx_buf_t                    *b;
0702     ngx_uint_t                    i, next;
0703     ngx_chain_t                  *cl, *body;
0704     ngx_list_part_t              *part;
0705     ngx_table_elt_t              *header;
0706     ngx_http_grpc_ctx_t          *ctx;
0707     ngx_http_upstream_t          *u;
0708     ngx_http_grpc_frame_t        *f;
0709     ngx_http_script_code_pt       code;
0710     ngx_http_grpc_loc_conf_t     *glcf;
0711     ngx_http_script_engine_t      e, le;
0712     ngx_http_script_len_code_pt   lcode;
0713 
0714     u = r->upstream;
0715 
0716     glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
0717 
0718     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
0719 
0720     len = sizeof(ngx_http_grpc_connection_start) - 1
0721           + sizeof(ngx_http_grpc_frame_t);             /* headers frame */
0722 
0723     /* :method header */
0724 
0725     if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) {
0726         len += 1;
0727         tmp_len = 0;
0728 
0729     } else {
0730         len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len;
0731         tmp_len = r->method_name.len;
0732     }
0733 
0734     /* :scheme header */
0735 
0736     len += 1;
0737 
0738     /* :path header */
0739 
0740     if (r->valid_unparsed_uri) {
0741         escape = 0;
0742         uri_len = r->unparsed_uri.len;
0743 
0744     } else {
0745         escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
0746                                     NGX_ESCAPE_URI);
0747         uri_len = r->uri.len + escape + sizeof("?") - 1 + r->args.len;
0748     }
0749 
0750     len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len;
0751 
0752     if (tmp_len < uri_len) {
0753         tmp_len = uri_len;
0754     }
0755 
0756     /* :authority header */
0757 
0758     if (!glcf->host_set) {
0759         len += 1 + NGX_HTTP_V2_INT_OCTETS + ctx->host.len;
0760 
0761         if (tmp_len < ctx->host.len) {
0762             tmp_len = ctx->host.len;
0763         }
0764     }
0765 
0766     /* other headers */
0767 
0768     ngx_http_script_flush_no_cacheable_variables(r, glcf->headers.flushes);
0769     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
0770 
0771     le.ip = glcf->headers.lengths->elts;
0772     le.request = r;
0773     le.flushed = 1;
0774 
0775     while (*(uintptr_t *) le.ip) {
0776 
0777         lcode = *(ngx_http_script_len_code_pt *) le.ip;
0778         key_len = lcode(&le);
0779 
0780         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0781             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0782         }
0783         le.ip += sizeof(uintptr_t);
0784 
0785         if (val_len == 0) {
0786             continue;
0787         }
0788 
0789         len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len
0790                  + NGX_HTTP_V2_INT_OCTETS + val_len;
0791 
0792         if (tmp_len < key_len) {
0793             tmp_len = key_len;
0794         }
0795 
0796         if (tmp_len < val_len) {
0797             tmp_len = val_len;
0798         }
0799     }
0800 
0801     if (glcf->upstream.pass_request_headers) {
0802         part = &r->headers_in.headers.part;
0803         header = part->elts;
0804 
0805         for (i = 0; /* void */; i++) {
0806 
0807             if (i >= part->nelts) {
0808                 if (part->next == NULL) {
0809                     break;
0810                 }
0811 
0812                 part = part->next;
0813                 header = part->elts;
0814                 i = 0;
0815             }
0816 
0817             if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
0818                               header[i].lowcase_key, header[i].key.len))
0819             {
0820                 continue;
0821             }
0822 
0823             len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len
0824                      + NGX_HTTP_V2_INT_OCTETS + header[i].value.len;
0825 
0826             if (tmp_len < header[i].key.len) {
0827                 tmp_len = header[i].key.len;
0828             }
0829 
0830             if (tmp_len < header[i].value.len) {
0831                 tmp_len = header[i].value.len;
0832             }
0833         }
0834     }
0835 
0836     /* continuation frames */
0837 
0838     len += sizeof(ngx_http_grpc_frame_t)
0839            * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE);
0840 
0841 
0842     b = ngx_create_temp_buf(r->pool, len);
0843     if (b == NULL) {
0844         return NGX_ERROR;
0845     }
0846 
0847     cl = ngx_alloc_chain_link(r->pool);
0848     if (cl == NULL) {
0849         return NGX_ERROR;
0850     }
0851 
0852     cl->buf = b;
0853     cl->next = NULL;
0854 
0855     tmp = ngx_palloc(r->pool, tmp_len * 3);
0856     if (tmp == NULL) {
0857         return NGX_ERROR;
0858     }
0859 
0860     key_tmp = tmp + tmp_len;
0861     val_tmp = tmp + 2 * tmp_len;
0862 
0863     /* connection preface */
0864 
0865     b->last = ngx_copy(b->last, ngx_http_grpc_connection_start,
0866                        sizeof(ngx_http_grpc_connection_start) - 1);
0867 
0868     /* headers frame */
0869 
0870     headers_frame = b->last;
0871 
0872     f = (ngx_http_grpc_frame_t *) b->last;
0873     b->last += sizeof(ngx_http_grpc_frame_t);
0874 
0875     f->length_0 = 0;
0876     f->length_1 = 0;
0877     f->length_2 = 0;
0878     f->type = NGX_HTTP_V2_HEADERS_FRAME;
0879     f->flags = 0;
0880     f->stream_id_0 = 0;
0881     f->stream_id_1 = 0;
0882     f->stream_id_2 = 0;
0883     f->stream_id_3 = 1;
0884 
0885     if (r->method == NGX_HTTP_GET) {
0886         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX);
0887 
0888         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0889                        "grpc header: \":method: GET\"");
0890 
0891     } else if (r->method == NGX_HTTP_POST) {
0892         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX);
0893 
0894         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0895                        "grpc header: \":method: POST\"");
0896 
0897     } else {
0898         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX);
0899         b->last = ngx_http_v2_write_value(b->last, r->method_name.data,
0900                                           r->method_name.len, tmp);
0901 
0902         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0903                        "grpc header: \":method: %V\"", &r->method_name);
0904     }
0905 
0906 #if (NGX_HTTP_SSL)
0907     if (u->ssl) {
0908         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);
0909 
0910         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0911                        "grpc header: \":scheme: https\"");
0912     } else
0913 #endif
0914     {
0915         *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX);
0916 
0917         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0918                        "grpc header: \":scheme: http\"");
0919     }
0920 
0921     if (r->valid_unparsed_uri) {
0922 
0923         if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') {
0924             *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX);
0925 
0926         } else {
0927             *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
0928             b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data,
0929                                               r->unparsed_uri.len, tmp);
0930         }
0931 
0932         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0933                        "grpc header: \":path: %V\"", &r->unparsed_uri);
0934 
0935     } else if (escape || r->args.len > 0) {
0936         p = val_tmp;
0937 
0938         if (escape) {
0939             p = (u_char *) ngx_escape_uri(p, r->uri.data, r->uri.len,
0940                                           NGX_ESCAPE_URI);
0941 
0942         } else {
0943             p = ngx_copy(p, r->uri.data, r->uri.len);
0944         }
0945 
0946         if (r->args.len > 0) {
0947             *p++ = '?';
0948             p = ngx_copy(p, r->args.data, r->args.len);
0949         }
0950 
0951         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
0952         b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp);
0953 
0954         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0955                        "grpc header: \":path: %*s\"", p - val_tmp, val_tmp);
0956 
0957     } else {
0958         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX);
0959         b->last = ngx_http_v2_write_value(b->last, r->uri.data,
0960                                           r->uri.len, tmp);
0961 
0962         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0963                        "grpc header: \":path: %V\"", &r->uri);
0964     }
0965 
0966     if (!glcf->host_set) {
0967         *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
0968         b->last = ngx_http_v2_write_value(b->last, ctx->host.data,
0969                                           ctx->host.len, tmp);
0970 
0971         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0972                        "grpc header: \":authority: %V\"", &ctx->host);
0973     }
0974 
0975     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
0976 
0977     e.ip = glcf->headers.values->elts;
0978     e.request = r;
0979     e.flushed = 1;
0980 
0981     le.ip = glcf->headers.lengths->elts;
0982 
0983     while (*(uintptr_t *) le.ip) {
0984 
0985         lcode = *(ngx_http_script_len_code_pt *) le.ip;
0986         key_len = lcode(&le);
0987 
0988         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0989             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0990         }
0991         le.ip += sizeof(uintptr_t);
0992 
0993         if (val_len == 0) {
0994             e.skip = 1;
0995 
0996             while (*(uintptr_t *) e.ip) {
0997                 code = *(ngx_http_script_code_pt *) e.ip;
0998                 code((ngx_http_script_engine_t *) &e);
0999             }
1000             e.ip += sizeof(uintptr_t);
1001 
1002             e.skip = 0;
1003 
1004             continue;
1005         }
1006 
1007         *b->last++ = 0;
1008 
1009         e.pos = key_tmp;
1010 
1011         code = *(ngx_http_script_code_pt *) e.ip;
1012         code((ngx_http_script_engine_t *) &e);
1013 
1014         b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp);
1015 
1016         e.pos = val_tmp;
1017 
1018         while (*(uintptr_t *) e.ip) {
1019             code = *(ngx_http_script_code_pt *) e.ip;
1020             code((ngx_http_script_engine_t *) &e);
1021         }
1022         e.ip += sizeof(uintptr_t);
1023 
1024         b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp);
1025 
1026 #if (NGX_DEBUG)
1027         if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1028             ngx_strlow(key_tmp, key_tmp, key_len);
1029 
1030             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1031                            "grpc header: \"%*s: %*s\"",
1032                            key_len, key_tmp, val_len, val_tmp);
1033         }
1034 #endif
1035     }
1036 
1037     if (glcf->upstream.pass_request_headers) {
1038         part = &r->headers_in.headers.part;
1039         header = part->elts;
1040 
1041         for (i = 0; /* void */; i++) {
1042 
1043             if (i >= part->nelts) {
1044                 if (part->next == NULL) {
1045                     break;
1046                 }
1047 
1048                 part = part->next;
1049                 header = part->elts;
1050                 i = 0;
1051             }
1052 
1053             if (ngx_hash_find(&glcf->headers.hash, header[i].hash,
1054                               header[i].lowcase_key, header[i].key.len))
1055             {
1056                 continue;
1057             }
1058 
1059             *b->last++ = 0;
1060 
1061             b->last = ngx_http_v2_write_name(b->last, header[i].key.data,
1062                                              header[i].key.len, tmp);
1063 
1064             b->last = ngx_http_v2_write_value(b->last, header[i].value.data,
1065                                               header[i].value.len, tmp);
1066 
1067 #if (NGX_DEBUG)
1068             if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1069                 ngx_strlow(tmp, header[i].key.data, header[i].key.len);
1070 
1071                 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1072                                "grpc header: \"%*s: %V\"",
1073                                header[i].key.len, tmp, &header[i].value);
1074             }
1075 #endif
1076         }
1077     }
1078 
1079     /* update headers frame length */
1080 
1081     len = b->last - headers_frame - sizeof(ngx_http_grpc_frame_t);
1082 
1083     if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
1084         len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
1085         next = 1;
1086 
1087     } else {
1088         next = 0;
1089     }
1090 
1091     f = (ngx_http_grpc_frame_t *) headers_frame;
1092 
1093     f->length_0 = (u_char) ((len >> 16) & 0xff);
1094     f->length_1 = (u_char) ((len >> 8) & 0xff);
1095     f->length_2 = (u_char) (len & 0xff);
1096 
1097     /* create additional continuation frames */
1098 
1099     p = headers_frame;
1100 
1101     while (next) {
1102         p += sizeof(ngx_http_grpc_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
1103         len = b->last - p;
1104 
1105         ngx_memmove(p + sizeof(ngx_http_grpc_frame_t), p, len);
1106         b->last += sizeof(ngx_http_grpc_frame_t);
1107 
1108         if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
1109             len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
1110             next = 1;
1111 
1112         } else {
1113             next = 0;
1114         }
1115 
1116         f = (ngx_http_grpc_frame_t *) p;
1117 
1118         f->length_0 = (u_char) ((len >> 16) & 0xff);
1119         f->length_1 = (u_char) ((len >> 8) & 0xff);
1120         f->length_2 = (u_char) (len & 0xff);
1121         f->type = NGX_HTTP_V2_CONTINUATION_FRAME;
1122         f->flags = 0;
1123         f->stream_id_0 = 0;
1124         f->stream_id_1 = 0;
1125         f->stream_id_2 = 0;
1126         f->stream_id_3 = 1;
1127     }
1128 
1129     f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG;
1130 
1131 #if (NGX_DEBUG)
1132     if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1133         u_char  buf[512];
1134         size_t  n, m;
1135 
1136         n = ngx_min(b->last - b->pos, 256);
1137         m = ngx_hex_dump(buf, b->pos, n) - buf;
1138 
1139         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1140                        "grpc header: %*s%s, len: %uz",
1141                        m, buf, b->last - b->pos > 256 ? "..." : "",
1142                        b->last - b->pos);
1143     }
1144 #endif
1145 
1146     if (r->request_body_no_buffering) {
1147 
1148         u->request_bufs = cl;
1149 
1150     } else {
1151 
1152         body = u->request_bufs;
1153         u->request_bufs = cl;
1154 
1155         if (body == NULL) {
1156             f = (ngx_http_grpc_frame_t *) headers_frame;
1157             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1158         }
1159 
1160         while (body) {
1161             b = ngx_alloc_buf(r->pool);
1162             if (b == NULL) {
1163                 return NGX_ERROR;
1164             }
1165 
1166             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1167 
1168             cl->next = ngx_alloc_chain_link(r->pool);
1169             if (cl->next == NULL) {
1170                 return NGX_ERROR;
1171             }
1172 
1173             cl = cl->next;
1174             cl->buf = b;
1175 
1176             body = body->next;
1177         }
1178 
1179         b->last_buf = 1;
1180     }
1181 
1182     u->output.output_filter = ngx_http_grpc_body_output_filter;
1183     u->output.filter_ctx = r;
1184 
1185     b->flush = 1;
1186     cl->next = NULL;
1187 
1188     return NGX_OK;
1189 }
1190 
1191 
1192 static ngx_int_t
1193 ngx_http_grpc_reinit_request(ngx_http_request_t *r)
1194 {
1195     ngx_http_grpc_ctx_t  *ctx;
1196 
1197     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
1198 
1199     if (ctx == NULL) {
1200         return NGX_OK;
1201     }
1202 
1203     ctx->state = 0;
1204     ctx->header_sent = 0;
1205     ctx->output_closed = 0;
1206     ctx->output_blocked = 0;
1207     ctx->parsing_headers = 0;
1208     ctx->end_stream = 0;
1209     ctx->done = 0;
1210     ctx->status = 0;
1211     ctx->rst = 0;
1212     ctx->connection = NULL;
1213 
1214     return NGX_OK;
1215 }
1216 
1217 
1218 static ngx_int_t
1219 ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
1220 {
1221     ngx_http_request_t  *r = data;
1222 
1223     off_t                   file_pos;
1224     u_char                 *p, *pos, *start;
1225     size_t                  len, limit;
1226     ngx_buf_t              *b;
1227     ngx_int_t               rc;
1228     ngx_uint_t              next, last;
1229     ngx_chain_t            *cl, *out, **ll;
1230     ngx_http_upstream_t    *u;
1231     ngx_http_grpc_ctx_t    *ctx;
1232     ngx_http_grpc_frame_t  *f;
1233 
1234     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1235                    "grpc output filter");
1236 
1237     ctx = ngx_http_grpc_get_ctx(r);
1238 
1239     if (ctx == NULL) {
1240         return NGX_ERROR;
1241     }
1242 
1243     if (in) {
1244         if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) {
1245             return NGX_ERROR;
1246         }
1247     }
1248 
1249     out = NULL;
1250     ll = &out;
1251 
1252     if (!ctx->header_sent) {
1253         /* first buffer contains headers */
1254 
1255         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1256                        "grpc output header");
1257 
1258         ctx->header_sent = 1;
1259 
1260         if (ctx->id != 1) {
1261             /*
1262              * keepalive connection: skip connection preface,
1263              * update stream identifiers
1264              */
1265 
1266             b = ctx->in->buf;
1267             b->pos += sizeof(ngx_http_grpc_connection_start) - 1;
1268 
1269             p = b->pos;
1270 
1271             while (p < b->last) {
1272                 f = (ngx_http_grpc_frame_t *) p;
1273                 p += sizeof(ngx_http_grpc_frame_t);
1274 
1275                 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1276                 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1277                 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1278                 f->stream_id_3 = (u_char) (ctx->id & 0xff);
1279 
1280                 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2;
1281             }
1282         }
1283 
1284         if (ctx->in->buf->last_buf) {
1285             ctx->output_closed = 1;
1286         }
1287 
1288         *ll = ctx->in;
1289         ll = &ctx->in->next;
1290 
1291         ctx->in = ctx->in->next;
1292     }
1293 
1294     if (ctx->out) {
1295         /* queued control frames */
1296 
1297         *ll = ctx->out;
1298 
1299         for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) {
1300             ll = &cl->next;
1301         }
1302 
1303         ctx->out = NULL;
1304     }
1305 
1306     f = NULL;
1307     last = 0;
1308 
1309     limit = ngx_max(0, ctx->send_window);
1310 
1311     if (limit > ctx->connection->send_window) {
1312         limit = ctx->connection->send_window;
1313     }
1314 
1315     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1316                    "grpc output limit: %uz w:%z:%uz",
1317                    limit, ctx->send_window, ctx->connection->send_window);
1318 
1319 #if (NGX_SUPPRESS_WARN)
1320     file_pos = 0;
1321     pos = NULL;
1322     cl = NULL;
1323 #endif
1324 
1325     in = ctx->in;
1326 
1327     while (in && limit > 0) {
1328 
1329         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1330                        "grpc output in  l:%d f:%d %p, pos %p, size: %z "
1331                        "file: %O, size: %O",
1332                        in->buf->last_buf,
1333                        in->buf->in_file,
1334                        in->buf->start, in->buf->pos,
1335                        in->buf->last - in->buf->pos,
1336                        in->buf->file_pos,
1337                        in->buf->file_last - in->buf->file_pos);
1338 
1339         if (ngx_buf_special(in->buf)) {
1340             goto next;
1341         }
1342 
1343         if (in->buf->in_file) {
1344             file_pos = in->buf->file_pos;
1345 
1346         } else {
1347             pos = in->buf->pos;
1348         }
1349 
1350         next = 0;
1351 
1352         do {
1353 
1354             cl = ngx_http_grpc_get_buf(r, ctx);
1355             if (cl == NULL) {
1356                 return NGX_ERROR;
1357             }
1358 
1359             b = cl->buf;
1360 
1361             f = (ngx_http_grpc_frame_t *) b->last;
1362             b->last += sizeof(ngx_http_grpc_frame_t);
1363 
1364             *ll = cl;
1365             ll = &cl->next;
1366 
1367             cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1368             if (cl == NULL) {
1369                 return NGX_ERROR;
1370             }
1371 
1372             b = cl->buf;
1373             start = b->start;
1374 
1375             ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1376 
1377             /*
1378              * restore b->start to preserve memory allocated in the buffer,
1379              * to reuse it later for headers and control frames
1380              */
1381 
1382             b->start = start;
1383 
1384             if (in->buf->in_file) {
1385                 b->file_pos = file_pos;
1386                 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1387 
1388                 if (file_pos >= in->buf->file_last) {
1389                     file_pos = in->buf->file_last;
1390                     next = 1;
1391                 }
1392 
1393                 b->file_last = file_pos;
1394                 len = (ngx_uint_t) (file_pos - b->file_pos);
1395 
1396             } else {
1397                 b->pos = pos;
1398                 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit);
1399 
1400                 if (pos >= in->buf->last) {
1401                     pos = in->buf->last;
1402                     next = 1;
1403                 }
1404 
1405                 b->last = pos;
1406                 len = (ngx_uint_t) (pos - b->pos);
1407             }
1408 
1409             b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
1410             b->shadow = in->buf;
1411             b->last_shadow = next;
1412 
1413             b->last_buf = 0;
1414             b->last_in_chain = 0;
1415 
1416             *ll = cl;
1417             ll = &cl->next;
1418 
1419             f->length_0 = (u_char) ((len >> 16) & 0xff);
1420             f->length_1 = (u_char) ((len >> 8) & 0xff);
1421             f->length_2 = (u_char) (len & 0xff);
1422             f->type = NGX_HTTP_V2_DATA_FRAME;
1423             f->flags = 0;
1424             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1425             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1426             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1427             f->stream_id_3 = (u_char) (ctx->id & 0xff);
1428 
1429             limit -= len;
1430             ctx->send_window -= len;
1431             ctx->connection->send_window -= len;
1432 
1433         } while (!next && limit > 0);
1434 
1435         if (!next) {
1436             /*
1437              * if the buffer wasn't fully sent due to flow control limits,
1438              * preserve position for future use
1439              */
1440 
1441             if (in->buf->in_file) {
1442                 in->buf->file_pos = file_pos;
1443 
1444             } else {
1445                 in->buf->pos = pos;
1446             }
1447 
1448             break;
1449         }
1450 
1451     next:
1452 
1453         if (in->buf->last_buf) {
1454             last = 1;
1455         }
1456 
1457         in = in->next;
1458     }
1459 
1460     ctx->in = in;
1461 
1462     if (last) {
1463 
1464         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1465                        "grpc output last");
1466 
1467         ctx->output_closed = 1;
1468 
1469         if (f) {
1470             f->flags |= NGX_HTTP_V2_END_STREAM_FLAG;
1471 
1472         } else {
1473             cl = ngx_http_grpc_get_buf(r, ctx);
1474             if (cl == NULL) {
1475                 return NGX_ERROR;
1476             }
1477 
1478             b = cl->buf;
1479 
1480             f = (ngx_http_grpc_frame_t *) b->last;
1481             b->last += sizeof(ngx_http_grpc_frame_t);
1482 
1483             f->length_0 = 0;
1484             f->length_1 = 0;
1485             f->length_2 = 0;
1486             f->type = NGX_HTTP_V2_DATA_FRAME;
1487             f->flags = NGX_HTTP_V2_END_STREAM_FLAG;
1488             f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
1489             f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
1490             f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
1491             f->stream_id_3 = (u_char) (ctx->id & 0xff);
1492 
1493             *ll = cl;
1494             ll = &cl->next;
1495         }
1496 
1497         cl->buf->last_buf = 1;
1498     }
1499 
1500     *ll = NULL;
1501 
1502 #if (NGX_DEBUG)
1503 
1504     for (cl = out; cl; cl = cl->next) {
1505         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1506                        "grpc output out l:%d f:%d %p, pos %p, size: %z "
1507                        "file: %O, size: %O",
1508                        cl->buf->last_buf,
1509                        cl->buf->in_file,
1510                        cl->buf->start, cl->buf->pos,
1511                        cl->buf->last - cl->buf->pos,
1512                        cl->buf->file_pos,
1513                        cl->buf->file_last - cl->buf->file_pos);
1514     }
1515 
1516     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1517                    "grpc output limit: %uz w:%z:%uz",
1518                    limit, ctx->send_window, ctx->connection->send_window);
1519 
1520 #endif
1521 
1522     rc = ngx_chain_writer(&r->upstream->writer, out);
1523 
1524     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1525                             (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter);
1526 
1527     for (cl = ctx->free; cl; cl = cl->next) {
1528 
1529         /* mark original buffers as sent */
1530 
1531         if (cl->buf->shadow) {
1532             if (cl->buf->last_shadow) {
1533                 b = cl->buf->shadow;
1534                 b->pos = b->last;
1535             }
1536 
1537             cl->buf->shadow = NULL;
1538         }
1539     }
1540 
1541     if (rc == NGX_OK && ctx->in) {
1542         rc = NGX_AGAIN;
1543     }
1544 
1545     if (rc == NGX_AGAIN) {
1546         ctx->output_blocked = 1;
1547 
1548     } else {
1549         ctx->output_blocked = 0;
1550     }
1551 
1552     if (ctx->done) {
1553 
1554         /*
1555          * We have already got the response and were sending some additional
1556          * control frames.  Even if there is still something unsent, stop
1557          * here anyway.
1558          */
1559 
1560         u = r->upstream;
1561         u->length = 0;
1562 
1563         if (ctx->in == NULL
1564             && ctx->out == NULL
1565             && ctx->output_closed
1566             && !ctx->output_blocked
1567             && ctx->state == ngx_http_grpc_st_start)
1568         {
1569             u->keepalive = 1;
1570         }
1571 
1572         ngx_post_event(u->peer.connection->read, &ngx_posted_events);
1573     }
1574 
1575     return rc;
1576 }
1577 
1578 
1579 static ngx_int_t
1580 ngx_http_grpc_process_header(ngx_http_request_t *r)
1581 {
1582     ngx_str_t                      *status_line;
1583     ngx_int_t                       rc, status;
1584     ngx_buf_t                      *b;
1585     ngx_table_elt_t                *h;
1586     ngx_http_upstream_t            *u;
1587     ngx_http_grpc_ctx_t            *ctx;
1588     ngx_http_upstream_header_t     *hh;
1589     ngx_http_upstream_main_conf_t  *umcf;
1590 
1591     u = r->upstream;
1592     b = &u->buffer;
1593 
1594 #if (NGX_DEBUG)
1595     if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) {
1596         u_char  buf[512];
1597         size_t  n, m;
1598 
1599         n = ngx_min(b->last - b->pos, 256);
1600         m = ngx_hex_dump(buf, b->pos, n) - buf;
1601 
1602         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1603                        "grpc response: %*s%s, len: %uz",
1604                        m, buf, b->last - b->pos > 256 ? "..." : "",
1605                        b->last - b->pos);
1606     }
1607 #endif
1608 
1609     ctx = ngx_http_grpc_get_ctx(r);
1610 
1611     if (ctx == NULL) {
1612         return NGX_ERROR;
1613     }
1614 
1615     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1616 
1617     for ( ;; ) {
1618 
1619         if (ctx->state < ngx_http_grpc_st_payload) {
1620 
1621             rc = ngx_http_grpc_parse_frame(r, ctx, b);
1622 
1623             if (rc == NGX_AGAIN) {
1624 
1625                 /*
1626                  * there can be a lot of window update frames,
1627                  * so we reset buffer if it is empty and we haven't
1628                  * started parsing headers yet
1629                  */
1630 
1631                 if (!ctx->parsing_headers) {
1632                     b->pos = b->start;
1633                     b->last = b->pos;
1634                 }
1635 
1636                 return NGX_AGAIN;
1637             }
1638 
1639             if (rc == NGX_ERROR) {
1640                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1641             }
1642 
1643             /*
1644              * RFC 7540 says that implementations MUST discard frames
1645              * that have unknown or unsupported types.  However, extension
1646              * frames that appear in the middle of a header block are
1647              * not permitted.  Also, for obvious reasons CONTINUATION frames
1648              * cannot appear before headers, and DATA frames are not expected
1649              * to appear before all headers are parsed.
1650              */
1651 
1652             if (ctx->type == NGX_HTTP_V2_DATA_FRAME
1653                 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
1654                     && !ctx->parsing_headers)
1655                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
1656                     && ctx->parsing_headers))
1657             {
1658                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1659                               "upstream sent unexpected http2 frame: %d",
1660                               ctx->type);
1661                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1662             }
1663 
1664             if (ctx->stream_id && ctx->stream_id != ctx->id) {
1665                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1666                               "upstream sent frame for unknown stream %ui",
1667                               ctx->stream_id);
1668                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1669             }
1670         }
1671 
1672         /* frame payload */
1673 
1674         if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
1675 
1676             rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
1677 
1678             if (rc == NGX_AGAIN) {
1679                 return NGX_AGAIN;
1680             }
1681 
1682             if (rc == NGX_ERROR) {
1683                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1684             }
1685 
1686             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1687                           "upstream rejected request with error %ui",
1688                           ctx->error);
1689 
1690             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1691         }
1692 
1693         if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
1694 
1695             rc = ngx_http_grpc_parse_goaway(r, ctx, b);
1696 
1697             if (rc == NGX_AGAIN) {
1698                 return NGX_AGAIN;
1699             }
1700 
1701             if (rc == NGX_ERROR) {
1702                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1703             }
1704 
1705             /*
1706              * If stream_id is lower than one we use, our
1707              * request won't be processed and needs to be retried.
1708              * If stream_id is greater or equal to the one we use,
1709              * we can continue normally (except we can't use this
1710              * connection for additional requests).  If there is
1711              * a real error, the connection will be closed.
1712              */
1713 
1714             if (ctx->stream_id < ctx->id) {
1715 
1716                 /* TODO: we can retry non-idempotent requests */
1717 
1718                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1719                               "upstream sent goaway with error %ui",
1720                               ctx->error);
1721 
1722                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1723             }
1724 
1725             continue;
1726         }
1727 
1728         if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
1729 
1730             rc = ngx_http_grpc_parse_window_update(r, ctx, b);
1731 
1732             if (rc == NGX_AGAIN) {
1733                 return NGX_AGAIN;
1734             }
1735 
1736             if (rc == NGX_ERROR) {
1737                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1738             }
1739 
1740             if (ctx->in) {
1741                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1742             }
1743 
1744             continue;
1745         }
1746 
1747         if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
1748 
1749             rc = ngx_http_grpc_parse_settings(r, ctx, b);
1750 
1751             if (rc == NGX_AGAIN) {
1752                 return NGX_AGAIN;
1753             }
1754 
1755             if (rc == NGX_ERROR) {
1756                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1757             }
1758 
1759             if (ctx->in) {
1760                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1761             }
1762 
1763             continue;
1764         }
1765 
1766         if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
1767 
1768             rc = ngx_http_grpc_parse_ping(r, ctx, b);
1769 
1770             if (rc == NGX_AGAIN) {
1771                 return NGX_AGAIN;
1772             }
1773 
1774             if (rc == NGX_ERROR) {
1775                 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1776             }
1777 
1778             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
1779             continue;
1780         }
1781 
1782         if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
1783             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1784                           "upstream sent unexpected push promise frame");
1785             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1786         }
1787 
1788         if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME
1789             && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME)
1790         {
1791             /* priority, unknown frames */
1792 
1793             if (b->last - b->pos < (ssize_t) ctx->rest) {
1794                 ctx->rest -= b->last - b->pos;
1795                 b->pos = b->last;
1796                 return NGX_AGAIN;
1797             }
1798 
1799             b->pos += ctx->rest;
1800             ctx->rest = 0;
1801             ctx->state = ngx_http_grpc_st_start;
1802 
1803             continue;
1804         }
1805 
1806         /* headers */
1807 
1808         for ( ;; ) {
1809 
1810             rc = ngx_http_grpc_parse_header(r, ctx, b);
1811 
1812             if (rc == NGX_AGAIN) {
1813                 break;
1814             }
1815 
1816             if (rc == NGX_OK) {
1817 
1818                 /* a header line has been parsed successfully */
1819 
1820                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1821                                "grpc header: \"%V: %V\"",
1822                                &ctx->name, &ctx->value);
1823 
1824                 if (ctx->name.len && ctx->name.data[0] == ':') {
1825 
1826                     if (ctx->name.len != sizeof(":status") - 1
1827                         || ngx_strncmp(ctx->name.data, ":status",
1828                                        sizeof(":status") - 1)
1829                            != 0)
1830                     {
1831                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1832                                       "upstream sent invalid header \"%V: %V\"",
1833                                       &ctx->name, &ctx->value);
1834                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1835                     }
1836 
1837                     if (ctx->status) {
1838                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1839                                       "upstream sent duplicate :status header");
1840                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1841                     }
1842 
1843                     status_line = &ctx->value;
1844 
1845                     if (status_line->len != 3) {
1846                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1847                                       "upstream sent invalid :status \"%V\"",
1848                                       status_line);
1849                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1850                     }
1851 
1852                     status = ngx_atoi(status_line->data, 3);
1853 
1854                     if (status == NGX_ERROR) {
1855                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1856                                       "upstream sent invalid :status \"%V\"",
1857                                       status_line);
1858                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1859                     }
1860 
1861                     if (status < NGX_HTTP_OK) {
1862                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1863                                       "upstream sent unexpected :status \"%V\"",
1864                                       status_line);
1865                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1866                     }
1867 
1868                     u->headers_in.status_n = status;
1869 
1870                     if (u->state && u->state->status == 0) {
1871                         u->state->status = status;
1872                     }
1873 
1874                     ctx->status = 1;
1875 
1876                     continue;
1877 
1878                 } else if (!ctx->status) {
1879                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1880                                   "upstream sent no :status header");
1881                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1882                 }
1883 
1884                 h = ngx_list_push(&u->headers_in.headers);
1885                 if (h == NULL) {
1886                     return NGX_ERROR;
1887                 }
1888 
1889                 h->key = ctx->name;
1890                 h->value = ctx->value;
1891                 h->lowcase_key = h->key.data;
1892                 h->hash = ngx_hash_key(h->key.data, h->key.len);
1893 
1894                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1895                                    h->lowcase_key, h->key.len);
1896 
1897                 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1898                     return NGX_ERROR;
1899                 }
1900 
1901                 continue;
1902             }
1903 
1904             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1905 
1906                 /* a whole header has been parsed successfully */
1907 
1908                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1909                                "grpc header done");
1910 
1911                 if (ctx->end_stream) {
1912                     u->headers_in.content_length_n = 0;
1913 
1914                     if (ctx->in == NULL
1915                         && ctx->out == NULL
1916                         && ctx->output_closed
1917                         && !ctx->output_blocked
1918                         && b->last == b->pos)
1919                     {
1920                         u->keepalive = 1;
1921                     }
1922                 }
1923 
1924                 return NGX_OK;
1925             }
1926 
1927             /* there was error while a header line parsing */
1928 
1929             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1930                           "upstream sent invalid header");
1931 
1932             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1933         }
1934 
1935         /* rc == NGX_AGAIN */
1936 
1937         if (ctx->rest == 0) {
1938             ctx->state = ngx_http_grpc_st_start;
1939             continue;
1940         }
1941 
1942         return NGX_AGAIN;
1943     }
1944 }
1945 
1946 
1947 static ngx_int_t
1948 ngx_http_grpc_filter_init(void *data)
1949 {
1950     ngx_http_grpc_ctx_t  *ctx = data;
1951 
1952     ngx_http_request_t   *r;
1953     ngx_http_upstream_t  *u;
1954 
1955     r = ctx->request;
1956     u = r->upstream;
1957 
1958     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1959         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1960         || r->method == NGX_HTTP_HEAD)
1961     {
1962         ctx->length = 0;
1963 
1964     } else {
1965         ctx->length = u->headers_in.content_length_n;
1966     }
1967 
1968     if (ctx->end_stream) {
1969 
1970         if (ctx->length > 0) {
1971             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1972                           "upstream prematurely closed stream");
1973             return NGX_ERROR;
1974         }
1975 
1976         u->length = 0;
1977 
1978     } else {
1979         u->length = 1;
1980     }
1981 
1982     return NGX_OK;
1983 }
1984 
1985 
1986 static ngx_int_t
1987 ngx_http_grpc_filter(void *data, ssize_t bytes)
1988 {
1989     ngx_http_grpc_ctx_t  *ctx = data;
1990 
1991     ngx_int_t             rc;
1992     ngx_buf_t            *b, *buf;
1993     ngx_chain_t          *cl, **ll;
1994     ngx_table_elt_t      *h;
1995     ngx_http_request_t   *r;
1996     ngx_http_upstream_t  *u;
1997 
1998     r = ctx->request;
1999     u = r->upstream;
2000     b = &u->buffer;
2001 
2002     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2003                    "grpc filter bytes:%z", bytes);
2004 
2005     b->pos = b->last;
2006     b->last += bytes;
2007 
2008     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2009         ll = &cl->next;
2010     }
2011 
2012     for ( ;; ) {
2013 
2014         if (ctx->state < ngx_http_grpc_st_payload) {
2015 
2016             rc = ngx_http_grpc_parse_frame(r, ctx, b);
2017 
2018             if (rc == NGX_AGAIN) {
2019 
2020                 if (ctx->done) {
2021 
2022                     if (ctx->length > 0) {
2023                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2024                                       "upstream prematurely closed stream");
2025                         return NGX_ERROR;
2026                     }
2027 
2028                     /*
2029                      * We have finished parsing the response and the
2030                      * remaining control frames.  If there are unsent
2031                      * control frames, post a write event to send them.
2032                      */
2033 
2034                     if (ctx->out) {
2035                         ngx_post_event(u->peer.connection->write,
2036                                        &ngx_posted_events);
2037                         return NGX_AGAIN;
2038                     }
2039 
2040                     u->length = 0;
2041 
2042                     if (ctx->in == NULL
2043                         && ctx->output_closed
2044                         && !ctx->output_blocked
2045                         && ctx->state == ngx_http_grpc_st_start)
2046                     {
2047                         u->keepalive = 1;
2048                     }
2049 
2050                     break;
2051                 }
2052 
2053                 return NGX_AGAIN;
2054             }
2055 
2056             if (rc == NGX_ERROR) {
2057                 return NGX_ERROR;
2058             }
2059 
2060             if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME
2061                  && !ctx->parsing_headers)
2062                 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME
2063                     && ctx->parsing_headers))
2064             {
2065                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2066                               "upstream sent unexpected http2 frame: %d",
2067                               ctx->type);
2068                 return NGX_ERROR;
2069             }
2070 
2071             if (ctx->type == NGX_HTTP_V2_DATA_FRAME) {
2072 
2073                 if (ctx->stream_id != ctx->id) {
2074                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2075                                   "upstream sent data frame "
2076                                   "for unknown stream %ui",
2077                                   ctx->stream_id);
2078                     return NGX_ERROR;
2079                 }
2080 
2081                 if (ctx->length != -1) {
2082                     if ((off_t) ctx->rest > ctx->length) {
2083                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2084                                       "upstream sent response body larger "
2085                                       "than indicated content length");
2086                         return NGX_ERROR;
2087                     }
2088 
2089                     ctx->length -= ctx->rest;
2090                 }
2091 
2092                 if (ctx->rest > ctx->recv_window) {
2093                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2094                                   "upstream violated stream flow control, "
2095                                   "received %uz data frame with window %uz",
2096                                   ctx->rest, ctx->recv_window);
2097                     return NGX_ERROR;
2098                 }
2099 
2100                 if (ctx->rest > ctx->connection->recv_window) {
2101                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2102                                   "upstream violated connection flow control, "
2103                                   "received %uz data frame with window %uz",
2104                                   ctx->rest, ctx->connection->recv_window);
2105                     return NGX_ERROR;
2106                 }
2107 
2108                 ctx->recv_window -= ctx->rest;
2109                 ctx->connection->recv_window -= ctx->rest;
2110 
2111                 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4
2112                     || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
2113                 {
2114                     if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) {
2115                         return NGX_ERROR;
2116                     }
2117 
2118                     ngx_post_event(u->peer.connection->write,
2119                                    &ngx_posted_events);
2120                 }
2121             }
2122 
2123             if (ctx->stream_id && ctx->stream_id != ctx->id) {
2124                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2125                               "upstream sent frame for unknown stream %ui",
2126                               ctx->stream_id);
2127                 return NGX_ERROR;
2128             }
2129 
2130             if (ctx->stream_id && ctx->done
2131                 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
2132                 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
2133             {
2134                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2135                               "upstream sent frame for closed stream %ui",
2136                               ctx->stream_id);
2137                 return NGX_ERROR;
2138             }
2139 
2140             ctx->padding = 0;
2141         }
2142 
2143         if (ctx->state == ngx_http_grpc_st_padding) {
2144 
2145             if (b->last - b->pos < (ssize_t) ctx->rest) {
2146                 ctx->rest -= b->last - b->pos;
2147                 b->pos = b->last;
2148                 return NGX_AGAIN;
2149             }
2150 
2151             b->pos += ctx->rest;
2152             ctx->rest = 0;
2153             ctx->state = ngx_http_grpc_st_start;
2154 
2155             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2156                 ctx->done = 1;
2157             }
2158 
2159             continue;
2160         }
2161 
2162         /* frame payload */
2163 
2164         if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) {
2165 
2166             rc = ngx_http_grpc_parse_rst_stream(r, ctx, b);
2167 
2168             if (rc == NGX_AGAIN) {
2169                 return NGX_AGAIN;
2170             }
2171 
2172             if (rc == NGX_ERROR) {
2173                 return NGX_ERROR;
2174             }
2175 
2176             if (ctx->error || !ctx->done) {
2177                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2178                               "upstream rejected request with error %ui",
2179                               ctx->error);
2180                 return NGX_ERROR;
2181             }
2182 
2183             if (ctx->rst) {
2184                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2185                               "upstream sent frame for closed stream %ui",
2186                               ctx->stream_id);
2187                 return NGX_ERROR;
2188             }
2189 
2190             ctx->rst = 1;
2191         }
2192 
2193         if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
2194 
2195             rc = ngx_http_grpc_parse_goaway(r, ctx, b);
2196 
2197             if (rc == NGX_AGAIN) {
2198                 return NGX_AGAIN;
2199             }
2200 
2201             if (rc == NGX_ERROR) {
2202                 return NGX_ERROR;
2203             }
2204 
2205             /*
2206              * If stream_id is lower than one we use, our
2207              * request won't be processed and needs to be retried.
2208              * If stream_id is greater or equal to the one we use,
2209              * we can continue normally (except we can't use this
2210              * connection for additional requests).  If there is
2211              * a real error, the connection will be closed.
2212              */
2213 
2214             if (ctx->stream_id < ctx->id) {
2215 
2216                 /* TODO: we can retry non-idempotent requests */
2217 
2218                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2219                               "upstream sent goaway with error %ui",
2220                               ctx->error);
2221 
2222                 return NGX_ERROR;
2223             }
2224 
2225             continue;
2226         }
2227 
2228         if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) {
2229 
2230             rc = ngx_http_grpc_parse_window_update(r, ctx, b);
2231 
2232             if (rc == NGX_AGAIN) {
2233                 return NGX_AGAIN;
2234             }
2235 
2236             if (rc == NGX_ERROR) {
2237                 return NGX_ERROR;
2238             }
2239 
2240             if (ctx->in) {
2241                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2242             }
2243 
2244             continue;
2245         }
2246 
2247         if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) {
2248 
2249             rc = ngx_http_grpc_parse_settings(r, ctx, b);
2250 
2251             if (rc == NGX_AGAIN) {
2252                 return NGX_AGAIN;
2253             }
2254 
2255             if (rc == NGX_ERROR) {
2256                 return NGX_ERROR;
2257             }
2258 
2259             if (ctx->in) {
2260                 ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2261             }
2262 
2263             continue;
2264         }
2265 
2266         if (ctx->type == NGX_HTTP_V2_PING_FRAME) {
2267 
2268             rc = ngx_http_grpc_parse_ping(r, ctx, b);
2269 
2270             if (rc == NGX_AGAIN) {
2271                 return NGX_AGAIN;
2272             }
2273 
2274             if (rc == NGX_ERROR) {
2275                 return NGX_ERROR;
2276             }
2277 
2278             ngx_post_event(u->peer.connection->write, &ngx_posted_events);
2279             continue;
2280         }
2281 
2282         if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) {
2283             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2284                           "upstream sent unexpected push promise frame");
2285             return NGX_ERROR;
2286         }
2287 
2288         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME
2289             || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME)
2290         {
2291             for ( ;; ) {
2292 
2293                 rc = ngx_http_grpc_parse_header(r, ctx, b);
2294 
2295                 if (rc == NGX_AGAIN) {
2296                     break;
2297                 }
2298 
2299                 if (rc == NGX_OK) {
2300 
2301                     /* a header line has been parsed successfully */
2302 
2303                     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2304                                    "grpc trailer: \"%V: %V\"",
2305                                    &ctx->name, &ctx->value);
2306 
2307                     if (ctx->name.len && ctx->name.data[0] == ':') {
2308                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2309                                       "upstream sent invalid "
2310                                       "trailer \"%V: %V\"",
2311                                       &ctx->name, &ctx->value);
2312                         return NGX_ERROR;
2313                     }
2314 
2315                     h = ngx_list_push(&u->headers_in.trailers);
2316                     if (h == NULL) {
2317                         return NGX_ERROR;
2318                     }
2319 
2320                     h->key = ctx->name;
2321                     h->value = ctx->value;
2322                     h->lowcase_key = h->key.data;
2323                     h->hash = ngx_hash_key(h->key.data, h->key.len);
2324 
2325                     continue;
2326                 }
2327 
2328                 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2329 
2330                     /* a whole header has been parsed successfully */
2331 
2332                     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2333                                    "grpc trailer done");
2334 
2335                     if (ctx->end_stream) {
2336                         ctx->done = 1;
2337                         break;
2338                     }
2339 
2340                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2341                                   "upstream sent trailer without "
2342                                   "end stream flag");
2343                     return NGX_ERROR;
2344                 }
2345 
2346                 /* there was error while a header line parsing */
2347 
2348                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2349                               "upstream sent invalid trailer");
2350 
2351                 return NGX_ERROR;
2352             }
2353 
2354             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2355                 continue;
2356             }
2357 
2358             /* rc == NGX_AGAIN */
2359 
2360             if (ctx->rest == 0) {
2361                 ctx->state = ngx_http_grpc_st_start;
2362                 continue;
2363             }
2364 
2365             return NGX_AGAIN;
2366         }
2367 
2368         if (ctx->type != NGX_HTTP_V2_DATA_FRAME) {
2369 
2370             /* priority, unknown frames */
2371 
2372             if (b->last - b->pos < (ssize_t) ctx->rest) {
2373                 ctx->rest -= b->last - b->pos;
2374                 b->pos = b->last;
2375                 return NGX_AGAIN;
2376             }
2377 
2378             b->pos += ctx->rest;
2379             ctx->rest = 0;
2380             ctx->state = ngx_http_grpc_st_start;
2381 
2382             continue;
2383         }
2384 
2385         /*
2386          * data frame:
2387          *
2388          * +---------------+
2389          * |Pad Length? (8)|
2390          * +---------------+-----------------------------------------------+
2391          * |                            Data (*)                         ...
2392          * +---------------------------------------------------------------+
2393          * |                           Padding (*)                       ...
2394          * +---------------------------------------------------------------+
2395          */
2396 
2397         if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2398 
2399             if (ctx->rest == 0) {
2400                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2401                               "upstream sent too short http2 frame");
2402                 return NGX_ERROR;
2403             }
2404 
2405             if (b->pos == b->last) {
2406                 return NGX_AGAIN;
2407             }
2408 
2409             ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG;
2410             ctx->padding = *b->pos++;
2411             ctx->rest -= 1;
2412 
2413             if (ctx->padding > ctx->rest) {
2414                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2415                               "upstream sent http2 frame with too long "
2416                               "padding: %d in frame %uz",
2417                               ctx->padding, ctx->rest);
2418                 return NGX_ERROR;
2419             }
2420 
2421             continue;
2422         }
2423 
2424         if (ctx->rest == ctx->padding) {
2425             goto done;
2426         }
2427 
2428         if (b->pos == b->last) {
2429             return NGX_AGAIN;
2430         }
2431 
2432         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2433         if (cl == NULL) {
2434             return NGX_ERROR;
2435         }
2436 
2437         *ll = cl;
2438         ll = &cl->next;
2439 
2440         buf = cl->buf;
2441 
2442         buf->flush = 1;
2443         buf->memory = 1;
2444 
2445         buf->pos = b->pos;
2446         buf->tag = u->output.tag;
2447 
2448         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2449                        "grpc output buf %p", buf->pos);
2450 
2451         if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2452 
2453             ctx->rest -= b->last - b->pos;
2454             b->pos = b->last;
2455             buf->last = b->pos;
2456 
2457             return NGX_AGAIN;
2458         }
2459 
2460         b->pos += ctx->rest - ctx->padding;
2461         buf->last = b->pos;
2462         ctx->rest = ctx->padding;
2463 
2464     done:
2465 
2466         if (ctx->padding) {
2467             ctx->state = ngx_http_grpc_st_padding;
2468             continue;
2469         }
2470 
2471         ctx->state = ngx_http_grpc_st_start;
2472 
2473         if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2474             ctx->done = 1;
2475         }
2476     }
2477 
2478     return NGX_OK;
2479 }
2480 
2481 
2482 static ngx_int_t
2483 ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2484     ngx_buf_t *b)
2485 {
2486     u_char                 ch, *p;
2487     ngx_http_grpc_state_e  state;
2488 
2489     state = ctx->state;
2490 
2491     for (p = b->pos; p < b->last; p++) {
2492         ch = *p;
2493 
2494 #if 0
2495         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2496                        "grpc frame byte: %02Xd, s:%d", ch, state);
2497 #endif
2498 
2499         switch (state) {
2500 
2501         case ngx_http_grpc_st_start:
2502             ctx->rest = ch << 16;
2503             state = ngx_http_grpc_st_length_2;
2504             break;
2505 
2506         case ngx_http_grpc_st_length_2:
2507             ctx->rest |= ch << 8;
2508             state = ngx_http_grpc_st_length_3;
2509             break;
2510 
2511         case ngx_http_grpc_st_length_3:
2512             ctx->rest |= ch;
2513 
2514             if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) {
2515                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2516                               "upstream sent too large http2 frame: %uz",
2517                               ctx->rest);
2518                 return NGX_ERROR;
2519             }
2520 
2521             state = ngx_http_grpc_st_type;
2522             break;
2523 
2524         case ngx_http_grpc_st_type:
2525             ctx->type = ch;
2526             state = ngx_http_grpc_st_flags;
2527             break;
2528 
2529         case ngx_http_grpc_st_flags:
2530             ctx->flags = ch;
2531             state = ngx_http_grpc_st_stream_id;
2532             break;
2533 
2534         case ngx_http_grpc_st_stream_id:
2535             ctx->stream_id = (ch & 0x7f) << 24;
2536             state = ngx_http_grpc_st_stream_id_2;
2537             break;
2538 
2539         case ngx_http_grpc_st_stream_id_2:
2540             ctx->stream_id |= ch << 16;
2541             state = ngx_http_grpc_st_stream_id_3;
2542             break;
2543 
2544         case ngx_http_grpc_st_stream_id_3:
2545             ctx->stream_id |= ch << 8;
2546             state = ngx_http_grpc_st_stream_id_4;
2547             break;
2548 
2549         case ngx_http_grpc_st_stream_id_4:
2550             ctx->stream_id |= ch;
2551 
2552             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2553                            "grpc frame: %d, len: %uz, f:%d, i:%ui",
2554                            ctx->type, ctx->rest, ctx->flags, ctx->stream_id);
2555 
2556             b->pos = p + 1;
2557 
2558             ctx->state = ngx_http_grpc_st_payload;
2559             ctx->frame_state = 0;
2560 
2561             return NGX_OK;
2562 
2563         /* suppress warning */
2564         case ngx_http_grpc_st_payload:
2565         case ngx_http_grpc_st_padding:
2566             break;
2567         }
2568     }
2569 
2570     b->pos = p;
2571     ctx->state = state;
2572 
2573     return NGX_AGAIN;
2574 }
2575 
2576 
2577 static ngx_int_t
2578 ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2579     ngx_buf_t *b)
2580 {
2581     u_char     ch, *p, *last;
2582     size_t     min;
2583     ngx_int_t  rc;
2584     enum {
2585         sw_start = 0,
2586         sw_padding_length,
2587         sw_dependency,
2588         sw_dependency_2,
2589         sw_dependency_3,
2590         sw_dependency_4,
2591         sw_weight,
2592         sw_fragment,
2593         sw_padding
2594     } state;
2595 
2596     state = ctx->frame_state;
2597 
2598     if (state == sw_start) {
2599 
2600         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2601                        "grpc parse header: start");
2602 
2603         if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) {
2604             ctx->parsing_headers = 1;
2605             ctx->fragment_state = 0;
2606 
2607             min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0)
2608                   + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0);
2609 
2610             if (ctx->rest < min) {
2611                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2612                               "upstream sent headers frame "
2613                               "with invalid length: %uz",
2614                               ctx->rest);
2615                 return NGX_ERROR;
2616             }
2617 
2618             if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
2619                 ctx->end_stream = 1;
2620             }
2621 
2622             if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) {
2623                 state = sw_padding_length;
2624 
2625             } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2626                 state = sw_dependency;
2627 
2628             } else {
2629                 state = sw_fragment;
2630             }
2631 
2632         } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) {
2633             state = sw_fragment;
2634         }
2635 
2636         ctx->padding = 0;
2637         ctx->frame_state = state;
2638     }
2639 
2640     if (state < sw_fragment) {
2641 
2642         if (b->last - b->pos < (ssize_t) ctx->rest) {
2643             last = b->last;
2644 
2645         } else {
2646             last = b->pos + ctx->rest;
2647         }
2648 
2649         for (p = b->pos; p < last; p++) {
2650             ch = *p;
2651 
2652 #if 0
2653             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2654                            "grpc header byte: %02Xd s:%d", ch, state);
2655 #endif
2656 
2657             /*
2658              * headers frame:
2659              *
2660              * +---------------+
2661              * |Pad Length? (8)|
2662              * +-+-------------+----------------------------------------------+
2663              * |E|                 Stream Dependency? (31)                    |
2664              * +-+-------------+----------------------------------------------+
2665              * |  Weight? (8)  |
2666              * +-+-------------+----------------------------------------------+
2667              * |                   Header Block Fragment (*)                ...
2668              * +--------------------------------------------------------------+
2669              * |                           Padding (*)                      ...
2670              * +--------------------------------------------------------------+
2671              */
2672 
2673             switch (state) {
2674 
2675             case sw_padding_length:
2676 
2677                 ctx->padding = ch;
2678 
2679                 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) {
2680                     state = sw_dependency;
2681                     break;
2682                 }
2683 
2684                 goto fragment;
2685 
2686             case sw_dependency:
2687                 state = sw_dependency_2;
2688                 break;
2689 
2690             case sw_dependency_2:
2691                 state = sw_dependency_3;
2692                 break;
2693 
2694             case sw_dependency_3:
2695                 state = sw_dependency_4;
2696                 break;
2697 
2698             case sw_dependency_4:
2699                 state = sw_weight;
2700                 break;
2701 
2702             case sw_weight:
2703                 goto fragment;
2704 
2705             /* suppress warning */
2706             case sw_start:
2707             case sw_fragment:
2708             case sw_padding:
2709                 break;
2710             }
2711         }
2712 
2713         ctx->rest -= p - b->pos;
2714         b->pos = p;
2715 
2716         ctx->frame_state = state;
2717         return NGX_AGAIN;
2718 
2719     fragment:
2720 
2721         p++;
2722         ctx->rest -= p - b->pos;
2723         b->pos = p;
2724 
2725         if (ctx->padding > ctx->rest) {
2726             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2727                           "upstream sent http2 frame with too long "
2728                           "padding: %d in frame %uz",
2729                           ctx->padding, ctx->rest);
2730             return NGX_ERROR;
2731         }
2732 
2733         state = sw_fragment;
2734         ctx->frame_state = state;
2735     }
2736 
2737     if (state == sw_fragment) {
2738 
2739         rc = ngx_http_grpc_parse_fragment(r, ctx, b);
2740 
2741         if (rc == NGX_AGAIN) {
2742             return NGX_AGAIN;
2743         }
2744 
2745         if (rc == NGX_ERROR) {
2746             return NGX_ERROR;
2747         }
2748 
2749         if (rc == NGX_OK) {
2750             return NGX_OK;
2751         }
2752 
2753         /* rc == NGX_DONE */
2754 
2755         state = sw_padding;
2756         ctx->frame_state = state;
2757     }
2758 
2759     if (state == sw_padding) {
2760 
2761         if (b->last - b->pos < (ssize_t) ctx->rest) {
2762 
2763             ctx->rest -= b->last - b->pos;
2764             b->pos = b->last;
2765 
2766             return NGX_AGAIN;
2767         }
2768 
2769         b->pos += ctx->rest;
2770         ctx->rest = 0;
2771 
2772         ctx->state = ngx_http_grpc_st_start;
2773 
2774         if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) {
2775 
2776             if (ctx->fragment_state) {
2777                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2778                               "upstream sent truncated http2 header");
2779                 return NGX_ERROR;
2780             }
2781 
2782             ctx->parsing_headers = 0;
2783 
2784             return NGX_HTTP_PARSE_HEADER_DONE;
2785         }
2786 
2787         return NGX_AGAIN;
2788     }
2789 
2790     /* unreachable */
2791 
2792     return NGX_ERROR;
2793 }
2794 
2795 
2796 static ngx_int_t
2797 ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
2798     ngx_buf_t *b)
2799 {
2800     u_char      ch, *p, *last;
2801     size_t      size;
2802     ngx_uint_t  index, size_update;
2803     enum {
2804         sw_start = 0,
2805         sw_index,
2806         sw_name_length,
2807         sw_name_length_2,
2808         sw_name_length_3,
2809         sw_name_length_4,
2810         sw_name,
2811         sw_name_bytes,
2812         sw_value_length,
2813         sw_value_length_2,
2814         sw_value_length_3,
2815         sw_value_length_4,
2816         sw_value,
2817         sw_value_bytes
2818     } state;
2819 
2820     /* header block fragment */
2821 
2822 #if 0
2823     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2824                    "grpc header fragment %p:%p rest:%uz",
2825                    b->pos, b->last, ctx->rest);
2826 #endif
2827 
2828     if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) {
2829         last = b->last;
2830 
2831     } else {
2832         last = b->pos + ctx->rest - ctx->padding;
2833     }
2834 
2835     state = ctx->fragment_state;
2836 
2837     for (p = b->pos; p < last; p++) {
2838         ch = *p;
2839 
2840 #if 0
2841         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2842                        "grpc header byte: %02Xd s:%d", ch, state);
2843 #endif
2844 
2845         switch (state) {
2846 
2847         case sw_start:
2848             ctx->index = 0;
2849 
2850             if ((ch & 0x80) == 0x80) {
2851                 /*
2852                  * indexed header:
2853                  *
2854                  *   0   1   2   3   4   5   6   7
2855                  * +---+---+---+---+---+---+---+---+
2856                  * | 1 |        Index (7+)         |
2857                  * +---+---------------------------+
2858                  */
2859 
2860                 index = ch & ~0x80;
2861 
2862                 if (index == 0 || index > 61) {
2863                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2864                                   "upstream sent invalid http2 "
2865                                   "table index: %ui", index);
2866                     return NGX_ERROR;
2867                 }
2868 
2869                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2870                                "grpc indexed header: %ui", index);
2871 
2872                 ctx->index = index;
2873                 ctx->literal = 0;
2874 
2875                 goto done;
2876 
2877             } else if ((ch & 0xc0) == 0x40) {
2878                 /*
2879                  * literal header with incremental indexing:
2880                  *
2881                  *   0   1   2   3   4   5   6   7
2882                  * +---+---+---+---+---+---+---+---+
2883                  * | 0 | 1 |      Index (6+)       |
2884                  * +---+---+-----------------------+
2885                  * | H |     Value Length (7+)     |
2886                  * +---+---------------------------+
2887                  * | Value String (Length octets)  |
2888                  * +-------------------------------+
2889                  *
2890                  *   0   1   2   3   4   5   6   7
2891                  * +---+---+---+---+---+---+---+---+
2892                  * | 0 | 1 |           0           |
2893                  * +---+---+-----------------------+
2894                  * | H |     Name Length (7+)      |
2895                  * +---+---------------------------+
2896                  * |  Name String (Length octets)  |
2897                  * +---+---------------------------+
2898                  * | H |     Value Length (7+)     |
2899                  * +---+---------------------------+
2900                  * | Value String (Length octets)  |
2901                  * +-------------------------------+
2902                  */
2903 
2904                 index = ch & ~0xc0;
2905 
2906                 if (index > 61) {
2907                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2908                                   "upstream sent invalid http2 "
2909                                   "table index: %ui", index);
2910                     return NGX_ERROR;
2911                 }
2912 
2913                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2914                                "grpc literal header: %ui", index);
2915 
2916                 if (index == 0) {
2917                     state = sw_name_length;
2918                     break;
2919                 }
2920 
2921                 ctx->index = index;
2922                 ctx->literal = 1;
2923 
2924                 state = sw_value_length;
2925                 break;
2926 
2927             } else if ((ch & 0xe0) == 0x20) {
2928                 /*
2929                  * dynamic table size update:
2930                  *
2931                  *   0   1   2   3   4   5   6   7
2932                  * +---+---+---+---+---+---+---+---+
2933                  * | 0 | 0 | 1 |   Max size (5+)   |
2934                  * +---+---------------------------+
2935                  */
2936 
2937                 size_update = ch & ~0xe0;
2938 
2939                 if (size_update > 0) {
2940                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2941                                   "upstream sent invalid http2 "
2942                                   "dynamic table size update: %ui",
2943                                   size_update);
2944                     return NGX_ERROR;
2945                 }
2946 
2947                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2948                                "grpc table size update: %ui", size_update);
2949 
2950                 break;
2951 
2952             } else if ((ch & 0xf0) == 0x10) {
2953                 /*
2954                  *  literal header field never indexed:
2955                  *
2956                  *   0   1   2   3   4   5   6   7
2957                  * +---+---+---+---+---+---+---+---+
2958                  * | 0 | 0 | 0 | 1 |  Index (4+)   |
2959                  * +---+---+-----------------------+
2960                  * | H |     Value Length (7+)     |
2961                  * +---+---------------------------+
2962                  * | Value String (Length octets)  |
2963                  * +-------------------------------+
2964                  *
2965                  *   0   1   2   3   4   5   6   7
2966                  * +---+---+---+---+---+---+---+---+
2967                  * | 0 | 0 | 0 | 1 |       0       |
2968                  * +---+---+-----------------------+
2969                  * | H |     Name Length (7+)      |
2970                  * +---+---------------------------+
2971                  * |  Name String (Length octets)  |
2972                  * +---+---------------------------+
2973                  * | H |     Value Length (7+)     |
2974                  * +---+---------------------------+
2975                  * | Value String (Length octets)  |
2976                  * +-------------------------------+
2977                  */
2978 
2979                 index = ch & ~0xf0;
2980 
2981                 if (index == 0x0f) {
2982                     ctx->index = index;
2983                     ctx->literal = 1;
2984                     state = sw_index;
2985                     break;
2986                 }
2987 
2988                 if (index == 0) {
2989                     state = sw_name_length;
2990                     break;
2991                 }
2992 
2993                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2994                                "grpc literal header never indexed: %ui",
2995                                index);
2996 
2997                 ctx->index = index;
2998                 ctx->literal = 1;
2999 
3000                 state = sw_value_length;
3001                 break;
3002 
3003             } else if ((ch & 0xf0) == 0x00) {
3004                 /*
3005                  * literal header field without indexing:
3006                  *
3007                  *   0   1   2   3   4   5   6   7
3008                  * +---+---+---+---+---+---+---+---+
3009                  * | 0 | 0 | 0 | 0 |  Index (4+)   |
3010                  * +---+---+-----------------------+
3011                  * | H |     Value Length (7+)     |
3012                  * +---+---------------------------+
3013                  * | Value String (Length octets)  |
3014                  * +-------------------------------+
3015                  *
3016                  *   0   1   2   3   4   5   6   7
3017                  * +---+---+---+---+---+---+---+---+
3018                  * | 0 | 0 | 0 | 0 |       0       |
3019                  * +---+---+-----------------------+
3020                  * | H |     Name Length (7+)      |
3021                  * +---+---------------------------+
3022                  * |  Name String (Length octets)  |
3023                  * +---+---------------------------+
3024                  * | H |     Value Length (7+)     |
3025                  * +---+---------------------------+
3026                  * | Value String (Length octets)  |
3027                  * +-------------------------------+
3028                  */
3029 
3030                 index = ch & ~0xf0;
3031 
3032                 if (index == 0x0f) {
3033                     ctx->index = index;
3034                     ctx->literal = 1;
3035                     state = sw_index;
3036                     break;
3037                 }
3038 
3039                 if (index == 0) {
3040                     state = sw_name_length;
3041                     break;
3042                 }
3043 
3044                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3045                                "grpc literal header without indexing: %ui",
3046                                index);
3047 
3048                 ctx->index = index;
3049                 ctx->literal = 1;
3050 
3051                 state = sw_value_length;
3052                 break;
3053             }
3054 
3055             /* not reached */
3056 
3057             return NGX_ERROR;
3058 
3059         case sw_index:
3060             ctx->index = ctx->index + (ch & ~0x80);
3061 
3062             if (ch & 0x80) {
3063                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3064                               "upstream sent http2 table index "
3065                               "with continuation flag");
3066                 return NGX_ERROR;
3067             }
3068 
3069             if (ctx->index > 61) {
3070                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3071                               "upstream sent invalid http2 "
3072                               "table index: %ui", ctx->index);
3073                 return NGX_ERROR;
3074             }
3075 
3076             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3077                            "grpc header index: %ui", ctx->index);
3078 
3079             state = sw_value_length;
3080             break;
3081 
3082         case sw_name_length:
3083             ctx->field_huffman = ch & 0x80 ? 1 : 0;
3084             ctx->field_length = ch & ~0x80;
3085 
3086             if (ctx->field_length == 0x7f) {
3087                 state = sw_name_length_2;
3088                 break;
3089             }
3090 
3091             if (ctx->field_length == 0) {
3092                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3093                               "upstream sent zero http2 "
3094                               "header name length");
3095                 return NGX_ERROR;
3096             }
3097 
3098             state = sw_name;
3099             break;
3100 
3101         case sw_name_length_2:
3102             ctx->field_length += ch & ~0x80;
3103 
3104             if (ch & 0x80) {
3105                 state = sw_name_length_3;
3106                 break;
3107             }
3108 
3109             state = sw_name;
3110             break;
3111 
3112         case sw_name_length_3:
3113             ctx->field_length += (ch & ~0x80) << 7;
3114 
3115             if (ch & 0x80) {
3116                 state = sw_name_length_4;
3117                 break;
3118             }
3119 
3120             state = sw_name;
3121             break;
3122 
3123         case sw_name_length_4:
3124             ctx->field_length += (ch & ~0x80) << 14;
3125 
3126             if (ch & 0x80) {
3127                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3128                               "upstream sent too large http2 "
3129                               "header name length");
3130                 return NGX_ERROR;
3131             }
3132 
3133             state = sw_name;
3134             break;
3135 
3136         case sw_name:
3137             ctx->name.len = ctx->field_huffman ?
3138                             ctx->field_length * 8 / 5 : ctx->field_length;
3139 
3140             ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1);
3141             if (ctx->name.data == NULL) {
3142                 return NGX_ERROR;
3143             }
3144 
3145             ctx->field_end = ctx->name.data;
3146             ctx->field_rest = ctx->field_length;
3147             ctx->field_state = 0;
3148 
3149             state = sw_name_bytes;
3150 
3151             /* fall through */
3152 
3153         case sw_name_bytes:
3154 
3155             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3156                            "grpc name: len:%uz h:%d last:%uz, rest:%uz",
3157                            ctx->field_length,
3158                            ctx->field_huffman,
3159                            last - p,
3160                            ctx->rest - (p - b->pos));
3161 
3162             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
3163             ctx->field_rest -= size;
3164 
3165             if (ctx->field_huffman) {
3166                 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
3167                                             &ctx->field_end,
3168                                             ctx->field_rest == 0,
3169                                             r->connection->log)
3170                     != NGX_OK)
3171                 {
3172                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3173                                   "upstream sent invalid encoded header");
3174                     return NGX_ERROR;
3175                 }
3176 
3177                 ctx->name.len = ctx->field_end - ctx->name.data;
3178                 ctx->name.data[ctx->name.len] = '\0';
3179 
3180             } else {
3181                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
3182                 ctx->name.data[ctx->name.len] = '\0';
3183             }
3184 
3185             p += size - 1;
3186 
3187             if (ctx->field_rest == 0) {
3188                 state = sw_value_length;
3189             }
3190 
3191             break;
3192 
3193         case sw_value_length:
3194             ctx->field_huffman = ch & 0x80 ? 1 : 0;
3195             ctx->field_length = ch & ~0x80;
3196 
3197             if (ctx->field_length == 0x7f) {
3198                 state = sw_value_length_2;
3199                 break;
3200             }
3201 
3202             if (ctx->field_length == 0) {
3203                 ngx_str_set(&ctx->value, "");
3204                 goto done;
3205             }
3206 
3207             state = sw_value;
3208             break;
3209 
3210         case sw_value_length_2:
3211             ctx->field_length += ch & ~0x80;
3212 
3213             if (ch & 0x80) {
3214                 state = sw_value_length_3;
3215                 break;
3216             }
3217 
3218             state = sw_value;
3219             break;
3220 
3221         case sw_value_length_3:
3222             ctx->field_length += (ch & ~0x80) << 7;
3223 
3224             if (ch & 0x80) {
3225                 state = sw_value_length_4;
3226                 break;
3227             }
3228 
3229             state = sw_value;
3230             break;
3231 
3232         case sw_value_length_4:
3233             ctx->field_length += (ch & ~0x80) << 14;
3234 
3235             if (ch & 0x80) {
3236                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3237                               "upstream sent too large http2 "
3238                               "header value length");
3239                 return NGX_ERROR;
3240             }
3241 
3242             state = sw_value;
3243             break;
3244 
3245         case sw_value:
3246             ctx->value.len = ctx->field_huffman ?
3247                              ctx->field_length * 8 / 5 : ctx->field_length;
3248 
3249             ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1);
3250             if (ctx->value.data == NULL) {
3251                 return NGX_ERROR;
3252             }
3253 
3254             ctx->field_end = ctx->value.data;
3255             ctx->field_rest = ctx->field_length;
3256             ctx->field_state = 0;
3257 
3258             state = sw_value_bytes;
3259 
3260             /* fall through */
3261 
3262         case sw_value_bytes:
3263 
3264             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3265                            "grpc value: len:%uz h:%d last:%uz, rest:%uz",
3266                            ctx->field_length,
3267                            ctx->field_huffman,
3268                            last - p,
3269                            ctx->rest - (p - b->pos));
3270 
3271             size = ngx_min(last - p, (ssize_t) ctx->field_rest);
3272             ctx->field_rest -= size;
3273 
3274             if (ctx->field_huffman) {
3275                 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size,
3276                                             &ctx->field_end,
3277                                             ctx->field_rest == 0,
3278                                             r->connection->log)
3279                     != NGX_OK)
3280                 {
3281                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3282                                   "upstream sent invalid encoded header");
3283                     return NGX_ERROR;
3284                 }
3285 
3286                 ctx->value.len = ctx->field_end - ctx->value.data;
3287                 ctx->value.data[ctx->value.len] = '\0';
3288 
3289             } else {
3290                 ctx->field_end = ngx_cpymem(ctx->field_end, p, size);
3291                 ctx->value.data[ctx->value.len] = '\0';
3292             }
3293 
3294             p += size - 1;
3295 
3296             if (ctx->field_rest == 0) {
3297                 goto done;
3298             }
3299 
3300             break;
3301         }
3302 
3303         continue;
3304 
3305     done:
3306 
3307         p++;
3308         ctx->rest -= p - b->pos;
3309         ctx->fragment_state = sw_start;
3310         b->pos = p;
3311 
3312         if (ctx->index) {
3313             ctx->name = *ngx_http_v2_get_static_name(ctx->index);
3314         }
3315 
3316         if (ctx->index && !ctx->literal) {
3317             ctx->value = *ngx_http_v2_get_static_value(ctx->index);
3318         }
3319 
3320         if (!ctx->index) {
3321             if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) {
3322                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3323                               "upstream sent invalid header: \"%V: %V\"",
3324                               &ctx->name, &ctx->value);
3325                 return NGX_ERROR;
3326             }
3327         }
3328 
3329         if (!ctx->index || ctx->literal) {
3330             if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) {
3331                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3332                               "upstream sent invalid header: \"%V: %V\"",
3333                               &ctx->name, &ctx->value);
3334                 return NGX_ERROR;
3335             }
3336         }
3337 
3338         return NGX_OK;
3339     }
3340 
3341     ctx->rest -= p - b->pos;
3342     ctx->fragment_state = state;
3343     b->pos = p;
3344 
3345     if (ctx->rest > ctx->padding) {
3346         return NGX_AGAIN;
3347     }
3348 
3349     return NGX_DONE;
3350 }
3351 
3352 
3353 static ngx_int_t
3354 ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s)
3355 {
3356     u_char      ch;
3357     ngx_uint_t  i;
3358 
3359     for (i = 0; i < s->len; i++) {
3360         ch = s->data[i];
3361 
3362         if (ch == ':' && i > 0) {
3363             return NGX_ERROR;
3364         }
3365 
3366         if (ch >= 'A' && ch <= 'Z') {
3367             return NGX_ERROR;
3368         }
3369 
3370         if (ch == '\0' || ch == CR || ch == LF) {
3371             return NGX_ERROR;
3372         }
3373     }
3374 
3375     return NGX_OK;
3376 }
3377 
3378 
3379 static ngx_int_t
3380 ngx_http_grpc_validate_header_value(ngx_http_request_t *r, ngx_str_t *s)
3381 {
3382     u_char      ch;
3383     ngx_uint_t  i;
3384 
3385     for (i = 0; i < s->len; i++) {
3386         ch = s->data[i];
3387 
3388         if (ch == '\0' || ch == CR || ch == LF) {
3389             return NGX_ERROR;
3390         }
3391     }
3392 
3393     return NGX_OK;
3394 }
3395 
3396 
3397 static ngx_int_t
3398 ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3399     ngx_buf_t *b)
3400 {
3401     u_char  ch, *p, *last;
3402     enum {
3403         sw_start = 0,
3404         sw_error_2,
3405         sw_error_3,
3406         sw_error_4
3407     } state;
3408 
3409     if (b->last - b->pos < (ssize_t) ctx->rest) {
3410         last = b->last;
3411 
3412     } else {
3413         last = b->pos + ctx->rest;
3414     }
3415 
3416     state = ctx->frame_state;
3417 
3418     if (state == sw_start) {
3419         if (ctx->rest != 4) {
3420             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3421                           "upstream sent rst stream frame "
3422                           "with invalid length: %uz",
3423                           ctx->rest);
3424             return NGX_ERROR;
3425         }
3426     }
3427 
3428     for (p = b->pos; p < last; p++) {
3429         ch = *p;
3430 
3431 #if 0
3432         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3433                        "grpc rst byte: %02Xd s:%d", ch, state);
3434 #endif
3435 
3436         switch (state) {
3437 
3438         case sw_start:
3439             ctx->error = (ngx_uint_t) ch << 24;
3440             state = sw_error_2;
3441             break;
3442 
3443         case sw_error_2:
3444             ctx->error |= ch << 16;
3445             state = sw_error_3;
3446             break;
3447 
3448         case sw_error_3:
3449             ctx->error |= ch << 8;
3450             state = sw_error_4;
3451             break;
3452 
3453         case sw_error_4:
3454             ctx->error |= ch;
3455             state = sw_start;
3456 
3457             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3458                            "grpc error: %ui", ctx->error);
3459 
3460             break;
3461         }
3462     }
3463 
3464     ctx->rest -= p - b->pos;
3465     ctx->frame_state = state;
3466     b->pos = p;
3467 
3468     if (ctx->rest > 0) {
3469         return NGX_AGAIN;
3470     }
3471 
3472     return NGX_OK;
3473 }
3474 
3475 
3476 static ngx_int_t
3477 ngx_http_grpc_parse_goaway(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3478     ngx_buf_t *b)
3479 {
3480     u_char  ch, *p, *last;
3481     enum {
3482         sw_start = 0,
3483         sw_last_stream_id_2,
3484         sw_last_stream_id_3,
3485         sw_last_stream_id_4,
3486         sw_error,
3487         sw_error_2,
3488         sw_error_3,
3489         sw_error_4,
3490         sw_debug
3491     } state;
3492 
3493     if (b->last - b->pos < (ssize_t) ctx->rest) {
3494         last = b->last;
3495 
3496     } else {
3497         last = b->pos + ctx->rest;
3498     }
3499 
3500     state = ctx->frame_state;
3501 
3502     if (state == sw_start) {
3503 
3504         if (ctx->stream_id) {
3505             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3506                           "upstream sent goaway frame "
3507                           "with non-zero stream id: %ui",
3508                           ctx->stream_id);
3509             return NGX_ERROR;
3510         }
3511 
3512         if (ctx->rest < 8) {
3513             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3514                           "upstream sent goaway frame "
3515                           "with invalid length: %uz",
3516                           ctx->rest);
3517             return NGX_ERROR;
3518         }
3519     }
3520 
3521     for (p = b->pos; p < last; p++) {
3522         ch = *p;
3523 
3524 #if 0
3525         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3526                        "grpc goaway byte: %02Xd s:%d", ch, state);
3527 #endif
3528 
3529         switch (state) {
3530 
3531         case sw_start:
3532             ctx->stream_id = (ch & 0x7f) << 24;
3533             state = sw_last_stream_id_2;
3534             break;
3535 
3536         case sw_last_stream_id_2:
3537             ctx->stream_id |= ch << 16;
3538             state = sw_last_stream_id_3;
3539             break;
3540 
3541         case sw_last_stream_id_3:
3542             ctx->stream_id |= ch << 8;
3543             state = sw_last_stream_id_4;
3544             break;
3545 
3546         case sw_last_stream_id_4:
3547             ctx->stream_id |= ch;
3548             state = sw_error;
3549             break;
3550 
3551         case sw_error:
3552             ctx->error = (ngx_uint_t) ch << 24;
3553             state = sw_error_2;
3554             break;
3555 
3556         case sw_error_2:
3557             ctx->error |= ch << 16;
3558             state = sw_error_3;
3559             break;
3560 
3561         case sw_error_3:
3562             ctx->error |= ch << 8;
3563             state = sw_error_4;
3564             break;
3565 
3566         case sw_error_4:
3567             ctx->error |= ch;
3568             state = sw_debug;
3569             break;
3570 
3571         case sw_debug:
3572             break;
3573         }
3574     }
3575 
3576     ctx->rest -= p - b->pos;
3577     ctx->frame_state = state;
3578     b->pos = p;
3579 
3580     if (ctx->rest > 0) {
3581         return NGX_AGAIN;
3582     }
3583 
3584     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3585                    "grpc goaway: %ui, stream %ui",
3586                    ctx->error, ctx->stream_id);
3587 
3588     ctx->state = ngx_http_grpc_st_start;
3589 
3590     return NGX_OK;
3591 }
3592 
3593 
3594 static ngx_int_t
3595 ngx_http_grpc_parse_window_update(ngx_http_request_t *r,
3596     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
3597 {
3598     u_char  ch, *p, *last;
3599     enum {
3600         sw_start = 0,
3601         sw_size_2,
3602         sw_size_3,
3603         sw_size_4
3604     } state;
3605 
3606     if (b->last - b->pos < (ssize_t) ctx->rest) {
3607         last = b->last;
3608 
3609     } else {
3610         last = b->pos + ctx->rest;
3611     }
3612 
3613     state = ctx->frame_state;
3614 
3615     if (state == sw_start) {
3616         if (ctx->rest != 4) {
3617             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3618                           "upstream sent window update frame "
3619                           "with invalid length: %uz",
3620                           ctx->rest);
3621             return NGX_ERROR;
3622         }
3623     }
3624 
3625     for (p = b->pos; p < last; p++) {
3626         ch = *p;
3627 
3628 #if 0
3629         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3630                        "grpc window update byte: %02Xd s:%d", ch, state);
3631 #endif
3632 
3633         switch (state) {
3634 
3635         case sw_start:
3636             ctx->window_update = (ch & 0x7f) << 24;
3637             state = sw_size_2;
3638             break;
3639 
3640         case sw_size_2:
3641             ctx->window_update |= ch << 16;
3642             state = sw_size_3;
3643             break;
3644 
3645         case sw_size_3:
3646             ctx->window_update |= ch << 8;
3647             state = sw_size_4;
3648             break;
3649 
3650         case sw_size_4:
3651             ctx->window_update |= ch;
3652             state = sw_start;
3653             break;
3654         }
3655     }
3656 
3657     ctx->rest -= p - b->pos;
3658     ctx->frame_state = state;
3659     b->pos = p;
3660 
3661     if (ctx->rest > 0) {
3662         return NGX_AGAIN;
3663     }
3664 
3665     ctx->state = ngx_http_grpc_st_start;
3666 
3667     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3668                    "grpc window update: %ui", ctx->window_update);
3669 
3670     if (ctx->stream_id) {
3671 
3672         if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW
3673                                  - ctx->send_window)
3674         {
3675             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3676                           "upstream sent too large window update");
3677             return NGX_ERROR;
3678         }
3679 
3680         ctx->send_window += ctx->window_update;
3681 
3682     } else {
3683 
3684         if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW
3685                                  - ctx->connection->send_window)
3686         {
3687             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3688                           "upstream sent too large window update");
3689             return NGX_ERROR;
3690         }
3691 
3692         ctx->connection->send_window += ctx->window_update;
3693     }
3694 
3695     return NGX_OK;
3696 }
3697 
3698 
3699 static ngx_int_t
3700 ngx_http_grpc_parse_settings(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
3701     ngx_buf_t *b)
3702 {
3703     u_char   ch, *p, *last;
3704     ssize_t  window_update;
3705     enum {
3706         sw_start = 0,
3707         sw_id,
3708         sw_id_2,
3709         sw_value,
3710         sw_value_2,
3711         sw_value_3,
3712         sw_value_4
3713     } state;
3714 
3715     if (b->last - b->pos < (ssize_t) ctx->rest) {
3716         last = b->last;
3717 
3718     } else {
3719         last = b->pos + ctx->rest;
3720     }
3721 
3722     state = ctx->frame_state;
3723 
3724     if (state == sw_start) {
3725 
3726         if (ctx->stream_id) {
3727             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3728                           "upstream sent settings frame "
3729                           "with non-zero stream id: %ui",
3730                           ctx->stream_id);
3731             return NGX_ERROR;
3732         }
3733 
3734         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
3735             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3736                            "grpc settings ack");
3737 
3738             if (ctx->rest != 0) {
3739                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3740                               "upstream sent settings frame "
3741                               "with ack flag and non-zero length: %uz",
3742                               ctx->rest);
3743                 return NGX_ERROR;
3744             }
3745 
3746             ctx->state = ngx_http_grpc_st_start;
3747 
3748             return NGX_OK;
3749         }
3750 
3751         if (ctx->rest % 6 != 0) {
3752             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3753                           "upstream sent settings frame "
3754                           "with invalid length: %uz",
3755                           ctx->rest);
3756             return NGX_ERROR;
3757         }
3758 
3759         if (ctx->free == NULL && ctx->settings++ > 1000) {
3760             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3761                           "upstream sent too many settings frames");
3762             return NGX_ERROR;
3763         }
3764     }
3765 
3766     for (p = b->pos; p < last; p++) {
3767         ch = *p;
3768 
3769 #if 0
3770         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3771                        "grpc settings byte: %02Xd s:%d", ch, state);
3772 #endif
3773 
3774         switch (state) {
3775 
3776         case sw_start:
3777         case sw_id:
3778             ctx->setting_id = ch << 8;
3779             state = sw_id_2;
3780             break;
3781 
3782         case sw_id_2:
3783             ctx->setting_id |= ch;
3784             state = sw_value;
3785             break;
3786 
3787         case sw_value:
3788             ctx->setting_value = (ngx_uint_t) ch << 24;
3789             state = sw_value_2;
3790             break;
3791 
3792         case sw_value_2:
3793             ctx->setting_value |= ch << 16;
3794             state = sw_value_3;
3795             break;
3796 
3797         case sw_value_3:
3798             ctx->setting_value |= ch << 8;
3799             state = sw_value_4;
3800             break;
3801 
3802         case sw_value_4:
3803             ctx->setting_value |= ch;
3804             state = sw_id;
3805 
3806             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3807                            "grpc setting: %ui %ui",
3808                            ctx->setting_id, ctx->setting_value);
3809 
3810             /*
3811              * The following settings are defined by the protocol:
3812              *
3813              * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH,
3814              * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE,
3815              * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE
3816              *
3817              * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in
3818              * a simple client.
3819              */
3820 
3821             if (ctx->setting_id == 0x04) {
3822                 /* SETTINGS_INITIAL_WINDOW_SIZE */
3823 
3824                 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) {
3825                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3826                                   "upstream sent settings frame "
3827                                   "with too large initial window size: %ui",
3828                                   ctx->setting_value);
3829                     return NGX_ERROR;
3830                 }
3831 
3832                 window_update = ctx->setting_value
3833                                 - ctx->connection->init_window;
3834                 ctx->connection->init_window = ctx->setting_value;
3835 
3836                 if (ctx->send_window > 0
3837                     && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW
3838                                        - ctx->send_window)
3839                 {
3840                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3841                                   "upstream sent settings frame "
3842                                   "with too large initial window size: %ui",
3843                                   ctx->setting_value);
3844                     return NGX_ERROR;
3845                 }
3846 
3847                 ctx->send_window += window_update;
3848             }
3849 
3850             break;
3851         }
3852     }
3853 
3854     ctx->rest -= p - b->pos;
3855     ctx->frame_state = state;
3856     b->pos = p;
3857 
3858     if (ctx->rest > 0) {
3859         return NGX_AGAIN;
3860     }
3861 
3862     ctx->state = ngx_http_grpc_st_start;
3863 
3864     return ngx_http_grpc_send_settings_ack(r, ctx);
3865 }
3866 
3867 
3868 static ngx_int_t
3869 ngx_http_grpc_parse_ping(ngx_http_request_t *r,
3870     ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b)
3871 {
3872     u_char  ch, *p, *last;
3873     enum {
3874         sw_start = 0,
3875         sw_data_2,
3876         sw_data_3,
3877         sw_data_4,
3878         sw_data_5,
3879         sw_data_6,
3880         sw_data_7,
3881         sw_data_8
3882     } state;
3883 
3884     if (b->last - b->pos < (ssize_t) ctx->rest) {
3885         last = b->last;
3886 
3887     } else {
3888         last = b->pos + ctx->rest;
3889     }
3890 
3891     state = ctx->frame_state;
3892 
3893     if (state == sw_start) {
3894 
3895         if (ctx->stream_id) {
3896             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3897                           "upstream sent ping frame "
3898                           "with non-zero stream id: %ui",
3899                           ctx->stream_id);
3900             return NGX_ERROR;
3901         }
3902 
3903         if (ctx->rest != 8) {
3904             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3905                           "upstream sent ping frame "
3906                           "with invalid length: %uz",
3907                           ctx->rest);
3908             return NGX_ERROR;
3909         }
3910 
3911         if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) {
3912             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3913                           "upstream sent ping frame with ack flag");
3914             return NGX_ERROR;
3915         }
3916 
3917         if (ctx->free == NULL && ctx->pings++ > 1000) {
3918             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3919                           "upstream sent too many ping frames");
3920             return NGX_ERROR;
3921         }
3922     }
3923 
3924     for (p = b->pos; p < last; p++) {
3925         ch = *p;
3926 
3927 #if 0
3928         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3929                        "grpc ping byte: %02Xd s:%d", ch, state);
3930 #endif
3931 
3932         if (state < sw_data_8) {
3933             ctx->ping_data[state] = ch;
3934             state++;
3935 
3936         } else {
3937             ctx->ping_data[7] = ch;
3938             state = sw_start;
3939 
3940             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3941                            "grpc ping");
3942         }
3943     }
3944 
3945     ctx->rest -= p - b->pos;
3946     ctx->frame_state = state;
3947     b->pos = p;
3948 
3949     if (ctx->rest > 0) {
3950         return NGX_AGAIN;
3951     }
3952 
3953     ctx->state = ngx_http_grpc_st_start;
3954 
3955     return ngx_http_grpc_send_ping_ack(r, ctx);
3956 }
3957 
3958 
3959 static ngx_int_t
3960 ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
3961 {
3962     ngx_chain_t            *cl, **ll;
3963     ngx_http_grpc_frame_t  *f;
3964 
3965     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3966                    "grpc send settings ack");
3967 
3968     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
3969         ll = &cl->next;
3970     }
3971 
3972     cl = ngx_http_grpc_get_buf(r, ctx);
3973     if (cl == NULL) {
3974         return NGX_ERROR;
3975     }
3976 
3977     f = (ngx_http_grpc_frame_t *) cl->buf->last;
3978     cl->buf->last += sizeof(ngx_http_grpc_frame_t);
3979 
3980     f->length_0 = 0;
3981     f->length_1 = 0;
3982     f->length_2 = 0;
3983     f->type = NGX_HTTP_V2_SETTINGS_FRAME;
3984     f->flags = NGX_HTTP_V2_ACK_FLAG;
3985     f->stream_id_0 = 0;
3986     f->stream_id_1 = 0;
3987     f->stream_id_2 = 0;
3988     f->stream_id_3 = 0;
3989 
3990     *ll = cl;
3991 
3992     return NGX_OK;
3993 }
3994 
3995 
3996 static ngx_int_t
3997 ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
3998 {
3999     ngx_chain_t            *cl, **ll;
4000     ngx_http_grpc_frame_t  *f;
4001 
4002     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4003                    "grpc send ping ack");
4004 
4005     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
4006         ll = &cl->next;
4007     }
4008 
4009     cl = ngx_http_grpc_get_buf(r, ctx);
4010     if (cl == NULL) {
4011         return NGX_ERROR;
4012     }
4013 
4014     f = (ngx_http_grpc_frame_t *) cl->buf->last;
4015     cl->buf->last += sizeof(ngx_http_grpc_frame_t);
4016 
4017     f->length_0 = 0;
4018     f->length_1 = 0;
4019     f->length_2 = 8;
4020     f->type = NGX_HTTP_V2_PING_FRAME;
4021     f->flags = NGX_HTTP_V2_ACK_FLAG;
4022     f->stream_id_0 = 0;
4023     f->stream_id_1 = 0;
4024     f->stream_id_2 = 0;
4025     f->stream_id_3 = 0;
4026 
4027     cl->buf->last = ngx_copy(cl->buf->last, ctx->ping_data, 8);
4028 
4029     *ll = cl;
4030 
4031     return NGX_OK;
4032 }
4033 
4034 
4035 static ngx_int_t
4036 ngx_http_grpc_send_window_update(ngx_http_request_t *r,
4037     ngx_http_grpc_ctx_t *ctx)
4038 {
4039     size_t                  n;
4040     ngx_chain_t            *cl, **ll;
4041     ngx_http_grpc_frame_t  *f;
4042 
4043     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4044                    "grpc send window update: %uz %uz",
4045                    ctx->connection->recv_window, ctx->recv_window);
4046 
4047     for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) {
4048         ll = &cl->next;
4049     }
4050 
4051     cl = ngx_http_grpc_get_buf(r, ctx);
4052     if (cl == NULL) {
4053         return NGX_ERROR;
4054     }
4055 
4056     f = (ngx_http_grpc_frame_t *) cl->buf->last;
4057     cl->buf->last += sizeof(ngx_http_grpc_frame_t);
4058 
4059     f->length_0 = 0;
4060     f->length_1 = 0;
4061     f->length_2 = 4;
4062     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
4063     f->flags = 0;
4064     f->stream_id_0 = 0;
4065     f->stream_id_1 = 0;
4066     f->stream_id_2 = 0;
4067     f->stream_id_3 = 0;
4068 
4069     n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window;
4070     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4071 
4072     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
4073     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
4074     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
4075     *cl->buf->last++ = (u_char) (n & 0xff);
4076 
4077     f = (ngx_http_grpc_frame_t *) cl->buf->last;
4078     cl->buf->last += sizeof(ngx_http_grpc_frame_t);
4079 
4080     f->length_0 = 0;
4081     f->length_1 = 0;
4082     f->length_2 = 4;
4083     f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME;
4084     f->flags = 0;
4085     f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff);
4086     f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff);
4087     f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff);
4088     f->stream_id_3 = (u_char) (ctx->id & 0xff);
4089 
4090     n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window;
4091     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4092 
4093     *cl->buf->last++ = (u_char) ((n >> 24) & 0xff);
4094     *cl->buf->last++ = (u_char) ((n >> 16) & 0xff);
4095     *cl->buf->last++ = (u_char) ((n >> 8) & 0xff);
4096     *cl->buf->last++ = (u_char) (n & 0xff);
4097 
4098     *ll = cl;
4099 
4100     return NGX_OK;
4101 }
4102 
4103 
4104 static ngx_chain_t *
4105 ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
4106 {
4107     u_char       *start;
4108     ngx_buf_t    *b;
4109     ngx_chain_t  *cl;
4110 
4111     cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
4112     if (cl == NULL) {
4113         return NULL;
4114     }
4115 
4116     b = cl->buf;
4117     start = b->start;
4118 
4119     if (start == NULL) {
4120 
4121         /*
4122          * each buffer is large enough to hold two window update
4123          * frames in a row
4124          */
4125 
4126         start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8);
4127         if (start == NULL) {
4128             return NULL;
4129         }
4130 
4131     }
4132 
4133     ngx_memzero(b, sizeof(ngx_buf_t));
4134 
4135     b->start = start;
4136     b->pos = start;
4137     b->last = start;
4138     b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8;
4139 
4140     b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
4141     b->temporary = 1;
4142     b->flush = 1;
4143 
4144     return cl;
4145 }
4146 
4147 
4148 static ngx_http_grpc_ctx_t *
4149 ngx_http_grpc_get_ctx(ngx_http_request_t *r)
4150 {
4151     ngx_http_grpc_ctx_t  *ctx;
4152     ngx_http_upstream_t  *u;
4153 
4154     ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
4155 
4156     if (ctx->connection == NULL) {
4157         u = r->upstream;
4158 
4159         if (ngx_http_grpc_get_connection_data(r, ctx, &u->peer) != NGX_OK) {
4160             return NULL;
4161         }
4162     }
4163 
4164     return ctx;
4165 }
4166 
4167 
4168 static ngx_int_t
4169 ngx_http_grpc_get_connection_data(ngx_http_request_t *r,
4170     ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc)
4171 {
4172     ngx_connection_t    *c;
4173     ngx_pool_cleanup_t  *cln;
4174 
4175     c = pc->connection;
4176 
4177     if (pc->cached) {
4178 
4179         /*
4180          * for cached connections, connection data can be found
4181          * in the cleanup handler
4182          */
4183 
4184         for (cln = c->pool->cleanup; cln; cln = cln->next) {
4185             if (cln->handler == ngx_http_grpc_cleanup) {
4186                 ctx->connection = cln->data;
4187                 break;
4188             }
4189         }
4190 
4191         if (ctx->connection == NULL) {
4192             ngx_log_error(NGX_LOG_ERR, c->log, 0,
4193                           "no connection data found for "
4194                           "keepalive http2 connection");
4195             return NGX_ERROR;
4196         }
4197 
4198         ctx->send_window = ctx->connection->init_window;
4199         ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4200 
4201         ctx->connection->last_stream_id += 2;
4202         ctx->id = ctx->connection->last_stream_id;
4203 
4204         return NGX_OK;
4205     }
4206 
4207     cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_grpc_conn_t));
4208     if (cln == NULL) {
4209         return NGX_ERROR;
4210     }
4211 
4212     cln->handler = ngx_http_grpc_cleanup;
4213     ctx->connection = cln->data;
4214 
4215     ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4216     ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4217     ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4218 
4219     ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW;
4220     ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW;
4221 
4222     ctx->id = 1;
4223     ctx->connection->last_stream_id = 1;
4224 
4225     return NGX_OK;
4226 }
4227 
4228 
4229 static void
4230 ngx_http_grpc_cleanup(void *data)
4231 {
4232 #if 0
4233     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
4234                    "grpc cleanup");
4235 #endif
4236     return;
4237 }
4238 
4239 
4240 static void
4241 ngx_http_grpc_abort_request(ngx_http_request_t *r)
4242 {
4243     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4244                    "abort grpc request");
4245     return;
4246 }
4247 
4248 
4249 static void
4250 ngx_http_grpc_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
4251 {
4252     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4253                    "finalize grpc request");
4254     return;
4255 }
4256 
4257 
4258 static ngx_int_t
4259 ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r,
4260     ngx_http_variable_value_t *v, uintptr_t data)
4261 {
4262     ngx_table_elt_t  *te;
4263 
4264     te = r->headers_in.te;
4265 
4266     if (te == NULL) {
4267         v->not_found = 1;
4268         return NGX_OK;
4269     }
4270 
4271     if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len,
4272                          (u_char *) "trailers", 8 - 1)
4273         == NULL)
4274     {
4275         v->not_found = 1;
4276         return NGX_OK;
4277     }
4278 
4279     v->valid = 1;
4280     v->no_cacheable = 0;
4281     v->not_found = 0;
4282 
4283     v->data = (u_char *) "trailers";
4284     v->len = sizeof("trailers") - 1;
4285 
4286     return NGX_OK;
4287 }
4288 
4289 
4290 static ngx_int_t
4291 ngx_http_grpc_add_variables(ngx_conf_t *cf)
4292 {
4293     ngx_http_variable_t  *var, *v;
4294 
4295     for (v = ngx_http_grpc_vars; v->name.len; v++) {
4296         var = ngx_http_add_variable(cf, &v->name, v->flags);
4297         if (var == NULL) {
4298             return NGX_ERROR;
4299         }
4300 
4301         var->get_handler = v->get_handler;
4302         var->data = v->data;
4303     }
4304 
4305     return NGX_OK;
4306 }
4307 
4308 
4309 static void *
4310 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf)
4311 {
4312     ngx_http_grpc_loc_conf_t  *conf;
4313 
4314     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_grpc_loc_conf_t));
4315     if (conf == NULL) {
4316         return NULL;
4317     }
4318 
4319     /*
4320      * set by ngx_pcalloc():
4321      *
4322      *     conf->upstream.ignore_headers = 0;
4323      *     conf->upstream.next_upstream = 0;
4324      *     conf->upstream.hide_headers_hash = { NULL, 0 };
4325      *     conf->upstream.ssl_name = NULL;
4326      *
4327      *     conf->headers_source = NULL;
4328      *     conf->headers.lengths = NULL;
4329      *     conf->headers.values = NULL;
4330      *     conf->headers.hash = { NULL, 0 };
4331      *     conf->host = { 0, NULL };
4332      *     conf->host_set = 0;
4333      *     conf->ssl = 0;
4334      *     conf->ssl_protocols = 0;
4335      *     conf->ssl_ciphers = { 0, NULL };
4336      *     conf->ssl_trusted_certificate = { 0, NULL };
4337      *     conf->ssl_crl = { 0, NULL };
4338      *     conf->ssl_certificate = { 0, NULL };
4339      *     conf->ssl_certificate_key = { 0, NULL };
4340      */
4341 
4342     conf->upstream.local = NGX_CONF_UNSET_PTR;
4343     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
4344     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
4345     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
4346     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
4347     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
4348     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
4349 
4350     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
4351 
4352     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
4353     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
4354 
4355     conf->upstream.intercept_errors = NGX_CONF_UNSET;
4356 
4357 #if (NGX_HTTP_SSL)
4358     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
4359     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
4360     conf->upstream.ssl_verify = NGX_CONF_UNSET;
4361     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
4362     conf->ssl_passwords = NGX_CONF_UNSET_PTR;
4363 #endif
4364 
4365     /* the hardcoded values */
4366     conf->upstream.cyclic_temp_file = 0;
4367     conf->upstream.buffering = 0;
4368     conf->upstream.ignore_client_abort = 0;
4369     conf->upstream.send_lowat = 0;
4370     conf->upstream.bufs.num = 0;
4371     conf->upstream.busy_buffers_size = 0;
4372     conf->upstream.max_temp_file_size = 0;
4373     conf->upstream.temp_file_write_size = 0;
4374     conf->upstream.pass_request_headers = 1;
4375     conf->upstream.pass_request_body = 1;
4376     conf->upstream.force_ranges = 0;
4377     conf->upstream.pass_trailers = 1;
4378     conf->upstream.preserve_output = 1;
4379 
4380     ngx_str_set(&conf->upstream.module, "grpc");
4381 
4382     return conf;
4383 }
4384 
4385 
4386 static char *
4387 ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
4388 {
4389     ngx_http_grpc_loc_conf_t *prev = parent;
4390     ngx_http_grpc_loc_conf_t *conf = child;
4391 
4392     ngx_int_t                  rc;
4393     ngx_hash_init_t            hash;
4394     ngx_http_core_loc_conf_t  *clcf;
4395 
4396     ngx_conf_merge_ptr_value(conf->upstream.local,
4397                               prev->upstream.local, NULL);
4398 
4399     ngx_conf_merge_value(conf->upstream.socket_keepalive,
4400                               prev->upstream.socket_keepalive, 0);
4401 
4402     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
4403                               prev->upstream.next_upstream_tries, 0);
4404 
4405     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
4406                               prev->upstream.connect_timeout, 60000);
4407 
4408     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
4409                               prev->upstream.send_timeout, 60000);
4410 
4411     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
4412                               prev->upstream.read_timeout, 60000);
4413 
4414     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
4415                               prev->upstream.next_upstream_timeout, 0);
4416 
4417     ngx_conf_merge_size_value(conf->upstream.buffer_size,
4418                               prev->upstream.buffer_size,
4419                               (size_t) ngx_pagesize);
4420 
4421     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
4422                               prev->upstream.ignore_headers,
4423                               NGX_CONF_BITMASK_SET);
4424 
4425     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
4426                               prev->upstream.next_upstream,
4427                               (NGX_CONF_BITMASK_SET
4428                                |NGX_HTTP_UPSTREAM_FT_ERROR
4429                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
4430 
4431     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
4432         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
4433                                        |NGX_HTTP_UPSTREAM_FT_OFF;
4434     }
4435 
4436     ngx_conf_merge_value(conf->upstream.intercept_errors,
4437                               prev->upstream.intercept_errors, 0);
4438 
4439 #if (NGX_HTTP_SSL)
4440 
4441     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
4442                               prev->upstream.ssl_session_reuse, 1);
4443 
4444     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
4445                                  (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
4446                                   |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
4447 
4448     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
4449                              "DEFAULT");
4450 
4451     if (conf->upstream.ssl_name == NULL) {
4452         conf->upstream.ssl_name = prev->upstream.ssl_name;
4453     }
4454 
4455     ngx_conf_merge_value(conf->upstream.ssl_server_name,
4456                               prev->upstream.ssl_server_name, 0);
4457     ngx_conf_merge_value(conf->upstream.ssl_verify,
4458                               prev->upstream.ssl_verify, 0);
4459     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
4460                               prev->ssl_verify_depth, 1);
4461     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
4462                               prev->ssl_trusted_certificate, "");
4463     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
4464 
4465     ngx_conf_merge_str_value(conf->ssl_certificate,
4466                               prev->ssl_certificate, "");
4467     ngx_conf_merge_str_value(conf->ssl_certificate_key,
4468                               prev->ssl_certificate_key, "");
4469     ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
4470 
4471     if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) {
4472         return NGX_CONF_ERROR;
4473     }
4474 
4475 #endif
4476 
4477     hash.max_size = 512;
4478     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
4479     hash.name = "grpc_headers_hash";
4480 
4481     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
4482             &prev->upstream, ngx_http_grpc_hide_headers, &hash)
4483         != NGX_OK)
4484     {
4485         return NGX_CONF_ERROR;
4486     }
4487 
4488     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
4489 
4490     if (clcf->noname
4491         && conf->upstream.upstream == NULL && conf->grpc_lengths == NULL)
4492     {
4493         conf->upstream.upstream = prev->upstream.upstream;
4494         conf->host = prev->host;
4495 
4496         conf->grpc_lengths = prev->grpc_lengths;
4497         conf->grpc_values = prev->grpc_values;
4498 
4499 #if (NGX_HTTP_SSL)
4500         conf->upstream.ssl = prev->upstream.ssl;
4501 #endif
4502     }
4503 
4504     if (clcf->lmt_excpt && clcf->handler == NULL
4505         && (conf->upstream.upstream || conf->grpc_lengths))
4506     {
4507         clcf->handler = ngx_http_grpc_handler;
4508     }
4509 
4510     if (conf->headers_source == NULL) {
4511         conf->headers = prev->headers;
4512         conf->headers_source = prev->headers_source;
4513         conf->host_set = prev->host_set;
4514     }
4515 
4516     rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers,
4517                                     ngx_http_grpc_headers);
4518     if (rc != NGX_OK) {
4519         return NGX_CONF_ERROR;
4520     }
4521 
4522     /*
4523      * special handling to preserve conf->headers in the "http" section
4524      * to inherit it to all servers
4525      */
4526 
4527     if (prev->headers.hash.buckets == NULL
4528         && conf->headers_source == prev->headers_source)
4529     {
4530         prev->headers = conf->headers;
4531         prev->host_set = conf->host_set;
4532     }
4533 
4534     return NGX_CONF_OK;
4535 }
4536 
4537 
4538 static ngx_int_t
4539 ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
4540     ngx_http_grpc_headers_t *headers, ngx_keyval_t *default_headers)
4541 {
4542     u_char                       *p;
4543     size_t                        size;
4544     uintptr_t                    *code;
4545     ngx_uint_t                    i;
4546     ngx_array_t                   headers_names, headers_merged;
4547     ngx_keyval_t                 *src, *s, *h;
4548     ngx_hash_key_t               *hk;
4549     ngx_hash_init_t               hash;
4550     ngx_http_script_compile_t     sc;
4551     ngx_http_script_copy_code_t  *copy;
4552 
4553     if (headers->hash.buckets) {
4554         return NGX_OK;
4555     }
4556 
4557     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
4558         != NGX_OK)
4559     {
4560         return NGX_ERROR;
4561     }
4562 
4563     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
4564         != NGX_OK)
4565     {
4566         return NGX_ERROR;
4567     }
4568 
4569     headers->lengths = ngx_array_create(cf->pool, 64, 1);
4570     if (headers->lengths == NULL) {
4571         return NGX_ERROR;
4572     }
4573 
4574     headers->values = ngx_array_create(cf->pool, 512, 1);
4575     if (headers->values == NULL) {
4576         return NGX_ERROR;
4577     }
4578 
4579     if (conf->headers_source) {
4580 
4581         src = conf->headers_source->elts;
4582         for (i = 0; i < conf->headers_source->nelts; i++) {
4583 
4584             if (src[i].key.len == 4
4585                 && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0)
4586             {
4587                 conf->host_set = 1;
4588             }
4589 
4590             s = ngx_array_push(&headers_merged);
4591             if (s == NULL) {
4592                 return NGX_ERROR;
4593             }
4594 
4595             *s = src[i];
4596         }
4597     }
4598 
4599     h = default_headers;
4600 
4601     while (h->key.len) {
4602 
4603         src = headers_merged.elts;
4604         for (i = 0; i < headers_merged.nelts; i++) {
4605             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
4606                 goto next;
4607             }
4608         }
4609 
4610         s = ngx_array_push(&headers_merged);
4611         if (s == NULL) {
4612             return NGX_ERROR;
4613         }
4614 
4615         *s = *h;
4616 
4617     next:
4618 
4619         h++;
4620     }
4621 
4622 
4623     src = headers_merged.elts;
4624     for (i = 0; i < headers_merged.nelts; i++) {
4625 
4626         hk = ngx_array_push(&headers_names);
4627         if (hk == NULL) {
4628             return NGX_ERROR;
4629         }
4630 
4631         hk->key = src[i].key;
4632         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
4633         hk->value = (void *) 1;
4634 
4635         if (src[i].value.len == 0) {
4636             continue;
4637         }
4638 
4639         copy = ngx_array_push_n(headers->lengths,
4640                                 sizeof(ngx_http_script_copy_code_t));
4641         if (copy == NULL) {
4642             return NGX_ERROR;
4643         }
4644 
4645         copy->code = (ngx_http_script_code_pt) (void *)
4646                                                  ngx_http_script_copy_len_code;
4647         copy->len = src[i].key.len;
4648 
4649         size = (sizeof(ngx_http_script_copy_code_t)
4650                 + src[i].key.len + sizeof(uintptr_t) - 1)
4651                & ~(sizeof(uintptr_t) - 1);
4652 
4653         copy = ngx_array_push_n(headers->values, size);
4654         if (copy == NULL) {
4655             return NGX_ERROR;
4656         }
4657 
4658         copy->code = ngx_http_script_copy_code;
4659         copy->len = src[i].key.len;
4660 
4661         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
4662         ngx_memcpy(p, src[i].key.data, src[i].key.len);
4663 
4664         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4665 
4666         sc.cf = cf;
4667         sc.source = &src[i].value;
4668         sc.flushes = &headers->flushes;
4669         sc.lengths = &headers->lengths;
4670         sc.values = &headers->values;
4671 
4672         if (ngx_http_script_compile(&sc) != NGX_OK) {
4673             return NGX_ERROR;
4674         }
4675 
4676         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
4677         if (code == NULL) {
4678             return NGX_ERROR;
4679         }
4680 
4681         *code = (uintptr_t) NULL;
4682 
4683         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
4684         if (code == NULL) {
4685             return NGX_ERROR;
4686         }
4687 
4688         *code = (uintptr_t) NULL;
4689     }
4690 
4691     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
4692     if (code == NULL) {
4693         return NGX_ERROR;
4694     }
4695 
4696     *code = (uintptr_t) NULL;
4697 
4698 
4699     hash.hash = &headers->hash;
4700     hash.key = ngx_hash_key_lc;
4701     hash.max_size = 512;
4702     hash.bucket_size = 64;
4703     hash.name = "grpc_headers_hash";
4704     hash.pool = cf->pool;
4705     hash.temp_pool = NULL;
4706 
4707     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
4708 }
4709 
4710 
4711 static char *
4712 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4713 {
4714     ngx_http_grpc_loc_conf_t *glcf = conf;
4715 
4716     size_t                      add;
4717     ngx_str_t                  *value, *url;
4718     ngx_url_t                   u;
4719     ngx_uint_t                  n;
4720     ngx_http_core_loc_conf_t   *clcf;
4721     ngx_http_script_compile_t   sc;
4722 
4723     if (glcf->upstream.upstream || glcf->grpc_lengths) {
4724         return "is duplicate";
4725     }
4726 
4727     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
4728 
4729     clcf->handler = ngx_http_grpc_handler;
4730 
4731     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
4732         clcf->auto_redirect = 1;
4733     }
4734 
4735     value = cf->args->elts;
4736 
4737     url = &value[1];
4738 
4739     n = ngx_http_script_variables_count(url);
4740 
4741     if (n) {
4742 
4743         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4744 
4745         sc.cf = cf;
4746         sc.source = url;
4747         sc.lengths = &glcf->grpc_lengths;
4748         sc.values = &glcf->grpc_values;
4749         sc.variables = n;
4750         sc.complete_lengths = 1;
4751         sc.complete_values = 1;
4752 
4753         if (ngx_http_script_compile(&sc) != NGX_OK) {
4754             return NGX_CONF_ERROR;
4755         }
4756 
4757 #if (NGX_HTTP_SSL)
4758         glcf->ssl = 1;
4759 #endif
4760 
4761         return NGX_CONF_OK;
4762     }
4763 
4764     if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) {
4765         add = 7;
4766 
4767     } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) {
4768 
4769 #if (NGX_HTTP_SSL)
4770         glcf->ssl = 1;
4771 
4772         add = 8;
4773 #else
4774         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4775                            "grpcs protocol requires SSL support");
4776         return NGX_CONF_ERROR;
4777 #endif
4778 
4779     } else {
4780         add = 0;
4781     }
4782 
4783     ngx_memzero(&u, sizeof(ngx_url_t));
4784 
4785     u.url.len = url->len - add;
4786     u.url.data = url->data + add;
4787     u.no_resolve = 1;
4788 
4789     glcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
4790     if (glcf->upstream.upstream == NULL) {
4791         return NGX_CONF_ERROR;
4792     }
4793 
4794     if (u.family != AF_UNIX) {
4795 
4796         if (u.no_port) {
4797             glcf->host = u.host;
4798 
4799         } else {
4800             glcf->host.len = u.host.len + 1 + u.port_text.len;
4801             glcf->host.data = u.host.data;
4802         }
4803 
4804     } else {
4805         ngx_str_set(&glcf->host, "localhost");
4806     }
4807 
4808     return NGX_CONF_OK;
4809 }
4810 
4811 
4812 #if (NGX_HTTP_SSL)
4813 
4814 static char *
4815 ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4816 {
4817     ngx_http_grpc_loc_conf_t *glcf = conf;
4818 
4819     ngx_str_t  *value;
4820 
4821     if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
4822         return "is duplicate";
4823     }
4824 
4825     value = cf->args->elts;
4826 
4827     glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
4828 
4829     if (glcf->ssl_passwords == NULL) {
4830         return NGX_CONF_ERROR;
4831     }
4832 
4833     return NGX_CONF_OK;
4834 }
4835 
4836 
4837 static ngx_int_t
4838 ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf)
4839 {
4840     ngx_pool_cleanup_t  *cln;
4841 
4842     glcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
4843     if (glcf->upstream.ssl == NULL) {
4844         return NGX_ERROR;
4845     }
4846 
4847     glcf->upstream.ssl->log = cf->log;
4848 
4849     if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL)
4850         != NGX_OK)
4851     {
4852         return NGX_ERROR;
4853     }
4854 
4855     cln = ngx_pool_cleanup_add(cf->pool, 0);
4856     if (cln == NULL) {
4857         ngx_ssl_cleanup_ctx(glcf->upstream.ssl);
4858         return NGX_ERROR;
4859     }
4860 
4861     cln->handler = ngx_ssl_cleanup_ctx;
4862     cln->data = glcf->upstream.ssl;
4863 
4864     if (glcf->ssl_certificate.len) {
4865 
4866         if (glcf->ssl_certificate_key.len == 0) {
4867             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4868                           "no \"grpc_ssl_certificate_key\" is defined "
4869                           "for certificate \"%V\"", &glcf->ssl_certificate);
4870             return NGX_ERROR;
4871         }
4872 
4873         if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate,
4874                                 &glcf->ssl_certificate_key, glcf->ssl_passwords)
4875             != NGX_OK)
4876         {
4877             return NGX_ERROR;
4878         }
4879     }
4880 
4881     if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0)
4882         != NGX_OK)
4883     {
4884         return NGX_ERROR;
4885     }
4886 
4887     if (glcf->upstream.ssl_verify) {
4888         if (glcf->ssl_trusted_certificate.len == 0) {
4889             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4890                       "no grpc_ssl_trusted_certificate for grpc_ssl_verify");
4891             return NGX_ERROR;
4892         }
4893 
4894         if (ngx_ssl_trusted_certificate(cf, glcf->upstream.ssl,
4895                                         &glcf->ssl_trusted_certificate,
4896                                         glcf->ssl_verify_depth)
4897             != NGX_OK)
4898         {
4899             return NGX_ERROR;
4900         }
4901 
4902         if (ngx_ssl_crl(cf, glcf->upstream.ssl, &glcf->ssl_crl) != NGX_OK) {
4903             return NGX_ERROR;
4904         }
4905     }
4906 
4907     if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl,
4908                                      glcf->upstream.ssl_session_reuse)
4909         != NGX_OK)
4910     {
4911         return NGX_ERROR;
4912     }
4913 
4914 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
4915 
4916     if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx,
4917                                 (u_char *) "\x02h2", 3)
4918         != 0)
4919     {
4920         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
4921                       "SSL_CTX_set_alpn_protos() failed");
4922         return NGX_ERROR;
4923     }
4924 
4925 #endif
4926 
4927     return NGX_OK;
4928 }
4929 
4930 #endif