Mercurial > hg > nginx
annotate src/http/modules/ngx_http_grpc_module.c @ 7736:a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Now "s", "V", and "v" format specifiers may be prefixed with "x" (lowercase)
or "X" (uppercase) to output corresponding data in hexadecimal format.
In collaboration with Maxim Dounin.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 28 Oct 2020 10:56:11 +0300 |
parents | 1a719ee45526 |
children | 88eca63261c3 |
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 | |
7736
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1144 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1145 "grpc header: %*xs%s, len: %uz", |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1146 (size_t) ngx_min(b->last - b->pos, 256), b->pos, |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1147 b->last - b->pos > 256 ? "..." : "", |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1148 b->last - b->pos); |
7233 | 1149 |
1150 if (r->request_body_no_buffering) { | |
1151 | |
1152 u->request_bufs = cl; | |
1153 | |
1154 } else { | |
1155 | |
1156 body = u->request_bufs; | |
1157 u->request_bufs = cl; | |
1158 | |
1159 if (body == NULL) { | |
1160 f = (ngx_http_grpc_frame_t *) headers_frame; | |
1161 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG; | |
1162 } | |
1163 | |
1164 while (body) { | |
1165 b = ngx_alloc_buf(r->pool); | |
1166 if (b == NULL) { | |
1167 return NGX_ERROR; | |
1168 } | |
1169 | |
1170 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); | |
1171 | |
1172 cl->next = ngx_alloc_chain_link(r->pool); | |
1173 if (cl->next == NULL) { | |
1174 return NGX_ERROR; | |
1175 } | |
1176 | |
1177 cl = cl->next; | |
1178 cl->buf = b; | |
1179 | |
1180 body = body->next; | |
1181 } | |
1182 | |
1183 b->last_buf = 1; | |
1184 } | |
1185 | |
1186 u->output.output_filter = ngx_http_grpc_body_output_filter; | |
1187 u->output.filter_ctx = r; | |
1188 | |
1189 b->flush = 1; | |
1190 cl->next = NULL; | |
1191 | |
1192 return NGX_OK; | |
1193 } | |
1194 | |
1195 | |
1196 static ngx_int_t | |
1197 ngx_http_grpc_reinit_request(ngx_http_request_t *r) | |
1198 { | |
1199 ngx_http_grpc_ctx_t *ctx; | |
1200 | |
1201 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); | |
1202 | |
1203 if (ctx == NULL) { | |
1204 return NGX_OK; | |
1205 } | |
1206 | |
1207 ctx->state = 0; | |
1208 ctx->header_sent = 0; | |
1209 ctx->output_closed = 0; | |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1210 ctx->output_blocked = 0; |
7233 | 1211 ctx->parsing_headers = 0; |
1212 ctx->end_stream = 0; | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1213 ctx->done = 0; |
7233 | 1214 ctx->status = 0; |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
1215 ctx->rst = 0; |
7233 | 1216 ctx->connection = NULL; |
1217 | |
1218 return NGX_OK; | |
1219 } | |
1220 | |
1221 | |
1222 static ngx_int_t | |
1223 ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in) | |
1224 { | |
1225 ngx_http_request_t *r = data; | |
1226 | |
1227 off_t file_pos; | |
1228 u_char *p, *pos, *start; | |
1229 size_t len, limit; | |
1230 ngx_buf_t *b; | |
1231 ngx_int_t rc; | |
1232 ngx_uint_t next, last; | |
1233 ngx_chain_t *cl, *out, **ll; | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1234 ngx_http_upstream_t *u; |
7233 | 1235 ngx_http_grpc_ctx_t *ctx; |
1236 ngx_http_grpc_frame_t *f; | |
1237 | |
1238 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1239 "grpc output filter"); | |
1240 | |
1241 ctx = ngx_http_grpc_get_ctx(r); | |
1242 | |
1243 if (ctx == NULL) { | |
1244 return NGX_ERROR; | |
1245 } | |
1246 | |
1247 if (in) { | |
1248 if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { | |
1249 return NGX_ERROR; | |
1250 } | |
1251 } | |
1252 | |
1253 out = NULL; | |
1254 ll = &out; | |
1255 | |
1256 if (!ctx->header_sent) { | |
1257 /* first buffer contains headers */ | |
1258 | |
1259 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1260 "grpc output header"); | |
1261 | |
1262 ctx->header_sent = 1; | |
1263 | |
1264 if (ctx->id != 1) { | |
1265 /* | |
1266 * keepalive connection: skip connection preface, | |
1267 * update stream identifiers | |
1268 */ | |
1269 | |
1270 b = ctx->in->buf; | |
1271 b->pos += sizeof(ngx_http_grpc_connection_start) - 1; | |
1272 | |
1273 p = b->pos; | |
1274 | |
1275 while (p < b->last) { | |
1276 f = (ngx_http_grpc_frame_t *) p; | |
1277 p += sizeof(ngx_http_grpc_frame_t); | |
1278 | |
1279 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1280 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1281 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1282 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1283 | |
1284 p += (f->length_0 << 16) + (f->length_1 << 8) + f->length_2; | |
1285 } | |
1286 } | |
1287 | |
1288 if (ctx->in->buf->last_buf) { | |
1289 ctx->output_closed = 1; | |
1290 } | |
1291 | |
1292 *ll = ctx->in; | |
1293 ll = &ctx->in->next; | |
1294 | |
1295 ctx->in = ctx->in->next; | |
1296 } | |
1297 | |
1298 if (ctx->out) { | |
1299 /* queued control frames */ | |
1300 | |
1301 *ll = ctx->out; | |
1302 | |
1303 for (cl = ctx->out, ll = &cl->next; cl; cl = cl->next) { | |
1304 ll = &cl->next; | |
1305 } | |
1306 | |
1307 ctx->out = NULL; | |
1308 } | |
1309 | |
1310 f = NULL; | |
1311 last = 0; | |
1312 | |
1313 limit = ngx_max(0, ctx->send_window); | |
1314 | |
1315 if (limit > ctx->connection->send_window) { | |
1316 limit = ctx->connection->send_window; | |
1317 } | |
1318 | |
1319 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1320 "grpc output limit: %uz w:%z:%uz", | |
1321 limit, ctx->send_window, ctx->connection->send_window); | |
1322 | |
1323 #if (NGX_SUPPRESS_WARN) | |
1324 file_pos = 0; | |
1325 pos = NULL; | |
1326 cl = NULL; | |
1327 #endif | |
1328 | |
1329 in = ctx->in; | |
1330 | |
1331 while (in && limit > 0) { | |
1332 | |
1333 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, | |
1334 "grpc output in l:%d f:%d %p, pos %p, size: %z " | |
1335 "file: %O, size: %O", | |
1336 in->buf->last_buf, | |
1337 in->buf->in_file, | |
1338 in->buf->start, in->buf->pos, | |
1339 in->buf->last - in->buf->pos, | |
1340 in->buf->file_pos, | |
1341 in->buf->file_last - in->buf->file_pos); | |
1342 | |
1343 if (ngx_buf_special(in->buf)) { | |
1344 goto next; | |
1345 } | |
1346 | |
1347 if (in->buf->in_file) { | |
1348 file_pos = in->buf->file_pos; | |
1349 | |
1350 } else { | |
1351 pos = in->buf->pos; | |
1352 } | |
1353 | |
1354 next = 0; | |
1355 | |
1356 do { | |
1357 | |
1358 cl = ngx_http_grpc_get_buf(r, ctx); | |
1359 if (cl == NULL) { | |
1360 return NGX_ERROR; | |
1361 } | |
1362 | |
1363 b = cl->buf; | |
1364 | |
1365 f = (ngx_http_grpc_frame_t *) b->last; | |
1366 b->last += sizeof(ngx_http_grpc_frame_t); | |
1367 | |
1368 *ll = cl; | |
1369 ll = &cl->next; | |
1370 | |
1371 cl = ngx_chain_get_free_buf(r->pool, &ctx->free); | |
1372 if (cl == NULL) { | |
1373 return NGX_ERROR; | |
1374 } | |
1375 | |
1376 b = cl->buf; | |
1377 start = b->start; | |
1378 | |
1379 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t)); | |
1380 | |
1381 /* | |
1382 * restore b->start to preserve memory allocated in the buffer, | |
1383 * to reuse it later for headers and control frames | |
1384 */ | |
1385 | |
1386 b->start = start; | |
1387 | |
1388 if (in->buf->in_file) { | |
1389 b->file_pos = file_pos; | |
1390 file_pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit); | |
1391 | |
1392 if (file_pos >= in->buf->file_last) { | |
1393 file_pos = in->buf->file_last; | |
1394 next = 1; | |
1395 } | |
1396 | |
1397 b->file_last = file_pos; | |
1398 len = (ngx_uint_t) (file_pos - b->file_pos); | |
1399 | |
1400 } else { | |
1401 b->pos = pos; | |
1402 pos += ngx_min(NGX_HTTP_V2_DEFAULT_FRAME_SIZE, limit); | |
1403 | |
1404 if (pos >= in->buf->last) { | |
1405 pos = in->buf->last; | |
1406 next = 1; | |
1407 } | |
1408 | |
1409 b->last = pos; | |
1410 len = (ngx_uint_t) (pos - b->pos); | |
1411 } | |
1412 | |
1413 b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter; | |
1414 b->shadow = in->buf; | |
1415 b->last_shadow = next; | |
1416 | |
1417 b->last_buf = 0; | |
1418 b->last_in_chain = 0; | |
1419 | |
1420 *ll = cl; | |
1421 ll = &cl->next; | |
1422 | |
1423 f->length_0 = (u_char) ((len >> 16) & 0xff); | |
1424 f->length_1 = (u_char) ((len >> 8) & 0xff); | |
1425 f->length_2 = (u_char) (len & 0xff); | |
1426 f->type = NGX_HTTP_V2_DATA_FRAME; | |
1427 f->flags = 0; | |
1428 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1429 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1430 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1431 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1432 | |
1433 limit -= len; | |
1434 ctx->send_window -= len; | |
1435 ctx->connection->send_window -= len; | |
1436 | |
1437 } while (!next && limit > 0); | |
1438 | |
1439 if (!next) { | |
1440 /* | |
1441 * if the buffer wasn't fully sent due to flow control limits, | |
1442 * preserve position for future use | |
1443 */ | |
1444 | |
1445 if (in->buf->in_file) { | |
1446 in->buf->file_pos = file_pos; | |
1447 | |
1448 } else { | |
1449 in->buf->pos = pos; | |
1450 } | |
1451 | |
1452 break; | |
1453 } | |
1454 | |
1455 next: | |
1456 | |
1457 if (in->buf->last_buf) { | |
1458 last = 1; | |
1459 } | |
1460 | |
1461 in = in->next; | |
1462 } | |
1463 | |
1464 ctx->in = in; | |
1465 | |
1466 if (last) { | |
1467 | |
1468 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1469 "grpc output last"); | |
1470 | |
1471 ctx->output_closed = 1; | |
1472 | |
1473 if (f) { | |
1474 f->flags |= NGX_HTTP_V2_END_STREAM_FLAG; | |
1475 | |
1476 } else { | |
1477 cl = ngx_http_grpc_get_buf(r, ctx); | |
1478 if (cl == NULL) { | |
1479 return NGX_ERROR; | |
1480 } | |
1481 | |
1482 b = cl->buf; | |
1483 | |
1484 f = (ngx_http_grpc_frame_t *) b->last; | |
1485 b->last += sizeof(ngx_http_grpc_frame_t); | |
1486 | |
1487 f->length_0 = 0; | |
1488 f->length_1 = 0; | |
1489 f->length_2 = 0; | |
1490 f->type = NGX_HTTP_V2_DATA_FRAME; | |
1491 f->flags = NGX_HTTP_V2_END_STREAM_FLAG; | |
1492 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
1493 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
1494 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
1495 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
1496 | |
1497 *ll = cl; | |
1498 ll = &cl->next; | |
1499 } | |
1500 | |
1501 cl->buf->last_buf = 1; | |
1502 } | |
1503 | |
1504 *ll = NULL; | |
1505 | |
1506 #if (NGX_DEBUG) | |
1507 | |
1508 for (cl = out; cl; cl = cl->next) { | |
1509 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, | |
1510 "grpc output out l:%d f:%d %p, pos %p, size: %z " | |
1511 "file: %O, size: %O", | |
1512 cl->buf->last_buf, | |
1513 cl->buf->in_file, | |
1514 cl->buf->start, cl->buf->pos, | |
1515 cl->buf->last - cl->buf->pos, | |
1516 cl->buf->file_pos, | |
1517 cl->buf->file_last - cl->buf->file_pos); | |
1518 } | |
1519 | |
1520 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1521 "grpc output limit: %uz w:%z:%uz", | |
1522 limit, ctx->send_window, ctx->connection->send_window); | |
1523 | |
1524 #endif | |
1525 | |
1526 rc = ngx_chain_writer(&r->upstream->writer, out); | |
1527 | |
1528 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, | |
1529 (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter); | |
1530 | |
1531 for (cl = ctx->free; cl; cl = cl->next) { | |
1532 | |
1533 /* mark original buffers as sent */ | |
1534 | |
1535 if (cl->buf->shadow) { | |
1536 if (cl->buf->last_shadow) { | |
1537 b = cl->buf->shadow; | |
1538 b->pos = b->last; | |
1539 } | |
1540 | |
1541 cl->buf->shadow = NULL; | |
1542 } | |
1543 } | |
1544 | |
1545 if (rc == NGX_OK && ctx->in) { | |
1546 rc = NGX_AGAIN; | |
1547 } | |
1548 | |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1549 if (rc == NGX_AGAIN) { |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1550 ctx->output_blocked = 1; |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1551 |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1552 } else { |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1553 ctx->output_blocked = 0; |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1554 } |
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1555 |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1556 if (ctx->done) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1557 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1558 /* |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1559 * 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
|
1560 * control frames. Even if there is still something unsent, stop |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1561 * here anyway. |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1562 */ |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1563 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1564 u = r->upstream; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1565 u->length = 0; |
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 if (ctx->in == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1568 && ctx->out == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1569 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1570 && !ctx->output_blocked |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1571 && ctx->state == ngx_http_grpc_st_start) |
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->keepalive = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1574 } |
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 ngx_post_event(u->peer.connection->read, &ngx_posted_events); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1577 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
1578 |
7233 | 1579 return rc; |
1580 } | |
1581 | |
1582 | |
1583 static ngx_int_t | |
1584 ngx_http_grpc_process_header(ngx_http_request_t *r) | |
1585 { | |
1586 ngx_str_t *status_line; | |
1587 ngx_int_t rc, status; | |
1588 ngx_buf_t *b; | |
1589 ngx_table_elt_t *h; | |
1590 ngx_http_upstream_t *u; | |
1591 ngx_http_grpc_ctx_t *ctx; | |
1592 ngx_http_upstream_header_t *hh; | |
1593 ngx_http_upstream_main_conf_t *umcf; | |
1594 | |
1595 u = r->upstream; | |
1596 b = &u->buffer; | |
1597 | |
7736
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1598 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1599 "grpc response: %*xs%s, len: %uz", |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1600 (size_t) ngx_min(b->last - b->pos, 256), |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1601 b->pos, b->last - b->pos > 256 ? "..." : "", |
a46fcf101cfc
Core: added format specifiers to output binary data as hex.
Vladimir Homutov <vl@nginx.com>
parents:
7730
diff
changeset
|
1602 b->last - b->pos); |
7233 | 1603 |
1604 ctx = ngx_http_grpc_get_ctx(r); | |
1605 | |
1606 if (ctx == NULL) { | |
1607 return NGX_ERROR; | |
1608 } | |
1609 | |
1610 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); | |
1611 | |
1612 for ( ;; ) { | |
1613 | |
1614 if (ctx->state < ngx_http_grpc_st_payload) { | |
1615 | |
1616 rc = ngx_http_grpc_parse_frame(r, ctx, b); | |
1617 | |
1618 if (rc == NGX_AGAIN) { | |
1619 | |
1620 /* | |
1621 * there can be a lot of window update frames, | |
1622 * so we reset buffer if it is empty and we haven't | |
1623 * started parsing headers yet | |
1624 */ | |
1625 | |
1626 if (!ctx->parsing_headers) { | |
1627 b->pos = b->start; | |
1628 b->last = b->pos; | |
1629 } | |
1630 | |
1631 return NGX_AGAIN; | |
1632 } | |
1633 | |
1634 if (rc == NGX_ERROR) { | |
1635 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1636 } | |
1637 | |
1638 /* | |
1639 * RFC 7540 says that implementations MUST discard frames | |
1640 * that have unknown or unsupported types. However, extension | |
1641 * frames that appear in the middle of a header block are | |
1642 * not permitted. Also, for obvious reasons CONTINUATION frames | |
1643 * cannot appear before headers, and DATA frames are not expected | |
1644 * to appear before all headers are parsed. | |
1645 */ | |
1646 | |
1647 if (ctx->type == NGX_HTTP_V2_DATA_FRAME | |
1648 || (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME | |
1649 && !ctx->parsing_headers) | |
1650 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME | |
1651 && ctx->parsing_headers)) | |
1652 { | |
1653 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1654 "upstream sent unexpected http2 frame: %d", | |
1655 ctx->type); | |
1656 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1657 } | |
1658 | |
1659 if (ctx->stream_id && ctx->stream_id != ctx->id) { | |
1660 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1661 "upstream sent frame for unknown stream %ui", | |
1662 ctx->stream_id); | |
1663 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1664 } | |
1665 } | |
1666 | |
1667 /* frame payload */ | |
1668 | |
1669 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) { | |
1670 | |
1671 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b); | |
1672 | |
1673 if (rc == NGX_AGAIN) { | |
1674 return NGX_AGAIN; | |
1675 } | |
1676 | |
1677 if (rc == NGX_ERROR) { | |
1678 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1679 } | |
1680 | |
1681 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1682 "upstream rejected request with error %ui", | |
1683 ctx->error); | |
1684 | |
1685 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1686 } | |
1687 | |
1688 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { | |
1689 | |
1690 rc = ngx_http_grpc_parse_goaway(r, ctx, b); | |
1691 | |
1692 if (rc == NGX_AGAIN) { | |
1693 return NGX_AGAIN; | |
1694 } | |
1695 | |
1696 if (rc == NGX_ERROR) { | |
1697 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1698 } | |
1699 | |
1700 /* | |
1701 * If stream_id is lower than one we use, our | |
1702 * request won't be processed and needs to be retried. | |
1703 * If stream_id is greater or equal to the one we use, | |
1704 * we can continue normally (except we can't use this | |
1705 * connection for additional requests). If there is | |
1706 * a real error, the connection will be closed. | |
1707 */ | |
1708 | |
1709 if (ctx->stream_id < ctx->id) { | |
1710 | |
1711 /* TODO: we can retry non-idempotent requests */ | |
1712 | |
1713 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1714 "upstream sent goaway with error %ui", | |
1715 ctx->error); | |
1716 | |
1717 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1718 } | |
1719 | |
1720 continue; | |
1721 } | |
1722 | |
1723 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) { | |
1724 | |
1725 rc = ngx_http_grpc_parse_window_update(r, ctx, b); | |
1726 | |
1727 if (rc == NGX_AGAIN) { | |
1728 return NGX_AGAIN; | |
1729 } | |
1730 | |
1731 if (rc == NGX_ERROR) { | |
1732 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1733 } | |
1734 | |
1735 if (ctx->in) { | |
1736 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1737 } | |
1738 | |
1739 continue; | |
1740 } | |
1741 | |
1742 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) { | |
1743 | |
1744 rc = ngx_http_grpc_parse_settings(r, ctx, b); | |
1745 | |
1746 if (rc == NGX_AGAIN) { | |
1747 return NGX_AGAIN; | |
1748 } | |
1749 | |
1750 if (rc == NGX_ERROR) { | |
1751 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1752 } | |
1753 | |
1754 if (ctx->in) { | |
1755 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1756 } | |
1757 | |
1758 continue; | |
1759 } | |
1760 | |
1761 if (ctx->type == NGX_HTTP_V2_PING_FRAME) { | |
1762 | |
1763 rc = ngx_http_grpc_parse_ping(r, ctx, b); | |
1764 | |
1765 if (rc == NGX_AGAIN) { | |
1766 return NGX_AGAIN; | |
1767 } | |
1768 | |
1769 if (rc == NGX_ERROR) { | |
1770 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1771 } | |
1772 | |
1773 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
1774 continue; | |
1775 } | |
1776 | |
1777 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { | |
1778 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1779 "upstream sent unexpected push promise frame"); | |
1780 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1781 } | |
1782 | |
1783 if (ctx->type != NGX_HTTP_V2_HEADERS_FRAME | |
1784 && ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME) | |
1785 { | |
1786 /* priority, unknown frames */ | |
1787 | |
1788 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
1789 ctx->rest -= b->last - b->pos; | |
1790 b->pos = b->last; | |
1791 return NGX_AGAIN; | |
1792 } | |
1793 | |
1794 b->pos += ctx->rest; | |
1795 ctx->rest = 0; | |
1796 ctx->state = ngx_http_grpc_st_start; | |
1797 | |
1798 continue; | |
1799 } | |
1800 | |
1801 /* headers */ | |
1802 | |
1803 for ( ;; ) { | |
1804 | |
1805 rc = ngx_http_grpc_parse_header(r, ctx, b); | |
1806 | |
1807 if (rc == NGX_AGAIN) { | |
1808 break; | |
1809 } | |
1810 | |
1811 if (rc == NGX_OK) { | |
1812 | |
1813 /* a header line has been parsed successfully */ | |
1814 | |
1815 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1816 "grpc header: \"%V: %V\"", | |
1817 &ctx->name, &ctx->value); | |
1818 | |
1819 if (ctx->name.len && ctx->name.data[0] == ':') { | |
1820 | |
1821 if (ctx->name.len != sizeof(":status") - 1 | |
1822 || ngx_strncmp(ctx->name.data, ":status", | |
1823 sizeof(":status") - 1) | |
1824 != 0) | |
1825 { | |
1826 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1827 "upstream sent invalid header \"%V: %V\"", | |
1828 &ctx->name, &ctx->value); | |
1829 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1830 } | |
1831 | |
1832 if (ctx->status) { | |
1833 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1834 "upstream sent duplicate :status header"); | |
1835 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1836 } | |
1837 | |
1838 status_line = &ctx->value; | |
1839 | |
1840 if (status_line->len != 3) { | |
1841 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1842 "upstream sent invalid :status \"%V\"", | |
1843 status_line); | |
1844 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1845 } | |
1846 | |
1847 status = ngx_atoi(status_line->data, 3); | |
1848 | |
1849 if (status == NGX_ERROR) { | |
1850 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1851 "upstream sent invalid :status \"%V\"", | |
1852 status_line); | |
1853 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1854 } | |
1855 | |
1856 if (status < NGX_HTTP_OK) { | |
1857 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1858 "upstream sent unexpected :status \"%V\"", | |
1859 status_line); | |
1860 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1861 } | |
1862 | |
1863 u->headers_in.status_n = status; | |
1864 | |
1865 if (u->state && u->state->status == 0) { | |
1866 u->state->status = status; | |
1867 } | |
1868 | |
1869 ctx->status = 1; | |
1870 | |
1871 continue; | |
1872 | |
1873 } else if (!ctx->status) { | |
1874 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1875 "upstream sent no :status header"); | |
1876 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1877 } | |
1878 | |
1879 h = ngx_list_push(&u->headers_in.headers); | |
1880 if (h == NULL) { | |
1881 return NGX_ERROR; | |
1882 } | |
1883 | |
1884 h->key = ctx->name; | |
1885 h->value = ctx->value; | |
1886 h->lowcase_key = h->key.data; | |
1887 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
1888 | |
1889 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, | |
1890 h->lowcase_key, h->key.len); | |
1891 | |
1892 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { | |
1893 return NGX_ERROR; | |
1894 } | |
1895 | |
1896 continue; | |
1897 } | |
1898 | |
1899 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
1900 | |
1901 /* a whole header has been parsed successfully */ | |
1902 | |
1903 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1904 "grpc header done"); | |
1905 | |
7235
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1906 if (ctx->end_stream) { |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1907 u->headers_in.content_length_n = 0; |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1908 |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1909 if (ctx->in == NULL |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1910 && ctx->out == NULL |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1911 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
1912 && !ctx->output_blocked |
7235
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1913 && b->last == b->pos) |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1914 { |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1915 u->keepalive = 1; |
c2a0a838c40f
gRPC: special handling of "trailer only" responses.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7234
diff
changeset
|
1916 } |
7233 | 1917 } |
1918 | |
1919 return NGX_OK; | |
1920 } | |
1921 | |
1922 /* there was error while a header line parsing */ | |
1923 | |
1924 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1925 "upstream sent invalid header"); | |
1926 | |
1927 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1928 } | |
1929 | |
1930 /* rc == NGX_AGAIN */ | |
1931 | |
1932 if (ctx->rest == 0) { | |
1933 ctx->state = ngx_http_grpc_st_start; | |
1934 continue; | |
1935 } | |
1936 | |
1937 return NGX_AGAIN; | |
1938 } | |
1939 } | |
1940 | |
1941 | |
1942 static ngx_int_t | |
1943 ngx_http_grpc_filter_init(void *data) | |
1944 { | |
1945 ngx_http_grpc_ctx_t *ctx = data; | |
1946 | |
1947 ngx_http_request_t *r; | |
1948 ngx_http_upstream_t *u; | |
1949 | |
1950 r = ctx->request; | |
1951 u = r->upstream; | |
1952 | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1953 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
|
1954 || 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
|
1955 || r->method == NGX_HTTP_HEAD) |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1956 { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1957 ctx->length = 0; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1958 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1959 } else { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1960 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
|
1961 } |
7233 | 1962 |
1963 if (ctx->end_stream) { | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1964 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1965 if (ctx->length > 0) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1966 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
|
1967 "upstream prematurely closed stream"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1968 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1969 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1970 |
7233 | 1971 u->length = 0; |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1972 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1973 } else { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
1974 u->length = 1; |
7233 | 1975 } |
1976 | |
1977 return NGX_OK; | |
1978 } | |
1979 | |
1980 | |
1981 static ngx_int_t | |
1982 ngx_http_grpc_filter(void *data, ssize_t bytes) | |
1983 { | |
1984 ngx_http_grpc_ctx_t *ctx = data; | |
1985 | |
1986 ngx_int_t rc; | |
1987 ngx_buf_t *b, *buf; | |
1988 ngx_chain_t *cl, **ll; | |
1989 ngx_table_elt_t *h; | |
1990 ngx_http_request_t *r; | |
1991 ngx_http_upstream_t *u; | |
1992 | |
1993 r = ctx->request; | |
1994 u = r->upstream; | |
1995 b = &u->buffer; | |
1996 | |
1997 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1998 "grpc filter bytes:%z", bytes); | |
1999 | |
2000 b->pos = b->last; | |
2001 b->last += bytes; | |
2002 | |
2003 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) { | |
2004 ll = &cl->next; | |
2005 } | |
2006 | |
2007 for ( ;; ) { | |
2008 | |
2009 if (ctx->state < ngx_http_grpc_st_payload) { | |
2010 | |
2011 rc = ngx_http_grpc_parse_frame(r, ctx, b); | |
2012 | |
2013 if (rc == NGX_AGAIN) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2014 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2015 if (ctx->done) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2016 |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2017 if (ctx->length > 0) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2018 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
|
2019 "upstream prematurely closed stream"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2020 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2021 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2022 |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2023 /* |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2024 * We have finished parsing the response and the |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2025 * remaining control frames. If there are unsent |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2026 * control frames, post a write event to send them. |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2027 */ |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2028 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2029 if (ctx->out) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2030 ngx_post_event(u->peer.connection->write, |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2031 &ngx_posted_events); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2032 return NGX_AGAIN; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2033 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2034 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2035 u->length = 0; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2036 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2037 if (ctx->in == NULL |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2038 && ctx->output_closed |
7350
67c6cb7f477c
gRPC: disabled keepalive when sending control frames was blocked.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7349
diff
changeset
|
2039 && !ctx->output_blocked |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2040 && ctx->state == ngx_http_grpc_st_start) |
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 u->keepalive = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2043 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2044 |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2045 break; |
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 |
7233 | 2048 return NGX_AGAIN; |
2049 } | |
2050 | |
2051 if (rc == NGX_ERROR) { | |
2052 return NGX_ERROR; | |
2053 } | |
2054 | |
2055 if ((ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME | |
2056 && !ctx->parsing_headers) | |
2057 || (ctx->type != NGX_HTTP_V2_CONTINUATION_FRAME | |
2058 && ctx->parsing_headers)) | |
2059 { | |
2060 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2061 "upstream sent unexpected http2 frame: %d", | |
2062 ctx->type); | |
2063 return NGX_ERROR; | |
2064 } | |
2065 | |
2066 if (ctx->type == NGX_HTTP_V2_DATA_FRAME) { | |
2067 | |
2068 if (ctx->stream_id != ctx->id) { | |
2069 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2070 "upstream sent data frame " | |
2071 "for unknown stream %ui", | |
2072 ctx->stream_id); | |
2073 return NGX_ERROR; | |
2074 } | |
2075 | |
7680
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2076 if (ctx->length != -1) { |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2077 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
|
2078 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
|
2079 "upstream sent response body larger " |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2080 "than indicated content length"); |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2081 return NGX_ERROR; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2082 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2083 |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2084 ctx->length -= ctx->rest; |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2085 } |
39501ce97e29
gRPC: generate error when response size is wrong.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7647
diff
changeset
|
2086 |
7233 | 2087 if (ctx->rest > ctx->recv_window) { |
2088 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2089 "upstream violated stream flow control, " | |
2090 "received %uz data frame with window %uz", | |
2091 ctx->rest, ctx->recv_window); | |
2092 return NGX_ERROR; | |
2093 } | |
2094 | |
2095 if (ctx->rest > ctx->connection->recv_window) { | |
2096 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2097 "upstream violated connection flow control, " | |
2098 "received %uz data frame with window %uz", | |
2099 ctx->rest, ctx->connection->recv_window); | |
2100 return NGX_ERROR; | |
2101 } | |
2102 | |
2103 ctx->recv_window -= ctx->rest; | |
2104 ctx->connection->recv_window -= ctx->rest; | |
2105 | |
2106 if (ctx->connection->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4 | |
2107 || ctx->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) | |
2108 { | |
2109 if (ngx_http_grpc_send_window_update(r, ctx) != NGX_OK) { | |
2110 return NGX_ERROR; | |
2111 } | |
2112 | |
2113 ngx_post_event(u->peer.connection->write, | |
2114 &ngx_posted_events); | |
2115 } | |
2116 } | |
2117 | |
2118 if (ctx->stream_id && ctx->stream_id != ctx->id) { | |
2119 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2120 "upstream sent frame for unknown stream %ui", | |
2121 ctx->stream_id); | |
2122 return NGX_ERROR; | |
2123 } | |
2124 | |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2125 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
|
2126 && 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
|
2127 && 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
|
2128 { |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2129 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2130 "upstream sent frame for closed stream %ui", |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2131 ctx->stream_id); |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2132 return NGX_ERROR; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2133 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2134 |
7233 | 2135 ctx->padding = 0; |
2136 } | |
2137 | |
2138 if (ctx->state == ngx_http_grpc_st_padding) { | |
2139 | |
2140 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2141 ctx->rest -= b->last - b->pos; | |
2142 b->pos = b->last; | |
2143 return NGX_AGAIN; | |
2144 } | |
2145 | |
2146 b->pos += ctx->rest; | |
2147 ctx->rest = 0; | |
2148 ctx->state = ngx_http_grpc_st_start; | |
2149 | |
2150 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2151 ctx->done = 1; |
7233 | 2152 } |
2153 | |
2154 continue; | |
2155 } | |
2156 | |
2157 /* frame payload */ | |
2158 | |
2159 if (ctx->type == NGX_HTTP_V2_RST_STREAM_FRAME) { | |
2160 | |
2161 rc = ngx_http_grpc_parse_rst_stream(r, ctx, b); | |
2162 | |
2163 if (rc == NGX_AGAIN) { | |
2164 return NGX_AGAIN; | |
2165 } | |
2166 | |
2167 if (rc == NGX_ERROR) { | |
2168 return NGX_ERROR; | |
2169 } | |
2170 | |
7646
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2171 if (ctx->error || !ctx->done) { |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2172 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
|
2173 "upstream rejected request with error %ui", |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2174 ctx->error); |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2175 return NGX_ERROR; |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2176 } |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2177 |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2178 if (ctx->rst) { |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2179 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
|
2180 "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
|
2181 ctx->stream_id); |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2182 return NGX_ERROR; |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2183 } |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2184 |
2096b21fcd10
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov <ru@nginx.com>
parents:
7619
diff
changeset
|
2185 ctx->rst = 1; |
7233 | 2186 } |
2187 | |
2188 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { | |
2189 | |
2190 rc = ngx_http_grpc_parse_goaway(r, ctx, b); | |
2191 | |
2192 if (rc == NGX_AGAIN) { | |
2193 return NGX_AGAIN; | |
2194 } | |
2195 | |
2196 if (rc == NGX_ERROR) { | |
2197 return NGX_ERROR; | |
2198 } | |
2199 | |
2200 /* | |
2201 * If stream_id is lower than one we use, our | |
2202 * request won't be processed and needs to be retried. | |
2203 * If stream_id is greater or equal to the one we use, | |
2204 * we can continue normally (except we can't use this | |
2205 * connection for additional requests). If there is | |
2206 * a real error, the connection will be closed. | |
2207 */ | |
2208 | |
2209 if (ctx->stream_id < ctx->id) { | |
2210 | |
2211 /* TODO: we can retry non-idempotent requests */ | |
2212 | |
2213 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2214 "upstream sent goaway with error %ui", | |
2215 ctx->error); | |
2216 | |
2217 return NGX_ERROR; | |
2218 } | |
2219 | |
2220 continue; | |
2221 } | |
2222 | |
2223 if (ctx->type == NGX_HTTP_V2_WINDOW_UPDATE_FRAME) { | |
2224 | |
2225 rc = ngx_http_grpc_parse_window_update(r, ctx, b); | |
2226 | |
2227 if (rc == NGX_AGAIN) { | |
2228 return NGX_AGAIN; | |
2229 } | |
2230 | |
2231 if (rc == NGX_ERROR) { | |
2232 return NGX_ERROR; | |
2233 } | |
2234 | |
2235 if (ctx->in) { | |
2236 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2237 } | |
2238 | |
2239 continue; | |
2240 } | |
2241 | |
2242 if (ctx->type == NGX_HTTP_V2_SETTINGS_FRAME) { | |
2243 | |
2244 rc = ngx_http_grpc_parse_settings(r, ctx, b); | |
2245 | |
2246 if (rc == NGX_AGAIN) { | |
2247 return NGX_AGAIN; | |
2248 } | |
2249 | |
2250 if (rc == NGX_ERROR) { | |
2251 return NGX_ERROR; | |
2252 } | |
2253 | |
2254 if (ctx->in) { | |
2255 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2256 } | |
2257 | |
2258 continue; | |
2259 } | |
2260 | |
2261 if (ctx->type == NGX_HTTP_V2_PING_FRAME) { | |
2262 | |
2263 rc = ngx_http_grpc_parse_ping(r, ctx, b); | |
2264 | |
2265 if (rc == NGX_AGAIN) { | |
2266 return NGX_AGAIN; | |
2267 } | |
2268 | |
2269 if (rc == NGX_ERROR) { | |
2270 return NGX_ERROR; | |
2271 } | |
2272 | |
2273 ngx_post_event(u->peer.connection->write, &ngx_posted_events); | |
2274 continue; | |
2275 } | |
2276 | |
2277 if (ctx->type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { | |
2278 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2279 "upstream sent unexpected push promise frame"); | |
2280 return NGX_ERROR; | |
2281 } | |
2282 | |
2283 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME | |
2284 || ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) | |
2285 { | |
2286 for ( ;; ) { | |
2287 | |
2288 rc = ngx_http_grpc_parse_header(r, ctx, b); | |
2289 | |
2290 if (rc == NGX_AGAIN) { | |
2291 break; | |
2292 } | |
2293 | |
2294 if (rc == NGX_OK) { | |
2295 | |
2296 /* a header line has been parsed successfully */ | |
2297 | |
2298 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2299 "grpc trailer: \"%V: %V\"", | |
2300 &ctx->name, &ctx->value); | |
2301 | |
2302 if (ctx->name.len && ctx->name.data[0] == ':') { | |
2303 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2304 "upstream sent invalid " | |
2305 "trailer \"%V: %V\"", | |
2306 &ctx->name, &ctx->value); | |
2307 return NGX_ERROR; | |
2308 } | |
2309 | |
2310 h = ngx_list_push(&u->headers_in.trailers); | |
2311 if (h == NULL) { | |
2312 return NGX_ERROR; | |
2313 } | |
2314 | |
2315 h->key = ctx->name; | |
2316 h->value = ctx->value; | |
2317 h->lowcase_key = h->key.data; | |
2318 h->hash = ngx_hash_key(h->key.data, h->key.len); | |
2319 | |
2320 continue; | |
2321 } | |
2322 | |
2323 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
2324 | |
2325 /* a whole header has been parsed successfully */ | |
2326 | |
2327 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2328 "grpc trailer done"); | |
2329 | |
2330 if (ctx->end_stream) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2331 ctx->done = 1; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2332 break; |
7233 | 2333 } |
2334 | |
2335 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2336 "upstream sent trailer without " | |
2337 "end stream flag"); | |
2338 return NGX_ERROR; | |
2339 } | |
2340 | |
2341 /* there was error while a header line parsing */ | |
2342 | |
2343 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2344 "upstream sent invalid trailer"); | |
2345 | |
2346 return NGX_ERROR; | |
2347 } | |
2348 | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2349 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2350 continue; |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2351 } |
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2352 |
7233 | 2353 /* rc == NGX_AGAIN */ |
2354 | |
2355 if (ctx->rest == 0) { | |
2356 ctx->state = ngx_http_grpc_st_start; | |
2357 continue; | |
2358 } | |
2359 | |
2360 return NGX_AGAIN; | |
2361 } | |
2362 | |
2363 if (ctx->type != NGX_HTTP_V2_DATA_FRAME) { | |
2364 | |
2365 /* priority, unknown frames */ | |
2366 | |
2367 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2368 ctx->rest -= b->last - b->pos; | |
2369 b->pos = b->last; | |
2370 return NGX_AGAIN; | |
2371 } | |
2372 | |
2373 b->pos += ctx->rest; | |
2374 ctx->rest = 0; | |
2375 ctx->state = ngx_http_grpc_st_start; | |
2376 | |
2377 continue; | |
2378 } | |
2379 | |
2380 /* | |
2381 * data frame: | |
2382 * | |
2383 * +---------------+ | |
2384 * |Pad Length? (8)| | |
2385 * +---------------+-----------------------------------------------+ | |
2386 * | Data (*) ... | |
2387 * +---------------------------------------------------------------+ | |
2388 * | Padding (*) ... | |
2389 * +---------------------------------------------------------------+ | |
2390 */ | |
2391 | |
2392 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) { | |
2393 | |
2394 if (ctx->rest == 0) { | |
2395 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2396 "upstream sent too short http2 frame"); | |
2397 return NGX_ERROR; | |
2398 } | |
2399 | |
2400 if (b->pos == b->last) { | |
2401 return NGX_AGAIN; | |
2402 } | |
2403 | |
2404 ctx->flags &= ~NGX_HTTP_V2_PADDED_FLAG; | |
2405 ctx->padding = *b->pos++; | |
2406 ctx->rest -= 1; | |
2407 | |
2408 if (ctx->padding > ctx->rest) { | |
2409 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2410 "upstream sent http2 frame with too long " | |
2411 "padding: %d in frame %uz", | |
2412 ctx->padding, ctx->rest); | |
2413 return NGX_ERROR; | |
2414 } | |
2415 | |
2416 continue; | |
2417 } | |
2418 | |
2419 if (ctx->rest == ctx->padding) { | |
2420 goto done; | |
2421 } | |
2422 | |
2423 if (b->pos == b->last) { | |
2424 return NGX_AGAIN; | |
2425 } | |
2426 | |
2427 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); | |
2428 if (cl == NULL) { | |
2429 return NGX_ERROR; | |
2430 } | |
2431 | |
2432 *ll = cl; | |
2433 ll = &cl->next; | |
2434 | |
2435 buf = cl->buf; | |
2436 | |
2437 buf->flush = 1; | |
2438 buf->memory = 1; | |
2439 | |
2440 buf->pos = b->pos; | |
2441 buf->tag = u->output.tag; | |
2442 | |
2443 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2444 "grpc output buf %p", buf->pos); | |
2445 | |
2446 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) { | |
2447 | |
2448 ctx->rest -= b->last - b->pos; | |
2449 b->pos = b->last; | |
2450 buf->last = b->pos; | |
2451 | |
2452 return NGX_AGAIN; | |
2453 } | |
2454 | |
2455 b->pos += ctx->rest - ctx->padding; | |
2456 buf->last = b->pos; | |
2457 ctx->rest = ctx->padding; | |
2458 | |
2459 done: | |
2460 | |
2461 if (ctx->padding) { | |
2462 ctx->state = ngx_http_grpc_st_padding; | |
2463 continue; | |
2464 } | |
2465 | |
2466 ctx->state = ngx_http_grpc_st_start; | |
2467 | |
2468 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
7349
f6047a579ca1
gRPC: improved keepalive handling.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7321
diff
changeset
|
2469 ctx->done = 1; |
7233 | 2470 } |
2471 } | |
2472 | |
2473 return NGX_OK; | |
2474 } | |
2475 | |
2476 | |
2477 static ngx_int_t | |
2478 ngx_http_grpc_parse_frame(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2479 ngx_buf_t *b) | |
2480 { | |
2481 u_char ch, *p; | |
2482 ngx_http_grpc_state_e state; | |
2483 | |
2484 state = ctx->state; | |
2485 | |
2486 for (p = b->pos; p < b->last; p++) { | |
2487 ch = *p; | |
2488 | |
2489 #if 0 | |
2490 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2491 "grpc frame byte: %02Xd, s:%d", ch, state); | |
2492 #endif | |
2493 | |
2494 switch (state) { | |
2495 | |
2496 case ngx_http_grpc_st_start: | |
2497 ctx->rest = ch << 16; | |
2498 state = ngx_http_grpc_st_length_2; | |
2499 break; | |
2500 | |
2501 case ngx_http_grpc_st_length_2: | |
2502 ctx->rest |= ch << 8; | |
2503 state = ngx_http_grpc_st_length_3; | |
2504 break; | |
2505 | |
2506 case ngx_http_grpc_st_length_3: | |
2507 ctx->rest |= ch; | |
2508 | |
2509 if (ctx->rest > NGX_HTTP_V2_DEFAULT_FRAME_SIZE) { | |
2510 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2511 "upstream sent too large http2 frame: %uz", | |
2512 ctx->rest); | |
2513 return NGX_ERROR; | |
2514 } | |
2515 | |
2516 state = ngx_http_grpc_st_type; | |
2517 break; | |
2518 | |
2519 case ngx_http_grpc_st_type: | |
2520 ctx->type = ch; | |
2521 state = ngx_http_grpc_st_flags; | |
2522 break; | |
2523 | |
2524 case ngx_http_grpc_st_flags: | |
2525 ctx->flags = ch; | |
2526 state = ngx_http_grpc_st_stream_id; | |
2527 break; | |
2528 | |
2529 case ngx_http_grpc_st_stream_id: | |
2530 ctx->stream_id = (ch & 0x7f) << 24; | |
2531 state = ngx_http_grpc_st_stream_id_2; | |
2532 break; | |
2533 | |
2534 case ngx_http_grpc_st_stream_id_2: | |
2535 ctx->stream_id |= ch << 16; | |
2536 state = ngx_http_grpc_st_stream_id_3; | |
2537 break; | |
2538 | |
2539 case ngx_http_grpc_st_stream_id_3: | |
2540 ctx->stream_id |= ch << 8; | |
2541 state = ngx_http_grpc_st_stream_id_4; | |
2542 break; | |
2543 | |
2544 case ngx_http_grpc_st_stream_id_4: | |
2545 ctx->stream_id |= ch; | |
2546 | |
2547 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2548 "grpc frame: %d, len: %uz, f:%d, i:%ui", | |
2549 ctx->type, ctx->rest, ctx->flags, ctx->stream_id); | |
2550 | |
2551 b->pos = p + 1; | |
2552 | |
2553 ctx->state = ngx_http_grpc_st_payload; | |
2554 ctx->frame_state = 0; | |
2555 | |
2556 return NGX_OK; | |
2557 | |
2558 /* suppress warning */ | |
2559 case ngx_http_grpc_st_payload: | |
2560 case ngx_http_grpc_st_padding: | |
2561 break; | |
2562 } | |
2563 } | |
2564 | |
2565 b->pos = p; | |
2566 ctx->state = state; | |
2567 | |
2568 return NGX_AGAIN; | |
2569 } | |
2570 | |
2571 | |
2572 static ngx_int_t | |
2573 ngx_http_grpc_parse_header(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2574 ngx_buf_t *b) | |
2575 { | |
2576 u_char ch, *p, *last; | |
2577 size_t min; | |
2578 ngx_int_t rc; | |
2579 enum { | |
2580 sw_start = 0, | |
2581 sw_padding_length, | |
2582 sw_dependency, | |
2583 sw_dependency_2, | |
2584 sw_dependency_3, | |
2585 sw_dependency_4, | |
2586 sw_weight, | |
2587 sw_fragment, | |
2588 sw_padding | |
2589 } state; | |
2590 | |
2591 state = ctx->frame_state; | |
2592 | |
2593 if (state == sw_start) { | |
2594 | |
2595 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2596 "grpc parse header: start"); | |
2597 | |
2598 if (ctx->type == NGX_HTTP_V2_HEADERS_FRAME) { | |
2599 ctx->parsing_headers = 1; | |
2600 ctx->fragment_state = 0; | |
2601 | |
2602 min = (ctx->flags & NGX_HTTP_V2_PADDED_FLAG ? 1 : 0) | |
2603 + (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG ? 5 : 0); | |
2604 | |
2605 if (ctx->rest < min) { | |
2606 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2607 "upstream sent headers frame " | |
2608 "with invalid length: %uz", | |
2609 ctx->rest); | |
2610 return NGX_ERROR; | |
2611 } | |
2612 | |
2613 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | |
2614 ctx->end_stream = 1; | |
2615 } | |
2616 | |
2617 if (ctx->flags & NGX_HTTP_V2_PADDED_FLAG) { | |
2618 state = sw_padding_length; | |
2619 | |
2620 } else if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) { | |
2621 state = sw_dependency; | |
2622 | |
2623 } else { | |
2624 state = sw_fragment; | |
2625 } | |
2626 | |
2627 } else if (ctx->type == NGX_HTTP_V2_CONTINUATION_FRAME) { | |
2628 state = sw_fragment; | |
2629 } | |
2630 | |
2631 ctx->padding = 0; | |
7242
25a4353633a0
gRPC: fixed missing state save in frame header parsing.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7240
diff
changeset
|
2632 ctx->frame_state = state; |
7233 | 2633 } |
2634 | |
2635 if (state < sw_fragment) { | |
2636 | |
2637 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2638 last = b->last; | |
2639 | |
2640 } else { | |
2641 last = b->pos + ctx->rest; | |
2642 } | |
2643 | |
2644 for (p = b->pos; p < last; p++) { | |
2645 ch = *p; | |
2646 | |
2647 #if 0 | |
2648 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2649 "grpc header byte: %02Xd s:%d", ch, state); | |
2650 #endif | |
2651 | |
2652 /* | |
2653 * headers frame: | |
2654 * | |
2655 * +---------------+ | |
2656 * |Pad Length? (8)| | |
2657 * +-+-------------+----------------------------------------------+ | |
2658 * |E| Stream Dependency? (31) | | |
2659 * +-+-------------+----------------------------------------------+ | |
2660 * | Weight? (8) | | |
2661 * +-+-------------+----------------------------------------------+ | |
2662 * | Header Block Fragment (*) ... | |
2663 * +--------------------------------------------------------------+ | |
2664 * | Padding (*) ... | |
2665 * +--------------------------------------------------------------+ | |
2666 */ | |
2667 | |
2668 switch (state) { | |
2669 | |
2670 case sw_padding_length: | |
2671 | |
2672 ctx->padding = ch; | |
2673 | |
2674 if (ctx->flags & NGX_HTTP_V2_PRIORITY_FLAG) { | |
2675 state = sw_dependency; | |
2676 break; | |
2677 } | |
2678 | |
2679 goto fragment; | |
2680 | |
2681 case sw_dependency: | |
2682 state = sw_dependency_2; | |
2683 break; | |
2684 | |
2685 case sw_dependency_2: | |
2686 state = sw_dependency_3; | |
2687 break; | |
2688 | |
2689 case sw_dependency_3: | |
2690 state = sw_dependency_4; | |
2691 break; | |
2692 | |
2693 case sw_dependency_4: | |
2694 state = sw_weight; | |
2695 break; | |
2696 | |
2697 case sw_weight: | |
2698 goto fragment; | |
2699 | |
2700 /* suppress warning */ | |
2701 case sw_start: | |
2702 case sw_fragment: | |
2703 case sw_padding: | |
2704 break; | |
2705 } | |
2706 } | |
2707 | |
2708 ctx->rest -= p - b->pos; | |
2709 b->pos = p; | |
2710 | |
2711 ctx->frame_state = state; | |
2712 return NGX_AGAIN; | |
2713 | |
2714 fragment: | |
2715 | |
2716 p++; | |
2717 ctx->rest -= p - b->pos; | |
2718 b->pos = p; | |
2719 | |
2720 if (ctx->padding > ctx->rest) { | |
2721 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2722 "upstream sent http2 frame with too long " | |
2723 "padding: %d in frame %uz", | |
2724 ctx->padding, ctx->rest); | |
2725 return NGX_ERROR; | |
2726 } | |
2727 | |
2728 state = sw_fragment; | |
2729 ctx->frame_state = state; | |
2730 } | |
2731 | |
2732 if (state == sw_fragment) { | |
2733 | |
2734 rc = ngx_http_grpc_parse_fragment(r, ctx, b); | |
2735 | |
2736 if (rc == NGX_AGAIN) { | |
2737 return NGX_AGAIN; | |
2738 } | |
2739 | |
2740 if (rc == NGX_ERROR) { | |
2741 return NGX_ERROR; | |
2742 } | |
2743 | |
2744 if (rc == NGX_OK) { | |
2745 return NGX_OK; | |
2746 } | |
2747 | |
2748 /* rc == NGX_DONE */ | |
2749 | |
2750 state = sw_padding; | |
2751 ctx->frame_state = state; | |
2752 } | |
2753 | |
2754 if (state == sw_padding) { | |
2755 | |
2756 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
2757 | |
2758 ctx->rest -= b->last - b->pos; | |
2759 b->pos = b->last; | |
2760 | |
2761 return NGX_AGAIN; | |
2762 } | |
2763 | |
2764 b->pos += ctx->rest; | |
2765 ctx->rest = 0; | |
2766 | |
2767 ctx->state = ngx_http_grpc_st_start; | |
2768 | |
2769 if (ctx->flags & NGX_HTTP_V2_END_HEADERS_FLAG) { | |
2770 | |
2771 if (ctx->fragment_state) { | |
2772 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2773 "upstream sent truncated http2 header"); | |
2774 return NGX_ERROR; | |
2775 } | |
2776 | |
2777 ctx->parsing_headers = 0; | |
2778 | |
2779 return NGX_HTTP_PARSE_HEADER_DONE; | |
2780 } | |
2781 | |
2782 return NGX_AGAIN; | |
2783 } | |
2784 | |
2785 /* unreachable */ | |
2786 | |
2787 return NGX_ERROR; | |
2788 } | |
2789 | |
2790 | |
2791 static ngx_int_t | |
2792 ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
2793 ngx_buf_t *b) | |
2794 { | |
2795 u_char ch, *p, *last; | |
2796 size_t size; | |
2797 ngx_uint_t index, size_update; | |
2798 enum { | |
2799 sw_start = 0, | |
2800 sw_index, | |
2801 sw_name_length, | |
2802 sw_name_length_2, | |
2803 sw_name_length_3, | |
2804 sw_name_length_4, | |
2805 sw_name, | |
2806 sw_name_bytes, | |
2807 sw_value_length, | |
2808 sw_value_length_2, | |
2809 sw_value_length_3, | |
2810 sw_value_length_4, | |
2811 sw_value, | |
2812 sw_value_bytes | |
2813 } state; | |
2814 | |
2815 /* header block fragment */ | |
2816 | |
2817 #if 0 | |
2818 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2819 "grpc header fragment %p:%p rest:%uz", | |
2820 b->pos, b->last, ctx->rest); | |
2821 #endif | |
2822 | |
2823 if (b->last - b->pos < (ssize_t) ctx->rest - ctx->padding) { | |
2824 last = b->last; | |
2825 | |
2826 } else { | |
2827 last = b->pos + ctx->rest - ctx->padding; | |
2828 } | |
2829 | |
2830 state = ctx->fragment_state; | |
2831 | |
2832 for (p = b->pos; p < last; p++) { | |
2833 ch = *p; | |
2834 | |
2835 #if 0 | |
2836 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2837 "grpc header byte: %02Xd s:%d", ch, state); | |
2838 #endif | |
2839 | |
2840 switch (state) { | |
2841 | |
2842 case sw_start: | |
2843 ctx->index = 0; | |
2844 | |
2845 if ((ch & 0x80) == 0x80) { | |
2846 /* | |
2847 * indexed header: | |
2848 * | |
2849 * 0 1 2 3 4 5 6 7 | |
2850 * +---+---+---+---+---+---+---+---+ | |
2851 * | 1 | Index (7+) | | |
2852 * +---+---------------------------+ | |
2853 */ | |
2854 | |
2855 index = ch & ~0x80; | |
2856 | |
2857 if (index == 0 || index > 61) { | |
2858 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2859 "upstream sent invalid http2 " | |
2860 "table index: %ui", index); | |
2861 return NGX_ERROR; | |
2862 } | |
2863 | |
2864 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2865 "grpc indexed header: %ui", index); | |
2866 | |
2867 ctx->index = index; | |
2868 ctx->literal = 0; | |
2869 | |
2870 goto done; | |
2871 | |
2872 } else if ((ch & 0xc0) == 0x40) { | |
2873 /* | |
2874 * literal header with incremental indexing: | |
2875 * | |
2876 * 0 1 2 3 4 5 6 7 | |
2877 * +---+---+---+---+---+---+---+---+ | |
2878 * | 0 | 1 | Index (6+) | | |
2879 * +---+---+-----------------------+ | |
2880 * | H | Value Length (7+) | | |
2881 * +---+---------------------------+ | |
2882 * | Value String (Length octets) | | |
2883 * +-------------------------------+ | |
2884 * | |
2885 * 0 1 2 3 4 5 6 7 | |
2886 * +---+---+---+---+---+---+---+---+ | |
2887 * | 0 | 1 | 0 | | |
2888 * +---+---+-----------------------+ | |
2889 * | H | Name Length (7+) | | |
2890 * +---+---------------------------+ | |
2891 * | Name String (Length octets) | | |
2892 * +---+---------------------------+ | |
2893 * | H | Value Length (7+) | | |
2894 * +---+---------------------------+ | |
2895 * | Value String (Length octets) | | |
2896 * +-------------------------------+ | |
2897 */ | |
2898 | |
2899 index = ch & ~0xc0; | |
2900 | |
2901 if (index > 61) { | |
2902 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2903 "upstream sent invalid http2 " | |
2904 "table index: %ui", index); | |
2905 return NGX_ERROR; | |
2906 } | |
2907 | |
2908 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2909 "grpc literal header: %ui", index); | |
2910 | |
2911 if (index == 0) { | |
2912 state = sw_name_length; | |
2913 break; | |
2914 } | |
2915 | |
2916 ctx->index = index; | |
2917 ctx->literal = 1; | |
2918 | |
2919 state = sw_value_length; | |
2920 break; | |
2921 | |
2922 } else if ((ch & 0xe0) == 0x20) { | |
2923 /* | |
2924 * dynamic table size update: | |
2925 * | |
2926 * 0 1 2 3 4 5 6 7 | |
2927 * +---+---+---+---+---+---+---+---+ | |
2928 * | 0 | 0 | 1 | Max size (5+) | | |
2929 * +---+---------------------------+ | |
2930 */ | |
2931 | |
2932 size_update = ch & ~0xe0; | |
2933 | |
2934 if (size_update > 0) { | |
2935 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2936 "upstream sent invalid http2 " | |
2937 "dynamic table size update: %ui", | |
2938 size_update); | |
2939 return NGX_ERROR; | |
2940 } | |
2941 | |
2942 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2943 "grpc table size update: %ui", size_update); | |
2944 | |
2945 break; | |
2946 | |
2947 } else if ((ch & 0xf0) == 0x10) { | |
2948 /* | |
2949 * literal header field never indexed: | |
2950 * | |
2951 * 0 1 2 3 4 5 6 7 | |
2952 * +---+---+---+---+---+---+---+---+ | |
2953 * | 0 | 0 | 0 | 1 | Index (4+) | | |
2954 * +---+---+-----------------------+ | |
2955 * | H | Value Length (7+) | | |
2956 * +---+---------------------------+ | |
2957 * | Value String (Length octets) | | |
2958 * +-------------------------------+ | |
2959 * | |
2960 * 0 1 2 3 4 5 6 7 | |
2961 * +---+---+---+---+---+---+---+---+ | |
2962 * | 0 | 0 | 0 | 1 | 0 | | |
2963 * +---+---+-----------------------+ | |
2964 * | H | Name Length (7+) | | |
2965 * +---+---------------------------+ | |
2966 * | Name String (Length octets) | | |
2967 * +---+---------------------------+ | |
2968 * | H | Value Length (7+) | | |
2969 * +---+---------------------------+ | |
2970 * | Value String (Length octets) | | |
2971 * +-------------------------------+ | |
2972 */ | |
2973 | |
2974 index = ch & ~0xf0; | |
2975 | |
2976 if (index == 0x0f) { | |
2977 ctx->index = index; | |
2978 ctx->literal = 1; | |
2979 state = sw_index; | |
2980 break; | |
2981 } | |
2982 | |
2983 if (index == 0) { | |
2984 state = sw_name_length; | |
2985 break; | |
2986 } | |
2987 | |
2988 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
2989 "grpc literal header never indexed: %ui", | |
2990 index); | |
2991 | |
2992 ctx->index = index; | |
2993 ctx->literal = 1; | |
2994 | |
2995 state = sw_value_length; | |
2996 break; | |
2997 | |
2998 } else if ((ch & 0xf0) == 0x00) { | |
2999 /* | |
3000 * literal header field without indexing: | |
3001 * | |
3002 * 0 1 2 3 4 5 6 7 | |
3003 * +---+---+---+---+---+---+---+---+ | |
3004 * | 0 | 0 | 0 | 0 | Index (4+) | | |
3005 * +---+---+-----------------------+ | |
3006 * | H | Value Length (7+) | | |
3007 * +---+---------------------------+ | |
3008 * | Value String (Length octets) | | |
3009 * +-------------------------------+ | |
3010 * | |
3011 * 0 1 2 3 4 5 6 7 | |
3012 * +---+---+---+---+---+---+---+---+ | |
3013 * | 0 | 0 | 0 | 0 | 0 | | |
3014 * +---+---+-----------------------+ | |
3015 * | H | Name Length (7+) | | |
3016 * +---+---------------------------+ | |
3017 * | Name String (Length octets) | | |
3018 * +---+---------------------------+ | |
3019 * | H | Value Length (7+) | | |
3020 * +---+---------------------------+ | |
3021 * | Value String (Length octets) | | |
3022 * +-------------------------------+ | |
3023 */ | |
3024 | |
3025 index = ch & ~0xf0; | |
3026 | |
3027 if (index == 0x0f) { | |
3028 ctx->index = index; | |
3029 ctx->literal = 1; | |
3030 state = sw_index; | |
3031 break; | |
3032 } | |
3033 | |
3034 if (index == 0) { | |
3035 state = sw_name_length; | |
3036 break; | |
3037 } | |
3038 | |
3039 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3040 "grpc literal header without indexing: %ui", | |
3041 index); | |
3042 | |
3043 ctx->index = index; | |
3044 ctx->literal = 1; | |
3045 | |
3046 state = sw_value_length; | |
3047 break; | |
3048 } | |
3049 | |
3050 /* not reached */ | |
3051 | |
3052 return NGX_ERROR; | |
3053 | |
3054 case sw_index: | |
3055 ctx->index = ctx->index + (ch & ~0x80); | |
3056 | |
3057 if (ch & 0x80) { | |
3058 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3059 "upstream sent http2 table index " | |
3060 "with continuation flag"); | |
3061 return NGX_ERROR; | |
3062 } | |
3063 | |
3064 if (ctx->index > 61) { | |
3065 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3066 "upstream sent invalid http2 " | |
3067 "table index: %ui", ctx->index); | |
3068 return NGX_ERROR; | |
3069 } | |
3070 | |
3071 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3072 "grpc header index: %ui", ctx->index); | |
3073 | |
3074 state = sw_value_length; | |
3075 break; | |
3076 | |
3077 case sw_name_length: | |
3078 ctx->field_huffman = ch & 0x80 ? 1 : 0; | |
3079 ctx->field_length = ch & ~0x80; | |
3080 | |
3081 if (ctx->field_length == 0x7f) { | |
3082 state = sw_name_length_2; | |
3083 break; | |
3084 } | |
3085 | |
3086 if (ctx->field_length == 0) { | |
3087 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3088 "upstream sent zero http2 " | |
3089 "header name length"); | |
3090 return NGX_ERROR; | |
3091 } | |
3092 | |
3093 state = sw_name; | |
3094 break; | |
3095 | |
3096 case sw_name_length_2: | |
3097 ctx->field_length += ch & ~0x80; | |
3098 | |
3099 if (ch & 0x80) { | |
3100 state = sw_name_length_3; | |
3101 break; | |
3102 } | |
3103 | |
3104 state = sw_name; | |
3105 break; | |
3106 | |
3107 case sw_name_length_3: | |
3108 ctx->field_length += (ch & ~0x80) << 7; | |
3109 | |
3110 if (ch & 0x80) { | |
3111 state = sw_name_length_4; | |
3112 break; | |
3113 } | |
3114 | |
3115 state = sw_name; | |
3116 break; | |
3117 | |
3118 case sw_name_length_4: | |
3119 ctx->field_length += (ch & ~0x80) << 14; | |
3120 | |
3121 if (ch & 0x80) { | |
3122 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3123 "upstream sent too large http2 " | |
3124 "header name length"); | |
3125 return NGX_ERROR; | |
3126 } | |
3127 | |
3128 state = sw_name; | |
3129 break; | |
3130 | |
3131 case sw_name: | |
3132 ctx->name.len = ctx->field_huffman ? | |
3133 ctx->field_length * 8 / 5 : ctx->field_length; | |
3134 | |
3135 ctx->name.data = ngx_pnalloc(r->pool, ctx->name.len + 1); | |
3136 if (ctx->name.data == NULL) { | |
3137 return NGX_ERROR; | |
3138 } | |
3139 | |
3140 ctx->field_end = ctx->name.data; | |
3141 ctx->field_rest = ctx->field_length; | |
3142 ctx->field_state = 0; | |
3143 | |
3144 state = sw_name_bytes; | |
3145 | |
3146 /* fall through */ | |
3147 | |
3148 case sw_name_bytes: | |
3149 | |
3150 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3151 "grpc name: len:%uz h:%d last:%uz, rest:%uz", | |
3152 ctx->field_length, | |
3153 ctx->field_huffman, | |
3154 last - p, | |
3155 ctx->rest - (p - b->pos)); | |
3156 | |
3157 size = ngx_min(last - p, (ssize_t) ctx->field_rest); | |
3158 ctx->field_rest -= size; | |
3159 | |
3160 if (ctx->field_huffman) { | |
3161 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, | |
3162 &ctx->field_end, | |
3163 ctx->field_rest == 0, | |
3164 r->connection->log) | |
3165 != NGX_OK) | |
3166 { | |
3167 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3168 "upstream sent invalid encoded header"); | |
3169 return NGX_ERROR; | |
3170 } | |
3171 | |
3172 ctx->name.len = ctx->field_end - ctx->name.data; | |
3173 ctx->name.data[ctx->name.len] = '\0'; | |
3174 | |
3175 } else { | |
7240
413189f03c8d
gRPC: fixed parsing response headers split on CONTINUATION frames.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7235
diff
changeset
|
3176 ctx->field_end = ngx_cpymem(ctx->field_end, p, size); |
7233 | 3177 ctx->name.data[ctx->name.len] = '\0'; |
3178 } | |
3179 | |
3180 p += size - 1; | |
3181 | |
3182 if (ctx->field_rest == 0) { | |
3183 state = sw_value_length; | |
3184 } | |
3185 | |
3186 break; | |
3187 | |
3188 case sw_value_length: | |
3189 ctx->field_huffman = ch & 0x80 ? 1 : 0; | |
3190 ctx->field_length = ch & ~0x80; | |
3191 | |
3192 if (ctx->field_length == 0x7f) { | |
3193 state = sw_value_length_2; | |
3194 break; | |
3195 } | |
3196 | |
3197 if (ctx->field_length == 0) { | |
3198 ngx_str_set(&ctx->value, ""); | |
3199 goto done; | |
3200 } | |
3201 | |
3202 state = sw_value; | |
3203 break; | |
3204 | |
3205 case sw_value_length_2: | |
3206 ctx->field_length += ch & ~0x80; | |
3207 | |
3208 if (ch & 0x80) { | |
3209 state = sw_value_length_3; | |
3210 break; | |
3211 } | |
3212 | |
3213 state = sw_value; | |
3214 break; | |
3215 | |
3216 case sw_value_length_3: | |
3217 ctx->field_length += (ch & ~0x80) << 7; | |
3218 | |
3219 if (ch & 0x80) { | |
3220 state = sw_value_length_4; | |
3221 break; | |
3222 } | |
3223 | |
3224 state = sw_value; | |
3225 break; | |
3226 | |
3227 case sw_value_length_4: | |
3228 ctx->field_length += (ch & ~0x80) << 14; | |
3229 | |
3230 if (ch & 0x80) { | |
3231 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3232 "upstream sent too large http2 " | |
3233 "header value length"); | |
3234 return NGX_ERROR; | |
3235 } | |
3236 | |
3237 state = sw_value; | |
3238 break; | |
3239 | |
3240 case sw_value: | |
3241 ctx->value.len = ctx->field_huffman ? | |
3242 ctx->field_length * 8 / 5 : ctx->field_length; | |
3243 | |
3244 ctx->value.data = ngx_pnalloc(r->pool, ctx->value.len + 1); | |
3245 if (ctx->value.data == NULL) { | |
3246 return NGX_ERROR; | |
3247 } | |
3248 | |
3249 ctx->field_end = ctx->value.data; | |
3250 ctx->field_rest = ctx->field_length; | |
3251 ctx->field_state = 0; | |
3252 | |
3253 state = sw_value_bytes; | |
3254 | |
3255 /* fall through */ | |
3256 | |
3257 case sw_value_bytes: | |
3258 | |
3259 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3260 "grpc value: len:%uz h:%d last:%uz, rest:%uz", | |
3261 ctx->field_length, | |
3262 ctx->field_huffman, | |
3263 last - p, | |
3264 ctx->rest - (p - b->pos)); | |
3265 | |
3266 size = ngx_min(last - p, (ssize_t) ctx->field_rest); | |
3267 ctx->field_rest -= size; | |
3268 | |
3269 if (ctx->field_huffman) { | |
3270 if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, | |
3271 &ctx->field_end, | |
3272 ctx->field_rest == 0, | |
3273 r->connection->log) | |
3274 != NGX_OK) | |
3275 { | |
3276 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3277 "upstream sent invalid encoded header"); | |
3278 return NGX_ERROR; | |
3279 } | |
3280 | |
3281 ctx->value.len = ctx->field_end - ctx->value.data; | |
3282 ctx->value.data[ctx->value.len] = '\0'; | |
3283 | |
3284 } else { | |
7240
413189f03c8d
gRPC: fixed parsing response headers split on CONTINUATION frames.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7235
diff
changeset
|
3285 ctx->field_end = ngx_cpymem(ctx->field_end, p, size); |
7233 | 3286 ctx->value.data[ctx->value.len] = '\0'; |
3287 } | |
3288 | |
3289 p += size - 1; | |
3290 | |
3291 if (ctx->field_rest == 0) { | |
3292 goto done; | |
3293 } | |
3294 | |
3295 break; | |
3296 } | |
3297 | |
3298 continue; | |
3299 | |
3300 done: | |
3301 | |
3302 p++; | |
3303 ctx->rest -= p - b->pos; | |
3304 ctx->fragment_state = sw_start; | |
3305 b->pos = p; | |
3306 | |
3307 if (ctx->index) { | |
3308 ctx->name = *ngx_http_v2_get_static_name(ctx->index); | |
3309 } | |
3310 | |
3311 if (ctx->index && !ctx->literal) { | |
3312 ctx->value = *ngx_http_v2_get_static_value(ctx->index); | |
3313 } | |
3314 | |
3315 if (!ctx->index) { | |
3316 if (ngx_http_grpc_validate_header_name(r, &ctx->name) != NGX_OK) { | |
3317 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3318 "upstream sent invalid header: \"%V: %V\"", | |
3319 &ctx->name, &ctx->value); | |
3320 return NGX_ERROR; | |
3321 } | |
3322 } | |
3323 | |
3324 if (!ctx->index || ctx->literal) { | |
3325 if (ngx_http_grpc_validate_header_value(r, &ctx->value) != NGX_OK) { | |
3326 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3327 "upstream sent invalid header: \"%V: %V\"", | |
3328 &ctx->name, &ctx->value); | |
3329 return NGX_ERROR; | |
3330 } | |
3331 } | |
3332 | |
3333 return NGX_OK; | |
3334 } | |
3335 | |
3336 ctx->rest -= p - b->pos; | |
3337 ctx->fragment_state = state; | |
3338 b->pos = p; | |
3339 | |
3340 if (ctx->rest > ctx->padding) { | |
3341 return NGX_AGAIN; | |
3342 } | |
3343 | |
3344 return NGX_DONE; | |
3345 } | |
3346 | |
3347 | |
3348 static ngx_int_t | |
3349 ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) | |
3350 { | |
3351 u_char ch; | |
3352 ngx_uint_t i; | |
3353 | |
3354 for (i = 0; i < s->len; i++) { | |
3355 ch = s->data[i]; | |
3356 | |
3357 if (ch == ':' && i > 0) { | |
3358 return NGX_ERROR; | |
3359 } | |
3360 | |
3361 if (ch >= 'A' && ch <= 'Z') { | |
3362 return NGX_ERROR; | |
3363 } | |
3364 | |
3365 if (ch == '\0' || ch == CR || ch == LF) { | |
3366 return NGX_ERROR; | |
3367 } | |
3368 } | |
3369 | |
3370 return NGX_OK; | |
3371 } | |
3372 | |
3373 | |
3374 static ngx_int_t | |
3375 ngx_http_grpc_validate_header_value(ngx_http_request_t *r, ngx_str_t *s) | |
3376 { | |
3377 u_char ch; | |
3378 ngx_uint_t i; | |
3379 | |
3380 for (i = 0; i < s->len; i++) { | |
3381 ch = s->data[i]; | |
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_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3394 ngx_buf_t *b) | |
3395 { | |
3396 u_char ch, *p, *last; | |
3397 enum { | |
3398 sw_start = 0, | |
3399 sw_error_2, | |
3400 sw_error_3, | |
3401 sw_error_4 | |
3402 } state; | |
3403 | |
3404 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3405 last = b->last; | |
3406 | |
3407 } else { | |
3408 last = b->pos + ctx->rest; | |
3409 } | |
3410 | |
3411 state = ctx->frame_state; | |
3412 | |
3413 if (state == sw_start) { | |
3414 if (ctx->rest != 4) { | |
3415 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3416 "upstream sent rst stream frame " | |
3417 "with invalid length: %uz", | |
3418 ctx->rest); | |
3419 return NGX_ERROR; | |
3420 } | |
3421 } | |
3422 | |
3423 for (p = b->pos; p < last; p++) { | |
3424 ch = *p; | |
3425 | |
3426 #if 0 | |
3427 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3428 "grpc rst byte: %02Xd s:%d", ch, state); | |
3429 #endif | |
3430 | |
3431 switch (state) { | |
3432 | |
3433 case sw_start: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3434 ctx->error = (ngx_uint_t) ch << 24; |
7233 | 3435 state = sw_error_2; |
3436 break; | |
3437 | |
3438 case sw_error_2: | |
3439 ctx->error |= ch << 16; | |
3440 state = sw_error_3; | |
3441 break; | |
3442 | |
3443 case sw_error_3: | |
3444 ctx->error |= ch << 8; | |
3445 state = sw_error_4; | |
3446 break; | |
3447 | |
3448 case sw_error_4: | |
3449 ctx->error |= ch; | |
3450 state = sw_start; | |
3451 | |
3452 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3453 "grpc error: %ui", ctx->error); | |
3454 | |
3455 break; | |
3456 } | |
3457 } | |
3458 | |
3459 ctx->rest -= p - b->pos; | |
3460 ctx->frame_state = state; | |
3461 b->pos = p; | |
3462 | |
3463 if (ctx->rest > 0) { | |
3464 return NGX_AGAIN; | |
3465 } | |
3466 | |
3467 return NGX_OK; | |
3468 } | |
3469 | |
3470 | |
3471 static ngx_int_t | |
3472 ngx_http_grpc_parse_goaway(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3473 ngx_buf_t *b) | |
3474 { | |
3475 u_char ch, *p, *last; | |
3476 enum { | |
3477 sw_start = 0, | |
3478 sw_last_stream_id_2, | |
3479 sw_last_stream_id_3, | |
3480 sw_last_stream_id_4, | |
3481 sw_error, | |
3482 sw_error_2, | |
3483 sw_error_3, | |
3484 sw_error_4, | |
3485 sw_debug | |
3486 } state; | |
3487 | |
3488 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3489 last = b->last; | |
3490 | |
3491 } else { | |
3492 last = b->pos + ctx->rest; | |
3493 } | |
3494 | |
3495 state = ctx->frame_state; | |
3496 | |
3497 if (state == sw_start) { | |
3498 | |
3499 if (ctx->stream_id) { | |
3500 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3501 "upstream sent goaway frame " | |
3502 "with non-zero stream id: %ui", | |
3503 ctx->stream_id); | |
3504 return NGX_ERROR; | |
3505 } | |
3506 | |
3507 if (ctx->rest < 8) { | |
3508 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3509 "upstream sent goaway frame " | |
3510 "with invalid length: %uz", | |
3511 ctx->rest); | |
3512 return NGX_ERROR; | |
3513 } | |
3514 } | |
3515 | |
3516 for (p = b->pos; p < last; p++) { | |
3517 ch = *p; | |
3518 | |
3519 #if 0 | |
3520 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3521 "grpc goaway byte: %02Xd s:%d", ch, state); | |
3522 #endif | |
3523 | |
3524 switch (state) { | |
3525 | |
3526 case sw_start: | |
3527 ctx->stream_id = (ch & 0x7f) << 24; | |
3528 state = sw_last_stream_id_2; | |
3529 break; | |
3530 | |
3531 case sw_last_stream_id_2: | |
3532 ctx->stream_id |= ch << 16; | |
3533 state = sw_last_stream_id_3; | |
3534 break; | |
3535 | |
3536 case sw_last_stream_id_3: | |
3537 ctx->stream_id |= ch << 8; | |
3538 state = sw_last_stream_id_4; | |
3539 break; | |
3540 | |
3541 case sw_last_stream_id_4: | |
3542 ctx->stream_id |= ch; | |
3543 state = sw_error; | |
3544 break; | |
3545 | |
3546 case sw_error: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3547 ctx->error = (ngx_uint_t) ch << 24; |
7233 | 3548 state = sw_error_2; |
3549 break; | |
3550 | |
3551 case sw_error_2: | |
3552 ctx->error |= ch << 16; | |
3553 state = sw_error_3; | |
3554 break; | |
3555 | |
3556 case sw_error_3: | |
3557 ctx->error |= ch << 8; | |
3558 state = sw_error_4; | |
3559 break; | |
3560 | |
3561 case sw_error_4: | |
3562 ctx->error |= ch; | |
3563 state = sw_debug; | |
3564 break; | |
3565 | |
3566 case sw_debug: | |
3567 break; | |
3568 } | |
3569 } | |
3570 | |
3571 ctx->rest -= p - b->pos; | |
3572 ctx->frame_state = state; | |
3573 b->pos = p; | |
3574 | |
3575 if (ctx->rest > 0) { | |
3576 return NGX_AGAIN; | |
3577 } | |
3578 | |
3579 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3580 "grpc goaway: %ui, stream %ui", | |
3581 ctx->error, ctx->stream_id); | |
3582 | |
3583 ctx->state = ngx_http_grpc_st_start; | |
3584 | |
3585 return NGX_OK; | |
3586 } | |
3587 | |
3588 | |
3589 static ngx_int_t | |
3590 ngx_http_grpc_parse_window_update(ngx_http_request_t *r, | |
3591 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b) | |
3592 { | |
3593 u_char ch, *p, *last; | |
3594 enum { | |
3595 sw_start = 0, | |
3596 sw_size_2, | |
3597 sw_size_3, | |
3598 sw_size_4 | |
3599 } state; | |
3600 | |
3601 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3602 last = b->last; | |
3603 | |
3604 } else { | |
3605 last = b->pos + ctx->rest; | |
3606 } | |
3607 | |
3608 state = ctx->frame_state; | |
3609 | |
3610 if (state == sw_start) { | |
3611 if (ctx->rest != 4) { | |
3612 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3613 "upstream sent window update frame " | |
3614 "with invalid length: %uz", | |
3615 ctx->rest); | |
3616 return NGX_ERROR; | |
3617 } | |
3618 } | |
3619 | |
3620 for (p = b->pos; p < last; p++) { | |
3621 ch = *p; | |
3622 | |
3623 #if 0 | |
3624 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3625 "grpc window update byte: %02Xd s:%d", ch, state); | |
3626 #endif | |
3627 | |
3628 switch (state) { | |
3629 | |
3630 case sw_start: | |
3631 ctx->window_update = (ch & 0x7f) << 24; | |
3632 state = sw_size_2; | |
3633 break; | |
3634 | |
3635 case sw_size_2: | |
3636 ctx->window_update |= ch << 16; | |
3637 state = sw_size_3; | |
3638 break; | |
3639 | |
3640 case sw_size_3: | |
3641 ctx->window_update |= ch << 8; | |
3642 state = sw_size_4; | |
3643 break; | |
3644 | |
3645 case sw_size_4: | |
3646 ctx->window_update |= ch; | |
3647 state = sw_start; | |
3648 break; | |
3649 } | |
3650 } | |
3651 | |
3652 ctx->rest -= p - b->pos; | |
3653 ctx->frame_state = state; | |
3654 b->pos = p; | |
3655 | |
3656 if (ctx->rest > 0) { | |
3657 return NGX_AGAIN; | |
3658 } | |
3659 | |
3660 ctx->state = ngx_http_grpc_st_start; | |
3661 | |
3662 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3663 "grpc window update: %ui", ctx->window_update); | |
3664 | |
3665 if (ctx->stream_id) { | |
3666 | |
3667 if (ctx->window_update > (size_t) NGX_HTTP_V2_MAX_WINDOW | |
3668 - ctx->send_window) | |
3669 { | |
3670 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3671 "upstream sent too large window update"); | |
3672 return NGX_ERROR; | |
3673 } | |
3674 | |
3675 ctx->send_window += ctx->window_update; | |
3676 | |
3677 } else { | |
3678 | |
3679 if (ctx->window_update > NGX_HTTP_V2_MAX_WINDOW | |
3680 - ctx->connection->send_window) | |
3681 { | |
3682 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3683 "upstream sent too large window update"); | |
3684 return NGX_ERROR; | |
3685 } | |
3686 | |
3687 ctx->connection->send_window += ctx->window_update; | |
3688 } | |
3689 | |
3690 return NGX_OK; | |
3691 } | |
3692 | |
3693 | |
3694 static ngx_int_t | |
3695 ngx_http_grpc_parse_settings(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, | |
3696 ngx_buf_t *b) | |
3697 { | |
3698 u_char ch, *p, *last; | |
3699 ssize_t window_update; | |
3700 enum { | |
3701 sw_start = 0, | |
3702 sw_id, | |
3703 sw_id_2, | |
3704 sw_value, | |
3705 sw_value_2, | |
3706 sw_value_3, | |
3707 sw_value_4 | |
3708 } state; | |
3709 | |
3710 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3711 last = b->last; | |
3712 | |
3713 } else { | |
3714 last = b->pos + ctx->rest; | |
3715 } | |
3716 | |
3717 state = ctx->frame_state; | |
3718 | |
3719 if (state == sw_start) { | |
3720 | |
3721 if (ctx->stream_id) { | |
3722 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3723 "upstream sent settings frame " | |
3724 "with non-zero stream id: %ui", | |
3725 ctx->stream_id); | |
3726 return NGX_ERROR; | |
3727 } | |
3728 | |
3729 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) { | |
3730 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3731 "grpc settings ack"); | |
3732 | |
3733 if (ctx->rest != 0) { | |
3734 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3735 "upstream sent settings frame " | |
3736 "with ack flag and non-zero length: %uz", | |
3737 ctx->rest); | |
3738 return NGX_ERROR; | |
3739 } | |
3740 | |
3741 ctx->state = ngx_http_grpc_st_start; | |
3742 | |
3743 return NGX_OK; | |
3744 } | |
3745 | |
3746 if (ctx->rest % 6 != 0) { | |
3747 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3748 "upstream sent settings frame " | |
3749 "with invalid length: %uz", | |
3750 ctx->rest); | |
3751 return NGX_ERROR; | |
3752 } | |
7379
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3753 |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3754 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
|
3755 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
|
3756 "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
|
3757 return NGX_ERROR; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3758 } |
7233 | 3759 } |
3760 | |
3761 for (p = b->pos; p < last; p++) { | |
3762 ch = *p; | |
3763 | |
3764 #if 0 | |
3765 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3766 "grpc settings byte: %02Xd s:%d", ch, state); | |
3767 #endif | |
3768 | |
3769 switch (state) { | |
3770 | |
3771 case sw_start: | |
3772 case sw_id: | |
3773 ctx->setting_id = ch << 8; | |
3774 state = sw_id_2; | |
3775 break; | |
3776 | |
3777 case sw_id_2: | |
3778 ctx->setting_id |= ch; | |
3779 state = sw_value; | |
3780 break; | |
3781 | |
3782 case sw_value: | |
7249
070c972336c4
gRPC: fixed possible sign extension of error and setting_value.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7242
diff
changeset
|
3783 ctx->setting_value = (ngx_uint_t) ch << 24; |
7233 | 3784 state = sw_value_2; |
3785 break; | |
3786 | |
3787 case sw_value_2: | |
3788 ctx->setting_value |= ch << 16; | |
3789 state = sw_value_3; | |
3790 break; | |
3791 | |
3792 case sw_value_3: | |
3793 ctx->setting_value |= ch << 8; | |
3794 state = sw_value_4; | |
3795 break; | |
3796 | |
3797 case sw_value_4: | |
3798 ctx->setting_value |= ch; | |
3799 state = sw_id; | |
3800 | |
3801 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3802 "grpc setting: %ui %ui", | |
3803 ctx->setting_id, ctx->setting_value); | |
3804 | |
3805 /* | |
3806 * The following settings are defined by the protocol: | |
3807 * | |
3808 * SETTINGS_HEADER_TABLE_SIZE, SETTINGS_ENABLE_PUSH, | |
3809 * SETTINGS_MAX_CONCURRENT_STREAMS, SETTINGS_INITIAL_WINDOW_SIZE, | |
3810 * SETTINGS_MAX_FRAME_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE | |
3811 * | |
3812 * Only SETTINGS_INITIAL_WINDOW_SIZE seems to be needed in | |
3813 * a simple client. | |
3814 */ | |
3815 | |
3816 if (ctx->setting_id == 0x04) { | |
3817 /* SETTINGS_INITIAL_WINDOW_SIZE */ | |
3818 | |
3819 if (ctx->setting_value > NGX_HTTP_V2_MAX_WINDOW) { | |
3820 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3821 "upstream sent settings frame " | |
3822 "with too large initial window size: %ui", | |
3823 ctx->setting_value); | |
3824 return NGX_ERROR; | |
3825 } | |
3826 | |
3827 window_update = ctx->setting_value | |
3828 - ctx->connection->init_window; | |
3829 ctx->connection->init_window = ctx->setting_value; | |
3830 | |
3831 if (ctx->send_window > 0 | |
3832 && window_update > (ssize_t) NGX_HTTP_V2_MAX_WINDOW | |
3833 - ctx->send_window) | |
3834 { | |
3835 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3836 "upstream sent settings frame " | |
3837 "with too large initial window size: %ui", | |
3838 ctx->setting_value); | |
3839 return NGX_ERROR; | |
3840 } | |
3841 | |
3842 ctx->send_window += window_update; | |
3843 } | |
3844 | |
3845 break; | |
3846 } | |
3847 } | |
3848 | |
3849 ctx->rest -= p - b->pos; | |
3850 ctx->frame_state = state; | |
3851 b->pos = p; | |
3852 | |
3853 if (ctx->rest > 0) { | |
3854 return NGX_AGAIN; | |
3855 } | |
3856 | |
3857 ctx->state = ngx_http_grpc_st_start; | |
3858 | |
3859 return ngx_http_grpc_send_settings_ack(r, ctx); | |
3860 } | |
3861 | |
3862 | |
3863 static ngx_int_t | |
3864 ngx_http_grpc_parse_ping(ngx_http_request_t *r, | |
3865 ngx_http_grpc_ctx_t *ctx, ngx_buf_t *b) | |
3866 { | |
3867 u_char ch, *p, *last; | |
3868 enum { | |
3869 sw_start = 0, | |
3870 sw_data_2, | |
3871 sw_data_3, | |
3872 sw_data_4, | |
3873 sw_data_5, | |
3874 sw_data_6, | |
3875 sw_data_7, | |
3876 sw_data_8 | |
3877 } state; | |
3878 | |
3879 if (b->last - b->pos < (ssize_t) ctx->rest) { | |
3880 last = b->last; | |
3881 | |
3882 } else { | |
3883 last = b->pos + ctx->rest; | |
3884 } | |
3885 | |
3886 state = ctx->frame_state; | |
3887 | |
3888 if (state == sw_start) { | |
3889 | |
3890 if (ctx->stream_id) { | |
3891 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3892 "upstream sent ping frame " | |
3893 "with non-zero stream id: %ui", | |
3894 ctx->stream_id); | |
3895 return NGX_ERROR; | |
3896 } | |
3897 | |
3898 if (ctx->rest != 8) { | |
3899 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3900 "upstream sent ping frame " | |
3901 "with invalid length: %uz", | |
3902 ctx->rest); | |
3903 return NGX_ERROR; | |
3904 } | |
3905 | |
3906 if (ctx->flags & NGX_HTTP_V2_ACK_FLAG) { | |
3907 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
3908 "upstream sent ping frame with ack flag"); | |
3909 return NGX_ERROR; | |
3910 } | |
7379
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3911 |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3912 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
|
3913 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
|
3914 "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
|
3915 return NGX_ERROR; |
57463f4e2fcd
gRPC: limited allocations due to ping and settings frames.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7371
diff
changeset
|
3916 } |
7233 | 3917 } |
3918 | |
3919 for (p = b->pos; p < last; p++) { | |
3920 ch = *p; | |
3921 | |
3922 #if 0 | |
3923 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3924 "grpc ping byte: %02Xd s:%d", ch, state); | |
3925 #endif | |
3926 | |
3927 if (state < sw_data_8) { | |
3928 ctx->ping_data[state] = ch; | |
3929 state++; | |
3930 | |
3931 } else { | |
3932 ctx->ping_data[7] = ch; | |
3933 state = sw_start; | |
3934 | |
3935 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3936 "grpc ping"); | |
3937 } | |
3938 } | |
3939 | |
3940 ctx->rest -= p - b->pos; | |
3941 ctx->frame_state = state; | |
3942 b->pos = p; | |
3943 | |
3944 if (ctx->rest > 0) { | |
3945 return NGX_AGAIN; | |
3946 } | |
3947 | |
3948 ctx->state = ngx_http_grpc_st_start; | |
3949 | |
3950 return ngx_http_grpc_send_ping_ack(r, ctx); | |
3951 } | |
3952 | |
3953 | |
3954 static ngx_int_t | |
3955 ngx_http_grpc_send_settings_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
3956 { | |
3957 ngx_chain_t *cl, **ll; | |
3958 ngx_http_grpc_frame_t *f; | |
3959 | |
3960 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3961 "grpc send settings ack"); | |
3962 | |
3963 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
3964 ll = &cl->next; | |
3965 } | |
3966 | |
3967 cl = ngx_http_grpc_get_buf(r, ctx); | |
3968 if (cl == NULL) { | |
3969 return NGX_ERROR; | |
3970 } | |
3971 | |
3972 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
3973 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
3974 | |
3975 f->length_0 = 0; | |
3976 f->length_1 = 0; | |
3977 f->length_2 = 0; | |
3978 f->type = NGX_HTTP_V2_SETTINGS_FRAME; | |
3979 f->flags = NGX_HTTP_V2_ACK_FLAG; | |
3980 f->stream_id_0 = 0; | |
3981 f->stream_id_1 = 0; | |
3982 f->stream_id_2 = 0; | |
3983 f->stream_id_3 = 0; | |
3984 | |
3985 *ll = cl; | |
3986 | |
3987 return NGX_OK; | |
3988 } | |
3989 | |
3990 | |
3991 static ngx_int_t | |
3992 ngx_http_grpc_send_ping_ack(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
3993 { | |
3994 ngx_chain_t *cl, **ll; | |
3995 ngx_http_grpc_frame_t *f; | |
3996 | |
3997 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3998 "grpc send ping ack"); | |
3999 | |
4000 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
4001 ll = &cl->next; | |
4002 } | |
4003 | |
4004 cl = ngx_http_grpc_get_buf(r, ctx); | |
4005 if (cl == NULL) { | |
4006 return NGX_ERROR; | |
4007 } | |
4008 | |
4009 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4010 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4011 | |
4012 f->length_0 = 0; | |
4013 f->length_1 = 0; | |
4014 f->length_2 = 8; | |
4015 f->type = NGX_HTTP_V2_PING_FRAME; | |
4016 f->flags = NGX_HTTP_V2_ACK_FLAG; | |
4017 f->stream_id_0 = 0; | |
4018 f->stream_id_1 = 0; | |
4019 f->stream_id_2 = 0; | |
4020 f->stream_id_3 = 0; | |
4021 | |
4022 cl->buf->last = ngx_copy(cl->buf->last, ctx->ping_data, 8); | |
4023 | |
4024 *ll = cl; | |
4025 | |
4026 return NGX_OK; | |
4027 } | |
4028 | |
4029 | |
4030 static ngx_int_t | |
4031 ngx_http_grpc_send_window_update(ngx_http_request_t *r, | |
4032 ngx_http_grpc_ctx_t *ctx) | |
4033 { | |
4034 size_t n; | |
4035 ngx_chain_t *cl, **ll; | |
4036 ngx_http_grpc_frame_t *f; | |
4037 | |
4038 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4039 "grpc send window update: %uz %uz", | |
4040 ctx->connection->recv_window, ctx->recv_window); | |
4041 | |
4042 for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { | |
4043 ll = &cl->next; | |
4044 } | |
4045 | |
4046 cl = ngx_http_grpc_get_buf(r, ctx); | |
4047 if (cl == NULL) { | |
4048 return NGX_ERROR; | |
4049 } | |
4050 | |
4051 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4052 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4053 | |
4054 f->length_0 = 0; | |
4055 f->length_1 = 0; | |
4056 f->length_2 = 4; | |
4057 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME; | |
4058 f->flags = 0; | |
4059 f->stream_id_0 = 0; | |
4060 f->stream_id_1 = 0; | |
4061 f->stream_id_2 = 0; | |
4062 f->stream_id_3 = 0; | |
4063 | |
4064 n = NGX_HTTP_V2_MAX_WINDOW - ctx->connection->recv_window; | |
4065 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4066 | |
4067 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff); | |
4068 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff); | |
4069 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff); | |
4070 *cl->buf->last++ = (u_char) (n & 0xff); | |
4071 | |
4072 f = (ngx_http_grpc_frame_t *) cl->buf->last; | |
4073 cl->buf->last += sizeof(ngx_http_grpc_frame_t); | |
4074 | |
4075 f->length_0 = 0; | |
4076 f->length_1 = 0; | |
4077 f->length_2 = 4; | |
4078 f->type = NGX_HTTP_V2_WINDOW_UPDATE_FRAME; | |
4079 f->flags = 0; | |
4080 f->stream_id_0 = (u_char) ((ctx->id >> 24) & 0xff); | |
4081 f->stream_id_1 = (u_char) ((ctx->id >> 16) & 0xff); | |
4082 f->stream_id_2 = (u_char) ((ctx->id >> 8) & 0xff); | |
4083 f->stream_id_3 = (u_char) (ctx->id & 0xff); | |
4084 | |
4085 n = NGX_HTTP_V2_MAX_WINDOW - ctx->recv_window; | |
4086 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4087 | |
4088 *cl->buf->last++ = (u_char) ((n >> 24) & 0xff); | |
4089 *cl->buf->last++ = (u_char) ((n >> 16) & 0xff); | |
4090 *cl->buf->last++ = (u_char) ((n >> 8) & 0xff); | |
4091 *cl->buf->last++ = (u_char) (n & 0xff); | |
4092 | |
4093 *ll = cl; | |
4094 | |
4095 return NGX_OK; | |
4096 } | |
4097 | |
4098 | |
4099 static ngx_chain_t * | |
4100 ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx) | |
4101 { | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4102 u_char *start; |
7233 | 4103 ngx_buf_t *b; |
4104 ngx_chain_t *cl; | |
4105 | |
4106 cl = ngx_chain_get_free_buf(r->pool, &ctx->free); | |
4107 if (cl == NULL) { | |
4108 return NULL; | |
4109 } | |
4110 | |
4111 b = cl->buf; | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4112 start = b->start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4113 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4114 if (start == NULL) { |
7233 | 4115 |
4116 /* | |
4117 * each buffer is large enough to hold two window update | |
4118 * frames in a row | |
4119 */ | |
4120 | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4121 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
|
4122 if (start == NULL) { |
7233 | 4123 return NULL; |
4124 } | |
4125 | |
4126 } | |
4127 | |
7305
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4128 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
|
4129 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4130 b->start = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4131 b->pos = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4132 b->last = start; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4133 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
|
4134 |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4135 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
|
4136 b->temporary = 1; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4137 b->flush = 1; |
6cfd45d4c754
gRPC: clearing buffers in ngx_http_grpc_get_buf().
Maxim Dounin <mdounin@mdounin.ru>
parents:
7271
diff
changeset
|
4138 |
7233 | 4139 return cl; |
4140 } | |
4141 | |
4142 | |
4143 static ngx_http_grpc_ctx_t * | |
4144 ngx_http_grpc_get_ctx(ngx_http_request_t *r) | |
4145 { | |
4146 ngx_http_grpc_ctx_t *ctx; | |
4147 ngx_http_upstream_t *u; | |
4148 | |
4149 ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module); | |
4150 | |
4151 if (ctx->connection == NULL) { | |
4152 u = r->upstream; | |
4153 | |
4154 if (ngx_http_grpc_get_connection_data(r, ctx, &u->peer) != NGX_OK) { | |
4155 return NULL; | |
4156 } | |
4157 } | |
4158 | |
4159 return ctx; | |
4160 } | |
4161 | |
4162 | |
4163 static ngx_int_t | |
4164 ngx_http_grpc_get_connection_data(ngx_http_request_t *r, | |
4165 ngx_http_grpc_ctx_t *ctx, ngx_peer_connection_t *pc) | |
4166 { | |
4167 ngx_connection_t *c; | |
4168 ngx_pool_cleanup_t *cln; | |
4169 | |
4170 c = pc->connection; | |
4171 | |
4172 if (pc->cached) { | |
4173 | |
4174 /* | |
4175 * for cached connections, connection data can be found | |
4176 * in the cleanup handler | |
4177 */ | |
4178 | |
4179 for (cln = c->pool->cleanup; cln; cln = cln->next) { | |
4180 if (cln->handler == ngx_http_grpc_cleanup) { | |
4181 ctx->connection = cln->data; | |
4182 break; | |
4183 } | |
4184 } | |
4185 | |
4186 if (ctx->connection == NULL) { | |
4187 ngx_log_error(NGX_LOG_ERR, c->log, 0, | |
4188 "no connection data found for " | |
4189 "keepalive http2 connection"); | |
4190 return NGX_ERROR; | |
4191 } | |
4192 | |
4193 ctx->send_window = ctx->connection->init_window; | |
4194 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4195 | |
4196 ctx->connection->last_stream_id += 2; | |
4197 ctx->id = ctx->connection->last_stream_id; | |
4198 | |
4199 return NGX_OK; | |
4200 } | |
4201 | |
4202 cln = ngx_pool_cleanup_add(c->pool, sizeof(ngx_http_grpc_conn_t)); | |
4203 if (cln == NULL) { | |
4204 return NGX_ERROR; | |
4205 } | |
4206 | |
4207 cln->handler = ngx_http_grpc_cleanup; | |
4208 ctx->connection = cln->data; | |
4209 | |
4210 ctx->connection->init_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4211 ctx->connection->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4212 ctx->connection->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4213 | |
4214 ctx->send_window = NGX_HTTP_V2_DEFAULT_WINDOW; | |
4215 ctx->recv_window = NGX_HTTP_V2_MAX_WINDOW; | |
4216 | |
4217 ctx->id = 1; | |
4218 ctx->connection->last_stream_id = 1; | |
4219 | |
4220 return NGX_OK; | |
4221 } | |
4222 | |
4223 | |
4224 static void | |
4225 ngx_http_grpc_cleanup(void *data) | |
4226 { | |
4227 #if 0 | |
4228 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
4229 "grpc cleanup"); | |
4230 #endif | |
4231 return; | |
4232 } | |
4233 | |
4234 | |
4235 static void | |
4236 ngx_http_grpc_abort_request(ngx_http_request_t *r) | |
4237 { | |
4238 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4239 "abort grpc request"); | |
4240 return; | |
4241 } | |
4242 | |
4243 | |
4244 static void | |
4245 ngx_http_grpc_finalize_request(ngx_http_request_t *r, ngx_int_t rc) | |
4246 { | |
4247 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
4248 "finalize grpc request"); | |
4249 return; | |
4250 } | |
4251 | |
4252 | |
7234
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4253 static ngx_int_t |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4254 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
|
4255 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
|
4256 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4257 ngx_table_elt_t *te; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4258 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4259 te = r->headers_in.te; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4260 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4261 if (te == NULL) { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4262 v->not_found = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4263 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4264 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4265 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4266 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
|
4267 (u_char *) "trailers", 8 - 1) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4268 == NULL) |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4269 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4270 v->not_found = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4271 return NGX_OK; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4272 } |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4273 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4274 v->valid = 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4275 v->no_cacheable = 0; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4276 v->not_found = 0; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4277 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4278 v->data = (u_char *) "trailers"; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4279 v->len = sizeof("trailers") - 1; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4280 |
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 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4285 static ngx_int_t |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4286 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
|
4287 { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4288 ngx_http_variable_t *var, *v; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4289 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4290 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
|
4291 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
|
4292 if (var == NULL) { |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4293 return NGX_ERROR; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4294 } |
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 var->get_handler = v->get_handler; |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4297 var->data = v->data; |
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 |
c693daca57f7
gRPC: special handling of the TE request header.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7233
diff
changeset
|
4300 return NGX_OK; |
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 |
7233 | 4304 static void * |
4305 ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) | |
4306 { | |
4307 ngx_http_grpc_loc_conf_t *conf; | |
4308 | |
4309 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_grpc_loc_conf_t)); | |
4310 if (conf == NULL) { | |
4311 return NULL; | |
4312 } | |
4313 | |
4314 /* | |
4315 * set by ngx_pcalloc(): | |
4316 * | |
4317 * conf->upstream.ignore_headers = 0; | |
4318 * conf->upstream.next_upstream = 0; | |
4319 * conf->upstream.hide_headers_hash = { NULL, 0 }; | |
4320 * conf->upstream.ssl_name = NULL; | |
4321 * | |
4322 * conf->headers.lengths = NULL; | |
4323 * conf->headers.values = NULL; | |
4324 * conf->headers.hash = { NULL, 0 }; | |
4325 * conf->host = { 0, NULL }; | |
4326 * conf->host_set = 0; | |
4327 * conf->ssl = 0; | |
4328 * conf->ssl_protocols = 0; | |
4329 * conf->ssl_ciphers = { 0, NULL }; | |
4330 * conf->ssl_trusted_certificate = { 0, NULL }; | |
4331 * conf->ssl_crl = { 0, NULL }; | |
4332 * conf->ssl_certificate = { 0, NULL }; | |
4333 * conf->ssl_certificate_key = { 0, NULL }; | |
4334 */ | |
4335 | |
4336 conf->upstream.local = NGX_CONF_UNSET_PTR; | |
7371
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4337 conf->upstream.socket_keepalive = NGX_CONF_UNSET; |
7233 | 4338 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; |
4339 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; | |
4340 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; | |
4341 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; | |
4342 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; | |
4343 | |
4344 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; | |
4345 | |
4346 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; | |
4347 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; | |
4348 | |
4349 conf->upstream.intercept_errors = NGX_CONF_UNSET; | |
4350 | |
4351 #if (NGX_HTTP_SSL) | |
4352 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; | |
4353 conf->upstream.ssl_server_name = NGX_CONF_UNSET; | |
4354 conf->upstream.ssl_verify = NGX_CONF_UNSET; | |
4355 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; | |
4356 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
|
4357 conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; |
7233 | 4358 #endif |
4359 | |
4360 /* the hardcoded values */ | |
4361 conf->upstream.cyclic_temp_file = 0; | |
4362 conf->upstream.buffering = 0; | |
4363 conf->upstream.ignore_client_abort = 0; | |
4364 conf->upstream.send_lowat = 0; | |
4365 conf->upstream.bufs.num = 0; | |
4366 conf->upstream.busy_buffers_size = 0; | |
4367 conf->upstream.max_temp_file_size = 0; | |
4368 conf->upstream.temp_file_write_size = 0; | |
4369 conf->upstream.pass_request_headers = 1; | |
4370 conf->upstream.pass_request_body = 1; | |
4371 conf->upstream.force_ranges = 0; | |
4372 conf->upstream.pass_trailers = 1; | |
4373 conf->upstream.preserve_output = 1; | |
4374 | |
7728
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4375 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
|
4376 |
7233 | 4377 ngx_str_set(&conf->upstream.module, "grpc"); |
4378 | |
4379 return conf; | |
4380 } | |
4381 | |
4382 | |
4383 static char * | |
4384 ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
4385 { | |
4386 ngx_http_grpc_loc_conf_t *prev = parent; | |
4387 ngx_http_grpc_loc_conf_t *conf = child; | |
4388 | |
4389 ngx_int_t rc; | |
4390 ngx_hash_init_t hash; | |
4391 ngx_http_core_loc_conf_t *clcf; | |
4392 | |
4393 ngx_conf_merge_ptr_value(conf->upstream.local, | |
4394 prev->upstream.local, NULL); | |
4395 | |
7371
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4396 ngx_conf_merge_value(conf->upstream.socket_keepalive, |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4397 prev->upstream.socket_keepalive, 0); |
8b68d50090e4
Upstream: proxy_socket_keepalive and friends.
Vladimir Homutov <vl@nginx.com>
parents:
7350
diff
changeset
|
4398 |
7233 | 4399 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, |
4400 prev->upstream.next_upstream_tries, 0); | |
4401 | |
4402 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, | |
4403 prev->upstream.connect_timeout, 60000); | |
4404 | |
4405 ngx_conf_merge_msec_value(conf->upstream.send_timeout, | |
4406 prev->upstream.send_timeout, 60000); | |
4407 | |
4408 ngx_conf_merge_msec_value(conf->upstream.read_timeout, | |
4409 prev->upstream.read_timeout, 60000); | |
4410 | |
4411 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, | |
4412 prev->upstream.next_upstream_timeout, 0); | |
4413 | |
4414 ngx_conf_merge_size_value(conf->upstream.buffer_size, | |
4415 prev->upstream.buffer_size, | |
4416 (size_t) ngx_pagesize); | |
4417 | |
4418 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, | |
4419 prev->upstream.ignore_headers, | |
4420 NGX_CONF_BITMASK_SET); | |
4421 | |
4422 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, | |
4423 prev->upstream.next_upstream, | |
4424 (NGX_CONF_BITMASK_SET | |
4425 |NGX_HTTP_UPSTREAM_FT_ERROR | |
4426 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); | |
4427 | |
4428 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { | |
4429 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET | |
4430 |NGX_HTTP_UPSTREAM_FT_OFF; | |
4431 } | |
4432 | |
4433 ngx_conf_merge_value(conf->upstream.intercept_errors, | |
4434 prev->upstream.intercept_errors, 0); | |
4435 | |
4436 #if (NGX_HTTP_SSL) | |
4437 | |
4438 ngx_conf_merge_value(conf->upstream.ssl_session_reuse, | |
4439 prev->upstream.ssl_session_reuse, 1); | |
4440 | |
4441 ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, | |
4442 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 | |
4443 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); | |
4444 | |
4445 ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, | |
4446 "DEFAULT"); | |
4447 | |
4448 if (conf->upstream.ssl_name == NULL) { | |
4449 conf->upstream.ssl_name = prev->upstream.ssl_name; | |
4450 } | |
4451 | |
4452 ngx_conf_merge_value(conf->upstream.ssl_server_name, | |
4453 prev->upstream.ssl_server_name, 0); | |
4454 ngx_conf_merge_value(conf->upstream.ssl_verify, | |
4455 prev->upstream.ssl_verify, 0); | |
4456 ngx_conf_merge_uint_value(conf->ssl_verify_depth, | |
4457 prev->ssl_verify_depth, 1); | |
4458 ngx_conf_merge_str_value(conf->ssl_trusted_certificate, | |
4459 prev->ssl_trusted_certificate, ""); | |
4460 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); | |
4461 | |
4462 ngx_conf_merge_str_value(conf->ssl_certificate, | |
4463 prev->ssl_certificate, ""); | |
4464 ngx_conf_merge_str_value(conf->ssl_certificate_key, | |
4465 prev->ssl_certificate_key, ""); | |
4466 ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); | |
4467 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4468 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
|
4469 prev->ssl_conf_commands, NULL); |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4470 |
7233 | 4471 if (conf->ssl && ngx_http_grpc_set_ssl(cf, conf) != NGX_OK) { |
4472 return NGX_CONF_ERROR; | |
4473 } | |
4474 | |
4475 #endif | |
4476 | |
4477 hash.max_size = 512; | |
4478 hash.bucket_size = ngx_align(64, ngx_cacheline_size); | |
4479 hash.name = "grpc_headers_hash"; | |
4480 | |
4481 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, | |
4482 &prev->upstream, ngx_http_grpc_hide_headers, &hash) | |
4483 != NGX_OK) | |
4484 { | |
4485 return NGX_CONF_ERROR; | |
4486 } | |
4487 | |
4488 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
4489 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4490 if (clcf->noname |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4491 && 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
|
4492 { |
7233 | 4493 conf->upstream.upstream = prev->upstream.upstream; |
4494 conf->host = prev->host; | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4495 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4496 conf->grpc_lengths = prev->grpc_lengths; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4497 conf->grpc_values = prev->grpc_values; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4498 |
7233 | 4499 #if (NGX_HTTP_SSL) |
4500 conf->upstream.ssl = prev->upstream.ssl; | |
4501 #endif | |
4502 } | |
4503 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4504 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
|
4505 && (conf->upstream.upstream || conf->grpc_lengths)) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4506 { |
7233 | 4507 clcf->handler = ngx_http_grpc_handler; |
4508 } | |
4509 | |
7728
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4510 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
|
4511 |
485dba3e2a01
Core: ngx_conf_set_keyval_slot() now accepts NGX_CONF_UNSET_PTR.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7680
diff
changeset
|
4512 if (conf->headers_source == prev->headers_source) { |
7233 | 4513 conf->headers = prev->headers; |
4514 conf->host_set = prev->host_set; | |
4515 } | |
4516 | |
4517 rc = ngx_http_grpc_init_headers(cf, conf, &conf->headers, | |
4518 ngx_http_grpc_headers); | |
4519 if (rc != NGX_OK) { | |
4520 return NGX_CONF_ERROR; | |
4521 } | |
4522 | |
4523 /* | |
4524 * special handling to preserve conf->headers in the "http" section | |
4525 * to inherit it to all servers | |
4526 */ | |
4527 | |
4528 if (prev->headers.hash.buckets == NULL | |
4529 && conf->headers_source == prev->headers_source) | |
4530 { | |
4531 prev->headers = conf->headers; | |
4532 prev->host_set = conf->host_set; | |
4533 } | |
4534 | |
4535 return NGX_CONF_OK; | |
4536 } | |
4537 | |
4538 | |
4539 static ngx_int_t | |
4540 ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf, | |
4541 ngx_http_grpc_headers_t *headers, ngx_keyval_t *default_headers) | |
4542 { | |
4543 u_char *p; | |
4544 size_t size; | |
4545 uintptr_t *code; | |
4546 ngx_uint_t i; | |
4547 ngx_array_t headers_names, headers_merged; | |
4548 ngx_keyval_t *src, *s, *h; | |
4549 ngx_hash_key_t *hk; | |
4550 ngx_hash_init_t hash; | |
4551 ngx_http_script_compile_t sc; | |
4552 ngx_http_script_copy_code_t *copy; | |
4553 | |
4554 if (headers->hash.buckets) { | |
4555 return NGX_OK; | |
4556 } | |
4557 | |
4558 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) | |
4559 != NGX_OK) | |
4560 { | |
4561 return NGX_ERROR; | |
4562 } | |
4563 | |
4564 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) | |
4565 != NGX_OK) | |
4566 { | |
4567 return NGX_ERROR; | |
4568 } | |
4569 | |
4570 headers->lengths = ngx_array_create(cf->pool, 64, 1); | |
4571 if (headers->lengths == NULL) { | |
4572 return NGX_ERROR; | |
4573 } | |
4574 | |
4575 headers->values = ngx_array_create(cf->pool, 512, 1); | |
4576 if (headers->values == NULL) { | |
4577 return NGX_ERROR; | |
4578 } | |
4579 | |
4580 if (conf->headers_source) { | |
4581 | |
4582 src = conf->headers_source->elts; | |
4583 for (i = 0; i < conf->headers_source->nelts; i++) { | |
4584 | |
4585 if (src[i].key.len == 4 | |
4586 && ngx_strncasecmp(src[i].key.data, (u_char *) "Host", 4) == 0) | |
4587 { | |
4588 conf->host_set = 1; | |
4589 } | |
4590 | |
4591 s = ngx_array_push(&headers_merged); | |
4592 if (s == NULL) { | |
4593 return NGX_ERROR; | |
4594 } | |
4595 | |
4596 *s = src[i]; | |
4597 } | |
4598 } | |
4599 | |
4600 h = default_headers; | |
4601 | |
4602 while (h->key.len) { | |
4603 | |
4604 src = headers_merged.elts; | |
4605 for (i = 0; i < headers_merged.nelts; i++) { | |
4606 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { | |
4607 goto next; | |
4608 } | |
4609 } | |
4610 | |
4611 s = ngx_array_push(&headers_merged); | |
4612 if (s == NULL) { | |
4613 return NGX_ERROR; | |
4614 } | |
4615 | |
4616 *s = *h; | |
4617 | |
4618 next: | |
4619 | |
4620 h++; | |
4621 } | |
4622 | |
4623 | |
4624 src = headers_merged.elts; | |
4625 for (i = 0; i < headers_merged.nelts; i++) { | |
4626 | |
4627 hk = ngx_array_push(&headers_names); | |
4628 if (hk == NULL) { | |
4629 return NGX_ERROR; | |
4630 } | |
4631 | |
4632 hk->key = src[i].key; | |
4633 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len); | |
4634 hk->value = (void *) 1; | |
4635 | |
4636 if (src[i].value.len == 0) { | |
4637 continue; | |
4638 } | |
4639 | |
4640 copy = ngx_array_push_n(headers->lengths, | |
4641 sizeof(ngx_http_script_copy_code_t)); | |
4642 if (copy == NULL) { | |
4643 return NGX_ERROR; | |
4644 } | |
4645 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
7249
diff
changeset
|
4646 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
|
4647 ngx_http_script_copy_len_code; |
7233 | 4648 copy->len = src[i].key.len; |
4649 | |
4650 size = (sizeof(ngx_http_script_copy_code_t) | |
4651 + src[i].key.len + sizeof(uintptr_t) - 1) | |
4652 & ~(sizeof(uintptr_t) - 1); | |
4653 | |
4654 copy = ngx_array_push_n(headers->values, size); | |
4655 if (copy == NULL) { | |
4656 return NGX_ERROR; | |
4657 } | |
4658 | |
4659 copy->code = ngx_http_script_copy_code; | |
4660 copy->len = src[i].key.len; | |
4661 | |
4662 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
4663 ngx_memcpy(p, src[i].key.data, src[i].key.len); | |
4664 | |
4665 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
4666 | |
4667 sc.cf = cf; | |
4668 sc.source = &src[i].value; | |
4669 sc.flushes = &headers->flushes; | |
4670 sc.lengths = &headers->lengths; | |
4671 sc.values = &headers->values; | |
4672 | |
4673 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
4674 return NGX_ERROR; | |
4675 } | |
4676 | |
4677 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); | |
4678 if (code == NULL) { | |
4679 return NGX_ERROR; | |
4680 } | |
4681 | |
4682 *code = (uintptr_t) NULL; | |
4683 | |
4684 code = ngx_array_push_n(headers->values, sizeof(uintptr_t)); | |
4685 if (code == NULL) { | |
4686 return NGX_ERROR; | |
4687 } | |
4688 | |
4689 *code = (uintptr_t) NULL; | |
4690 } | |
4691 | |
4692 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); | |
4693 if (code == NULL) { | |
4694 return NGX_ERROR; | |
4695 } | |
4696 | |
4697 *code = (uintptr_t) NULL; | |
4698 | |
4699 | |
4700 hash.hash = &headers->hash; | |
4701 hash.key = ngx_hash_key_lc; | |
4702 hash.max_size = 512; | |
4703 hash.bucket_size = 64; | |
4704 hash.name = "grpc_headers_hash"; | |
4705 hash.pool = cf->pool; | |
4706 hash.temp_pool = NULL; | |
4707 | |
4708 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); | |
4709 } | |
4710 | |
4711 | |
4712 static char * | |
4713 ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
4714 { | |
4715 ngx_http_grpc_loc_conf_t *glcf = conf; | |
4716 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4717 size_t add; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4718 ngx_str_t *value, *url; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4719 ngx_url_t u; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4720 ngx_uint_t n; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4721 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
|
4722 ngx_http_script_compile_t sc; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4723 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4724 if (glcf->upstream.upstream || glcf->grpc_lengths) { |
7233 | 4725 return "is duplicate"; |
4726 } | |
4727 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4728 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
|
4729 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4730 clcf->handler = ngx_http_grpc_handler; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4731 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4732 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
|
4733 clcf->auto_redirect = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4734 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4735 |
7233 | 4736 value = cf->args->elts; |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4737 |
7233 | 4738 url = &value[1]; |
4739 | |
7619
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4740 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
|
4741 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4742 if (n) { |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4743 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4744 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
|
4745 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4746 sc.cf = cf; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4747 sc.source = url; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4748 sc.lengths = &glcf->grpc_lengths; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4749 sc.values = &glcf->grpc_values; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4750 sc.variables = n; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4751 sc.complete_lengths = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4752 sc.complete_values = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4753 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4754 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
|
4755 return NGX_CONF_ERROR; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4756 } |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4757 |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4758 #if (NGX_HTTP_SSL) |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4759 glcf->ssl = 1; |
6439ef81e37d
gRPC: variables support in the "grpc_pass" directive.
Vladimir Homutov <vl@nginx.com>
parents:
7473
diff
changeset
|
4760 #endif |
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 return NGX_CONF_OK; |
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 |
7233 | 4765 if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) { |
4766 add = 7; | |
4767 | |
4768 } else if (ngx_strncasecmp(url->data, (u_char *) "grpcs://", 8) == 0) { | |
4769 | |
4770 #if (NGX_HTTP_SSL) | |
4771 glcf->ssl = 1; | |
4772 | |
4773 add = 8; | |
4774 #else | |
4775 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4776 "grpcs protocol requires SSL support"); | |
4777 return NGX_CONF_ERROR; | |
4778 #endif | |
4779 | |
4780 } else { | |
4781 add = 0; | |
4782 } | |
4783 | |
4784 ngx_memzero(&u, sizeof(ngx_url_t)); | |
4785 | |
4786 u.url.len = url->len - add; | |
4787 u.url.data = url->data + add; | |
4788 u.no_resolve = 1; | |
4789 | |
4790 glcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); | |
4791 if (glcf->upstream.upstream == NULL) { | |
4792 return NGX_CONF_ERROR; | |
4793 } | |
4794 | |
4795 if (u.family != AF_UNIX) { | |
4796 | |
4797 if (u.no_port) { | |
4798 glcf->host = u.host; | |
4799 | |
4800 } else { | |
4801 glcf->host.len = u.host.len + 1 + u.port_text.len; | |
4802 glcf->host.data = u.host.data; | |
4803 } | |
4804 | |
4805 } else { | |
4806 ngx_str_set(&glcf->host, "localhost"); | |
4807 } | |
4808 | |
4809 return NGX_CONF_OK; | |
4810 } | |
4811 | |
4812 | |
4813 #if (NGX_HTTP_SSL) | |
4814 | |
4815 static char * | |
4816 ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
4817 { | |
4818 ngx_http_grpc_loc_conf_t *glcf = conf; | |
4819 | |
4820 ngx_str_t *value; | |
4821 | |
4822 if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) { | |
4823 return "is duplicate"; | |
4824 } | |
4825 | |
4826 value = cf->args->elts; | |
4827 | |
4828 glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); | |
4829 | |
4830 if (glcf->ssl_passwords == NULL) { | |
4831 return NGX_CONF_ERROR; | |
4832 } | |
4833 | |
4834 return NGX_CONF_OK; | |
4835 } | |
4836 | |
4837 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4838 static char * |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4839 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
|
4840 { |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4841 #ifndef SSL_CONF_FLAG_FILE |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4842 return "is not supported on this platform"; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4843 #endif |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4844 |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4845 return NGX_CONF_OK; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4846 } |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4847 |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4848 |
7233 | 4849 static ngx_int_t |
4850 ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) | |
4851 { | |
4852 ngx_pool_cleanup_t *cln; | |
4853 | |
4854 glcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); | |
4855 if (glcf->upstream.ssl == NULL) { | |
4856 return NGX_ERROR; | |
4857 } | |
4858 | |
4859 glcf->upstream.ssl->log = cf->log; | |
4860 | |
4861 if (ngx_ssl_create(glcf->upstream.ssl, glcf->ssl_protocols, NULL) | |
4862 != NGX_OK) | |
4863 { | |
4864 return NGX_ERROR; | |
4865 } | |
4866 | |
4867 cln = ngx_pool_cleanup_add(cf->pool, 0); | |
4868 if (cln == NULL) { | |
7473
8981dbb12254
SSL: fixed potential leak on memory allocation errors.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7379
diff
changeset
|
4869 ngx_ssl_cleanup_ctx(glcf->upstream.ssl); |
7233 | 4870 return NGX_ERROR; |
4871 } | |
4872 | |
4873 cln->handler = ngx_ssl_cleanup_ctx; | |
4874 cln->data = glcf->upstream.ssl; | |
4875 | |
4876 if (glcf->ssl_certificate.len) { | |
4877 | |
4878 if (glcf->ssl_certificate_key.len == 0) { | |
4879 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
4880 "no \"grpc_ssl_certificate_key\" is defined " | |
4881 "for certificate \"%V\"", &glcf->ssl_certificate); | |
4882 return NGX_ERROR; | |
4883 } | |
4884 | |
4885 if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate, | |
4886 &glcf->ssl_certificate_key, glcf->ssl_passwords) | |
4887 != NGX_OK) | |
4888 { | |
4889 return NGX_ERROR; | |
4890 } | |
4891 } | |
4892 | |
4893 if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) | |
4894 != NGX_OK) | |
4895 { | |
4896 return NGX_ERROR; | |
4897 } | |
4898 | |
4899 if (glcf->upstream.ssl_verify) { | |
4900 if (glcf->ssl_trusted_certificate.len == 0) { | |
4901 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
4902 "no grpc_ssl_trusted_certificate for grpc_ssl_verify"); | |
4903 return NGX_ERROR; | |
4904 } | |
4905 | |
4906 if (ngx_ssl_trusted_certificate(cf, glcf->upstream.ssl, | |
4907 &glcf->ssl_trusted_certificate, | |
4908 glcf->ssl_verify_depth) | |
4909 != NGX_OK) | |
4910 { | |
4911 return NGX_ERROR; | |
4912 } | |
4913 | |
4914 if (ngx_ssl_crl(cf, glcf->upstream.ssl, &glcf->ssl_crl) != NGX_OK) { | |
4915 return NGX_ERROR; | |
4916 } | |
4917 } | |
4918 | |
7320
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4919 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
|
4920 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
|
4921 != NGX_OK) |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4922 { |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4923 return NGX_ERROR; |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4924 } |
696df3ac27ac
SSL: save sessions for upstream peers using a callback function.
Sergey Kandaurov <pluknet@nginx.com>
parents:
7305
diff
changeset
|
4925 |
7233 | 4926 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation |
4927 | |
4928 if (SSL_CTX_set_alpn_protos(glcf->upstream.ssl->ctx, | |
4929 (u_char *) "\x02h2", 3) | |
4930 != 0) | |
4931 { | |
4932 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, | |
4933 "SSL_CTX_set_alpn_protos() failed"); | |
4934 return NGX_ERROR; | |
4935 } | |
4936 | |
4937 #endif | |
4938 | |
7730
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4939 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
|
4940 != NGX_OK) |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4941 { |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4942 return NGX_ERROR; |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4943 } |
1a719ee45526
Upstream: proxy_ssl_conf_command and friends.
Maxim Dounin <mdounin@mdounin.ru>
parents:
7728
diff
changeset
|
4944 |
7233 | 4945 return NGX_OK; |
4946 } | |
4947 | |
4948 #endif |