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