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