Mercurial > hg > nginx
annotate src/http/modules/ngx_http_grpc_module.c @ 7730:1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Similarly to ssl_conf_command, proxy_ssl_conf_command (grpc_ssl_conf_command,
uwsgi_ssl_conf_command) can be used to set arbitrary OpenSSL configuration
parameters as long as nginx is compiled with OpenSSL 1.0.2 or later,
when connecting to upstream servers with SSL. Full list of available
configuration commands can be found in the SSL_CONF_cmd manual page
(https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 22 Oct 2020 18:00:23 +0300 |
parents | 485dba3e2a01 |
children | a46fcf101cfc |
rev | line source |
---|---|
7233 | 1 |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
14 ngx_array_t *flushes; | |
15 ngx_array_t *lengths; | |
16 ngx_array_t *values; | |
17 ngx_hash_t hash; | |
18 } ngx_http_grpc_headers_t; | |
19 | |
20 | |
21 typedef struct { | |
22 ngx_http_upstream_conf_t upstream; | |
23 | |
24 ngx_http_grpc_headers_t headers; | |
25 ngx_array_t *headers_source; | |
26 | |
27 ngx_str_t host; | |
28 ngx_uint_t host_set; | |
29 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
30 ngx_array_t *grpc_lengths; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
31 ngx_array_t *grpc_values; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
32 |
7233 | 33 #if (NGX_HTTP_SSL) |
34 ngx_uint_t ssl; | |
35 ngx_uint_t ssl_protocols; | |
36 ngx_str_t ssl_ciphers; | |
37 ngx_uint_t ssl_verify_depth; | |
38 ngx_str_t ssl_trusted_certificate; | |
39 ngx_str_t ssl_crl; | |
40 ngx_str_t ssl_certificate; | |
41 ngx_str_t ssl_certificate_key; | |
42 ngx_array_t *ssl_passwords; | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
43 ngx_array_t *ssl_conf_commands; |
7233 | 44 #endif |
45 } ngx_http_grpc_loc_conf_t; | |
46 | |
47 | |
48 typedef enum { | |
49 ngx_http_grpc_st_start = 0, | |
50 ngx_http_grpc_st_length_2, | |
51 ngx_http_grpc_st_length_3, | |
52 ngx_http_grpc_st_type, | |
53 ngx_http_grpc_st_flags, | |
54 ngx_http_grpc_st_stream_id, | |
55 ngx_http_grpc_st_stream_id_2, | |
56 ngx_http_grpc_st_stream_id_3, | |
57 ngx_http_grpc_st_stream_id_4, | |
58 ngx_http_grpc_st_payload, | |
59 ngx_http_grpc_st_padding | |
60 } ngx_http_grpc_state_e; | |
61 | |
62 | |
63 typedef struct { | |
64 size_t init_window; | |
65 size_t send_window; | |
66 size_t recv_window; | |
67 ngx_uint_t last_stream_id; | |
68 } ngx_http_grpc_conn_t; | |
69 | |
70 | |
71 typedef struct { | |
72 ngx_http_grpc_state_e state; | |
73 ngx_uint_t frame_state; | |
74 ngx_uint_t fragment_state; | |
75 | |
76 ngx_chain_t *in; | |
77 ngx_chain_t *out; | |
78 ngx_chain_t *free; | |
79 ngx_chain_t *busy; | |
80 | |
81 ngx_http_grpc_conn_t *connection; | |
82 | |
83 ngx_uint_t id; | |
84 | |
7379
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
85 ngx_uint_t pings; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
86 ngx_uint_t settings; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
87 |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
88 off_t length; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
89 |
7233 | 90 ssize_t send_window; |
91 size_t recv_window; | |
92 | |
93 size_t rest; | |
94 ngx_uint_t stream_id; | |
95 u_char type; | |
96 u_char flags; | |
97 u_char padding; | |
98 | |
99 ngx_uint_t error; | |
100 ngx_uint_t window_update; | |
101 | |
102 ngx_uint_t setting_id; | |
103 ngx_uint_t setting_value; | |
104 | |
105 u_char ping_data[8]; | |
106 | |
107 ngx_uint_t index; | |
108 ngx_str_t name; | |
109 ngx_str_t value; | |
110 | |
111 u_char *field_end; | |
112 size_t field_length; | |
113 size_t field_rest; | |
114 u_char field_state; | |
115 | |
116 unsigned literal:1; | |
117 unsigned field_huffman:1; | |
118 | |
119 unsigned header_sent:1; | |
120 unsigned output_closed:1; | |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
121 unsigned output_blocked:1; |
7233 | 122 unsigned parsing_headers:1; |
123 unsigned end_stream:1; | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
124 unsigned done:1; |
7233 | 125 unsigned status:1; |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
126 unsigned rst:1; |
7233 | 127 |
128 ngx_http_request_t *request; | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
129 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
130 ngx_str_t host; |
7233 | 131 } ngx_http_grpc_ctx_t; |
132 | |
133 | |
134 typedef struct { | |
135 u_char length_0; | |
136 u_char length_1; | |
137 u_char length_2; | |
138 u_char type; | |
139 u_char flags; | |
140 u_char stream_id_0; | |
141 u_char stream_id_1; | |
142 u_char stream_id_2; | |
143 u_char stream_id_3; | |
144 } ngx_http_grpc_frame_t; | |
145 | |
146 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
147 static ngx_int_t ngx_http_grpc_eval(ngx_http_request_t *r, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
148 ngx_http_grpc_ctx_t *ctx, ngx_http_grpc_loc_conf_t *glcf); |
7233 | 149 static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r); |
150 static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r); | |
151 static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in); | |
152 static ngx_int_t ngx_http_grpc_process_header(ngx_http_request_t *r); | |
153 static ngx_int_t ngx_http_grpc_filter_init(void *data); | |
154 static ngx_int_t ngx_http_grpc_filter(void *data, ssize_t bytes); | |
155 | |
156 static ngx_int_t ngx_http_grpc_parse_frame(ngx_http_request_t *r, | |
157 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
158 static ngx_int_t ngx_http_grpc_parse_header(ngx_http_request_t *r, | |
159 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
160 static ngx_int_t ngx_http_grpc_parse_fragment(ngx_http_request_t *r, | |
161 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
162 static ngx_int_t ngx_http_grpc_validate_header_name(ngx_http_request_t *r, | |
163 ngx_str_t *s); | |
164 static ngx_int_t ngx_http_grpc_validate_header_value(ngx_http_request_t *r, | |
165 ngx_str_t *s); | |
166 static ngx_int_t ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, | |
167 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
168 static ngx_int_t ngx_http_grpc_parse_goaway(ngx_http_request_t *r, | |
169 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
170 static ngx_int_t ngx_http_grpc_parse_window_update(ngx_http_request_t *r, | |
171 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
172 static ngx_int_t ngx_http_grpc_parse_settings(ngx_http_request_t *r, | |
173 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
174 static ngx_int_t ngx_http_grpc_parse_ping(ngx_http_request_t *r, | |
175 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b); | |
176 | |
177 static ngx_int_t ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, | |
178 ngx_http_grpc_ctx_t *ctx); | |
179 static ngx_int_t ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, | |
180 ngx_http_grpc_ctx_t *ctx); | |
181 static ngx_int_t ngx_http_grpc_send_window_update(ngx_http_request_t *r, | |
182 ngx_http_grpc_ctx_t *ctx); | |
183 | |
184 static ngx_chain_t *ngx_http_grpc_get_buf(ngx_http_request_t *r, | |
185 ngx_http_grpc_ctx_t *ctx); | |
186 static ngx_http_grpc_ctx_t *ngx_http_grpc_get_ctx(ngx_http_request_t *r); | |
187 static ngx_int_t ngx_http_grpc_get_connection_data(ngx_http_request_t *r, | |
188 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc); | |
189 static void ngx_http_grpc_cleanup(void *data); | |
190 | |
191 static void ngx_http_grpc_abort_request(ngx_http_request_t *r); | |
192 static void ngx_http_grpc_finalize_request(ngx_http_request_t *r, | |
193 ngx_int_t rc); | |
194 | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
195 static ngx_int_t ngx_http_grpc_internal_trailers_variable( |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
196 ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
197 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
198 static ngx_int_t ngx_http_grpc_add_variables(ngx_conf_t *cf); |
7233 | 199 static void *ngx_http_grpc_create_loc_conf(ngx_conf_t *cf); |
200 static char *ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, | |
201 void *parent, void *child); | |
202 static ngx_int_t ngx_http_grpc_init_headers(ngx_conf_t *cf, | |
203 ngx_http_grpc_loc_conf_t *conf, ngx_http_grpc_headers_t *headers, | |
204 ngx_keyval_t *default_headers); | |
205 | |
206 static char *ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
207 void *conf); | |
208 | |
209 #if (NGX_HTTP_SSL) | |
210 static char *ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, | |
211 ngx_command_t *cmd, void *conf); | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
212 static char *ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
213 void *data); |
7233 | 214 static ngx_int_t ngx_http_grpc_set_ssl(ngx_conf_t *cf, |
215 ngx_http_grpc_loc_conf_t *glcf); | |
216 #endif | |
217 | |
218 | |
219 static ngx_conf_bitmask_t ngx_http_grpc_next_upstream_masks[] = { | |
220 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, | |
221 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, | |
222 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, | |
223 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, | |
224 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, | |
225 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, | |
226 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, | |
227 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 }, | |
228 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 }, | |
229 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, | |
230 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 }, | |
231 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, | |
232 { ngx_null_string, 0 } | |
233 }; | |
234 | |
235 | |
236 #if (NGX_HTTP_SSL) | |
237 | |
238 static ngx_conf_bitmask_t ngx_http_grpc_ssl_protocols[] = { | |
239 { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, | |
240 { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, | |
241 { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, | |
242 { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, | |
243 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, | |
244 { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 }, | |
245 { ngx_null_string, 0 } | |
246 }; | |
247 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
248 static ngx_conf_post_t ngx_http_grpc_ssl_conf_command_post = |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
249 { ngx_http_grpc_ssl_conf_command_check }; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
250 |
7233 | 251 #endif |
252 | |
253 | |
254 static ngx_command_t ngx_http_grpc_commands[] = { | |
255 | |
256 { ngx_string("grpc_pass"), | |
257 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, | |
258 ngx_http_grpc_pass, | |
259 NGX_HTTP_LOC_CONF_OFFSET, | |
260 0, | |
261 NULL }, | |
262 | |
263 { ngx_string("grpc_bind"), | |
264 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | |
265 ngx_http_upstream_bind_set_slot, | |
266 NGX_HTTP_LOC_CONF_OFFSET, | |
267 offsetof(ngx_http_grpc_loc_conf_t, upstream.local), | |
268 NULL }, | |
269 | |
7371
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
270 { ngx_string("grpc_socket_keepalive"), |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
271 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
272 ngx_conf_set_flag_slot, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
273 NGX_HTTP_LOC_CONF_OFFSET, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
274 offsetof(ngx_http_grpc_loc_conf_t, upstream.socket_keepalive), |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
275 NULL }, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
276 |
7233 | 277 { ngx_string("grpc_connect_timeout"), |
278 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
279 ngx_conf_set_msec_slot, | |
280 NGX_HTTP_LOC_CONF_OFFSET, | |
281 offsetof(ngx_http_grpc_loc_conf_t, upstream.connect_timeout), | |
282 NULL }, | |
283 | |
284 { ngx_string("grpc_send_timeout"), | |
285 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
286 ngx_conf_set_msec_slot, | |
287 NGX_HTTP_LOC_CONF_OFFSET, | |
288 offsetof(ngx_http_grpc_loc_conf_t, upstream.send_timeout), | |
289 NULL }, | |
290 | |
291 { ngx_string("grpc_intercept_errors"), | |
292 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
293 ngx_conf_set_flag_slot, | |
294 NGX_HTTP_LOC_CONF_OFFSET, | |
295 offsetof(ngx_http_grpc_loc_conf_t, upstream.intercept_errors), | |
296 NULL }, | |
297 | |
298 { ngx_string("grpc_buffer_size"), | |
299 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
300 ngx_conf_set_size_slot, | |
301 NGX_HTTP_LOC_CONF_OFFSET, | |
302 offsetof(ngx_http_grpc_loc_conf_t, upstream.buffer_size), | |
303 NULL }, | |
304 | |
305 { ngx_string("grpc_read_timeout"), | |
306 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
307 ngx_conf_set_msec_slot, | |
308 NGX_HTTP_LOC_CONF_OFFSET, | |
309 offsetof(ngx_http_grpc_loc_conf_t, upstream.read_timeout), | |
310 NULL }, | |
311 | |
312 { ngx_string("grpc_next_upstream"), | |
313 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
314 ngx_conf_set_bitmask_slot, | |
315 NGX_HTTP_LOC_CONF_OFFSET, | |
316 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream), | |
317 &ngx_http_grpc_next_upstream_masks }, | |
318 | |
319 { ngx_string("grpc_next_upstream_tries"), | |
320 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
321 ngx_conf_set_num_slot, | |
322 NGX_HTTP_LOC_CONF_OFFSET, | |
323 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_tries), | |
324 NULL }, | |
325 | |
326 { ngx_string("grpc_next_upstream_timeout"), | |
327 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
328 ngx_conf_set_msec_slot, | |
329 NGX_HTTP_LOC_CONF_OFFSET, | |
330 offsetof(ngx_http_grpc_loc_conf_t, upstream.next_upstream_timeout), | |
331 NULL }, | |
332 | |
333 { ngx_string("grpc_set_header"), | |
334 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
335 ngx_conf_set_keyval_slot, | |
336 NGX_HTTP_LOC_CONF_OFFSET, | |
337 offsetof(ngx_http_grpc_loc_conf_t, headers_source), | |
338 NULL }, | |
339 | |
340 { ngx_string("grpc_pass_header"), | |
341 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
342 ngx_conf_set_str_array_slot, | |
343 NGX_HTTP_LOC_CONF_OFFSET, | |
344 offsetof(ngx_http_grpc_loc_conf_t, upstream.pass_headers), | |
345 NULL }, | |
346 | |
347 { ngx_string("grpc_hide_header"), | |
348 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
349 ngx_conf_set_str_array_slot, | |
350 NGX_HTTP_LOC_CONF_OFFSET, | |
351 offsetof(ngx_http_grpc_loc_conf_t, upstream.hide_headers), | |
352 NULL }, | |
353 | |
354 { ngx_string("grpc_ignore_headers"), | |
355 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
356 ngx_conf_set_bitmask_slot, | |
357 NGX_HTTP_LOC_CONF_OFFSET, | |
358 offsetof(ngx_http_grpc_loc_conf_t, upstream.ignore_headers), | |
359 &ngx_http_upstream_ignore_headers_masks }, | |
360 | |
361 #if (NGX_HTTP_SSL) | |
362 | |
363 { ngx_string("grpc_ssl_session_reuse"), | |
364 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
365 ngx_conf_set_flag_slot, | |
366 NGX_HTTP_LOC_CONF_OFFSET, | |
367 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_session_reuse), | |
368 NULL }, | |
369 | |
370 { ngx_string("grpc_ssl_protocols"), | |
371 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
372 ngx_conf_set_bitmask_slot, | |
373 NGX_HTTP_LOC_CONF_OFFSET, | |
374 offsetof(ngx_http_grpc_loc_conf_t, ssl_protocols), | |
375 &ngx_http_grpc_ssl_protocols }, | |
376 | |
377 { ngx_string("grpc_ssl_ciphers"), | |
378 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
379 ngx_conf_set_str_slot, | |
380 NGX_HTTP_LOC_CONF_OFFSET, | |
381 offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers), | |
382 NULL }, | |
383 | |
384 { ngx_string("grpc_ssl_name"), | |
385 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
386 ngx_http_set_complex_value_slot, | |
387 NGX_HTTP_LOC_CONF_OFFSET, | |
388 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_name), | |
389 NULL }, | |
390 | |
391 { ngx_string("grpc_ssl_server_name"), | |
392 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
393 ngx_conf_set_flag_slot, | |
394 NGX_HTTP_LOC_CONF_OFFSET, | |
395 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_server_name), | |
396 NULL }, | |
397 | |
398 { ngx_string("grpc_ssl_verify"), | |
399 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
400 ngx_conf_set_flag_slot, | |
401 NGX_HTTP_LOC_CONF_OFFSET, | |
402 offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_verify), | |
403 NULL }, | |
404 | |
405 { ngx_string("grpc_ssl_verify_depth"), | |
406 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
407 ngx_conf_set_num_slot, | |
408 NGX_HTTP_LOC_CONF_OFFSET, | |
409 offsetof(ngx_http_grpc_loc_conf_t, ssl_verify_depth), | |
410 NULL }, | |
411 | |
412 { ngx_string("grpc_ssl_trusted_certificate"), | |
413 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
414 ngx_conf_set_str_slot, | |
415 NGX_HTTP_LOC_CONF_OFFSET, | |
416 offsetof(ngx_http_grpc_loc_conf_t, ssl_trusted_certificate), | |
417 NULL }, | |
418 | |
419 { ngx_string("grpc_ssl_crl"), | |
420 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
421 ngx_conf_set_str_slot, | |
422 NGX_HTTP_LOC_CONF_OFFSET, | |
423 offsetof(ngx_http_grpc_loc_conf_t, ssl_crl), | |
424 NULL }, | |
425 | |
426 { ngx_string("grpc_ssl_certificate"), | |
427 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
428 ngx_conf_set_str_slot, | |
429 NGX_HTTP_LOC_CONF_OFFSET, | |
430 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate), | |
431 NULL }, | |
432 | |
433 { ngx_string("grpc_ssl_certificate_key"), | |
434 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
435 ngx_conf_set_str_slot, | |
436 NGX_HTTP_LOC_CONF_OFFSET, | |
437 offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key), | |
438 NULL }, | |
439 | |
440 { ngx_string("grpc_ssl_password_file"), | |
441 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
442 ngx_http_grpc_ssl_password_file, | |
443 NGX_HTTP_LOC_CONF_OFFSET, | |
444 0, | |
445 NULL }, | |
446 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
447 { ngx_string("grpc_ssl_conf_command"), |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
448 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
449 ngx_conf_set_keyval_slot, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
450 NGX_HTTP_LOC_CONF_OFFSET, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
451 offsetof(ngx_http_grpc_loc_conf_t, ssl_conf_commands), |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
452 &ngx_http_grpc_ssl_conf_command_post }, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
453 |
7233 | 454 #endif |
455 | |
456 ngx_null_command | |
457 }; | |
458 | |
459 | |
460 static ngx_http_module_t ngx_http_grpc_module_ctx = { | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
461 ngx_http_grpc_add_variables, /* preconfiguration */ |
7233 | 462 NULL, /* postconfiguration */ |
463 | |
464 NULL, /* create main configuration */ | |
465 NULL, /* init main configuration */ | |
466 | |
467 NULL, /* create server configuration */ | |
468 NULL, /* merge server configuration */ | |
469 | |
470 ngx_http_grpc_create_loc_conf, /* create location configuration */ | |
471 ngx_http_grpc_merge_loc_conf /* merge location configuration */ | |
472 }; | |
473 | |
474 | |
475 ngx_module_t ngx_http_grpc_module = { | |
476 NGX_MODULE_V1, | |
477 &ngx_http_grpc_module_ctx, /* module context */ | |
478 ngx_http_grpc_commands, /* module directives */ | |
479 NGX_HTTP_MODULE, /* module type */ | |
480 NULL, /* init master */ | |
481 NULL, /* init module */ | |
482 NULL, /* init process */ | |
483 NULL, /* init thread */ | |
484 NULL, /* exit thread */ | |
485 NULL, /* exit process */ | |
486 NULL, /* exit master */ | |
487 NGX_MODULE_V1_PADDING | |
488 }; | |
489 | |
490 | |
491 static u_char ngx_http_grpc_connection_start[] = | |
492 "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* connection preface */ | |
493 | |
494 "\x00\x00\x12\x04\x00\x00\x00\x00\x00" /* settings frame */ | |
495 "\x00\x01\x00\x00\x00\x00" /* header table size */ | |
496 "\x00\x02\x00\x00\x00\x00" /* disable push */ | |
497 "\x00\x04\x7f\xff\xff\xff" /* initial window */ | |
498 | |
499 "\x00\x00\x04\x08\x00\x00\x00\x00\x00" /* window update frame */ | |
500 "\x7f\xff\x00\x00"; | |
501 | |
502 | |
503 static ngx_keyval_t ngx_http_grpc_headers[] = { | |
504 { ngx_string("Content-Length"), ngx_string("$content_length") }, | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
505 { ngx_string("TE"), ngx_string("$grpc_internal_trailers") }, |
7233 | 506 { ngx_string("Host"), ngx_string("") }, |
507 { ngx_string("Connection"), ngx_string("") }, | |
508 { ngx_string("Transfer-Encoding"), ngx_string("") }, | |
509 { ngx_string("Keep-Alive"), ngx_string("") }, | |
510 { ngx_string("Expect"), ngx_string("") }, | |
511 { ngx_string("Upgrade"), ngx_string("") }, | |
512 { ngx_null_string, ngx_null_string } | |
513 }; | |
514 | |
515 | |
516 static ngx_str_t ngx_http_grpc_hide_headers[] = { | |
517 ngx_string("Date"), | |
518 ngx_string("Server"), | |
519 ngx_string("X-Accel-Expires"), | |
520 ngx_string("X-Accel-Redirect"), | |
521 ngx_string("X-Accel-Limit-Rate"), | |
522 ngx_string("X-Accel-Buffering"), | |
523 ngx_string("X-Accel-Charset"), | |
524 ngx_null_string | |
525 }; | |
526 | |
527 | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
528 static ngx_http_variable_t ngx_http_grpc_vars[] = { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
529 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
530 { ngx_string("grpc_internal_trailers"), NULL, |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
531 ngx_http_grpc_internal_trailers_variable, 0, |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
532 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
533 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
534 ngx_http_null_variable |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
535 }; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
536 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
537 |
7233 | 538 static ngx_int_t |
539 ngx_http_grpc_handler(ngx_http_request_t *r) | |
540 { | |
541 ngx_int_t rc; | |
542 ngx_http_upstream_t *u; | |
543 ngx_http_grpc_ctx_t *ctx; | |
544 ngx_http_grpc_loc_conf_t *glcf; | |
545 | |
546 if (ngx_http_upstream_create(r) != NGX_OK) { | |
547 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
548 } | |
549 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
550 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t)); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
551 if (ctx == NULL) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
552 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
553 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
554 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
555 ctx->request = r; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
556 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
557 ngx_http_set_ctx(r, ctx, ngx_http_grpc_module); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
558 |
7233 | 559 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); |
560 | |
561 u = r->upstream; | |
562 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
563 if (glcf->grpc_lengths == NULL) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
564 ctx->host = glcf->host; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
565 |
7233 | 566 #if (NGX_HTTP_SSL) |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
567 u->ssl = (glcf->upstream.ssl != NULL); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
568 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
569 if (u->ssl) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
570 ngx_str_set(&u->schema, "grpcs://"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
571 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
572 } else { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
573 ngx_str_set(&u->schema, "grpc://"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
574 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
575 #else |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
576 ngx_str_set(&u->schema, "grpc://"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
577 #endif |
7233 | 578 |
579 } else { | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
580 if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
581 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
582 } |
7233 | 583 } |
584 | |
585 u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module; | |
586 | |
587 u->conf = &glcf->upstream; | |
588 | |
589 u->create_request = ngx_http_grpc_create_request; | |
590 u->reinit_request = ngx_http_grpc_reinit_request; | |
591 u->process_header = ngx_http_grpc_process_header; | |
592 u->abort_request = ngx_http_grpc_abort_request; | |
593 u->finalize_request = ngx_http_grpc_finalize_request; | |
594 | |
595 u->input_filter_init = ngx_http_grpc_filter_init; | |
596 u->input_filter = ngx_http_grpc_filter; | |
597 u->input_filter_ctx = ctx; | |
598 | |
599 r->request_body_no_buffering = 1; | |
600 | |
601 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); | |
602 | |
603 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | |
604 return rc; | |
605 } | |
606 | |
607 return NGX_DONE; | |
608 } | |
609 | |
610 | |
611 static ngx_int_t | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
612 ngx_http_grpc_eval(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
613 ngx_http_grpc_loc_conf_t *glcf) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
614 { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
615 size_t add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
616 ngx_url_t url; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
617 ngx_http_upstream_t *u; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
618 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
619 ngx_memzero(&url, sizeof(ngx_url_t)); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
620 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
621 if (ngx_http_script_run(r, &url.url, glcf->grpc_lengths->elts, 0, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
622 glcf->grpc_values->elts) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
623 == NULL) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
624 { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
625 return NGX_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
626 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
627 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
628 if (url.url.len > 7 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
629 && ngx_strncasecmp(url.url.data, (u_char *) "grpc://", 7) == 0) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
630 { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
631 add = 7; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
632 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
633 } else if (url.url.len > 8 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
634 && ngx_strncasecmp(url.url.data, (u_char *) "grpcs://", 8) == 0) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
635 { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
636 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
637 #if (NGX_HTTP_SSL) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
638 add = 8; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
639 r->upstream->ssl = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
640 #else |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
641 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
642 "grpcs protocol requires SSL support"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
643 return NGX_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
644 #endif |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
645 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
646 } else { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
647 add = 0; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
648 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
649 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
650 u = r->upstream; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
651 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
652 if (add) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
653 u->schema.len = add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
654 u->schema.data = url.url.data; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
655 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
656 url.url.data += add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
657 url.url.len -= add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
658 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
659 } else { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
660 ngx_str_set(&u->schema, "grpc://"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
661 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
662 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
663 url.no_resolve = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
664 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
665 if (ngx_parse_url(r->pool, &url) != NGX_OK) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
666 if (url.err) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
667 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
668 "%s in upstream \"%V\"", url.err, &url.url); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
669 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
670 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
671 return NGX_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
672 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
673 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
674 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
675 if (u->resolved == NULL) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
676 return NGX_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
677 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
678 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
679 if (url.addrs) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
680 u->resolved->sockaddr = url.addrs[0].sockaddr; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
681 u->resolved->socklen = url.addrs[0].socklen; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
682 u->resolved->name = url.addrs[0].name; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
683 u->resolved->naddrs = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
684 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
685 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
686 u->resolved->host = url.host; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
687 u->resolved->port = url.port; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
688 u->resolved->no_port = url.no_port; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
689 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
690 if (url.family != AF_UNIX) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
691 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
692 if (url.no_port) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
693 ctx->host = url.host; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
694 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
695 } else { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
696 ctx->host.len = url.host.len + 1 + url.port_text.len; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
697 ctx->host.data = url.host.data; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
698 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
699 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
700 } else { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
701 ngx_str_set(&ctx->host, "localhost"); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
702 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
703 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
704 return NGX_OK; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
705 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
706 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
707 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
708 static ngx_int_t |
7233 | 709 ngx_http_grpc_create_request(ngx_http_request_t *r) |
710 { | |
711 u_char *p, *tmp, *key_tmp, *val_tmp, *headers_frame; | |
712 size_t len, tmp_len, key_len, val_len, uri_len; | |
713 uintptr_t escape; | |
714 ngx_buf_t *b; | |
715 ngx_uint_t i, next; | |
716 ngx_chain_t *cl, *body; | |
717 ngx_list_part_t *part; | |
718 ngx_table_elt_t *header; | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
719 ngx_http_grpc_ctx_t *ctx; |
7233 | 720 ngx_http_upstream_t *u; |
721 ngx_http_grpc_frame_t *f; | |
722 ngx_http_script_code_pt code; | |
723 ngx_http_grpc_loc_conf_t *glcf; | |
724 ngx_http_script_engine_t e, le; | |
725 ngx_http_script_len_code_pt lcode; | |
726 | |
727 u = r->upstream; | |
728 | |
729 glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); | |
730 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
731 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
732 |
7233 | 733 len = sizeof(ngx_http_grpc_connection_start) - 1 |
734 + sizeof(ngx_http_grpc_frame_t); /* headers frame */ | |
735 | |
736 /* :method header */ | |
737 | |
738 if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_POST) { | |
739 len += 1; | |
740 tmp_len = 0; | |
741 | |
742 } else { | |
743 len += 1 + NGX_HTTP_V2_INT_OCTETS + r->method_name.len; | |
744 tmp_len = r->method_name.len; | |
745 } | |
746 | |
747 /* :scheme header */ | |
748 | |
749 len += 1; | |
750 | |
751 /* :path header */ | |
752 | |
753 if (r->valid_unparsed_uri) { | |
754 escape = 0; | |
755 uri_len = r->unparsed_uri.len; | |
756 | |
757 } else { | |
758 escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, | |
759 NGX_ESCAPE_URI); | |
760 uri_len = r->uri.len + escape + sizeof("?") - 1 + r->args.len; | |
761 } | |
762 | |
763 len += 1 + NGX_HTTP_V2_INT_OCTETS + uri_len; | |
764 | |
765 if (tmp_len < uri_len) { | |
766 tmp_len = uri_len; | |
767 } | |
768 | |
769 /* :authority header */ | |
770 | |
771 if (!glcf->host_set) { | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
772 len += 1 + NGX_HTTP_V2_INT_OCTETS + ctx->host.len; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
773 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
774 if (tmp_len < ctx->host.len) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
775 tmp_len = ctx->host.len; |
7233 | 776 } |
777 } | |
778 | |
779 /* other headers */ | |
780 | |
781 ngx_http_script_flush_no_cacheable_variables(r, glcf->headers.flushes); | |
782 ngx_memzero(&le, sizeof(ngx_http_script_engine_t)); | |
783 | |
784 le.ip = glcf->headers.lengths->elts; | |
785 le.request = r; | |
786 le.flushed = 1; | |
787 | |
788 while (*(uintptr_t *) le.ip) { | |
789 | |
790 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
791 key_len = lcode(&le); | |
792 | |
793 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { | |
794 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
795 } | |
796 le.ip += sizeof(uintptr_t); | |
797 | |
798 if (val_len == 0) { | |
799 continue; | |
800 } | |
801 | |
802 len += 1 + NGX_HTTP_V2_INT_OCTETS + key_len | |
803 + NGX_HTTP_V2_INT_OCTETS + val_len; | |
804 | |
805 if (tmp_len < key_len) { | |
806 tmp_len = key_len; | |
807 } | |
808 | |
809 if (tmp_len < val_len) { | |
810 tmp_len = val_len; | |
811 } | |
812 } | |
813 | |
814 if (glcf->upstream.pass_request_headers) { | |
815 part = &r->headers_in.headers.part; | |
816 header = part->elts; | |
817 | |
818 for (i = 0; /* void */; i++) { | |
819 | |
820 if (i >= part->nelts) { | |
821 if (part->next == NULL) { | |
822 break; | |
823 } | |
824 | |
825 part = part->next; | |
826 header = part->elts; | |
827 i = 0; | |
828 } | |
829 | |
830 if (ngx_hash_find(&glcf->headers.hash, header[i].hash, | |
831 header[i].lowcase_key, header[i].key.len)) | |
832 { | |
833 continue; | |
834 } | |
835 | |
836 len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len | |
837 + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; | |
838 | |
839 if (tmp_len < header[i].key.len) { | |
840 tmp_len = header[i].key.len; | |
841 } | |
842 | |
843 if (tmp_len < header[i].value.len) { | |
844 tmp_len = header[i].value.len; | |
845 } | |
846 } | |
847 } | |
848 | |
849 /* continuation frames */ | |
850 | |
851 len += sizeof(ngx_http_grpc_frame_t) | |
852 * (len / NGX_HTTP_V2_DEFAULT_FRAME_SIZE); | |
853 | |
854 | |
855 b = ngx_create_temp_buf(r->pool, len); | |
856 if (b == NULL) { | |
857 return NGX_ERROR; | |
858 } | |
859 | |
860 cl = ngx_alloc_chain_link(r->pool); | |
861 if (cl == NULL) { | |
862 return NGX_ERROR; | |
863 } | |
864 | |
865 cl->buf = b; | |
866 cl->next = NULL; | |
867 | |
868 tmp = ngx_palloc(r->pool, tmp_len * 3); | |
869 if (tmp == NULL) { | |
870 return NGX_ERROR; | |
871 } | |
872 | |
873 key_tmp = tmp + tmp_len; | |
874 val_tmp = tmp + 2 * tmp_len; | |
875 | |
876 /* connection preface */ | |
877 | |
878 b->last = ngx_copy(b->last, ngx_http_grpc_connection_start, | |
879 sizeof(ngx_http_grpc_connection_start) - 1); | |
880 | |
881 /* headers frame */ | |
882 | |
883 headers_frame = b->last; | |
884 | |
885 f = (ngx_http_grpc_frame_t *) b->last; | |
886 b->last += sizeof(ngx_http_grpc_frame_t); | |
887 | |
888 f->length_0 = 0; | |
889 f->length_1 = 0; | |
890 f->length_2 = 0; | |
891 f->type = NGX_HTTP_V2_HEADERS_FRAME; | |
892 f->flags = 0; | |
893 f->stream_id_0 = 0; | |
894 f->stream_id_1 = 0; | |
895 f->stream_id_2 = 0; | |
896 f->stream_id_3 = 1; | |
897 | |
898 if (r->method == NGX_HTTP_GET) { | |
899 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX); | |
900 | |
901 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
902 "grpc header: \":method: GET\""); | |
903 | |
904 } else if (r->method == NGX_HTTP_POST) { | |
905 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_POST_INDEX); | |
906 | |
907 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
908 "grpc header: \":method: POST\""); | |
909 | |
910 } else { | |
911 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_METHOD_INDEX); | |
912 b->last = ngx_http_v2_write_value(b->last, r->method_name.data, | |
913 r->method_name.len, tmp); | |
914 | |
915 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
916 "grpc header: \":method: %V\"", &r->method_name); | |
917 } | |
918 | |
919 #if (NGX_HTTP_SSL) | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
920 if (u->ssl) { |
7233 | 921 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); |
922 | |
923 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
924 "grpc header: \":scheme: https\""); | |
925 } else | |
926 #endif | |
927 { | |
928 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); | |
929 | |
930 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
931 "grpc header: \":scheme: http\""); | |
932 } | |
933 | |
934 if (r->valid_unparsed_uri) { | |
935 | |
936 if (r->unparsed_uri.len == 1 && r->unparsed_uri.data[0] == '/') { | |
937 *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_PATH_ROOT_INDEX); | |
938 | |
939 } else { | |
940 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); | |
941 b->last = ngx_http_v2_write_value(b->last, r->unparsed_uri.data, | |
942 r->unparsed_uri.len, tmp); | |
943 } | |
944 | |
945 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
946 "grpc header: \":path: %V\"", &r->unparsed_uri); | |
947 | |
948 } else if (escape || r->args.len > 0) { | |
949 p = val_tmp; | |
950 | |
951 if (escape) { | |
952 p = (u_char *) ngx_escape_uri(p, r->uri.data, r->uri.len, | |
953 NGX_ESCAPE_URI); | |
954 | |
955 } else { | |
956 p = ngx_copy(p, r->uri.data, r->uri.len); | |
957 } | |
958 | |
959 if (r->args.len > 0) { | |
960 *p++ = '?'; | |
961 p = ngx_copy(p, r->args.data, r->args.len); | |
962 } | |
963 | |
964 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); | |
965 b->last = ngx_http_v2_write_value(b->last, val_tmp, p - val_tmp, tmp); | |
966 | |
967 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
968 "grpc header: \":path: %*s\"", p - val_tmp, val_tmp); | |
969 | |
970 } else { | |
971 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); | |
972 b->last = ngx_http_v2_write_value(b->last, r->uri.data, | |
973 r->uri.len, tmp); | |
974 | |
975 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
976 "grpc header: \":path: %V\"", &r->uri); | |
977 } | |
978 | |
979 if (!glcf->host_set) { | |
980 *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
981 b->last = ngx_http_v2_write_value(b->last, ctx->host.data, |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
982 ctx->host.len, tmp); |
7233 | 983 |
984 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
985 "grpc header: \":authority: %V\"", &ctx->host); |
7233 | 986 } |
987 | |
988 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | |
989 | |
990 e.ip = glcf->headers.values->elts; | |
991 e.request = r; | |
992 e.flushed = 1; | |
993 | |
994 le.ip = glcf->headers.lengths->elts; | |
995 | |
996 while (*(uintptr_t *) le.ip) { | |
997 | |
998 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
999 key_len = lcode(&le); | |
1000 | |
1001 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { | |
1002 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
1003 } | |
1004 le.ip += sizeof(uintptr_t); | |
1005 | |
1006 if (val_len == 0) { | |
1007 e.skip = 1; | |
1008 | |
1009 while (*(uintptr_t *) e.ip) { | |
1010 code = *(ngx_http_script_code_pt *) e.ip; | |
1011 code((ngx_http_script_engine_t *) &e); | |
1012 } | |
1013 e.ip += sizeof(uintptr_t); | |
1014 | |
1015 e.skip = 0; | |
1016 | |
1017 continue; | |
1018 } | |
1019 | |
1020 *b->last++ = 0; | |
1021 | |
1022 e.pos = key_tmp; | |
1023 | |
1024 code = *(ngx_http_script_code_pt *) e.ip; | |
1025 code((ngx_http_script_engine_t *) &e); | |
1026 | |
1027 b->last = ngx_http_v2_write_name(b->last, key_tmp, key_len, tmp); | |
1028 | |
1029 e.pos = val_tmp; | |
1030 | |
1031 while (*(uintptr_t *) e.ip) { | |
1032 code = *(ngx_http_script_code_pt *) e.ip; | |
1033 code((ngx_http_script_engine_t *) &e); | |
1034 } | |
1035 e.ip += sizeof(uintptr_t); | |
1036 | |
1037 b->last = ngx_http_v2_write_value(b->last, val_tmp, val_len, tmp); | |
1038 | |
1039 #if (NGX_DEBUG) | |
1040 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { | |
1041 ngx_strlow(key_tmp, key_tmp, key_len); | |
1042 | |
1043 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1044 "grpc header: \"%*s: %*s\"", | |
1045 key_len, key_tmp, val_len, val_tmp); | |
1046 } | |
1047 #endif | |
1048 } | |
1049 | |
1050 if (glcf->upstream.pass_request_headers) { | |
1051 part = &r->headers_in.headers.part; | |
1052 header = part->elts; | |
1053 | |
1054 for (i = 0; /* void */; i++) { | |
1055 | |
1056 if (i >= part->nelts) { | |
1057 if (part->next == NULL) { | |
1058 break; | |
1059 } | |
1060 | |
1061 part = part->next; | |
1062 header = part->elts; | |
1063 i = 0; | |
1064 } | |
1065 | |
1066 if (ngx_hash_find(&glcf->headers.hash, header[i].hash, | |
1067 header[i].lowcase_key, header[i].key.len)) | |
1068 { | |
1069 continue; | |
1070 } | |
1071 | |
1072 *b->last++ = 0; | |
1073 | |
1074 b->last = ngx_http_v2_write_name(b->last, header[i].key.data, | |
1075 header[i].key.len, tmp); | |
1076 | |
1077 b->last = ngx_http_v2_write_value(b->last, header[i].value.data, | |
1078 header[i].value.len, tmp); | |
1079 | |
1080 #if (NGX_DEBUG) | |
1081 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { | |
1082 ngx_strlow(tmp, header[i].key.data, header[i].key.len); | |
1083 | |
1084 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1085 "grpc header: \"%*s: %V\"", | |
1086 header[i].key.len, tmp, &header[i].value); | |
1087 } | |
1088 #endif | |
1089 } | |
1090 } | |
1091 | |
1092 /* update headers frame length */ | |
1093 | |
1094 len = b->last - headers_frame - sizeof(ngx_http_grpc_frame_t); | |
1095 | |
1096 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) { | |
1097 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; | |
1098 next = 1; | |
1099 | |
1100 } else { | |
1101 next = 0; | |
1102 } | |
1103 | |
1104 f = (ngx_http_grpc_frame_t *) headers_frame; | |
1105 | |
1106 f->length_0 = (u_char) ((len >> 16) & 0xff); | |
1107 f->length_1 = (u_char) ((len >> 8) & 0xff); | |
1108 f->length_2 = (u_char) (len & 0xff); | |
1109 | |
1110 /* create additional continuation frames */ | |
1111 | |
1112 p = headers_frame; | |
1113 | |
1114 while (next) { | |
1115 p += sizeof(ngx_http_grpc_frame_t) + NGX_HTTP_V2_DEFAULT_FRAME_SIZE; | |
1116 len = b->last - p; | |
1117 | |
1118 ngx_memmove(p + sizeof(ngx_http_grpc_frame_t), p, len); | |
1119 b->last += sizeof(ngx_http_grpc_frame_t); | |
1120 | |
1121 if (len > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) { | |
1122 len = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; | |
1123 next = 1; | |
1124 | |
1125 } else { | |
1126 next = 0; | |
1127 } | |
1128 | |
1129 f = (ngx_http_grpc_frame_t *) p; | |
1130 | |
1131 f->length_0 = (u_char) ((len >> 16) & 0xff); | |
1132 f->length_1 = (u_char) ((len >> 8) & 0xff); | |
1133 f->length_2 = (u_char) (len & 0xff); | |
1134 f->type = NGX_HTTP_V2_CONTINUATION_FRAME; | |
1135 f->flags = 0; | |
1136 f->stream_id_0 = 0; | |
1137 f->stream_id_1 = 0; | |
1138 f->stream_id_2 = 0; | |
1139 f->stream_id_3 = 1; | |
1140 } | |
1141 | |
1142 f->flags |= NGX_HTTP_V2_END_HEADERS_FLAG; | |
1143 | |
1144 #if (NGX_DEBUG) | |
1145 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { | |
1146 u_char buf[512]; | |
1147 size_t n, m; | |
1148 | |
1149 n = ngx_min(b->last - b->pos, 256); | |
1150 m = ngx_hex_dump(buf, b->pos, n) - buf; | |
1151 | |
1152 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1153 "grpc header: %*s%s, len: %uz", | |
1154 m, buf, b->last - b->pos > 256 ? "..." : "", | |
1155 b->last - b->pos); | |
1156 } | |
1157 #endif | |
1158 | |
1159 if (r->request_body_no_buffering) { | |
1160 | |
1161 u->request_bufs = cl; | |
1162 | |
1163 } else { | |
1164 | |
1165 body = u->request_bufs; | |
1166 u->request_bufs = cl; | |
1167 | |
1168 if (body == NULL) { | |
1169 f = (ngx_http_grpc_frame_t *) headers_frame; | |
1170 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG; | |
1171 } | |
1172 | |
1173 while (body) { | |
1174 b = ngx_alloc_buf(r->pool); | |
1175 if (b == NULL) { | |
1176 return NGX_ERROR; | |
1177 } | |
1178 | |
1179 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); | |
1180 | |
1181 cl->next = ngx_alloc_chain_link(r->pool); | |
1182 if (cl->next == NULL) { | |
1183 return NGX_ERROR; | |
1184 } | |
1185 | |
1186 cl = cl->next; | |
1187 cl->buf = b; | |
1188 | |
1189 body = body->next; | |
1190 } | |
1191 | |
1192 b->last_buf = 1; | |
1193 } | |
1194 | |
1195 u->output.output_filter = ngx_http_grpc_body_output_filter; | |
1196 u->output.filter_ctx = r; | |
1197 | |
1198 b->flush = 1; | |
1199 cl->next = NULL; | |
1200 | |
1201 return NGX_OK; | |
1202 } | |
1203 | |
1204 | |
1205 static ngx_int_t | |
1206 ngx_http_grpc_reinit_request(ngx_http_request_t *r) | |
1207 { | |
1208 ngx_http_grpc_ctx_t *ctx; | |
1209 | |
1210 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); | |
1211 | |
1212 if (ctx == NULL) { | |
1213 return NGX_OK; | |
1214 } | |
1215 | |
1216 ctx->state = 0; | |
1217 ctx->header_sent = 0; | |
1218 ctx->output_closed = 0; | |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1219 ctx->output_blocked = 0; |
7233 | 1220 ctx->parsing_headers = 0; |
1221 ctx->end_stream = 0; | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1222 ctx->done = 0; |
7233 | 1223 ctx->status = 0; |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
1224 ctx->rst = 0; |
7233 | 1225 ctx->connection = NULL; |
1226 | |
1227 return NGX_OK; | |
1228 } | |
1229 | |
1230 | |
1231 static ngx_int_t | |
1232 ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) | |
1233 { | |
1234 ngx_http_request_t *r = data; | |
1235 | |
1236 off_t file_pos; | |
1237 u_char *p, *pos, *start; | |
1238 size_t len, limit; | |
1239 ngx_buf_t *b; | |
1240 ngx_int_t rc; | |
1241 ngx_uint_t next, last; | |
1242 ngx_chain_t *cl, *out, **ll; | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1243 ngx_http_upstream_t *u; |
7233 | 1244 ngx_http_grpc_ctx_t *ctx; |
1245 ngx_http_grpc_frame_t *f; | |
1246 | |
1247 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1248 "grpc output filter"); | |
1249 | |
1250 ctx = ngx_http_grpc_get_ctx(r); | |
1251 | |
1252 if (ctx == NULL) { | |
1253 return NGX_ERROR; | |
1254 } | |
1255 | |
1256 if (in) { | |
1257 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { | |
1258 return NGX_ERROR; | |
1259 } | |
1260 } | |
1261 | |
1262 out = NULL; | |
1263 ll = &out; | |
1264 | |
1265 if (!ctx->header_sent) { | |
1266 /* first buffer contains headers */ | |
1267 | |
1268 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1269 "grpc output header"); | |
1270 | |
1271 ctx->header_sent = 1; | |
1272 | |
1273 if (ctx->id != 1) { | |
1274 /* | |
1275 * keepalive connection: skip connection preface, | |
1276 * update stream identifiers | |
1277 */ | |
1278 | |
1279 b = ctx->in->buf; | |
1280 b->pos += sizeof(ngx_http_grpc_connection_start) - 1; | |
1281 | |
1282 p = b->pos; | |
1283 | |
1284 while (p < b->last) { | |
1285 f = (ngx_http_grpc_frame_t *) p; | |
1286 p += sizeof(ngx_http_grpc_frame_t); | |
1287 | |
1288 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1289 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1290 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1291 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1292 | |
1293 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2; | |
1294 } | |
1295 } | |
1296 | |
1297 if (ctx->in->buf->last_buf) { | |
1298 ctx->output_closed = 1; | |
1299 } | |
1300 | |
1301 *ll = ctx->in; | |
1302 ll = &ctx->in->next; | |
1303 | |
1304 ctx->in = ctx->in->next; | |
1305 } | |
1306 | |
1307 if (ctx->out) { | |
1308 /* queued control frames */ | |
1309 | |
1310 *ll = ctx->out; | |
1311 | |
1312 for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) { | |
1313 ll = &cl->next; | |
1314 } | |
1315 | |
1316 ctx->out = NULL; | |
1317 } | |
1318 | |
1319 f = NULL; | |
1320 last = 0; | |
1321 | |
1322 limit = ngx_max(0, ctx->send_window); | |
1323 | |
1324 if (limit > ctx->connection->send_window) { | |
1325 limit = ctx->connection->send_window; | |
1326 } | |
1327 | |
1328 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1329 "grpc output limit: %uz w:%z:%uz", | |
1330 limit, ctx->send_window, ctx->connection->send_window); | |
1331 | |
1332 #if (NGX_SUPPRESS_WARN) | |
1333 file_pos = 0; | |
1334 pos = NULL; | |
1335 cl = NULL; | |
1336 #endif | |
1337 | |
1338 in = ctx->in; | |
1339 | |
1340 while (in && limit > 0) { | |
1341 | |
1342 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, | |
1343 "grpc output in l:%d f:%d %p, pos %p, size: %z " | |
1344 "file: %O, size: %O", | |
1345 in->buf->last_buf, | |
1346 in->buf->in_file, | |
1347 in->buf->start, in->buf->pos, | |
1348 in->buf->last - in->buf->pos, | |
1349 in->buf->file_pos, | |
1350 in->buf->file_last - in->buf->file_pos); | |
1351 | |
1352 if (ngx_buf_special(in->buf)) { | |
1353 goto next; | |
1354 } | |
1355 | |
1356 if (in->buf->in_file) { | |
1357 file_pos = in->buf->file_pos; | |
1358 | |
1359 } else { | |
1360 pos = in->buf->pos; | |
1361 } | |
1362 | |
1363 next = 0; | |
1364 | |
1365 do { | |
1366 | |
1367 cl = ngx_http_grpc_get_buf(r, ctx); | |
1368 if (cl == NULL) { | |
1369 return NGX_ERROR; | |
1370 } | |
1371 | |
1372 b = cl->buf; | |
1373 | |
1374 f = (ngx_http_grpc_frame_t *) b->last; | |
1375 b->last += sizeof(ngx_http_grpc_frame_t); | |
1376 | |
1377 *ll = cl; | |
1378 ll = &cl->next; | |
1379 | |
1380 cl = ngx_chain_get_free_buf(r->pool, &ctx->free); | |
1381 if (cl == NULL) { | |
1382 return NGX_ERROR; | |
1383 } | |
1384 | |
1385 b = cl->buf; | |
1386 start = b->start; | |
1387 | |
1388 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t)); | |
1389 | |
1390 /* | |
1391 * restore b->start to preserve memory allocated in the buffer, | |
1392 * to reuse it later for headers and control frames | |
1393 */ | |
1394 | |
1395 b->start = start; | |
1396 | |
1397 if (in->buf->in_file) { | |
1398 b->file_pos = file_pos; | |
1399 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit); | |
1400 | |
1401 if (file_pos >= in->buf->file_last) { | |
1402 file_pos = in->buf->file_last; | |
1403 next = 1; | |
1404 } | |
1405 | |
1406 b->file_last = file_pos; | |
1407 len = (ngx_uint_t) (file_pos - b->file_pos); | |
1408 | |
1409 } else { | |
1410 b->pos = pos; | |
1411 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit); | |
1412 | |
1413 if (pos >= in->buf->last) { | |
1414 pos = in->buf->last; | |
1415 next = 1; | |
1416 } | |
1417 | |
1418 b->last = pos; | |
1419 len = (ngx_uint_t) (pos - b->pos); | |
1420 } | |
1421 | |
1422 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter; | |
1423 b->shadow = in->buf; | |
1424 b->last_shadow = next; | |
1425 | |
1426 b->last_buf = 0; | |
1427 b->last_in_chain = 0; | |
1428 | |
1429 *ll = cl; | |
1430 ll = &cl->next; | |
1431 | |
1432 f->length_0 = (u_char) ((len >> 16) & 0xff); | |
1433 f->length_1 = (u_char) ((len >> 8) & 0xff); | |
1434 f->length_2 = (u_char) (len & 0xff); | |
1435 f->type = NGX_HTTP_V2_DATA_FRAME; | |
1436 f->flags = 0; | |
1437 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1438 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1439 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1440 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1441 | |
1442 limit -= len; | |
1443 ctx->send_window -= len; | |
1444 ctx->connection->send_window -= len; | |
1445 | |
1446 } while (!next && limit > 0); | |
1447 | |
1448 if (!next) { | |
1449 /* | |
1450 * if the buffer wasn't fully sent due to flow control limits, | |
1451 * preserve position for future use | |
1452 */ | |
1453 | |
1454 if (in->buf->in_file) { | |
1455 in->buf->file_pos = file_pos; | |
1456 | |
1457 } else { | |
1458 in->buf->pos = pos; | |
1459 } | |
1460 | |
1461 break; | |
1462 } | |
1463 | |
1464 next: | |
1465 | |
1466 if (in->buf->last_buf) { | |
1467 last = 1; | |
1468 } | |
1469 | |
1470 in = in->next; | |
1471 } | |
1472 | |
1473 ctx->in = in; | |
1474 | |
1475 if (last) { | |
1476 | |
1477 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1478 "grpc output last"); | |
1479 | |
1480 ctx->output_closed = 1; | |
1481 | |
1482 if (f) { | |
1483 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG; | |
1484 | |
1485 } else { | |
1486 cl = ngx_http_grpc_get_buf(r, ctx); | |
1487 if (cl == NULL) { | |
1488 return NGX_ERROR; | |
1489 } | |
1490 | |
1491 b = cl->buf; | |
1492 | |
1493 f = (ngx_http_grpc_frame_t *) b->last; | |
1494 b->last += sizeof(ngx_http_grpc_frame_t); | |
1495 | |
1496 f->length_0 = 0; | |
1497 f->length_1 = 0; | |
1498 f->length_2 = 0; | |
1499 f->type = NGX_HTTP_V2_DATA_FRAME; | |
1500 f->flags = NGX_HTTP_V2_END_STREAM_FLAG; | |
1501 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1502 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1503 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1504 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1505 | |
1506 *ll = cl; | |
1507 ll = &cl->next; | |
1508 } | |
1509 | |
1510 cl->buf->last_buf = 1; | |
1511 } | |
1512 | |
1513 *ll = NULL; | |
1514 | |
1515 #if (NGX_DEBUG) | |
1516 | |
1517 for (cl = out; cl; cl = cl->next) { | |
1518 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, | |
1519 "grpc output out l:%d f:%d %p, pos %p, size: %z " | |
1520 "file: %O, size: %O", | |
1521 cl->buf->last_buf, | |
1522 cl->buf->in_file, | |
1523 cl->buf->start, cl->buf->pos, | |
1524 cl->buf->last - cl->buf->pos, | |
1525 cl->buf->file_pos, | |
1526 cl->buf->file_last - cl->buf->file_pos); | |
1527 } | |
1528 | |
1529 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1530 "grpc output limit: %uz w:%z:%uz", | |
1531 limit, ctx->send_window, ctx->connection->send_window); | |
1532 | |
1533 #endif | |
1534 | |
1535 rc = ngx_chain_writer(&r->upstream->writer, out); | |
1536 | |
1537 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, | |
1538 (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter); | |
1539 | |
1540 for (cl = ctx->free; cl; cl = cl->next) { | |
1541 | |
1542 /* mark original buffers as sent */ | |
1543 | |
1544 if (cl->buf->shadow) { | |
1545 if (cl->buf->last_shadow) { | |
1546 b = cl->buf->shadow; | |
1547 b->pos = b->last; | |
1548 } | |
1549 | |
1550 cl->buf->shadow = NULL; | |
1551 } | |
1552 } | |
1553 | |
1554 if (rc == NGX_OK && ctx->in) { | |
1555 rc = NGX_AGAIN; | |
1556 } | |
1557 | |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1558 if (rc == NGX_AGAIN) { |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1559 ctx->output_blocked = 1; |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1560 |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1561 } else { |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1562 ctx->output_blocked = 0; |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1563 } |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1564 |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1565 if (ctx->done) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1566 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1567 /* |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1568 * We have already got the response and were sending some additional |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1569 * control frames. Even if there is still something unsent, stop |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1570 * here anyway. |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1571 */ |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1572 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1573 u = r->upstream; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1574 u->length = 0; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1575 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1576 if (ctx->in == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1577 && ctx->out == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1578 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1579 && !ctx->output_blocked |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1580 && ctx->state == ngx_http_grpc_st_start) |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1581 { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1582 u->keepalive = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1583 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1584 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1585 ngx_post_event(u->peer.connection->read, &ngx_posted_events); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1586 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1587 |
7233 | 1588 return rc; |
1589 } | |
1590 | |
1591 | |
1592 static ngx_int_t | |
1593 ngx_http_grpc_process_header(ngx_http_request_t *r) | |
1594 { | |
1595 ngx_str_t *status_line; | |
1596 ngx_int_t rc, status; | |
1597 ngx_buf_t *b; | |
1598 ngx_table_elt_t *h; | |
1599 ngx_http_upstream_t *u; | |
1600 ngx_http_grpc_ctx_t *ctx; | |
1601 ngx_http_upstream_header_t *hh; | |
1602 ngx_http_upstream_main_conf_t *umcf; | |
1603 | |
1604 u = r->upstream; | |
1605 b = &u->buffer; | |
1606 | |
1607 #if (NGX_DEBUG) | |
1608 if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { | |
1609 u_char buf[512]; | |
1610 size_t n, m; | |
1611 | |
1612 n = ngx_min(b->last - b->pos, 256); | |
1613 m = ngx_hex_dump(buf, b->pos, n) - buf; | |
1614 | |
1615 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1616 "grpc response: %*s%s, len: %uz", | |
1617 m, buf, b->last - b->pos > 256 ? "..." : "", | |
1618 b->last - b->pos); | |
1619 } | |
1620 #endif | |
1621 | |
1622 ctx = ngx_http_grpc_get_ctx(r); | |
1623 | |
1624 if (ctx == NULL) { | |
1625 return NGX_ERROR; | |
1626 } | |
1627 | |
1628 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); | |
1629 | |
1630 for ( ;; ) { | |
1631 | |
1632 if (ctx->state < ngx_http_grpc_st_payload) { | |
1633 | |
1634 rc = ngx_http_grpc_parse_frame(r, ctx, b); | |
1635 | |
1636 if (rc == NGX_AGAIN) { | |
1637 | |
1638 /* | |
1639 * there can be a lot of window update frames, | |
1640 * so we reset buffer if it is empty and we haven't | |
1641 * started parsing headers yet | |
1642 */ | |
1643 | |
1644 if (!ctx->parsing_headers) { | |
1645 b->pos = b->start; | |
1646 b->last = b->pos; | |
1647 } | |
1648 | |
1649 return NGX_AGAIN; | |
1650 } | |
1651 | |
1652 if (rc == NGX_ERROR) { | |
1653 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1654 } | |
1655 | |
1656 /* | |
1657 * RFC 7540 says that implementations MUST discard frames | |
1658 * that have unknown or unsupported types. However, extension | |
1659 * frames that appear in the middle of a header block are | |
1660 * not permitted. Also, for obvious reasons CONTINUATION frames | |
1661 * cannot appear before headers, and DATA frames are not expected | |
1662 * to appear before all headers are parsed. | |
1663 */ | |
1664 | |
1665 if (ctx->type == NGX_HTTP_V2_DATA_FRAME | |
1666 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME | |
1667 && !ctx->parsing_headers) | |
1668 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME | |
1669 && ctx->parsing_headers)) | |
1670 { | |
1671 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1672 "upstream sent unexpected http2 frame: %d", | |
1673 ctx->type); | |
1674 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1675 } | |
1676 | |
1677 if (ctx->stream_id && ctx->stream_id != ctx->id) { | |
1678 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1679 "upstream sent frame for unknown stream %ui", | |
1680 ctx->stream_id); | |
1681 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1682 } | |
1683 } | |
1684 | |
1685 /* frame payload */ | |
1686 | |
1687 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) { | |
1688 | |
1689 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b); | |
1690 | |
1691 if (rc == NGX_AGAIN) { | |
1692 return NGX_AGAIN; | |
1693 } | |
1694 | |
1695 if (rc == NGX_ERROR) { | |
1696 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1697 } | |
1698 | |
1699 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1700 "upstream rejected request with error %ui", | |
1701 ctx->error); | |
1702 | |
1703 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1704 } | |
1705 | |
1706 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { | |
1707 | |
1708 rc = ngx_http_grpc_parse_goaway(r, ctx, b); | |
1709 | |
1710 if (rc == NGX_AGAIN) { | |
1711 return NGX_AGAIN; | |
1712 } | |
1713 | |
1714 if (rc == NGX_ERROR) { | |
1715 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1716 } | |
1717 | |
1718 /* | |
1719 * If stream_id is lower than one we use, our | |
1720 * request won't be processed and needs to be retried. | |
1721 * If stream_id is greater or equal to the one we use, | |
1722 * we can continue normally (except we can't use this | |
1723 * connection for additional requests). If there is | |
1724 * a real error, the connection will be closed. | |
1725 */ | |
1726 | |
1727 if (ctx->stream_id < ctx->id) { | |
1728 | |
1729 /* TODO: we can retry non-idempotent requests */ | |
1730 | |
1731 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1732 "upstream sent goaway with error %ui", | |
1733 ctx->error); | |
1734 | |
1735 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1736 } | |
1737 | |
1738 continue; | |
1739 } | |
1740 | |
1741 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) { | |
1742 | |
1743 rc = ngx_http_grpc_parse_window_update(r, ctx, b); | |
1744 | |
1745 if (rc == NGX_AGAIN) { | |
1746 return NGX_AGAIN; | |
1747 } | |
1748 | |
1749 if (rc == NGX_ERROR) { | |
1750 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1751 } | |
1752 | |
1753 if (ctx->in) { | |
1754 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1755 } | |
1756 | |
1757 continue; | |
1758 } | |
1759 | |
1760 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) { | |
1761 | |
1762 rc = ngx_http_grpc_parse_settings(r, ctx, b); | |
1763 | |
1764 if (rc == NGX_AGAIN) { | |
1765 return NGX_AGAIN; | |
1766 } | |
1767 | |
1768 if (rc == NGX_ERROR) { | |
1769 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1770 } | |
1771 | |
1772 if (ctx->in) { | |
1773 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1774 } | |
1775 | |
1776 continue; | |
1777 } | |
1778 | |
1779 if (ctx->type == NGX_HTTP_V2_PING_FRAME) { | |
1780 | |
1781 rc = ngx_http_grpc_parse_ping(r, ctx, b); | |
1782 | |
1783 if (rc == NGX_AGAIN) { | |
1784 return NGX_AGAIN; | |
1785 } | |
1786 | |
1787 if (rc == NGX_ERROR) { | |
1788 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1789 } | |
1790 | |
1791 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1792 continue; | |
1793 } | |
1794 | |
1795 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { | |
1796 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1797 "upstream sent unexpected push promise frame"); | |
1798 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1799 } | |
1800 | |
1801 if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME | |
1802 && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME) | |
1803 { | |
1804 /* priority, unknown frames */ | |
1805 | |
1806 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
1807 ctx->rest -= b->last - b->pos; | |
1808 b->pos = b->last; | |
1809 return NGX_AGAIN; | |
1810 } | |
1811 | |
1812 b->pos += ctx->rest; | |
1813 ctx->rest = 0; | |
1814 ctx->state = ngx_http_grpc_st_start; | |
1815 | |
1816 continue; | |
1817 } | |
1818 | |
1819 /* headers */ | |
1820 | |
1821 for ( ;; ) { | |
1822 | |
1823 rc = ngx_http_grpc_parse_header(r, ctx, b); | |
1824 | |
1825 if (rc == NGX_AGAIN) { | |
1826 break; | |
1827 } | |
1828 | |
1829 if (rc == NGX_OK) { | |
1830 | |
1831 /* a header line has been parsed successfully */ | |
1832 | |
1833 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1834 "grpc header: \"%V: %V\"", | |
1835 &ctx->name, &ctx->value); | |
1836 | |
1837 if (ctx->name.len && ctx->name.data[0] == ':') { | |
1838 | |
1839 if (ctx->name.len != sizeof(":status") - 1 | |
1840 || ngx_strncmp(ctx->name.data, ":status", | |
1841 sizeof(":status") - 1) | |
1842 != 0) | |
1843 { | |
1844 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1845 "upstream sent invalid header \"%V: %V\"", | |
1846 &ctx->name, &ctx->value); | |
1847 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1848 } | |
1849 | |
1850 if (ctx->status) { | |
1851 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1852 "upstream sent duplicate :status header"); | |
1853 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1854 } | |
1855 | |
1856 status_line = &ctx->value; | |
1857 | |
1858 if (status_line->len != 3) { | |
1859 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1860 "upstream sent invalid :status \"%V\"", | |
1861 status_line); | |
1862 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1863 } | |
1864 | |
1865 status = ngx_atoi(status_line->data, 3); | |
1866 | |
1867 if (status == NGX_ERROR) { | |
1868 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1869 "upstream sent invalid :status \"%V\"", | |
1870 status_line); | |
1871 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1872 } | |
1873 | |
1874 if (status < NGX_HTTP_OK) { | |
1875 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1876 "upstream sent unexpected :status \"%V\"", | |
1877 status_line); | |
1878 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1879 } | |
1880 | |
1881 u->headers_in.status_n = status; | |
1882 | |
1883 if (u->state && u->state->status == 0) { | |
1884 u->state->status = status; | |
1885 } | |
1886 | |
1887 ctx->status = 1; | |
1888 | |
1889 continue; | |
1890 | |
1891 } else if (!ctx->status) { | |
1892 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1893 "upstream sent no :status header"); | |
1894 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1895 } | |
1896 | |
1897 h = ngx_list_push(&u->headers_in.headers); | |
1898 if (h == NULL) { | |
1899 return NGX_ERROR; | |
1900 } | |
1901 | |
1902 h->key = ctx->name; | |
1903 h->value = ctx->value; | |
1904 h->lowcase_key = h->key.data; | |
1905 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
1906 | |
1907 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, | |
1908 h->lowcase_key, h->key.len); | |
1909 | |
1910 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { | |
1911 return NGX_ERROR; | |
1912 } | |
1913 | |
1914 continue; | |
1915 } | |
1916 | |
1917 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
1918 | |
1919 /* a whole header has been parsed successfully */ | |
1920 | |
1921 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1922 "grpc header done"); | |
1923 | |
7235
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1924 if (ctx->end_stream) { |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1925 u->headers_in.content_length_n = 0; |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1926 |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1927 if (ctx->in == NULL |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1928 && ctx->out == NULL |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1929 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1930 && !ctx->output_blocked |
7235
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1931 && b->last == b->pos) |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1932 { |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1933 u->keepalive = 1; |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1934 } |
7233 | 1935 } |
1936 | |
1937 return NGX_OK; | |
1938 } | |
1939 | |
1940 /* there was error while a header line parsing */ | |
1941 | |
1942 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1943 "upstream sent invalid header"); | |
1944 | |
1945 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1946 } | |
1947 | |
1948 /* rc == NGX_AGAIN */ | |
1949 | |
1950 if (ctx->rest == 0) { | |
1951 ctx->state = ngx_http_grpc_st_start; | |
1952 continue; | |
1953 } | |
1954 | |
1955 return NGX_AGAIN; | |
1956 } | |
1957 } | |
1958 | |
1959 | |
1960 static ngx_int_t | |
1961 ngx_http_grpc_filter_init(void *data) | |
1962 { | |
1963 ngx_http_grpc_ctx_t *ctx = data; | |
1964 | |
1965 ngx_http_request_t *r; | |
1966 ngx_http_upstream_t *u; | |
1967 | |
1968 r = ctx->request; | |
1969 u = r->upstream; | |
1970 | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1971 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1972 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1973 || r->method == NGX_HTTP_HEAD) |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1974 { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1975 ctx->length = 0; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1976 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1977 } else { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1978 ctx->length = u->headers_in.content_length_n; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1979 } |
7233 | 1980 |
1981 if (ctx->end_stream) { | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1982 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1983 if (ctx->length > 0) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1984 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1985 "upstream prematurely closed stream"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1986 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1987 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1988 |
7233 | 1989 u->length = 0; |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1990 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1991 } else { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1992 u->length = 1; |
7233 | 1993 } |
1994 | |
1995 return NGX_OK; | |
1996 } | |
1997 | |
1998 | |
1999 static ngx_int_t | |
2000 ngx_http_grpc_filter(void *data, ssize_t bytes) | |
2001 { | |
2002 ngx_http_grpc_ctx_t *ctx = data; | |
2003 | |
2004 ngx_int_t rc; | |
2005 ngx_buf_t *b, *buf; | |
2006 ngx_chain_t *cl, **ll; | |
2007 ngx_table_elt_t *h; | |
2008 ngx_http_request_t *r; | |
2009 ngx_http_upstream_t *u; | |
2010 | |
2011 r = ctx->request; | |
2012 u = r->upstream; | |
2013 b = &u->buffer; | |
2014 | |
2015 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2016 "grpc filter bytes:%z", bytes); | |
2017 | |
2018 b->pos = b->last; | |
2019 b->last += bytes; | |
2020 | |
2021 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { | |
2022 ll = &cl->next; | |
2023 } | |
2024 | |
2025 for ( ;; ) { | |
2026 | |
2027 if (ctx->state < ngx_http_grpc_st_payload) { | |
2028 | |
2029 rc = ngx_http_grpc_parse_frame(r, ctx, b); | |
2030 | |
2031 if (rc == NGX_AGAIN) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2032 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2033 if (ctx->done) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2034 |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2035 if (ctx->length > 0) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2036 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2037 "upstream prematurely closed stream"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2038 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2039 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2040 |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2041 /* |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2042 * We have finished parsing the response and the |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2043 * remaining control frames. If there are unsent |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2044 * control frames, post a write event to send them. |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2045 */ |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2046 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2047 if (ctx->out) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2048 ngx_post_event(u->peer.connection->write, |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2049 &ngx_posted_events); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2050 return NGX_AGAIN; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2051 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2052 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2053 u->length = 0; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2054 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2055 if (ctx->in == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2056 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
2057 && !ctx->output_blocked |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2058 && ctx->state == ngx_http_grpc_st_start) |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2059 { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2060 u->keepalive = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2061 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2062 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2063 break; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2064 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2065 |
7233 | 2066 return NGX_AGAIN; |
2067 } | |
2068 | |
2069 if (rc == NGX_ERROR) { | |
2070 return NGX_ERROR; | |
2071 } | |
2072 | |
2073 if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME | |
2074 && !ctx->parsing_headers) | |
2075 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME | |
2076 && ctx->parsing_headers)) | |
2077 { | |
2078 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2079 "upstream sent unexpected http2 frame: %d", | |
2080 ctx->type); | |
2081 return NGX_ERROR; | |
2082 } | |
2083 | |
2084 if (ctx->type == NGX_HTTP_V2_DATA_FRAME) { | |
2085 | |
2086 if (ctx->stream_id != ctx->id) { | |
2087 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2088 "upstream sent data frame " | |
2089 "for unknown stream %ui", | |
2090 ctx->stream_id); | |
2091 return NGX_ERROR; | |
2092 } | |
2093 | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2094 if (ctx->length != -1) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2095 if ((off_t) ctx->rest > ctx->length) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2096 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2097 "upstream sent response body larger " |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2098 "than indicated content length"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2099 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2100 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2101 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2102 ctx->length -= ctx->rest; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2103 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2104 |
7233 | 2105 if (ctx->rest > ctx->recv_window) { |
2106 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2107 "upstream violated stream flow control, " | |
2108 "received %uz data frame with window %uz", | |
2109 ctx->rest, ctx->recv_window); | |
2110 return NGX_ERROR; | |
2111 } | |
2112 | |
2113 if (ctx->rest > ctx->connection->recv_window) { | |
2114 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2115 "upstream violated connection flow control, " | |
2116 "received %uz data frame with window %uz", | |
2117 ctx->rest, ctx->connection->recv_window); | |
2118 return NGX_ERROR; | |
2119 } | |
2120 | |
2121 ctx->recv_window -= ctx->rest; | |
2122 ctx->connection->recv_window -= ctx->rest; | |
2123 | |
2124 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4 | |
2125 || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) | |
2126 { | |
2127 if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) { | |
2128 return NGX_ERROR; | |
2129 } | |
2130 | |
2131 ngx_post_event(u->peer.connection->write, | |
2132 &ngx_posted_events); | |
2133 } | |
2134 } | |
2135 | |
2136 if (ctx->stream_id && ctx->stream_id != ctx->id) { | |
2137 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2138 "upstream sent frame for unknown stream %ui", | |
2139 ctx->stream_id); | |
2140 return NGX_ERROR; | |
2141 } | |
2142 | |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2143 if (ctx->stream_id && ctx->done |
7647
716eddd74bc2
gRPC: WINDOW_UPDATE after END_STREAM handling (ticket #1797).
Ruslan Ermilov <ru@nginx.com>
parents:
7646
diff
changeset
|
2144 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME |
716eddd74bc2
gRPC: WINDOW_UPDATE after END_STREAM handling (ticket #1797).
Ruslan Ermilov <ru@nginx.com>
parents:
7646
diff
changeset
|
2145 && ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME) |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2146 { |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2147 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2148 "upstream sent frame for closed stream %ui", |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2149 ctx->stream_id); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2150 return NGX_ERROR; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2151 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2152 |
7233 | 2153 ctx->padding = 0; |
2154 } | |
2155 | |
2156 if (ctx->state == ngx_http_grpc_st_padding) { | |
2157 | |
2158 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2159 ctx->rest -= b->last - b->pos; | |
2160 b->pos = b->last; | |
2161 return NGX_AGAIN; | |
2162 } | |
2163 | |
2164 b->pos += ctx->rest; | |
2165 ctx->rest = 0; | |
2166 ctx->state = ngx_http_grpc_st_start; | |
2167 | |
2168 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2169 ctx->done = 1; |
7233 | 2170 } |
2171 | |
2172 continue; | |
2173 } | |
2174 | |
2175 /* frame payload */ | |
2176 | |
2177 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) { | |
2178 | |
2179 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b); | |
2180 | |
2181 if (rc == NGX_AGAIN) { | |
2182 return NGX_AGAIN; | |
2183 } | |
2184 | |
2185 if (rc == NGX_ERROR) { | |
2186 return NGX_ERROR; | |
2187 } | |
2188 | |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2189 if (ctx->error || !ctx->done) { |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2190 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2191 "upstream rejected request with error %ui", |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2192 ctx->error); |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2193 return NGX_ERROR; |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2194 } |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2195 |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2196 if (ctx->rst) { |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2197 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2198 "upstream sent frame for closed stream %ui", |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2199 ctx->stream_id); |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2200 return NGX_ERROR; |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2201 } |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2202 |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2203 ctx->rst = 1; |
7233 | 2204 } |
2205 | |
2206 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { | |
2207 | |
2208 rc = ngx_http_grpc_parse_goaway(r, ctx, b); | |
2209 | |
2210 if (rc == NGX_AGAIN) { | |
2211 return NGX_AGAIN; | |
2212 } | |
2213 | |
2214 if (rc == NGX_ERROR) { | |
2215 return NGX_ERROR; | |
2216 } | |
2217 | |
2218 /* | |
2219 * If stream_id is lower than one we use, our | |
2220 * request won't be processed and needs to be retried. | |
2221 * If stream_id is greater or equal to the one we use, | |
2222 * we can continue normally (except we can't use this | |
2223 * connection for additional requests). If there is | |
2224 * a real error, the connection will be closed. | |
2225 */ | |
2226 | |
2227 if (ctx->stream_id < ctx->id) { | |
2228 | |
2229 /* TODO: we can retry non-idempotent requests */ | |
2230 | |
2231 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2232 "upstream sent goaway with error %ui", | |
2233 ctx->error); | |
2234 | |
2235 return NGX_ERROR; | |
2236 } | |
2237 | |
2238 continue; | |
2239 } | |
2240 | |
2241 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) { | |
2242 | |
2243 rc = ngx_http_grpc_parse_window_update(r, ctx, b); | |
2244 | |
2245 if (rc == NGX_AGAIN) { | |
2246 return NGX_AGAIN; | |
2247 } | |
2248 | |
2249 if (rc == NGX_ERROR) { | |
2250 return NGX_ERROR; | |
2251 } | |
2252 | |
2253 if (ctx->in) { | |
2254 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2255 } | |
2256 | |
2257 continue; | |
2258 } | |
2259 | |
2260 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) { | |
2261 | |
2262 rc = ngx_http_grpc_parse_settings(r, ctx, b); | |
2263 | |
2264 if (rc == NGX_AGAIN) { | |
2265 return NGX_AGAIN; | |
2266 } | |
2267 | |
2268 if (rc == NGX_ERROR) { | |
2269 return NGX_ERROR; | |
2270 } | |
2271 | |
2272 if (ctx->in) { | |
2273 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2274 } | |
2275 | |
2276 continue; | |
2277 } | |
2278 | |
2279 if (ctx->type == NGX_HTTP_V2_PING_FRAME) { | |
2280 | |
2281 rc = ngx_http_grpc_parse_ping(r, ctx, b); | |
2282 | |
2283 if (rc == NGX_AGAIN) { | |
2284 return NGX_AGAIN; | |
2285 } | |
2286 | |
2287 if (rc == NGX_ERROR) { | |
2288 return NGX_ERROR; | |
2289 } | |
2290 | |
2291 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2292 continue; | |
2293 } | |
2294 | |
2295 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { | |
2296 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2297 "upstream sent unexpected push promise frame"); | |
2298 return NGX_ERROR; | |
2299 } | |
2300 | |
2301 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME | |
2302 || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) | |
2303 { | |
2304 for ( ;; ) { | |
2305 | |
2306 rc = ngx_http_grpc_parse_header(r, ctx, b); | |
2307 | |
2308 if (rc == NGX_AGAIN) { | |
2309 break; | |
2310 } | |
2311 | |
2312 if (rc == NGX_OK) { | |
2313 | |
2314 /* a header line has been parsed successfully */ | |
2315 | |
2316 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2317 "grpc trailer: \"%V: %V\"", | |
2318 &ctx->name, &ctx->value); | |
2319 | |
2320 if (ctx->name.len && ctx->name.data[0] == ':') { | |
2321 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2322 "upstream sent invalid " | |
2323 "trailer \"%V: %V\"", | |
2324 &ctx->name, &ctx->value); | |
2325 return NGX_ERROR; | |
2326 } | |
2327 | |
2328 h = ngx_list_push(&u->headers_in.trailers); | |
2329 if (h == NULL) { | |
2330 return NGX_ERROR; | |
2331 } | |
2332 | |
2333 h->key = ctx->name; | |
2334 h->value = ctx->value; | |
2335 h->lowcase_key = h->key.data; | |
2336 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
2337 | |
2338 continue; | |
2339 } | |
2340 | |
2341 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
2342 | |
2343 /* a whole header has been parsed successfully */ | |
2344 | |
2345 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2346 "grpc trailer done"); | |
2347 | |
2348 if (ctx->end_stream) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2349 ctx->done = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2350 break; |
7233 | 2351 } |
2352 | |
2353 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2354 "upstream sent trailer without " | |
2355 "end stream flag"); | |
2356 return NGX_ERROR; | |
2357 } | |
2358 | |
2359 /* there was error while a header line parsing */ | |
2360 | |
2361 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2362 "upstream sent invalid trailer"); | |
2363 | |
2364 return NGX_ERROR; | |
2365 } | |
2366 | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2367 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2368 continue; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2369 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2370 |
7233 | 2371 /* rc == NGX_AGAIN */ |
2372 | |
2373 if (ctx->rest == 0) { | |
2374 ctx->state = ngx_http_grpc_st_start; | |
2375 continue; | |
2376 } | |
2377 | |
2378 return NGX_AGAIN; | |
2379 } | |
2380 | |
2381 if (ctx->type != NGX_HTTP_V2_DATA_FRAME) { | |
2382 | |
2383 /* priority, unknown frames */ | |
2384 | |
2385 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2386 ctx->rest -= b->last - b->pos; | |
2387 b->pos = b->last; | |
2388 return NGX_AGAIN; | |
2389 } | |
2390 | |
2391 b->pos += ctx->rest; | |
2392 ctx->rest = 0; | |
2393 ctx->state = ngx_http_grpc_st_start; | |
2394 | |
2395 continue; | |
2396 } | |
2397 | |
2398 /* | |
2399 * data frame: | |
2400 * | |
2401 * +---------------+ | |
2402 * |Pad Length? (8)| | |
2403 * +---------------+-----------------------------------------------+ | |
2404 * | Data (*) ... | |
2405 * +---------------------------------------------------------------+ | |
2406 * | Padding (*) ... | |
2407 * +---------------------------------------------------------------+ | |
2408 */ | |
2409 | |
2410 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) { | |
2411 | |
2412 if (ctx->rest == 0) { | |
2413 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2414 "upstream sent too short http2 frame"); | |
2415 return NGX_ERROR; | |
2416 } | |
2417 | |
2418 if (b->pos == b->last) { | |
2419 return NGX_AGAIN; | |
2420 } | |
2421 | |
2422 ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG; | |
2423 ctx->padding = *b->pos++; | |
2424 ctx->rest -= 1; | |
2425 | |
2426 if (ctx->padding > ctx->rest) { | |
2427 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2428 "upstream sent http2 frame with too long " | |
2429 "padding: %d in frame %uz", | |
2430 ctx->padding, ctx->rest); | |
2431 return NGX_ERROR; | |
2432 } | |
2433 | |
2434 continue; | |
2435 } | |
2436 | |
2437 if (ctx->rest == ctx->padding) { | |
2438 goto done; | |
2439 } | |
2440 | |
2441 if (b->pos == b->last) { | |
2442 return NGX_AGAIN; | |
2443 } | |
2444 | |
2445 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); | |
2446 if (cl == NULL) { | |
2447 return NGX_ERROR; | |
2448 } | |
2449 | |
2450 *ll = cl; | |
2451 ll = &cl->next; | |
2452 | |
2453 buf = cl->buf; | |
2454 | |
2455 buf->flush = 1; | |
2456 buf->memory = 1; | |
2457 | |
2458 buf->pos = b->pos; | |
2459 buf->tag = u->output.tag; | |
2460 | |
2461 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2462 "grpc output buf %p", buf->pos); | |
2463 | |
2464 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) { | |
2465 | |
2466 ctx->rest -= b->last - b->pos; | |
2467 b->pos = b->last; | |
2468 buf->last = b->pos; | |
2469 | |
2470 return NGX_AGAIN; | |
2471 } | |
2472 | |
2473 b->pos += ctx->rest - ctx->padding; | |
2474 buf->last = b->pos; | |
2475 ctx->rest = ctx->padding; | |
2476 | |
2477 done: | |
2478 | |
2479 if (ctx->padding) { | |
2480 ctx->state = ngx_http_grpc_st_padding; | |
2481 continue; | |
2482 } | |
2483 | |
2484 ctx->state = ngx_http_grpc_st_start; | |
2485 | |
2486 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2487 ctx->done = 1; |
7233 | 2488 } |
2489 } | |
2490 | |
2491 return NGX_OK; | |
2492 } | |
2493 | |
2494 | |
2495 static ngx_int_t | |
2496 ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2497 ngx_buf_t *b) | |
2498 { | |
2499 u_char ch, *p; | |
2500 ngx_http_grpc_state_e state; | |
2501 | |
2502 state = ctx->state; | |
2503 | |
2504 for (p = b->pos; p < b->last; p++) { | |
2505 ch = *p; | |
2506 | |
2507 #if 0 | |
2508 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2509 "grpc frame byte: %02Xd, s:%d", ch, state); | |
2510 #endif | |
2511 | |
2512 switch (state) { | |
2513 | |
2514 case ngx_http_grpc_st_start: | |
2515 ctx->rest = ch << 16; | |
2516 state = ngx_http_grpc_st_length_2; | |
2517 break; | |
2518 | |
2519 case ngx_http_grpc_st_length_2: | |
2520 ctx->rest |= ch << 8; | |
2521 state = ngx_http_grpc_st_length_3; | |
2522 break; | |
2523 | |
2524 case ngx_http_grpc_st_length_3: | |
2525 ctx->rest |= ch; | |
2526 | |
2527 if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) { | |
2528 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2529 "upstream sent too large http2 frame: %uz", | |
2530 ctx->rest); | |
2531 return NGX_ERROR; | |
2532 } | |
2533 | |
2534 state = ngx_http_grpc_st_type; | |
2535 break; | |
2536 | |
2537 case ngx_http_grpc_st_type: | |
2538 ctx->type = ch; | |
2539 state = ngx_http_grpc_st_flags; | |
2540 break; | |
2541 | |
2542 case ngx_http_grpc_st_flags: | |
2543 ctx->flags = ch; | |
2544 state = ngx_http_grpc_st_stream_id; | |
2545 break; | |
2546 | |
2547 case ngx_http_grpc_st_stream_id: | |
2548 ctx->stream_id = (ch & 0x7f) << 24; | |
2549 state = ngx_http_grpc_st_stream_id_2; | |
2550 break; | |
2551 | |
2552 case ngx_http_grpc_st_stream_id_2: | |
2553 ctx->stream_id |= ch << 16; | |
2554 state = ngx_http_grpc_st_stream_id_3; | |
2555 break; | |
2556 | |
2557 case ngx_http_grpc_st_stream_id_3: | |
2558 ctx->stream_id |= ch << 8; | |
2559 state = ngx_http_grpc_st_stream_id_4; | |
2560 break; | |
2561 | |
2562 case ngx_http_grpc_st_stream_id_4: | |
2563 ctx->stream_id |= ch; | |
2564 | |
2565 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2566 "grpc frame: %d, len: %uz, f:%d, i:%ui", | |
2567 ctx->type, ctx->rest, ctx->flags, ctx->stream_id); | |
2568 | |
2569 b->pos = p + 1; | |
2570 | |
2571 ctx->state = ngx_http_grpc_st_payload; | |
2572 ctx->frame_state = 0; | |
2573 | |
2574 return NGX_OK; | |
2575 | |
2576 /* suppress warning */ | |
2577 case ngx_http_grpc_st_payload: | |
2578 case ngx_http_grpc_st_padding: | |
2579 break; | |
2580 } | |
2581 } | |
2582 | |
2583 b->pos = p; | |
2584 ctx->state = state; | |
2585 | |
2586 return NGX_AGAIN; | |
2587 } | |
2588 | |
2589 | |
2590 static ngx_int_t | |
2591 ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2592 ngx_buf_t *b) | |
2593 { | |
2594 u_char ch, *p, *last; | |
2595 size_t min; | |
2596 ngx_int_t rc; | |
2597 enum { | |
2598 sw_start = 0, | |
2599 sw_padding_length, | |
2600 sw_dependency, | |
2601 sw_dependency_2, | |
2602 sw_dependency_3, | |
2603 sw_dependency_4, | |
2604 sw_weight, | |
2605 sw_fragment, | |
2606 sw_padding | |
2607 } state; | |
2608 | |
2609 state = ctx->frame_state; | |
2610 | |
2611 if (state == sw_start) { | |
2612 | |
2613 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2614 "grpc parse header: start"); | |
2615 | |
2616 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) { | |
2617 ctx->parsing_headers = 1; | |
2618 ctx->fragment_state = 0; | |
2619 | |
2620 min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0) | |
2621 + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0); | |
2622 | |
2623 if (ctx->rest < min) { | |
2624 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2625 "upstream sent headers frame " | |
2626 "with invalid length: %uz", | |
2627 ctx->rest); | |
2628 return NGX_ERROR; | |
2629 } | |
2630 | |
2631 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
2632 ctx->end_stream = 1; | |
2633 } | |
2634 | |
2635 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) { | |
2636 state = sw_padding_length; | |
2637 | |
2638 } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) { | |
2639 state = sw_dependency; | |
2640 | |
2641 } else { | |
2642 state = sw_fragment; | |
2643 } | |
2644 | |
2645 } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) { | |
2646 state = sw_fragment; | |
2647 } | |
2648 | |
2649 ctx->padding = 0; | |
7242
25a4353633a0
gRPC: fixed missing state save in frame header parsing.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7240
diff
changeset
|
2650 ctx->frame_state = state; |
7233 | 2651 } |
2652 | |
2653 if (state < sw_fragment) { | |
2654 | |
2655 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2656 last = b->last; | |
2657 | |
2658 } else { | |
2659 last = b->pos + ctx->rest; | |
2660 } | |
2661 | |
2662 for (p = b->pos; p < last; p++) { | |
2663 ch = *p; | |
2664 | |
2665 #if 0 | |
2666 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2667 "grpc header byte: %02Xd s:%d", ch, state); | |
2668 #endif | |
2669 | |
2670 /* | |
2671 * headers frame: | |
2672 * | |
2673 * +---------------+ | |
2674 * |Pad Length? (8)| | |
2675 * +-+-------------+----------------------------------------------+ | |
2676 * |E| Stream Dependency? (31) | | |
2677 * +-+-------------+----------------------------------------------+ | |
2678 * | Weight? (8) | | |
2679 * +-+-------------+----------------------------------------------+ | |
2680 * | Header Block Fragment (*) ... | |
2681 * +--------------------------------------------------------------+ | |
2682 * | Padding (*) ... | |
2683 * +--------------------------------------------------------------+ | |
2684 */ | |
2685 | |
2686 switch (state) { | |
2687 | |
2688 case sw_padding_length: | |
2689 | |
2690 ctx->padding = ch; | |
2691 | |
2692 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) { | |
2693 state = sw_dependency; | |
2694 break; | |
2695 } | |
2696 | |
2697 goto fragment; | |
2698 | |
2699 case sw_dependency: | |
2700 state = sw_dependency_2; | |
2701 break; | |
2702 | |
2703 case sw_dependency_2: | |
2704 state = sw_dependency_3; | |
2705 break; | |
2706 | |
2707 case sw_dependency_3: | |
2708 state = sw_dependency_4; | |
2709 break; | |
2710 | |
2711 case sw_dependency_4: | |
2712 state = sw_weight; | |
2713 break; | |
2714 | |
2715 case sw_weight: | |
2716 goto fragment; | |
2717 | |
2718 /* suppress warning */ | |
2719 case sw_start: | |
2720 case sw_fragment: | |
2721 case sw_padding: | |
2722 break; | |
2723 } | |
2724 } | |
2725 | |
2726 ctx->rest -= p - b->pos; | |
2727 b->pos = p; | |
2728 | |
2729 ctx->frame_state = state; | |
2730 return NGX_AGAIN; | |
2731 | |
2732 fragment: | |
2733 | |
2734 p++; | |
2735 ctx->rest -= p - b->pos; | |
2736 b->pos = p; | |
2737 | |
2738 if (ctx->padding > ctx->rest) { | |
2739 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2740 "upstream sent http2 frame with too long " | |
2741 "padding: %d in frame %uz", | |
2742 ctx->padding, ctx->rest); | |
2743 return NGX_ERROR; | |
2744 } | |
2745 | |
2746 state = sw_fragment; | |
2747 ctx->frame_state = state; | |
2748 } | |
2749 | |
2750 if (state == sw_fragment) { | |
2751 | |
2752 rc = ngx_http_grpc_parse_fragment(r, ctx, b); | |
2753 | |
2754 if (rc == NGX_AGAIN) { | |
2755 return NGX_AGAIN; | |
2756 } | |
2757 | |
2758 if (rc == NGX_ERROR) { | |
2759 return NGX_ERROR; | |
2760 } | |
2761 | |
2762 if (rc == NGX_OK) { | |
2763 return NGX_OK; | |
2764 } | |
2765 | |
2766 /* rc == NGX_DONE */ | |
2767 | |
2768 state = sw_padding; | |
2769 ctx->frame_state = state; | |
2770 } | |
2771 | |
2772 if (state == sw_padding) { | |
2773 | |
2774 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2775 | |
2776 ctx->rest -= b->last - b->pos; | |
2777 b->pos = b->last; | |
2778 | |
2779 return NGX_AGAIN; | |
2780 } | |
2781 | |
2782 b->pos += ctx->rest; | |
2783 ctx->rest = 0; | |
2784 | |
2785 ctx->state = ngx_http_grpc_st_start; | |
2786 | |
2787 if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) { | |
2788 | |
2789 if (ctx->fragment_state) { | |
2790 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2791 "upstream sent truncated http2 header"); | |
2792 return NGX_ERROR; | |
2793 } | |
2794 | |
2795 ctx->parsing_headers = 0; | |
2796 | |
2797 return NGX_HTTP_PARSE_HEADER_DONE; | |
2798 } | |
2799 | |
2800 return NGX_AGAIN; | |
2801 } | |
2802 | |
2803 /* unreachable */ | |
2804 | |
2805 return NGX_ERROR; | |
2806 } | |
2807 | |
2808 | |
2809 static ngx_int_t | |
2810 ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2811 ngx_buf_t *b) | |
2812 { | |
2813 u_char ch, *p, *last; | |
2814 size_t size; | |
2815 ngx_uint_t index, size_update; | |
2816 enum { | |
2817 sw_start = 0, | |
2818 sw_index, | |
2819 sw_name_length, | |
2820 sw_name_length_2, | |
2821 sw_name_length_3, | |
2822 sw_name_length_4, | |
2823 sw_name, | |
2824 sw_name_bytes, | |
2825 sw_value_length, | |
2826 sw_value_length_2, | |
2827 sw_value_length_3, | |
2828 sw_value_length_4, | |
2829 sw_value, | |
2830 sw_value_bytes | |
2831 } state; | |
2832 | |
2833 /* header block fragment */ | |
2834 | |
2835 #if 0 | |
2836 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2837 "grpc header fragment %p:%p rest:%uz", | |
2838 b->pos, b->last, ctx->rest); | |
2839 #endif | |
2840 | |
2841 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) { | |
2842 last = b->last; | |
2843 | |
2844 } else { | |
2845 last = b->pos + ctx->rest - ctx->padding; | |
2846 } | |
2847 | |
2848 state = ctx->fragment_state; | |
2849 | |
2850 for (p = b->pos; p < last; p++) { | |
2851 ch = *p; | |
2852 | |
2853 #if 0 | |
2854 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2855 "grpc header byte: %02Xd s:%d", ch, state); | |
2856 #endif | |
2857 | |
2858 switch (state) { | |
2859 | |
2860 case sw_start: | |
2861 ctx->index = 0; | |
2862 | |
2863 if ((ch & 0x80) == 0x80) { | |
2864 /* | |
2865 * indexed header: | |
2866 * | |
2867 * 0 1 2 3 4 5 6 7 | |
2868 * +---+---+---+---+---+---+---+---+ | |
2869 * | 1 | Index (7+) | | |
2870 * +---+---------------------------+ | |
2871 */ | |
2872 | |
2873 index = ch & ~0x80; | |
2874 | |
2875 if (index == 0 || index > 61) { | |
2876 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2877 "upstream sent invalid http2 " | |
2878 "table index: %ui", index); | |
2879 return NGX_ERROR; | |
2880 } | |
2881 | |
2882 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2883 "grpc indexed header: %ui", index); | |
2884 | |
2885 ctx->index = index; | |
2886 ctx->literal = 0; | |
2887 | |
2888 goto done; | |
2889 | |
2890 } else if ((ch & 0xc0) == 0x40) { | |
2891 /* | |
2892 * literal header with incremental indexing: | |
2893 * | |
2894 * 0 1 2 3 4 5 6 7 | |
2895 * +---+---+---+---+---+---+---+---+ | |
2896 * | 0 | 1 | Index (6+) | | |
2897 * +---+---+-----------------------+ | |
2898 * | H | Value Length (7+) | | |
2899 * +---+---------------------------+ | |
2900 * | Value String (Length octets) | | |
2901 * +-------------------------------+ | |
2902 * | |
2903 * 0 1 2 3 4 5 6 7 | |
2904 * +---+---+---+---+---+---+---+---+ | |
2905 * | 0 | 1 | 0 | | |
2906 * +---+---+-----------------------+ | |
2907 * | H | Name Length (7+) | | |
2908 * +---+---------------------------+ | |
2909 * | Name String (Length octets) | | |
2910 * +---+---------------------------+ | |
2911 * | H | Value Length (7+) | | |
2912 * +---+---------------------------+ | |
2913 * | Value String (Length octets) | | |
2914 * +-------------------------------+ | |
2915 */ | |
2916 | |
2917 index = ch & ~0xc0; | |
2918 | |
2919 if (index > 61) { | |
2920 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2921 "upstream sent invalid http2 " | |
2922 "table index: %ui", index); | |
2923 return NGX_ERROR; | |
2924 } | |
2925 | |
2926 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2927 "grpc literal header: %ui", index); | |
2928 | |
2929 if (index == 0) { | |
2930 state = sw_name_length; | |
2931 break; | |
2932 } | |
2933 | |
2934 ctx->index = index; | |
2935 ctx->literal = 1; | |
2936 | |
2937 state = sw_value_length; | |
2938 break; | |
2939 | |
2940 } else if ((ch & 0xe0) == 0x20) { | |
2941 /* | |
2942 * dynamic table size update: | |
2943 * | |
2944 * 0 1 2 3 4 5 6 7 | |
2945 * +---+---+---+---+---+---+---+---+ | |
2946 * | 0 | 0 | 1 | Max size (5+) | | |
2947 * +---+---------------------------+ | |
2948 */ | |
2949 | |
2950 size_update = ch & ~0xe0; | |
2951 | |
2952 if (size_update > 0) { | |
2953 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2954 "upstream sent invalid http2 " | |
2955 "dynamic table size update: %ui", | |
2956 size_update); | |
2957 return NGX_ERROR; | |
2958 } | |
2959 | |
2960 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2961 "grpc table size update: %ui", size_update); | |
2962 | |
2963 break; | |
2964 | |
2965 } else if ((ch & 0xf0) == 0x10) { | |
2966 /* | |
2967 * literal header field never indexed: | |
2968 * | |
2969 * 0 1 2 3 4 5 6 7 | |
2970 * +---+---+---+---+---+---+---+---+ | |
2971 * | 0 | 0 | 0 | 1 | Index (4+) | | |
2972 * +---+---+-----------------------+ | |
2973 * | H | Value Length (7+) | | |
2974 * +---+---------------------------+ | |
2975 * | Value String (Length octets) | | |
2976 * +-------------------------------+ | |
2977 * | |
2978 * 0 1 2 3 4 5 6 7 | |
2979 * +---+---+---+---+---+---+---+---+ | |
2980 * | 0 | 0 | 0 | 1 | 0 | | |
2981 * +---+---+-----------------------+ | |
2982 * | H | Name Length (7+) | | |
2983 * +---+---------------------------+ | |
2984 * | Name String (Length octets) | | |
2985 * +---+---------------------------+ | |
2986 * | H | Value Length (7+) | | |
2987 * +---+---------------------------+ | |
2988 * | Value String (Length octets) | | |
2989 * +-------------------------------+ | |
2990 */ | |
2991 | |
2992 index = ch & ~0xf0; | |
2993 | |
2994 if (index == 0x0f) { | |
2995 ctx->index = index; | |
2996 ctx->literal = 1; | |
2997 state = sw_index; | |
2998 break; | |
2999 } | |
3000 | |
3001 if (index == 0) { | |
3002 state = sw_name_length; | |
3003 break; | |
3004 } | |
3005 | |
3006 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3007 "grpc literal header never indexed: %ui", | |
3008 index); | |
3009 | |
3010 ctx->index = index; | |
3011 ctx->literal = 1; | |
3012 | |
3013 state = sw_value_length; | |
3014 break; | |
3015 | |
3016 } else if ((ch & 0xf0) == 0x00) { | |
3017 /* | |
3018 * literal header field without indexing: | |
3019 * | |
3020 * 0 1 2 3 4 5 6 7 | |
3021 * +---+---+---+---+---+---+---+---+ | |
3022 * | 0 | 0 | 0 | 0 | Index (4+) | | |
3023 * +---+---+-----------------------+ | |
3024 * | H | Value Length (7+) | | |
3025 * +---+---------------------------+ | |
3026 * | Value String (Length octets) | | |
3027 * +-------------------------------+ | |
3028 * | |
3029 * 0 1 2 3 4 5 6 7 | |
3030 * +---+---+---+---+---+---+---+---+ | |
3031 * | 0 | 0 | 0 | 0 | 0 | | |
3032 * +---+---+-----------------------+ | |
3033 * | H | Name Length (7+) | | |
3034 * +---+---------------------------+ | |
3035 * | Name String (Length octets) | | |
3036 * +---+---------------------------+ | |
3037 * | H | Value Length (7+) | | |
3038 * +---+---------------------------+ | |
3039 * | Value String (Length octets) | | |
3040 * +-------------------------------+ | |
3041 */ | |
3042 | |
3043 index = ch & ~0xf0; | |
3044 | |
3045 if (index == 0x0f) { | |
3046 ctx->index = index; | |
3047 ctx->literal = 1; | |
3048 state = sw_index; | |
3049 break; | |
3050 } | |
3051 | |
3052 if (index == 0) { | |
3053 state = sw_name_length; | |
3054 break; | |
3055 } | |
3056 | |
3057 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3058 "grpc literal header without indexing: %ui", | |
3059 index); | |
3060 | |
3061 ctx->index = index; | |
3062 ctx->literal = 1; | |
3063 | |
3064 state = sw_value_length; | |
3065 break; | |
3066 } | |
3067 | |
3068 /* not reached */ | |
3069 | |
3070 return NGX_ERROR; | |
3071 | |
3072 case sw_index: | |
3073 ctx->index = ctx->index + (ch & ~0x80); | |
3074 | |
3075 if (ch & 0x80) { | |
3076 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3077 "upstream sent http2 table index " | |
3078 "with continuation flag"); | |
3079 return NGX_ERROR; | |
3080 } | |
3081 | |
3082 if (ctx->index > 61) { | |
3083 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3084 "upstream sent invalid http2 " | |
3085 "table index: %ui", ctx->index); | |
3086 return NGX_ERROR; | |
3087 } | |
3088 | |
3089 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3090 "grpc header index: %ui", ctx->index); | |
3091 | |
3092 state = sw_value_length; | |
3093 break; | |
3094 | |
3095 case sw_name_length: | |
3096 ctx->field_huffman = ch & 0x80 ? 1 : 0; | |
3097 ctx->field_length = ch & ~0x80; | |
3098 | |
3099 if (ctx->field_length == 0x7f) { | |
3100 state = sw_name_length_2; | |
3101 break; | |
3102 } | |
3103 | |
3104 if (ctx->field_length == 0) { | |
3105 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3106 "upstream sent zero http2 " | |
3107 "header name length"); | |
3108 return NGX_ERROR; | |
3109 } | |
3110 | |
3111 state = sw_name; | |
3112 break; | |
3113 | |
3114 case sw_name_length_2: | |
3115 ctx->field_length += ch & ~0x80; | |
3116 | |
3117 if (ch & 0x80) { | |
3118 state = sw_name_length_3; | |
3119 break; | |
3120 } | |
3121 | |
3122 state = sw_name; | |
3123 break; | |
3124 | |
3125 case sw_name_length_3: | |
3126 ctx->field_length += (ch & ~0x80) << 7; | |
3127 | |
3128 if (ch & 0x80) { | |
3129 state = sw_name_length_4; | |
3130 break; | |
3131 } | |
3132 | |
3133 state = sw_name; | |
3134 break; | |
3135 | |
3136 case sw_name_length_4: | |
3137 ctx->field_length += (ch & ~0x80) << 14; | |
3138 | |
3139 if (ch & 0x80) { | |
3140 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3141 "upstream sent too large http2 " | |
3142 "header name length"); | |
3143 return NGX_ERROR; | |
3144 } | |
3145 | |
3146 state = sw_name; | |
3147 break; | |
3148 | |
3149 case sw_name: | |
3150 ctx->name.len = ctx->field_huffman ? | |
3151 ctx->field_length * 8 / 5 : ctx->field_length; | |
3152 | |
3153 ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1); | |
3154 if (ctx->name.data == NULL) { | |
3155 return NGX_ERROR; | |
3156 } | |
3157 | |
3158 ctx->field_end = ctx->name.data; | |
3159 ctx->field_rest = ctx->field_length; | |
3160 ctx->field_state = 0; | |
3161 | |
3162 state = sw_name_bytes; | |
3163 | |
3164 /* fall through */ | |
3165 | |
3166 case sw_name_bytes: | |
3167 | |
3168 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3169 "grpc name: len:%uz h:%d last:%uz, rest:%uz", | |
3170 ctx->field_length, | |
3171 ctx->field_huffman, | |
3172 last - p, | |
3173 ctx->rest - (p - b->pos)); | |
3174 | |
3175 size = ngx_min(last - p, (ssize_t) ctx->field_rest); | |
3176 ctx->field_rest -= size; | |
3177 | |
3178 if (ctx->field_huffman) { | |
3179 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, | |
3180 &ctx->field_end, | |
3181 ctx->field_rest == 0, | |
3182 r->connection->log) | |
3183 != NGX_OK) | |
3184 { | |
3185 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3186 "upstream sent invalid encoded header"); | |
3187 return NGX_ERROR; | |
3188 } | |
3189 | |
3190 ctx->name.len = ctx->field_end - ctx->name.data; | |
3191 ctx->name.data[ctx->name.len] = '\0'; | |
3192 | |
3193 } else { | |
7240
413189f03c8d
gRPC: fixed parsing response headers split on CONTINUATION frames.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7235
diff
changeset
|
3194 ctx->field_end = ngx_cpymem(ctx->field_end, p, size); |
7233 | 3195 ctx->name.data[ctx->name.len] = '\0'; |
3196 } | |
3197 | |
3198 p += size - 1; | |
3199 | |
3200 if (ctx->field_rest == 0) { | |
3201 state = sw_value_length; | |
3202 } | |
3203 | |
3204 break; | |
3205 | |
3206 case sw_value_length: | |
3207 ctx->field_huffman = ch & 0x80 ? 1 : 0; | |
3208 ctx->field_length = ch & ~0x80; | |
3209 | |
3210 if (ctx->field_length == 0x7f) { | |
3211 state = sw_value_length_2; | |
3212 break; | |
3213 } | |
3214 | |
3215 if (ctx->field_length == 0) { | |
3216 ngx_str_set(&ctx->value, ""); | |
3217 goto done; | |
3218 } | |
3219 | |
3220 state = sw_value; | |
3221 break; | |
3222 | |
3223 case sw_value_length_2: | |
3224 ctx->field_length += ch & ~0x80; | |
3225 | |
3226 if (ch & 0x80) { | |
3227 state = sw_value_length_3; | |
3228 break; | |
3229 } | |
3230 | |
3231 state = sw_value; | |
3232 break; | |
3233 | |
3234 case sw_value_length_3: | |
3235 ctx->field_length += (ch & ~0x80) << 7; | |
3236 | |
3237 if (ch & 0x80) { | |
3238 state = sw_value_length_4; | |
3239 break; | |
3240 } | |
3241 | |
3242 state = sw_value; | |
3243 break; | |
3244 | |
3245 case sw_value_length_4: | |
3246 ctx->field_length += (ch & ~0x80) << 14; | |
3247 | |
3248 if (ch & 0x80) { | |
3249 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3250 "upstream sent too large http2 " | |
3251 "header value length"); | |
3252 return NGX_ERROR; | |
3253 } | |
3254 | |
3255 state = sw_value; | |
3256 break; | |
3257 | |
3258 case sw_value: | |
3259 ctx->value.len = ctx->field_huffman ? | |
3260 ctx->field_length * 8 / 5 : ctx->field_length; | |
3261 | |
3262 ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1); | |
3263 if (ctx->value.data == NULL) { | |
3264 return NGX_ERROR; | |
3265 } | |
3266 | |
3267 ctx->field_end = ctx->value.data; | |
3268 ctx->field_rest = ctx->field_length; | |
3269 ctx->field_state = 0; | |
3270 | |
3271 state = sw_value_bytes; | |
3272 | |
3273 /* fall through */ | |
3274 | |
3275 case sw_value_bytes: | |
3276 | |
3277 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3278 "grpc value: len:%uz h:%d last:%uz, rest:%uz", | |
3279 ctx->field_length, | |
3280 ctx->field_huffman, | |
3281 last - p, | |
3282 ctx->rest - (p - b->pos)); | |
3283 | |
3284 size = ngx_min(last - p, (ssize_t) ctx->field_rest); | |
3285 ctx->field_rest -= size; | |
3286 | |
3287 if (ctx->field_huffman) { | |
3288 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, | |
3289 &ctx->field_end, | |
3290 ctx->field_rest == 0, | |
3291 r->connection->log) | |
3292 != NGX_OK) | |
3293 { | |
3294 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3295 "upstream sent invalid encoded header"); | |
3296 return NGX_ERROR; | |
3297 } | |
3298 | |
3299 ctx->value.len = ctx->field_end - ctx->value.data; | |
3300 ctx->value.data[ctx->value.len] = '\0'; | |
3301 | |
3302 } else { | |
7240
413189f03c8d
gRPC: fixed parsing response headers split on CONTINUATION frames.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7235
diff
changeset
|
3303 ctx->field_end = ngx_cpymem(ctx->field_end, p, size); |
7233 | 3304 ctx->value.data[ctx->value.len] = '\0'; |
3305 } | |
3306 | |
3307 p += size - 1; | |
3308 | |
3309 if (ctx->field_rest == 0) { | |
3310 goto done; | |
3311 } | |
3312 | |
3313 break; | |
3314 } | |
3315 | |
3316 continue; | |
3317 | |
3318 done: | |
3319 | |
3320 p++; | |
3321 ctx->rest -= p - b->pos; | |
3322 ctx->fragment_state = sw_start; | |
3323 b->pos = p; | |
3324 | |
3325 if (ctx->index) { | |
3326 ctx->name = *ngx_http_v2_get_static_name(ctx->index); | |
3327 } | |
3328 | |
3329 if (ctx->index && !ctx->literal) { | |
3330 ctx->value = *ngx_http_v2_get_static_value(ctx->index); | |
3331 } | |
3332 | |
3333 if (!ctx->index) { | |
3334 if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) { | |
3335 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3336 "upstream sent invalid header: \"%V: %V\"", | |
3337 &ctx->name, &ctx->value); | |
3338 return NGX_ERROR; | |
3339 } | |
3340 } | |
3341 | |
3342 if (!ctx->index || ctx->literal) { | |
3343 if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) { | |
3344 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3345 "upstream sent invalid header: \"%V: %V\"", | |
3346 &ctx->name, &ctx->value); | |
3347 return NGX_ERROR; | |
3348 } | |
3349 } | |
3350 | |
3351 return NGX_OK; | |
3352 } | |
3353 | |
3354 ctx->rest -= p - b->pos; | |
3355 ctx->fragment_state = state; | |
3356 b->pos = p; | |
3357 | |
3358 if (ctx->rest > ctx->padding) { | |
3359 return NGX_AGAIN; | |
3360 } | |
3361 | |
3362 return NGX_DONE; | |
3363 } | |
3364 | |
3365 | |
3366 static ngx_int_t | |
3367 ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) | |
3368 { | |
3369 u_char ch; | |
3370 ngx_uint_t i; | |
3371 | |
3372 for (i = 0; i < s->len; i++) { | |
3373 ch = s->data[i]; | |
3374 | |
3375 if (ch == ':' && i > 0) { | |
3376 return NGX_ERROR; | |
3377 } | |
3378 | |
3379 if (ch >= 'A' && ch <= 'Z') { | |
3380 return NGX_ERROR; | |
3381 } | |
3382 | |
3383 if (ch == '\0' || ch == CR || ch == LF) { | |
3384 return NGX_ERROR; | |
3385 } | |
3386 } | |
3387 | |
3388 return NGX_OK; | |
3389 } | |
3390 | |
3391 | |
3392 static ngx_int_t | |
3393 ngx_http_grpc_validate_header_value(ngx_http_request_t *r, ngx_str_t *s) | |
3394 { | |
3395 u_char ch; | |
3396 ngx_uint_t i; | |
3397 | |
3398 for (i = 0; i < s->len; i++) { | |
3399 ch = s->data[i]; | |
3400 | |
3401 if (ch == '\0' || ch == CR || ch == LF) { | |
3402 return NGX_ERROR; | |
3403 } | |
3404 } | |
3405 | |
3406 return NGX_OK; | |
3407 } | |
3408 | |
3409 | |
3410 static ngx_int_t | |
3411 ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3412 ngx_buf_t *b) | |
3413 { | |
3414 u_char ch, *p, *last; | |
3415 enum { | |
3416 sw_start = 0, | |
3417 sw_error_2, | |
3418 sw_error_3, | |
3419 sw_error_4 | |
3420 } state; | |
3421 | |
3422 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3423 last = b->last; | |
3424 | |
3425 } else { | |
3426 last = b->pos + ctx->rest; | |
3427 } | |
3428 | |
3429 state = ctx->frame_state; | |
3430 | |
3431 if (state == sw_start) { | |
3432 if (ctx->rest != 4) { | |
3433 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3434 "upstream sent rst stream frame " | |
3435 "with invalid length: %uz", | |
3436 ctx->rest); | |
3437 return NGX_ERROR; | |
3438 } | |
3439 } | |
3440 | |
3441 for (p = b->pos; p < last; p++) { | |
3442 ch = *p; | |
3443 | |
3444 #if 0 | |
3445 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3446 "grpc rst byte: %02Xd s:%d", ch, state); | |
3447 #endif | |
3448 | |
3449 switch (state) { | |
3450 | |
3451 case sw_start: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3452 ctx->error = (ngx_uint_t) ch << 24; |
7233 | 3453 state = sw_error_2; |
3454 break; | |
3455 | |
3456 case sw_error_2: | |
3457 ctx->error |= ch << 16; | |
3458 state = sw_error_3; | |
3459 break; | |
3460 | |
3461 case sw_error_3: | |
3462 ctx->error |= ch << 8; | |
3463 state = sw_error_4; | |
3464 break; | |
3465 | |
3466 case sw_error_4: | |
3467 ctx->error |= ch; | |
3468 state = sw_start; | |
3469 | |
3470 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3471 "grpc error: %ui", ctx->error); | |
3472 | |
3473 break; | |
3474 } | |
3475 } | |
3476 | |
3477 ctx->rest -= p - b->pos; | |
3478 ctx->frame_state = state; | |
3479 b->pos = p; | |
3480 | |
3481 if (ctx->rest > 0) { | |
3482 return NGX_AGAIN; | |
3483 } | |
3484 | |
3485 return NGX_OK; | |
3486 } | |
3487 | |
3488 | |
3489 static ngx_int_t | |
3490 ngx_http_grpc_parse_goaway(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3491 ngx_buf_t *b) | |
3492 { | |
3493 u_char ch, *p, *last; | |
3494 enum { | |
3495 sw_start = 0, | |
3496 sw_last_stream_id_2, | |
3497 sw_last_stream_id_3, | |
3498 sw_last_stream_id_4, | |
3499 sw_error, | |
3500 sw_error_2, | |
3501 sw_error_3, | |
3502 sw_error_4, | |
3503 sw_debug | |
3504 } state; | |
3505 | |
3506 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3507 last = b->last; | |
3508 | |
3509 } else { | |
3510 last = b->pos + ctx->rest; | |
3511 } | |
3512 | |
3513 state = ctx->frame_state; | |
3514 | |
3515 if (state == sw_start) { | |
3516 | |
3517 if (ctx->stream_id) { | |
3518 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3519 "upstream sent goaway frame " | |
3520 "with non-zero stream id: %ui", | |
3521 ctx->stream_id); | |
3522 return NGX_ERROR; | |
3523 } | |
3524 | |
3525 if (ctx->rest < 8) { | |
3526 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3527 "upstream sent goaway frame " | |
3528 "with invalid length: %uz", | |
3529 ctx->rest); | |
3530 return NGX_ERROR; | |
3531 } | |
3532 } | |
3533 | |
3534 for (p = b->pos; p < last; p++) { | |
3535 ch = *p; | |
3536 | |
3537 #if 0 | |
3538 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3539 "grpc goaway byte: %02Xd s:%d", ch, state); | |
3540 #endif | |
3541 | |
3542 switch (state) { | |
3543 | |
3544 case sw_start: | |
3545 ctx->stream_id = (ch & 0x7f) << 24; | |
3546 state = sw_last_stream_id_2; | |
3547 break; | |
3548 | |
3549 case sw_last_stream_id_2: | |
3550 ctx->stream_id |= ch << 16; | |
3551 state = sw_last_stream_id_3; | |
3552 break; | |
3553 | |
3554 case sw_last_stream_id_3: | |
3555 ctx->stream_id |= ch << 8; | |
3556 state = sw_last_stream_id_4; | |
3557 break; | |
3558 | |
3559 case sw_last_stream_id_4: | |
3560 ctx->stream_id |= ch; | |
3561 state = sw_error; | |
3562 break; | |
3563 | |
3564 case sw_error: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3565 ctx->error = (ngx_uint_t) ch << 24; |
7233 | 3566 state = sw_error_2; |
3567 break; | |
3568 | |
3569 case sw_error_2: | |
3570 ctx->error |= ch << 16; | |
3571 state = sw_error_3; | |
3572 break; | |
3573 | |
3574 case sw_error_3: | |
3575 ctx->error |= ch << 8; | |
3576 state = sw_error_4; | |
3577 break; | |
3578 | |
3579 case sw_error_4: | |
3580 ctx->error |= ch; | |
3581 state = sw_debug; | |
3582 break; | |
3583 | |
3584 case sw_debug: | |
3585 break; | |
3586 } | |
3587 } | |
3588 | |
3589 ctx->rest -= p - b->pos; | |
3590 ctx->frame_state = state; | |
3591 b->pos = p; | |
3592 | |
3593 if (ctx->rest > 0) { | |
3594 return NGX_AGAIN; | |
3595 } | |
3596 | |
3597 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3598 "grpc goaway: %ui, stream %ui", | |
3599 ctx->error, ctx->stream_id); | |
3600 | |
3601 ctx->state = ngx_http_grpc_st_start; | |
3602 | |
3603 return NGX_OK; | |
3604 } | |
3605 | |
3606 | |
3607 static ngx_int_t | |
3608 ngx_http_grpc_parse_window_update(ngx_http_request_t *r, | |
3609 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b) | |
3610 { | |
3611 u_char ch, *p, *last; | |
3612 enum { | |
3613 sw_start = 0, | |
3614 sw_size_2, | |
3615 sw_size_3, | |
3616 sw_size_4 | |
3617 } state; | |
3618 | |
3619 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3620 last = b->last; | |
3621 | |
3622 } else { | |
3623 last = b->pos + ctx->rest; | |
3624 } | |
3625 | |
3626 state = ctx->frame_state; | |
3627 | |
3628 if (state == sw_start) { | |
3629 if (ctx->rest != 4) { | |
3630 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3631 "upstream sent window update frame " | |
3632 "with invalid length: %uz", | |
3633 ctx->rest); | |
3634 return NGX_ERROR; | |
3635 } | |
3636 } | |
3637 | |
3638 for (p = b->pos; p < last; p++) { | |
3639 ch = *p; | |
3640 | |
3641 #if 0 | |
3642 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3643 "grpc window update byte: %02Xd s:%d", ch, state); | |
3644 #endif | |
3645 | |
3646 switch (state) { | |
3647 | |
3648 case sw_start: | |
3649 ctx->window_update = (ch & 0x7f) << 24; | |
3650 state = sw_size_2; | |
3651 break; | |
3652 | |
3653 case sw_size_2: | |
3654 ctx->window_update |= ch << 16; | |
3655 state = sw_size_3; | |
3656 break; | |
3657 | |
3658 case sw_size_3: | |
3659 ctx->window_update |= ch << 8; | |
3660 state = sw_size_4; | |
3661 break; | |
3662 | |
3663 case sw_size_4: | |
3664 ctx->window_update |= ch; | |
3665 state = sw_start; | |
3666 break; | |
3667 } | |
3668 } | |
3669 | |
3670 ctx->rest -= p - b->pos; | |
3671 ctx->frame_state = state; | |
3672 b->pos = p; | |
3673 | |
3674 if (ctx->rest > 0) { | |
3675 return NGX_AGAIN; | |
3676 } | |
3677 | |
3678 ctx->state = ngx_http_grpc_st_start; | |
3679 | |
3680 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3681 "grpc window update: %ui", ctx->window_update); | |
3682 | |
3683 if (ctx->stream_id) { | |
3684 | |
3685 if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW | |
3686 - ctx->send_window) | |
3687 { | |
3688 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3689 "upstream sent too large window update"); | |
3690 return NGX_ERROR; | |
3691 } | |
3692 | |
3693 ctx->send_window += ctx->window_update; | |
3694 | |
3695 } else { | |
3696 | |
3697 if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW | |
3698 - ctx->connection->send_window) | |
3699 { | |
3700 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3701 "upstream sent too large window update"); | |
3702 return NGX_ERROR; | |
3703 } | |
3704 | |
3705 ctx->connection->send_window += ctx->window_update; | |
3706 } | |
3707 | |
3708 return NGX_OK; | |
3709 } | |
3710 | |
3711 | |
3712 static ngx_int_t | |
3713 ngx_http_grpc_parse_settings(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3714 ngx_buf_t *b) | |
3715 { | |
3716 u_char ch, *p, *last; | |
3717 ssize_t window_update; | |
3718 enum { | |
3719 sw_start = 0, | |
3720 sw_id, | |
3721 sw_id_2, | |
3722 sw_value, | |
3723 sw_value_2, | |
3724 sw_value_3, | |
3725 sw_value_4 | |
3726 } state; | |
3727 | |
3728 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3729 last = b->last; | |
3730 | |
3731 } else { | |
3732 last = b->pos + ctx->rest; | |
3733 } | |
3734 | |
3735 state = ctx->frame_state; | |
3736 | |
3737 if (state == sw_start) { | |
3738 | |
3739 if (ctx->stream_id) { | |
3740 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3741 "upstream sent settings frame " | |
3742 "with non-zero stream id: %ui", | |
3743 ctx->stream_id); | |
3744 return NGX_ERROR; | |
3745 } | |
3746 | |
3747 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) { | |
3748 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3749 "grpc settings ack"); | |
3750 | |
3751 if (ctx->rest != 0) { | |
3752 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3753 "upstream sent settings frame " | |
3754 "with ack flag and non-zero length: %uz", | |
3755 ctx->rest); | |
3756 return NGX_ERROR; | |
3757 } | |
3758 | |
3759 ctx->state = ngx_http_grpc_st_start; | |
3760 | |
3761 return NGX_OK; | |
3762 } | |
3763 | |
3764 if (ctx->rest % 6 != 0) { | |
3765 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3766 "upstream sent settings frame " | |
3767 "with invalid length: %uz", | |
3768 ctx->rest); | |
3769 return NGX_ERROR; | |
3770 } | |
7379
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3771 |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3772 if (ctx->free == NULL && ctx->settings++ > 1000) { |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3773 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3774 "upstream sent too many settings frames"); |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3775 return NGX_ERROR; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3776 } |
7233 | 3777 } |
3778 | |
3779 for (p = b->pos; p < last; p++) { | |
3780 ch = *p; | |
3781 | |
3782 #if 0 | |
3783 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3784 "grpc settings byte: %02Xd s:%d", ch, state); | |
3785 #endif | |
3786 | |
3787 switch (state) { | |
3788 | |
3789 case sw_start: | |
3790 case sw_id: | |
3791 ctx->setting_id = ch << 8; | |
3792 state = sw_id_2; | |
3793 break; | |
3794 | |
3795 case sw_id_2: | |
3796 ctx->setting_id |= ch; | |
3797 state = sw_value; | |
3798 break; | |
3799 | |
3800 case sw_value: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3801 ctx->setting_value = (ngx_uint_t) ch << 24; |
7233 | 3802 state = sw_value_2; |
3803 break; | |
3804 | |
3805 case sw_value_2: | |
3806 ctx->setting_value |= ch << 16; | |
3807 state = sw_value_3; | |
3808 break; | |
3809 | |
3810 case sw_value_3: | |
3811 ctx->setting_value |= ch << 8; | |
3812 state = sw_value_4; | |
3813 break; | |
3814 | |
3815 case sw_value_4: | |
3816 ctx->setting_value |= ch; | |
3817 state = sw_id; | |
3818 | |
3819 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3820 "grpc setting: %ui %ui", | |
3821 ctx->setting_id, ctx->setting_value); | |
3822 | |
3823 /* | |
3824 * The following settings are defined by the protocol: | |
3825 * | |
3826 * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH, | |
3827 * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE, | |
3828 * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE | |
3829 * | |
3830 * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in | |
3831 * a simple client. | |
3832 */ | |
3833 | |
3834 if (ctx->setting_id == 0x04) { | |
3835 /* SETTINGS_INITIAL_WINDOW_SIZE */ | |
3836 | |
3837 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) { | |
3838 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3839 "upstream sent settings frame " | |
3840 "with too large initial window size: %ui", | |
3841 ctx->setting_value); | |
3842 return NGX_ERROR; | |
3843 } | |
3844 | |
3845 window_update = ctx->setting_value | |
3846 - ctx->connection->init_window; | |
3847 ctx->connection->init_window = ctx->setting_value; | |
3848 | |
3849 if (ctx->send_window > 0 | |
3850 && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW | |
3851 - ctx->send_window) | |
3852 { | |
3853 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3854 "upstream sent settings frame " | |
3855 "with too large initial window size: %ui", | |
3856 ctx->setting_value); | |
3857 return NGX_ERROR; | |
3858 } | |
3859 | |
3860 ctx->send_window += window_update; | |
3861 } | |
3862 | |
3863 break; | |
3864 } | |
3865 } | |
3866 | |
3867 ctx->rest -= p - b->pos; | |
3868 ctx->frame_state = state; | |
3869 b->pos = p; | |
3870 | |
3871 if (ctx->rest > 0) { | |
3872 return NGX_AGAIN; | |
3873 } | |
3874 | |
3875 ctx->state = ngx_http_grpc_st_start; | |
3876 | |
3877 return ngx_http_grpc_send_settings_ack(r, ctx); | |
3878 } | |
3879 | |
3880 | |
3881 static ngx_int_t | |
3882 ngx_http_grpc_parse_ping(ngx_http_request_t *r, | |
3883 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b) | |
3884 { | |
3885 u_char ch, *p, *last; | |
3886 enum { | |
3887 sw_start = 0, | |
3888 sw_data_2, | |
3889 sw_data_3, | |
3890 sw_data_4, | |
3891 sw_data_5, | |
3892 sw_data_6, | |
3893 sw_data_7, | |
3894 sw_data_8 | |
3895 } state; | |
3896 | |
3897 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3898 last = b->last; | |
3899 | |
3900 } else { | |
3901 last = b->pos + ctx->rest; | |
3902 } | |
3903 | |
3904 state = ctx->frame_state; | |
3905 | |
3906 if (state == sw_start) { | |
3907 | |
3908 if (ctx->stream_id) { | |
3909 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3910 "upstream sent ping frame " | |
3911 "with non-zero stream id: %ui", | |
3912 ctx->stream_id); | |
3913 return NGX_ERROR; | |
3914 } | |
3915 | |
3916 if (ctx->rest != 8) { | |
3917 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3918 "upstream sent ping frame " | |
3919 "with invalid length: %uz", | |
3920 ctx->rest); | |
3921 return NGX_ERROR; | |
3922 } | |
3923 | |
3924 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) { | |
3925 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3926 "upstream sent ping frame with ack flag"); | |
3927 return NGX_ERROR; | |
3928 } | |
7379
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3929 |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3930 if (ctx->free == NULL && ctx->pings++ > 1000) { |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3931 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3932 "upstream sent too many ping frames"); |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3933 return NGX_ERROR; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3934 } |
7233 | 3935 } |
3936 | |
3937 for (p = b->pos; p < last; p++) { | |
3938 ch = *p; | |
3939 | |
3940 #if 0 | |
3941 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3942 "grpc ping byte: %02Xd s:%d", ch, state); | |
3943 #endif | |
3944 | |
3945 if (state < sw_data_8) { | |
3946 ctx->ping_data[state] = ch; | |
3947 state++; | |
3948 | |
3949 } else { | |
3950 ctx->ping_data[7] = ch; | |
3951 state = sw_start; | |
3952 | |
3953 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3954 "grpc ping"); | |
3955 } | |
3956 } | |
3957 | |
3958 ctx->rest -= p - b->pos; | |
3959 ctx->frame_state = state; | |
3960 b->pos = p; | |
3961 | |
3962 if (ctx->rest > 0) { | |
3963 return NGX_AGAIN; | |
3964 } | |
3965 | |
3966 ctx->state = ngx_http_grpc_st_start; | |
3967 | |
3968 return ngx_http_grpc_send_ping_ack(r, ctx); | |
3969 } | |
3970 | |
3971 | |
3972 static ngx_int_t | |
3973 ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
3974 { | |
3975 ngx_chain_t *cl, **ll; | |
3976 ngx_http_grpc_frame_t *f; | |
3977 | |
3978 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3979 "grpc send settings ack"); | |
3980 | |
3981 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
3982 ll = &cl->next; | |
3983 } | |
3984 | |
3985 cl = ngx_http_grpc_get_buf(r, ctx); | |
3986 if (cl == NULL) { | |
3987 return NGX_ERROR; | |
3988 } | |
3989 | |
3990 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
3991 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
3992 | |
3993 f->length_0 = 0; | |
3994 f->length_1 = 0; | |
3995 f->length_2 = 0; | |
3996 f->type = NGX_HTTP_V2_SETTINGS_FRAME; | |
3997 f->flags = NGX_HTTP_V2_ACK_FLAG; | |
3998 f->stream_id_0 = 0; | |
3999 f->stream_id_1 = 0; | |
4000 f->stream_id_2 = 0; | |
4001 f->stream_id_3 = 0; | |
4002 | |
4003 *ll = cl; | |
4004 | |
4005 return NGX_OK; | |
4006 } | |
4007 | |
4008 | |
4009 static ngx_int_t | |
4010 ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
4011 { | |
4012 ngx_chain_t *cl, **ll; | |
4013 ngx_http_grpc_frame_t *f; | |
4014 | |
4015 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4016 "grpc send ping ack"); | |
4017 | |
4018 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
4019 ll = &cl->next; | |
4020 } | |
4021 | |
4022 cl = ngx_http_grpc_get_buf(r, ctx); | |
4023 if (cl == NULL) { | |
4024 return NGX_ERROR; | |
4025 } | |
4026 | |
4027 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4028 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4029 | |
4030 f->length_0 = 0; | |
4031 f->length_1 = 0; | |
4032 f->length_2 = 8; | |
4033 f->type = NGX_HTTP_V2_PING_FRAME; | |
4034 f->flags = NGX_HTTP_V2_ACK_FLAG; | |
4035 f->stream_id_0 = 0; | |
4036 f->stream_id_1 = 0; | |
4037 f->stream_id_2 = 0; | |
4038 f->stream_id_3 = 0; | |
4039 | |
4040 cl->buf->last = ngx_copy(cl->buf->last, ctx->ping_data, 8); | |
4041 | |
4042 *ll = cl; | |
4043 | |
4044 return NGX_OK; | |
4045 } | |
4046 | |
4047 | |
4048 static ngx_int_t | |
4049 ngx_http_grpc_send_window_update(ngx_http_request_t *r, | |
4050 ngx_http_grpc_ctx_t *ctx) | |
4051 { | |
4052 size_t n; | |
4053 ngx_chain_t *cl, **ll; | |
4054 ngx_http_grpc_frame_t *f; | |
4055 | |
4056 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4057 "grpc send window update: %uz %uz", | |
4058 ctx->connection->recv_window, ctx->recv_window); | |
4059 | |
4060 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
4061 ll = &cl->next; | |
4062 } | |
4063 | |
4064 cl = ngx_http_grpc_get_buf(r, ctx); | |
4065 if (cl == NULL) { | |
4066 return NGX_ERROR; | |
4067 } | |
4068 | |
4069 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4070 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4071 | |
4072 f->length_0 = 0; | |
4073 f->length_1 = 0; | |
4074 f->length_2 = 4; | |
4075 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME; | |
4076 f->flags = 0; | |
4077 f->stream_id_0 = 0; | |
4078 f->stream_id_1 = 0; | |
4079 f->stream_id_2 = 0; | |
4080 f->stream_id_3 = 0; | |
4081 | |
4082 n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window; | |
4083 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4084 | |
4085 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff); | |
4086 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff); | |
4087 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff); | |
4088 *cl->buf->last++ = (u_char) (n & 0xff); | |
4089 | |
4090 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4091 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4092 | |
4093 f->length_0 = 0; | |
4094 f->length_1 = 0; | |
4095 f->length_2 = 4; | |
4096 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME; | |
4097 f->flags = 0; | |
4098 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
4099 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
4100 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
4101 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
4102 | |
4103 n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window; | |
4104 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4105 | |
4106 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff); | |
4107 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff); | |
4108 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff); | |
4109 *cl->buf->last++ = (u_char) (n & 0xff); | |
4110 | |
4111 *ll = cl; | |
4112 | |
4113 return NGX_OK; | |
4114 } | |
4115 | |
4116 | |
4117 static ngx_chain_t * | |
4118 ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
4119 { | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4120 u_char *start; |
7233 | 4121 ngx_buf_t *b; |
4122 ngx_chain_t *cl; | |
4123 | |
4124 cl = ngx_chain_get_free_buf(r->pool, &ctx->free); | |
4125 if (cl == NULL) { | |
4126 return NULL; | |
4127 } | |
4128 | |
4129 b = cl->buf; | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4130 start = b->start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4131 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4132 if (start == NULL) { |
7233 | 4133 |
4134 /* | |
4135 * each buffer is large enough to hold two window update | |
4136 * frames in a row | |
4137 */ | |
4138 | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4139 start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8); |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4140 if (start == NULL) { |
7233 | 4141 return NULL; |
4142 } | |
4143 | |
4144 } | |
4145 | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4146 ngx_memzero(b, sizeof(ngx_buf_t)); |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4147 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4148 b->start = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4149 b->pos = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4150 b->last = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4151 b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4152 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4153 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4154 b->temporary = 1; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4155 b->flush = 1; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4156 |
7233 | 4157 return cl; |
4158 } | |
4159 | |
4160 | |
4161 static ngx_http_grpc_ctx_t * | |
4162 ngx_http_grpc_get_ctx(ngx_http_request_t *r) | |
4163 { | |
4164 ngx_http_grpc_ctx_t *ctx; | |
4165 ngx_http_upstream_t *u; | |
4166 | |
4167 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); | |
4168 | |
4169 if (ctx->connection == NULL) { | |
4170 u = r->upstream; | |
4171 | |
4172 if (ngx_http_grpc_get_connection_data(r, ctx, &u->peer) != NGX_OK) { | |
4173 return NULL; | |
4174 } | |
4175 } | |
4176 | |
4177 return ctx; | |
4178 } | |
4179 | |
4180 | |
4181 static ngx_int_t | |
4182 ngx_http_grpc_get_connection_data(ngx_http_request_t *r, | |
4183 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc) | |
4184 { | |
4185 ngx_connection_t *c; | |
4186 ngx_pool_cleanup_t *cln; | |
4187 | |
4188 c = pc->connection; | |
4189 | |
4190 if (pc->cached) { | |
4191 | |
4192 /* | |
4193 * for cached connections, connection data can be found | |
4194 * in the cleanup handler | |
4195 */ | |
4196 | |
4197 for (cln = c->pool->cleanup; cln; cln = cln->next) { | |
4198 if (cln->handler == ngx_http_grpc_cleanup) { | |
4199 ctx->connection = cln->data; | |
4200 break; | |
4201 } | |
4202 } | |
4203 | |
4204 if (ctx->connection == NULL) { | |
4205 ngx_log_error(NGX_LOG_ERR, c->log, 0, | |
4206 "no connection data found for " | |
4207 "keepalive http2 connection"); | |
4208 return NGX_ERROR; | |
4209 } | |
4210 | |
4211 ctx->send_window = ctx->connection->init_window; | |
4212 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4213 | |
4214 ctx->connection->last_stream_id += 2; | |
4215 ctx->id = ctx->connection->last_stream_id; | |
4216 | |
4217 return NGX_OK; | |
4218 } | |
4219 | |
4220 cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_grpc_conn_t)); | |
4221 if (cln == NULL) { | |
4222 return NGX_ERROR; | |
4223 } | |
4224 | |
4225 cln->handler = ngx_http_grpc_cleanup; | |
4226 ctx->connection = cln->data; | |
4227 | |
4228 ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4229 ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4230 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4231 | |
4232 ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4233 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4234 | |
4235 ctx->id = 1; | |
4236 ctx->connection->last_stream_id = 1; | |
4237 | |
4238 return NGX_OK; | |
4239 } | |
4240 | |
4241 | |
4242 static void | |
4243 ngx_http_grpc_cleanup(void *data) | |
4244 { | |
4245 #if 0 | |
4246 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
4247 "grpc cleanup"); | |
4248 #endif | |
4249 return; | |
4250 } | |
4251 | |
4252 | |
4253 static void | |
4254 ngx_http_grpc_abort_request(ngx_http_request_t *r) | |
4255 { | |
4256 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4257 "abort grpc request"); | |
4258 return; | |
4259 } | |
4260 | |
4261 | |
4262 static void | |
4263 ngx_http_grpc_finalize_request(ngx_http_request_t *r, ngx_int_t rc) | |
4264 { | |
4265 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4266 "finalize grpc request"); | |
4267 return; | |
4268 } | |
4269 | |
4270 | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4271 static ngx_int_t |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4272 ngx_http_grpc_internal_trailers_variable(ngx_http_request_t *r, |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4273 ngx_http_variable_value_t *v, uintptr_t data) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4274 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4275 ngx_table_elt_t *te; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4276 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4277 te = r->headers_in.te; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4278 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4279 if (te == NULL) { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4280 v->not_found = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4281 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4282 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4283 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4284 if (ngx_strlcasestrn(te->value.data, te->value.data + te->value.len, |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4285 (u_char *) "trailers", 8 - 1) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4286 == NULL) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4287 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4288 v->not_found = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4289 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4290 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4291 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4292 v->valid = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4293 v->no_cacheable = 0; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4294 v->not_found = 0; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4295 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4296 v->data = (u_char *) "trailers"; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4297 v->len = sizeof("trailers") - 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4298 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4299 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4300 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4301 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4302 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4303 static ngx_int_t |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4304 ngx_http_grpc_add_variables(ngx_conf_t *cf) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4305 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4306 ngx_http_variable_t *var, *v; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4307 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4308 for (v = ngx_http_grpc_vars; v->name.len; v++) { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4309 var = ngx_http_add_variable(cf, &v->name, v->flags); |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4310 if (var == NULL) { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4311 return NGX_ERROR; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4312 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4313 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4314 var->get_handler = v->get_handler; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4315 var->data = v->data; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4316 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4317 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4318 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4319 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4320 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4321 |
7233 | 4322 static void * |
4323 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) | |
4324 { | |
4325 ngx_http_grpc_loc_conf_t *conf; | |
4326 | |
4327 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_grpc_loc_conf_t)); | |
4328 if (conf == NULL) { | |
4329 return NULL; | |
4330 } | |
4331 | |
4332 /* | |
4333 * set by ngx_pcalloc(): | |
4334 * | |
4335 * conf->upstream.ignore_headers = 0; | |
4336 * conf->upstream.next_upstream = 0; | |
4337 * conf->upstream.hide_headers_hash = { NULL, 0 }; | |
4338 * conf->upstream.ssl_name = NULL; | |
4339 * | |
4340 * conf->headers.lengths = NULL; | |
4341 * conf->headers.values = NULL; | |
4342 * conf->headers.hash = { NULL, 0 }; | |
4343 * conf->host = { 0, NULL }; | |
4344 * conf->host_set = 0; | |
4345 * conf->ssl = 0; | |
4346 * conf->ssl_protocols = 0; | |
4347 * conf->ssl_ciphers = { 0, NULL }; | |
4348 * conf->ssl_trusted_certificate = { 0, NULL }; | |
4349 * conf->ssl_crl = { 0, NULL }; | |
4350 * conf->ssl_certificate = { 0, NULL }; | |
4351 * conf->ssl_certificate_key = { 0, NULL }; | |
4352 */ | |
4353 | |
4354 conf->upstream.local = NGX_CONF_UNSET_PTR; | |
7371
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4355 conf->upstream.socket_keepalive = NGX_CONF_UNSET; |
7233 | 4356 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; |
4357 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; | |
4358 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; | |
4359 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; | |
4360 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; | |
4361 | |
4362 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; | |
4363 | |
4364 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; | |
4365 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; | |
4366 | |
4367 conf->upstream.intercept_errors = NGX_CONF_UNSET; | |
4368 | |
4369 #if (NGX_HTTP_SSL) | |
4370 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; | |
4371 conf->upstream.ssl_server_name = NGX_CONF_UNSET; | |
4372 conf->upstream.ssl_verify = NGX_CONF_UNSET; | |
4373 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; | |
4374 conf->ssl_passwords = NGX_CONF_UNSET_PTR; | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4375 conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; |
7233 | 4376 #endif |
4377 | |
4378 /* the hardcoded values */ | |
4379 conf->upstream.cyclic_temp_file = 0; | |
4380 conf->upstream.buffering = 0; | |
4381 conf->upstream.ignore_client_abort = 0; | |
4382 conf->upstream.send_lowat = 0; | |
4383 conf->upstream.bufs.num = 0; | |
4384 conf->upstream.busy_buffers_size = 0; | |
4385 conf->upstream.max_temp_file_size = 0; | |
4386 conf->upstream.temp_file_write_size = 0; | |
4387 conf->upstream.pass_request_headers = 1; | |
4388 conf->upstream.pass_request_body = 1; | |
4389 conf->upstream.force_ranges = 0; | |
4390 conf->upstream.pass_trailers = 1; | |
4391 conf->upstream.preserve_output = 1; | |
4392 | |
7728
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4393 conf->headers_source = NGX_CONF_UNSET_PTR; |
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4394 |
7233 | 4395 ngx_str_set(&conf->upstream.module, "grpc"); |
4396 | |
4397 return conf; | |
4398 } | |
4399 | |
4400 | |
4401 static char * | |
4402 ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
4403 { | |
4404 ngx_http_grpc_loc_conf_t *prev = parent; | |
4405 ngx_http_grpc_loc_conf_t *conf = child; | |
4406 | |
4407 ngx_int_t rc; | |
4408 ngx_hash_init_t hash; | |
4409 ngx_http_core_loc_conf_t *clcf; | |
4410 | |
4411 ngx_conf_merge_ptr_value(conf->upstream.local, | |
4412 prev->upstream.local, NULL); | |
4413 | |
7371
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4414 ngx_conf_merge_value(conf->upstream.socket_keepalive, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4415 prev->upstream.socket_keepalive, 0); |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4416 |
7233 | 4417 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, |
4418 prev->upstream.next_upstream_tries, 0); | |
4419 | |
4420 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, | |
4421 prev->upstream.connect_timeout, 60000); | |
4422 | |
4423 ngx_conf_merge_msec_value(conf->upstream.send_timeout, | |
4424 prev->upstream.send_timeout, 60000); | |
4425 | |
4426 ngx_conf_merge_msec_value(conf->upstream.read_timeout, | |
4427 prev->upstream.read_timeout, 60000); | |
4428 | |
4429 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, | |
4430 prev->upstream.next_upstream_timeout, 0); | |
4431 | |
4432 ngx_conf_merge_size_value(conf->upstream.buffer_size, | |
4433 prev->upstream.buffer_size, | |
4434 (size_t) ngx_pagesize); | |
4435 | |
4436 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, | |
4437 prev->upstream.ignore_headers, | |
4438 NGX_CONF_BITMASK_SET); | |
4439 | |
4440 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, | |
4441 prev->upstream.next_upstream, | |
4442 (NGX_CONF_BITMASK_SET | |
4443 |NGX_HTTP_UPSTREAM_FT_ERROR | |
4444 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); | |
4445 | |
4446 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { | |
4447 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET | |
4448 |NGX_HTTP_UPSTREAM_FT_OFF; | |
4449 } | |
4450 | |
4451 ngx_conf_merge_value(conf->upstream.intercept_errors, | |
4452 prev->upstream.intercept_errors, 0); | |
4453 | |
4454 #if (NGX_HTTP_SSL) | |
4455 | |
4456 ngx_conf_merge_value(conf->upstream.ssl_session_reuse, | |
4457 prev->upstream.ssl_session_reuse, 1); | |
4458 | |
4459 ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, | |
4460 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 | |
4461 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); | |
4462 | |
4463 ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, | |
4464 "DEFAULT"); | |
4465 | |
4466 if (conf->upstream.ssl_name == NULL) { | |
4467 conf->upstream.ssl_name = prev->upstream.ssl_name; | |
4468 } | |
4469 | |
4470 ngx_conf_merge_value(conf->upstream.ssl_server_name, | |
4471 prev->upstream.ssl_server_name, 0); | |
4472 ngx_conf_merge_value(conf->upstream.ssl_verify, | |
4473 prev->upstream.ssl_verify, 0); | |
4474 ngx_conf_merge_uint_value(conf->ssl_verify_depth, | |
4475 prev->ssl_verify_depth, 1); | |
4476 ngx_conf_merge_str_value(conf->ssl_trusted_certificate, | |
4477 prev->ssl_trusted_certificate, ""); | |
4478 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); | |
4479 | |
4480 ngx_conf_merge_str_value(conf->ssl_certificate, | |
4481 prev->ssl_certificate, ""); | |
4482 ngx_conf_merge_str_value(conf->ssl_certificate_key, | |
4483 prev->ssl_certificate_key, ""); | |
4484 ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); | |
4485 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4486 ngx_conf_merge_ptr_value(conf->ssl_conf_commands, |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4487 prev->ssl_conf_commands, NULL); |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4488 |
7233 | 4489 if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) { |
4490 return NGX_CONF_ERROR; | |
4491 } | |
4492 | |
4493 #endif | |
4494 | |
4495 hash.max_size = 512; | |
4496 hash.bucket_size = ngx_align(64, ngx_cacheline_size); | |
4497 hash.name = "grpc_headers_hash"; | |
4498 | |
4499 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, | |
4500 &prev->upstream, ngx_http_grpc_hide_headers, &hash) | |
4501 != NGX_OK) | |
4502 { | |
4503 return NGX_CONF_ERROR; | |
4504 } | |
4505 | |
4506 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
4507 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4508 if (clcf->noname |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4509 && conf->upstream.upstream == NULL && conf->grpc_lengths == NULL) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4510 { |
7233 | 4511 conf->upstream.upstream = prev->upstream.upstream; |
4512 conf->host = prev->host; | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4513 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4514 conf->grpc_lengths = prev->grpc_lengths; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4515 conf->grpc_values = prev->grpc_values; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4516 |
7233 | 4517 #if (NGX_HTTP_SSL) |
4518 conf->upstream.ssl = prev->upstream.ssl; | |
4519 #endif | |
4520 } | |
4521 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4522 if (clcf->lmt_excpt && clcf->handler == NULL |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4523 && (conf->upstream.upstream || conf->grpc_lengths)) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4524 { |
7233 | 4525 clcf->handler = ngx_http_grpc_handler; |
4526 } | |
4527 | |
7728
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4528 ngx_conf_merge_ptr_value(conf->headers_source, prev->headers_source, NULL); |
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4529 |
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4530 if (conf->headers_source == prev->headers_source) { |
7233 | 4531 conf->headers = prev->headers; |
4532 conf->host_set = prev->host_set; | |
4533 } | |
4534 | |
4535 rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers, | |
4536 ngx_http_grpc_headers); | |
4537 if (rc != NGX_OK) { | |
4538 return NGX_CONF_ERROR; | |
4539 } | |
4540 | |
4541 /* | |
4542 * special handling to preserve conf->headers in the "http" section | |
4543 * to inherit it to all servers | |
4544 */ | |
4545 | |
4546 if (prev->headers.hash.buckets == NULL | |
4547 && conf->headers_source == prev->headers_source) | |
4548 { | |
4549 prev->headers = conf->headers; | |
4550 prev->host_set = conf->host_set; | |
4551 } | |
4552 | |
4553 return NGX_CONF_OK; | |
4554 } | |
4555 | |
4556 | |
4557 static ngx_int_t | |
4558 ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf, | |
4559 ngx_http_grpc_headers_t *headers, ngx_keyval_t *default_headers) | |
4560 { | |
4561 u_char *p; | |
4562 size_t size; | |
4563 uintptr_t *code; | |
4564 ngx_uint_t i; | |
4565 ngx_array_t headers_names, headers_merged; | |
4566 ngx_keyval_t *src, *s, *h; | |
4567 ngx_hash_key_t *hk; | |
4568 ngx_hash_init_t hash; | |
4569 ngx_http_script_compile_t sc; | |
4570 ngx_http_script_copy_code_t *copy; | |
4571 | |
4572 if (headers->hash.buckets) { | |
4573 return NGX_OK; | |
4574 } | |
4575 | |
4576 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) | |
4577 != NGX_OK) | |
4578 { | |
4579 return NGX_ERROR; | |
4580 } | |
4581 | |
4582 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) | |
4583 != NGX_OK) | |
4584 { | |
4585 return NGX_ERROR; | |
4586 } | |
4587 | |
4588 headers->lengths = ngx_array_create(cf->pool, 64, 1); | |
4589 if (headers->lengths == NULL) { | |
4590 return NGX_ERROR; | |
4591 } | |
4592 | |
4593 headers->values = ngx_array_create(cf->pool, 512, 1); | |
4594 if (headers->values == NULL) { | |
4595 return NGX_ERROR; | |
4596 } | |
4597 | |
4598 if (conf->headers_source) { | |
4599 | |
4600 src = conf->headers_source->elts; | |
4601 for (i = 0; i < conf->headers_source->nelts; i++) { | |
4602 | |
4603 if (src[i].key.len == 4 | |
4604 && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0) | |
4605 { | |
4606 conf->host_set = 1; | |
4607 } | |
4608 | |
4609 s = ngx_array_push(&headers_merged); | |
4610 if (s == NULL) { | |
4611 return NGX_ERROR; | |
4612 } | |
4613 | |
4614 *s = src[i]; | |
4615 } | |
4616 } | |
4617 | |
4618 h = default_headers; | |
4619 | |
4620 while (h->key.len) { | |
4621 | |
4622 src = headers_merged.elts; | |
4623 for (i = 0; i < headers_merged.nelts; i++) { | |
4624 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { | |
4625 goto next; | |
4626 } | |
4627 } | |
4628 | |
4629 s = ngx_array_push(&headers_merged); | |
4630 if (s == NULL) { | |
4631 return NGX_ERROR; | |
4632 } | |
4633 | |
4634 *s = *h; | |
4635 | |
4636 next: | |
4637 | |
4638 h++; | |
4639 } | |
4640 | |
4641 | |
4642 src = headers_merged.elts; | |
4643 for (i = 0; i < headers_merged.nelts; i++) { | |
4644 | |
4645 hk = ngx_array_push(&headers_names); | |
4646 if (hk == NULL) { | |
4647 return NGX_ERROR; | |
4648 } | |
4649 | |
4650 hk->key = src[i].key; | |
4651 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len); | |
4652 hk->value = (void *) 1; | |
4653 | |
4654 if (src[i].value.len == 0) { | |
4655 continue; | |
4656 } | |
4657 | |
4658 copy = ngx_array_push_n(headers->lengths, | |
4659 sizeof(ngx_http_script_copy_code_t)); | |
4660 if (copy == NULL) { | |
4661 return NGX_ERROR; | |
4662 } | |
4663 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
7249
diff
changeset
|
4664 copy->code = (ngx_http_script_code_pt) (void *) |
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
7249
diff
changeset
|
4665 ngx_http_script_copy_len_code; |
7233 | 4666 copy->len = src[i].key.len; |
4667 | |
4668 size = (sizeof(ngx_http_script_copy_code_t) | |
4669 + src[i].key.len + sizeof(uintptr_t) - 1) | |
4670 & ~(sizeof(uintptr_t) - 1); | |
4671 | |
4672 copy = ngx_array_push_n(headers->values, size); | |
4673 if (copy == NULL) { | |
4674 return NGX_ERROR; | |
4675 } | |
4676 | |
4677 copy->code = ngx_http_script_copy_code; | |
4678 copy->len = src[i].key.len; | |
4679 | |
4680 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
4681 ngx_memcpy(p, src[i].key.data, src[i].key.len); | |
4682 | |
4683 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
4684 | |
4685 sc.cf = cf; | |
4686 sc.source = &src[i].value; | |
4687 sc.flushes = &headers->flushes; | |
4688 sc.lengths = &headers->lengths; | |
4689 sc.values = &headers->values; | |
4690 | |
4691 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
4692 return NGX_ERROR; | |
4693 } | |
4694 | |
4695 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); | |
4696 if (code == NULL) { | |
4697 return NGX_ERROR; | |
4698 } | |
4699 | |
4700 *code = (uintptr_t) NULL; | |
4701 | |
4702 code = ngx_array_push_n(headers->values, sizeof(uintptr_t)); | |
4703 if (code == NULL) { | |
4704 return NGX_ERROR; | |
4705 } | |
4706 | |
4707 *code = (uintptr_t) NULL; | |
4708 } | |
4709 | |
4710 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); | |
4711 if (code == NULL) { | |
4712 return NGX_ERROR; | |
4713 } | |
4714 | |
4715 *code = (uintptr_t) NULL; | |
4716 | |
4717 | |
4718 hash.hash = &headers->hash; | |
4719 hash.key = ngx_hash_key_lc; | |
4720 hash.max_size = 512; | |
4721 hash.bucket_size = 64; | |
4722 hash.name = "grpc_headers_hash"; | |
4723 hash.pool = cf->pool; | |
4724 hash.temp_pool = NULL; | |
4725 | |
4726 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); | |
4727 } | |
4728 | |
4729 | |
4730 static char * | |
4731 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
4732 { | |
4733 ngx_http_grpc_loc_conf_t *glcf = conf; | |
4734 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4735 size_t add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4736 ngx_str_t *value, *url; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4737 ngx_url_t u; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4738 ngx_uint_t n; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4739 ngx_http_core_loc_conf_t *clcf; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4740 ngx_http_script_compile_t sc; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4741 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4742 if (glcf->upstream.upstream || glcf->grpc_lengths) { |
7233 | 4743 return "is duplicate"; |
4744 } | |
4745 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4746 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4747 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4748 clcf->handler = ngx_http_grpc_handler; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4749 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4750 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4751 clcf->auto_redirect = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4752 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4753 |
7233 | 4754 value = cf->args->elts; |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4755 |
7233 | 4756 url = &value[1]; |
4757 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4758 n = ngx_http_script_variables_count(url); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4759 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4760 if (n) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4761 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4762 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4763 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4764 sc.cf = cf; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4765 sc.source = url; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4766 sc.lengths = &glcf->grpc_lengths; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4767 sc.values = &glcf->grpc_values; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4768 sc.variables = n; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4769 sc.complete_lengths = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4770 sc.complete_values = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4771 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4772 if (ngx_http_script_compile(&sc) != NGX_OK) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4773 return NGX_CONF_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4774 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4775 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4776 #if (NGX_HTTP_SSL) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4777 glcf->ssl = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4778 #endif |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4779 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4780 return NGX_CONF_OK; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4781 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4782 |
7233 | 4783 if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) { |
4784 add = 7; | |
4785 | |
4786 } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) { | |
4787 | |
4788 #if (NGX_HTTP_SSL) | |
4789 glcf->ssl = 1; | |
4790 | |
4791 add = 8; | |
4792 #else | |
4793 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4794 "grpcs protocol requires SSL support"); | |
4795 return NGX_CONF_ERROR; | |
4796 #endif | |
4797 | |
4798 } else { | |
4799 add = 0; | |
4800 } | |
4801 | |
4802 ngx_memzero(&u, sizeof(ngx_url_t)); | |
4803 | |
4804 u.url.len = url->len - add; | |
4805 u.url.data = url->data + add; | |
4806 u.no_resolve = 1; | |
4807 | |
4808 glcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); | |
4809 if (glcf->upstream.upstream == NULL) { | |
4810 return NGX_CONF_ERROR; | |
4811 } | |
4812 | |
4813 if (u.family != AF_UNIX) { | |
4814 | |
4815 if (u.no_port) { | |
4816 glcf->host = u.host; | |
4817 | |
4818 } else { | |
4819 glcf->host.len = u.host.len + 1 + u.port_text.len; | |
4820 glcf->host.data = u.host.data; | |
4821 } | |
4822 | |
4823 } else { | |
4824 ngx_str_set(&glcf->host, "localhost"); | |
4825 } | |
4826 | |
4827 return NGX_CONF_OK; | |
4828 } | |
4829 | |
4830 | |
4831 #if (NGX_HTTP_SSL) | |
4832 | |
4833 static char * | |
4834 ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
4835 { | |
4836 ngx_http_grpc_loc_conf_t *glcf = conf; | |
4837 | |
4838 ngx_str_t *value; | |
4839 | |
4840 if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) { | |
4841 return "is duplicate"; | |
4842 } | |
4843 | |
4844 value = cf->args->elts; | |
4845 | |
4846 glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); | |
4847 | |
4848 if (glcf->ssl_passwords == NULL) { | |
4849 return NGX_CONF_ERROR; | |
4850 } | |
4851 | |
4852 return NGX_CONF_OK; | |
4853 } | |
4854 | |
4855 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4856 static char * |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4857 ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4858 { |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4859 #ifndef SSL_CONF_FLAG_FILE |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4860 return "is not supported on this platform"; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4861 #endif |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4862 |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4863 return NGX_CONF_OK; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4864 } |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4865 |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4866 |
7233 | 4867 static ngx_int_t |
4868 ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) | |
4869 { | |
4870 ngx_pool_cleanup_t *cln; | |
4871 | |
4872 glcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); | |
4873 if (glcf->upstream.ssl == NULL) { | |
4874 return NGX_ERROR; | |
4875 } | |
4876 | |
4877 glcf->upstream.ssl->log = cf->log; | |
4878 | |
4879 if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL) | |
4880 != NGX_OK) | |
4881 { | |
4882 return NGX_ERROR; | |
4883 } | |
4884 | |
4885 cln = ngx_pool_cleanup_add(cf->pool, 0); | |
4886 if (cln == NULL) { | |
7473
8981dbb12254
SSL: fixed potential leak on memory allocation errors.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7379
diff
changeset
|
4887 ngx_ssl_cleanup_ctx(glcf->upstream.ssl); |
7233 | 4888 return NGX_ERROR; |
4889 } | |
4890 | |
4891 cln->handler = ngx_ssl_cleanup_ctx; | |
4892 cln->data = glcf->upstream.ssl; | |
4893 | |
4894 if (glcf->ssl_certificate.len) { | |
4895 | |
4896 if (glcf->ssl_certificate_key.len == 0) { | |
4897 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
4898 "no \"grpc_ssl_certificate_key\" is defined " | |
4899 "for certificate \"%V\"", &glcf->ssl_certificate); | |
4900 return NGX_ERROR; | |
4901 } | |
4902 | |
4903 if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate, | |
4904 &glcf->ssl_certificate_key, glcf->ssl_passwords) | |
4905 != NGX_OK) | |
4906 { | |
4907 return NGX_ERROR; | |
4908 } | |
4909 } | |
4910 | |
4911 if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) | |
4912 != NGX_OK) | |
4913 { | |
4914 return NGX_ERROR; | |
4915 } | |
4916 | |
4917 if (glcf->upstream.ssl_verify) { | |
4918 if (glcf->ssl_trusted_certificate.len == 0) { | |
4919 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
4920 "no grpc_ssl_trusted_certificate for grpc_ssl_verify"); | |
4921 return NGX_ERROR; | |
4922 } | |
4923 | |
4924 if (ngx_ssl_trusted_certificate(cf, glcf->upstream.ssl, | |
4925 &glcf->ssl_trusted_certificate, | |
4926 glcf->ssl_verify_depth) | |
4927 != NGX_OK) | |
4928 { | |
4929 return NGX_ERROR; | |
4930 } | |
4931 | |
4932 if (ngx_ssl_crl(cf, glcf->upstream.ssl, &glcf->ssl_crl) != NGX_OK) { | |
4933 return NGX_ERROR; | |
4934 } | |
4935 } | |
4936 | |
7320
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4937 if (ngx_ssl_client_session_cache(cf, glcf->upstream.ssl, |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4938 glcf->upstream.ssl_session_reuse) |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4939 != NGX_OK) |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4940 { |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4941 return NGX_ERROR; |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4942 } |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4943 |
7233 | 4944 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation |
4945 | |
4946 if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx, | |
4947 (u_char *) "\x02h2", 3) | |
4948 != 0) | |
4949 { | |
4950 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, | |
4951 "SSL_CTX_set_alpn_protos() failed"); | |
4952 return NGX_ERROR; | |
4953 } | |
4954 | |
4955 #endif | |
4956 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4957 if (ngx_ssl_conf_commands(cf, glcf->upstream.ssl, glcf->ssl_conf_commands) |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4958 != NGX_OK) |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4959 { |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4960 return NGX_ERROR; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4961 } |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4962 |
7233 | 4963 return NGX_OK; |
4964 } | |
4965 | |
4966 #endif |