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