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