Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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