Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

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