1
2 /*
3 * Copyright (C) Igor Sysoev
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 caches; /* ngx_http_file_cache_t * */
15 } ngx_http_proxy_main_conf_t;
16
17
18 typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
19
20 typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
21 ngx_table_elt_t *h, size_t prefix, size_t len,
22 ngx_http_proxy_rewrite_t *pr);
23
24 struct ngx_http_proxy_rewrite_s {
25 ngx_http_proxy_rewrite_pt handler;
26
27 union {
28 ngx_http_complex_value_t complex;
29 #if (NGX_PCRE)
30 ngx_http_regex_t *regex;
31 #endif
32 } pattern;
33
34 ngx_http_complex_value_t replacement;
35 };
36
37
38 typedef struct {
39 ngx_str_t key_start;
40 ngx_str_t schema;
41 ngx_str_t host_header;
42 ngx_str_t port;
43 ngx_str_t uri;
44 } ngx_http_proxy_vars_t;
45
46
47 typedef struct {
48 ngx_array_t *flushes;
49 ngx_array_t *lengths;
50 ngx_array_t *values;
51 ngx_hash_t hash;
52 } ngx_http_proxy_headers_t;
53
54
55 typedef struct {
56 ngx_http_upstream_conf_t upstream;
57
58 ngx_array_t *body_flushes;
59 ngx_array_t *body_lengths;
60 ngx_array_t *body_values;
61 ngx_str_t body_source;
62
63 ngx_http_proxy_headers_t headers;
64 #if (NGX_HTTP_CACHE)
65 ngx_http_proxy_headers_t headers_cache;
66 #endif
67 ngx_array_t *headers_source;
68
69 ngx_array_t *proxy_lengths;
70 ngx_array_t *proxy_values;
71
72 ngx_array_t *redirects;
73 ngx_array_t *cookie_domains;
74 ngx_array_t *cookie_paths;
75
76 ngx_http_complex_value_t *method;
77 ngx_str_t location;
78 ngx_str_t url;
79
80 #if (NGX_HTTP_CACHE)
81 ngx_http_complex_value_t cache_key;
82 #endif
83
84 ngx_http_proxy_vars_t vars;
85
86 ngx_flag_t redirect;
87
88 ngx_uint_t http_version;
89
90 ngx_uint_t headers_hash_max_size;
91 ngx_uint_t headers_hash_bucket_size;
92
93 #if (NGX_HTTP_SSL)
94 ngx_uint_t ssl;
95 ngx_uint_t ssl_protocols;
96 ngx_str_t ssl_ciphers;
97 ngx_uint_t ssl_verify_depth;
98 ngx_str_t ssl_trusted_certificate;
99 ngx_str_t ssl_crl;
100 ngx_str_t ssl_certificate;
101 ngx_str_t ssl_certificate_key;
102 ngx_array_t *ssl_passwords;
103 #endif
104
105 #if (NGX_HAVE_FSTACK)
106 ngx_flag_t kernel_network_stack;
107 #endif
108 } ngx_http_proxy_loc_conf_t;
109
110
111 typedef struct {
112 ngx_http_status_t status;
113 ngx_http_chunked_t chunked;
114 ngx_http_proxy_vars_t vars;
115 off_t internal_body_length;
116
117 ngx_chain_t *free;
118 ngx_chain_t *busy;
119
120 unsigned head:1;
121 unsigned internal_chunked:1;
122 unsigned header_sent:1;
123 } ngx_http_proxy_ctx_t;
124
125
126 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
127 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
128 #if (NGX_HTTP_CACHE)
129 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
130 #endif
131 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
132 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
133 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
134 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
135 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
136 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
137 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
138 ngx_buf_t *buf);
139 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
140 ngx_buf_t *buf);
141 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
142 ssize_t bytes);
143 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
144 ssize_t bytes);
145 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
146 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
147 ngx_int_t rc);
148
149 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
150 ngx_http_variable_value_t *v, uintptr_t data);
151 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
152 ngx_http_variable_value_t *v, uintptr_t data);
153 static ngx_int_t
154 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
155 ngx_http_variable_value_t *v, uintptr_t data);
156 static ngx_int_t
157 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
158 ngx_http_variable_value_t *v, uintptr_t data);
159 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
160 ngx_http_variable_value_t *v, uintptr_t data);
161 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
162 ngx_table_elt_t *h, size_t prefix);
163 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
164 ngx_table_elt_t *h);
165 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
166 ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
167 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
168 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
169
170 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
171 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
172 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
173 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
174 void *parent, void *child);
175 static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
176 ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
177 ngx_keyval_t *default_headers);
178
179 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
180 void *conf);
181 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
182 void *conf);
183 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
184 void *conf);
185 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
186 void *conf);
187 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
188 void *conf);
189 #if (NGX_HTTP_CACHE)
190 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
191 void *conf);
192 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
193 void *conf);
194 #endif
195 #if (NGX_HTTP_SSL)
196 static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
197 ngx_command_t *cmd, void *conf);
198 #endif
199
200 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
201
202 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
203 ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
204
205 #if (NGX_HTTP_SSL)
206 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
207 ngx_http_proxy_loc_conf_t *plcf);
208 #endif
209 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
210
211
212 static ngx_conf_post_t ngx_http_proxy_lowat_post =
213 { ngx_http_proxy_lowat_check };
214
215
216 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
217 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
218 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
219 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
220 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
221 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
222 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
223 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
224 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
225 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
226 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
227 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
228 { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
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_proxy_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
246 #endif
247
248
249 static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
250 { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
251 { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
252 { ngx_null_string, 0 }
253 };
254
255
256 ngx_module_t ngx_http_proxy_module;
257
258
259 static ngx_command_t ngx_http_proxy_commands[] = {
260
261 { ngx_string("proxy_pass"),
262 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
263 ngx_http_proxy_pass,
264 NGX_HTTP_LOC_CONF_OFFSET,
265 0,
266 NULL },
267
268 { ngx_string("proxy_redirect"),
269 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
270 ngx_http_proxy_redirect,
271 NGX_HTTP_LOC_CONF_OFFSET,
272 0,
273 NULL },
274
275 { ngx_string("proxy_cookie_domain"),
276 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
277 ngx_http_proxy_cookie_domain,
278 NGX_HTTP_LOC_CONF_OFFSET,
279 0,
280 NULL },
281
282 { ngx_string("proxy_cookie_path"),
283 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
284 ngx_http_proxy_cookie_path,
285 NGX_HTTP_LOC_CONF_OFFSET,
286 0,
287 NULL },
288
289 { ngx_string("proxy_store"),
290 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
291 ngx_http_proxy_store,
292 NGX_HTTP_LOC_CONF_OFFSET,
293 0,
294 NULL },
295
296 { ngx_string("proxy_store_access"),
297 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
298 ngx_conf_set_access_slot,
299 NGX_HTTP_LOC_CONF_OFFSET,
300 offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
301 NULL },
302
303 { ngx_string("proxy_buffering"),
304 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
305 ngx_conf_set_flag_slot,
306 NGX_HTTP_LOC_CONF_OFFSET,
307 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
308 NULL },
309
310 { ngx_string("proxy_request_buffering"),
311 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
312 ngx_conf_set_flag_slot,
313 NGX_HTTP_LOC_CONF_OFFSET,
314 offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering),
315 NULL },
316
317 { ngx_string("proxy_ignore_client_abort"),
318 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
319 ngx_conf_set_flag_slot,
320 NGX_HTTP_LOC_CONF_OFFSET,
321 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
322 NULL },
323
324 { ngx_string("proxy_bind"),
325 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
326 ngx_http_upstream_bind_set_slot,
327 NGX_HTTP_LOC_CONF_OFFSET,
328 offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
329 NULL },
330
331 { ngx_string("proxy_socket_keepalive"),
332 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
333 ngx_conf_set_flag_slot,
334 NGX_HTTP_LOC_CONF_OFFSET,
335 offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive),
336 NULL },
337
338 { ngx_string("proxy_connect_timeout"),
339 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
340 ngx_conf_set_msec_slot,
341 NGX_HTTP_LOC_CONF_OFFSET,
342 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
343 NULL },
344
345 { ngx_string("proxy_send_timeout"),
346 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
347 ngx_conf_set_msec_slot,
348 NGX_HTTP_LOC_CONF_OFFSET,
349 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
350 NULL },
351
352 { ngx_string("proxy_send_lowat"),
353 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
354 ngx_conf_set_size_slot,
355 NGX_HTTP_LOC_CONF_OFFSET,
356 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
357 &ngx_http_proxy_lowat_post },
358
359 { ngx_string("proxy_intercept_errors"),
360 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
361 ngx_conf_set_flag_slot,
362 NGX_HTTP_LOC_CONF_OFFSET,
363 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
364 NULL },
365
366 { ngx_string("proxy_set_header"),
367 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
368 ngx_conf_set_keyval_slot,
369 NGX_HTTP_LOC_CONF_OFFSET,
370 offsetof(ngx_http_proxy_loc_conf_t, headers_source),
371 NULL },
372
373 { ngx_string("proxy_headers_hash_max_size"),
374 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
375 ngx_conf_set_num_slot,
376 NGX_HTTP_LOC_CONF_OFFSET,
377 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
378 NULL },
379
380 { ngx_string("proxy_headers_hash_bucket_size"),
381 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
382 ngx_conf_set_num_slot,
383 NGX_HTTP_LOC_CONF_OFFSET,
384 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
385 NULL },
386
387 { ngx_string("proxy_set_body"),
388 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
389 ngx_conf_set_str_slot,
390 NGX_HTTP_LOC_CONF_OFFSET,
391 offsetof(ngx_http_proxy_loc_conf_t, body_source),
392 NULL },
393
394 { ngx_string("proxy_method"),
395 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
396 ngx_http_set_complex_value_slot,
397 NGX_HTTP_LOC_CONF_OFFSET,
398 offsetof(ngx_http_proxy_loc_conf_t, method),
399 NULL },
400
401 { ngx_string("proxy_pass_request_headers"),
402 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
403 ngx_conf_set_flag_slot,
404 NGX_HTTP_LOC_CONF_OFFSET,
405 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
406 NULL },
407
408 { ngx_string("proxy_pass_request_body"),
409 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
410 ngx_conf_set_flag_slot,
411 NGX_HTTP_LOC_CONF_OFFSET,
412 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
413 NULL },
414
415 { ngx_string("proxy_buffer_size"),
416 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
417 ngx_conf_set_size_slot,
418 NGX_HTTP_LOC_CONF_OFFSET,
419 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
420 NULL },
421
422 { ngx_string("proxy_read_timeout"),
423 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
424 ngx_conf_set_msec_slot,
425 NGX_HTTP_LOC_CONF_OFFSET,
426 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
427 NULL },
428
429 { ngx_string("proxy_buffers"),
430 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
431 ngx_conf_set_bufs_slot,
432 NGX_HTTP_LOC_CONF_OFFSET,
433 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
434 NULL },
435
436 { ngx_string("proxy_busy_buffers_size"),
437 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
438 ngx_conf_set_size_slot,
439 NGX_HTTP_LOC_CONF_OFFSET,
440 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
441 NULL },
442
443 { ngx_string("proxy_force_ranges"),
444 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
445 ngx_conf_set_flag_slot,
446 NGX_HTTP_LOC_CONF_OFFSET,
447 offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
448 NULL },
449
450 { ngx_string("proxy_limit_rate"),
451 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
452 ngx_conf_set_size_slot,
453 NGX_HTTP_LOC_CONF_OFFSET,
454 offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
455 NULL },
456
457 #if (NGX_HTTP_CACHE)
458
459 { ngx_string("proxy_cache"),
460 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
461 ngx_http_proxy_cache,
462 NGX_HTTP_LOC_CONF_OFFSET,
463 0,
464 NULL },
465
466 { ngx_string("proxy_cache_key"),
467 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
468 ngx_http_proxy_cache_key,
469 NGX_HTTP_LOC_CONF_OFFSET,
470 0,
471 NULL },
472
473 { ngx_string("proxy_cache_path"),
474 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
475 ngx_http_file_cache_set_slot,
476 NGX_HTTP_MAIN_CONF_OFFSET,
477 offsetof(ngx_http_proxy_main_conf_t, caches),
478 &ngx_http_proxy_module },
479
480 { ngx_string("proxy_cache_bypass"),
481 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
482 ngx_http_set_predicate_slot,
483 NGX_HTTP_LOC_CONF_OFFSET,
484 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
485 NULL },
486
487 { ngx_string("proxy_no_cache"),
488 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
489 ngx_http_set_predicate_slot,
490 NGX_HTTP_LOC_CONF_OFFSET,
491 offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
492 NULL },
493
494 { ngx_string("proxy_cache_valid"),
495 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
496 ngx_http_file_cache_valid_set_slot,
497 NGX_HTTP_LOC_CONF_OFFSET,
498 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
499 NULL },
500
501 { ngx_string("proxy_cache_min_uses"),
502 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
503 ngx_conf_set_num_slot,
504 NGX_HTTP_LOC_CONF_OFFSET,
505 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
506 NULL },
507
508 { ngx_string("proxy_cache_max_range_offset"),
509 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
510 ngx_conf_set_off_slot,
511 NGX_HTTP_LOC_CONF_OFFSET,
512 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset),
513 NULL },
514
515 { ngx_string("proxy_cache_use_stale"),
516 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
517 ngx_conf_set_bitmask_slot,
518 NGX_HTTP_LOC_CONF_OFFSET,
519 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
520 &ngx_http_proxy_next_upstream_masks },
521
522 { ngx_string("proxy_cache_methods"),
523 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
524 ngx_conf_set_bitmask_slot,
525 NGX_HTTP_LOC_CONF_OFFSET,
526 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
527 &ngx_http_upstream_cache_method_mask },
528
529 { ngx_string("proxy_cache_lock"),
530 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
531 ngx_conf_set_flag_slot,
532 NGX_HTTP_LOC_CONF_OFFSET,
533 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
534 NULL },
535
536 { ngx_string("proxy_cache_lock_timeout"),
537 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
538 ngx_conf_set_msec_slot,
539 NGX_HTTP_LOC_CONF_OFFSET,
540 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
541 NULL },
542
543 { ngx_string("proxy_cache_lock_age"),
544 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
545 ngx_conf_set_msec_slot,
546 NGX_HTTP_LOC_CONF_OFFSET,
547 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age),
548 NULL },
549
550 { ngx_string("proxy_cache_revalidate"),
551 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
552 ngx_conf_set_flag_slot,
553 NGX_HTTP_LOC_CONF_OFFSET,
554 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
555 NULL },
556
557 { ngx_string("proxy_cache_convert_head"),
558 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
559 ngx_conf_set_flag_slot,
560 NGX_HTTP_LOC_CONF_OFFSET,
561 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_convert_head),
562 NULL },
563
564 { ngx_string("proxy_cache_background_update"),
565 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
566 ngx_conf_set_flag_slot,
567 NGX_HTTP_LOC_CONF_OFFSET,
568 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_background_update),
569 NULL },
570
571 #endif
572
573 { ngx_string("proxy_temp_path"),
574 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
575 ngx_conf_set_path_slot,
576 NGX_HTTP_LOC_CONF_OFFSET,
577 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
578 NULL },
579
580 { ngx_string("proxy_max_temp_file_size"),
581 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
582 ngx_conf_set_size_slot,
583 NGX_HTTP_LOC_CONF_OFFSET,
584 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
585 NULL },
586
587 { ngx_string("proxy_temp_file_write_size"),
588 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
589 ngx_conf_set_size_slot,
590 NGX_HTTP_LOC_CONF_OFFSET,
591 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
592 NULL },
593
594 { ngx_string("proxy_next_upstream"),
595 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
596 ngx_conf_set_bitmask_slot,
597 NGX_HTTP_LOC_CONF_OFFSET,
598 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
599 &ngx_http_proxy_next_upstream_masks },
600
601 { ngx_string("proxy_next_upstream_tries"),
602 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
603 ngx_conf_set_num_slot,
604 NGX_HTTP_LOC_CONF_OFFSET,
605 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
606 NULL },
607
608 { ngx_string("proxy_next_upstream_timeout"),
609 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
610 ngx_conf_set_msec_slot,
611 NGX_HTTP_LOC_CONF_OFFSET,
612 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
613 NULL },
614
615 { ngx_string("proxy_pass_header"),
616 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
617 ngx_conf_set_str_array_slot,
618 NGX_HTTP_LOC_CONF_OFFSET,
619 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
620 NULL },
621
622 { ngx_string("proxy_hide_header"),
623 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
624 ngx_conf_set_str_array_slot,
625 NGX_HTTP_LOC_CONF_OFFSET,
626 offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
627 NULL },
628
629 { ngx_string("proxy_ignore_headers"),
630 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
631 ngx_conf_set_bitmask_slot,
632 NGX_HTTP_LOC_CONF_OFFSET,
633 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
634 &ngx_http_upstream_ignore_headers_masks },
635
636 { ngx_string("proxy_http_version"),
637 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
638 ngx_conf_set_enum_slot,
639 NGX_HTTP_LOC_CONF_OFFSET,
640 offsetof(ngx_http_proxy_loc_conf_t, http_version),
641 &ngx_http_proxy_http_version },
642
643 #if (NGX_HTTP_SSL)
644
645 { ngx_string("proxy_ssl_session_reuse"),
646 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
647 ngx_conf_set_flag_slot,
648 NGX_HTTP_LOC_CONF_OFFSET,
649 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
650 NULL },
651
652 { ngx_string("proxy_ssl_protocols"),
653 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
654 ngx_conf_set_bitmask_slot,
655 NGX_HTTP_LOC_CONF_OFFSET,
656 offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
657 &ngx_http_proxy_ssl_protocols },
658
659 { ngx_string("proxy_ssl_ciphers"),
660 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
661 ngx_conf_set_str_slot,
662 NGX_HTTP_LOC_CONF_OFFSET,
663 offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
664 NULL },
665
666 { ngx_string("proxy_ssl_name"),
667 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
668 ngx_http_set_complex_value_slot,
669 NGX_HTTP_LOC_CONF_OFFSET,
670 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name),
671 NULL },
672
673 { ngx_string("proxy_ssl_server_name"),
674 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
675 ngx_conf_set_flag_slot,
676 NGX_HTTP_LOC_CONF_OFFSET,
677 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
678 NULL },
679
680 { ngx_string("proxy_ssl_verify"),
681 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
682 ngx_conf_set_flag_slot,
683 NGX_HTTP_LOC_CONF_OFFSET,
684 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
685 NULL },
686
687 { ngx_string("proxy_ssl_verify_depth"),
688 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
689 ngx_conf_set_num_slot,
690 NGX_HTTP_LOC_CONF_OFFSET,
691 offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
692 NULL },
693
694 { ngx_string("proxy_ssl_trusted_certificate"),
695 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
696 ngx_conf_set_str_slot,
697 NGX_HTTP_LOC_CONF_OFFSET,
698 offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
699 NULL },
700
701 { ngx_string("proxy_ssl_crl"),
702 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
703 ngx_conf_set_str_slot,
704 NGX_HTTP_LOC_CONF_OFFSET,
705 offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
706 NULL },
707
708 { ngx_string("proxy_ssl_certificate"),
709 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
710 ngx_conf_set_str_slot,
711 NGX_HTTP_LOC_CONF_OFFSET,
712 offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
713 NULL },
714
715 { ngx_string("proxy_ssl_certificate_key"),
716 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
717 ngx_conf_set_str_slot,
718 NGX_HTTP_LOC_CONF_OFFSET,
719 offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
720 NULL },
721
722 { ngx_string("proxy_ssl_password_file"),
723 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
724 ngx_http_proxy_ssl_password_file,
725 NGX_HTTP_LOC_CONF_OFFSET,
726 0,
727 NULL },
728
729 #endif
730
731 #if (NGX_HAVE_FSTACK)
732
733 { ngx_string("proxy_kernel_network_stack"),
734 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
735 ngx_conf_set_flag_slot,
736 NGX_HTTP_LOC_CONF_OFFSET,
737 offsetof(ngx_http_proxy_loc_conf_t, kernel_network_stack),
738 NULL },
739
740 #endif
741
742 ngx_null_command
743 };
744
745
746 static ngx_http_module_t ngx_http_proxy_module_ctx = {
747 ngx_http_proxy_add_variables, /* preconfiguration */
748 NULL, /* postconfiguration */
749
750 ngx_http_proxy_create_main_conf, /* create main configuration */
751 NULL, /* init main configuration */
752
753 NULL, /* create server configuration */
754 NULL, /* merge server configuration */
755
756 ngx_http_proxy_create_loc_conf, /* create location configuration */
757 ngx_http_proxy_merge_loc_conf /* merge location configuration */
758 };
759
760
761 ngx_module_t ngx_http_proxy_module = {
762 NGX_MODULE_V1,
763 &ngx_http_proxy_module_ctx, /* module context */
764 ngx_http_proxy_commands, /* module directives */
765 NGX_HTTP_MODULE, /* module type */
766 NULL, /* init master */
767 NULL, /* init module */
768 NULL, /* init process */
769 NULL, /* init thread */
770 NULL, /* exit thread */
771 NULL, /* exit process */
772 NULL, /* exit master */
773 NGX_MODULE_V1_PADDING
774 };
775
776
777 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
778 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
779
780
781 static ngx_keyval_t ngx_http_proxy_headers[] = {
782 { ngx_string("Host"), ngx_string("$proxy_host") },
783 { ngx_string("Connection"), ngx_string("close") },
784 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
785 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
786 { ngx_string("TE"), ngx_string("") },
787 { ngx_string("Keep-Alive"), ngx_string("") },
788 { ngx_string("Expect"), ngx_string("") },
789 { ngx_string("Upgrade"), ngx_string("") },
790 { ngx_null_string, ngx_null_string }
791 };
792
793
794 static ngx_str_t ngx_http_proxy_hide_headers[] = {
795 ngx_string("Date"),
796 ngx_string("Server"),
797 ngx_string("X-Pad"),
798 ngx_string("X-Accel-Expires"),
799 ngx_string("X-Accel-Redirect"),
800 ngx_string("X-Accel-Limit-Rate"),
801 ngx_string("X-Accel-Buffering"),
802 ngx_string("X-Accel-Charset"),
803 ngx_null_string
804 };
805
806
807 #if (NGX_HTTP_CACHE)
808
809 static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
810 { ngx_string("Host"), ngx_string("$proxy_host") },
811 { ngx_string("Connection"), ngx_string("close") },
812 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
813 { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
814 { ngx_string("TE"), ngx_string("") },
815 { ngx_string("Keep-Alive"), ngx_string("") },
816 { ngx_string("Expect"), ngx_string("") },
817 { ngx_string("Upgrade"), ngx_string("") },
818 { ngx_string("If-Modified-Since"),
819 ngx_string("$upstream_cache_last_modified") },
820 { ngx_string("If-Unmodified-Since"), ngx_string("") },
821 { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") },
822 { ngx_string("If-Match"), ngx_string("") },
823 { ngx_string("Range"), ngx_string("") },
824 { ngx_string("If-Range"), ngx_string("") },
825 { ngx_null_string, ngx_null_string }
826 };
827
828 #endif
829
830
831 static ngx_http_variable_t ngx_http_proxy_vars[] = {
832
833 { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
834 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
835
836 { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
837 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
838
839 { ngx_string("proxy_add_x_forwarded_for"), NULL,
840 ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
841
842 #if 0
843 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
844 #endif
845
846 { ngx_string("proxy_internal_body_length"), NULL,
847 ngx_http_proxy_internal_body_length_variable, 0,
848 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
849
850 { ngx_string("proxy_internal_chunked"), NULL,
851 ngx_http_proxy_internal_chunked_variable, 0,
852 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
853
854 ngx_http_null_variable
855 };
856
857
858 static ngx_path_init_t ngx_http_proxy_temp_path = {
859 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
860 };
861
862
863 static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t * r)864 ngx_http_proxy_handler(ngx_http_request_t *r)
865 {
866 ngx_int_t rc;
867 ngx_http_upstream_t *u;
868 ngx_http_proxy_ctx_t *ctx;
869 ngx_http_proxy_loc_conf_t *plcf;
870 #if (NGX_HTTP_CACHE)
871 ngx_http_proxy_main_conf_t *pmcf;
872 #endif
873
874 if (ngx_http_upstream_create(r) != NGX_OK) {
875 return NGX_HTTP_INTERNAL_SERVER_ERROR;
876 }
877
878 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
879 if (ctx == NULL) {
880 return NGX_HTTP_INTERNAL_SERVER_ERROR;
881 }
882
883 ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
884
885 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
886
887 u = r->upstream;
888
889 if (plcf->proxy_lengths == NULL) {
890 ctx->vars = plcf->vars;
891 u->schema = plcf->vars.schema;
892 #if (NGX_HTTP_SSL)
893 u->ssl = (plcf->upstream.ssl != NULL);
894 #endif
895
896 } else {
897 if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
898 return NGX_HTTP_INTERNAL_SERVER_ERROR;
899 }
900 }
901
902 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
903
904 u->conf = &plcf->upstream;
905
906 #if (NGX_HTTP_CACHE)
907 pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);
908
909 u->caches = &pmcf->caches;
910 u->create_key = ngx_http_proxy_create_key;
911 #endif
912
913 u->create_request = ngx_http_proxy_create_request;
914 u->reinit_request = ngx_http_proxy_reinit_request;
915 u->process_header = ngx_http_proxy_process_status_line;
916 u->abort_request = ngx_http_proxy_abort_request;
917 u->finalize_request = ngx_http_proxy_finalize_request;
918 r->state = 0;
919
920 if (plcf->redirects) {
921 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
922 }
923
924 if (plcf->cookie_domains || plcf->cookie_paths) {
925 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
926 }
927
928 u->buffering = plcf->upstream.buffering;
929
930 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
931 if (u->pipe == NULL) {
932 return NGX_HTTP_INTERNAL_SERVER_ERROR;
933 }
934
935 u->pipe->input_filter = ngx_http_proxy_copy_filter;
936 u->pipe->input_ctx = r;
937
938 u->input_filter_init = ngx_http_proxy_input_filter_init;
939 u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
940 u->input_filter_ctx = r;
941
942 u->accel = 1;
943
944 #if (NGX_HAVE_FSTACK)
945 u->peer.belong_to_host = plcf->kernel_network_stack;
946 #endif
947
948
949 if (!plcf->upstream.request_buffering
950 && plcf->body_values == NULL && plcf->upstream.pass_request_body
951 && (!r->headers_in.chunked
952 || plcf->http_version == NGX_HTTP_VERSION_11))
953 {
954 r->request_body_no_buffering = 1;
955 }
956
957 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
958
959 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
960 return rc;
961 }
962
963 return NGX_DONE;
964 }
965
966
967 static ngx_int_t
ngx_http_proxy_eval(ngx_http_request_t * r,ngx_http_proxy_ctx_t * ctx,ngx_http_proxy_loc_conf_t * plcf)968 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
969 ngx_http_proxy_loc_conf_t *plcf)
970 {
971 u_char *p;
972 size_t add;
973 u_short port;
974 ngx_str_t proxy;
975 ngx_url_t url;
976 ngx_http_upstream_t *u;
977
978 if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
979 plcf->proxy_values->elts)
980 == NULL)
981 {
982 return NGX_ERROR;
983 }
984
985 if (proxy.len > 7
986 && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
987 {
988 add = 7;
989 port = 80;
990
991 #if (NGX_HTTP_SSL)
992
993 } else if (proxy.len > 8
994 && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
995 {
996 add = 8;
997 port = 443;
998 r->upstream->ssl = 1;
999
1000 #endif
1001
1002 } else {
1003 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1004 "invalid URL prefix in \"%V\"", &proxy);
1005 return NGX_ERROR;
1006 }
1007
1008 u = r->upstream;
1009
1010 u->schema.len = add;
1011 u->schema.data = proxy.data;
1012
1013 ngx_memzero(&url, sizeof(ngx_url_t));
1014
1015 url.url.len = proxy.len - add;
1016 url.url.data = proxy.data + add;
1017 url.default_port = port;
1018 url.uri_part = 1;
1019 url.no_resolve = 1;
1020
1021 if (ngx_parse_url(r->pool, &url) != NGX_OK) {
1022 if (url.err) {
1023 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1024 "%s in upstream \"%V\"", url.err, &url.url);
1025 }
1026
1027 return NGX_ERROR;
1028 }
1029
1030 if (url.uri.len) {
1031 if (url.uri.data[0] == '?') {
1032 p = ngx_pnalloc(r->pool, url.uri.len + 1);
1033 if (p == NULL) {
1034 return NGX_ERROR;
1035 }
1036
1037 *p++ = '/';
1038 ngx_memcpy(p, url.uri.data, url.uri.len);
1039
1040 url.uri.len++;
1041 url.uri.data = p - 1;
1042 }
1043 }
1044
1045 ctx->vars.key_start = u->schema;
1046
1047 ngx_http_proxy_set_vars(&url, &ctx->vars);
1048
1049 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
1050 if (u->resolved == NULL) {
1051 return NGX_ERROR;
1052 }
1053
1054 if (url.addrs) {
1055 u->resolved->sockaddr = url.addrs[0].sockaddr;
1056 u->resolved->socklen = url.addrs[0].socklen;
1057 u->resolved->name = url.addrs[0].name;
1058 u->resolved->naddrs = 1;
1059 }
1060
1061 u->resolved->host = url.host;
1062 u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
1063 u->resolved->no_port = url.no_port;
1064
1065 return NGX_OK;
1066 }
1067
1068
1069 #if (NGX_HTTP_CACHE)
1070
1071 static ngx_int_t
ngx_http_proxy_create_key(ngx_http_request_t * r)1072 ngx_http_proxy_create_key(ngx_http_request_t *r)
1073 {
1074 size_t len, loc_len;
1075 u_char *p;
1076 uintptr_t escape;
1077 ngx_str_t *key;
1078 ngx_http_upstream_t *u;
1079 ngx_http_proxy_ctx_t *ctx;
1080 ngx_http_proxy_loc_conf_t *plcf;
1081
1082 u = r->upstream;
1083
1084 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1085
1086 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1087
1088 key = ngx_array_push(&r->cache->keys);
1089 if (key == NULL) {
1090 return NGX_ERROR;
1091 }
1092
1093 if (plcf->cache_key.value.data) {
1094
1095 if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
1096 return NGX_ERROR;
1097 }
1098
1099 return NGX_OK;
1100 }
1101
1102 *key = ctx->vars.key_start;
1103
1104 key = ngx_array_push(&r->cache->keys);
1105 if (key == NULL) {
1106 return NGX_ERROR;
1107 }
1108
1109 if (plcf->proxy_lengths && ctx->vars.uri.len) {
1110
1111 *key = ctx->vars.uri;
1112 u->uri = ctx->vars.uri;
1113
1114 return NGX_OK;
1115
1116 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
1117 *key = r->unparsed_uri;
1118 u->uri = r->unparsed_uri;
1119
1120 return NGX_OK;
1121 }
1122
1123 loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
1124
1125 if (r->quoted_uri || r->space_in_uri || r->internal) {
1126 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1127 r->uri.len - loc_len, NGX_ESCAPE_URI);
1128 } else {
1129 escape = 0;
1130 }
1131
1132 len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1133 + sizeof("?") - 1 + r->args.len;
1134
1135 p = ngx_pnalloc(r->pool, len);
1136 if (p == NULL) {
1137 return NGX_ERROR;
1138 }
1139
1140 key->data = p;
1141
1142 if (r->valid_location) {
1143 p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
1144 }
1145
1146 if (escape) {
1147 ngx_escape_uri(p, r->uri.data + loc_len,
1148 r->uri.len - loc_len, NGX_ESCAPE_URI);
1149 p += r->uri.len - loc_len + escape;
1150
1151 } else {
1152 p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
1153 }
1154
1155 if (r->args.len > 0) {
1156 *p++ = '?';
1157 p = ngx_copy(p, r->args.data, r->args.len);
1158 }
1159
1160 key->len = p - key->data;
1161 u->uri = *key;
1162
1163 return NGX_OK;
1164 }
1165
1166 #endif
1167
1168
1169 static ngx_int_t
ngx_http_proxy_create_request(ngx_http_request_t * r)1170 ngx_http_proxy_create_request(ngx_http_request_t *r)
1171 {
1172 size_t len, uri_len, loc_len, body_len,
1173 key_len, val_len;
1174 uintptr_t escape;
1175 ngx_buf_t *b;
1176 ngx_str_t method;
1177 ngx_uint_t i, unparsed_uri;
1178 ngx_chain_t *cl, *body;
1179 ngx_list_part_t *part;
1180 ngx_table_elt_t *header;
1181 ngx_http_upstream_t *u;
1182 ngx_http_proxy_ctx_t *ctx;
1183 ngx_http_script_code_pt code;
1184 ngx_http_proxy_headers_t *headers;
1185 ngx_http_script_engine_t e, le;
1186 ngx_http_proxy_loc_conf_t *plcf;
1187 ngx_http_script_len_code_pt lcode;
1188
1189 u = r->upstream;
1190
1191 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1192
1193 #if (NGX_HTTP_CACHE)
1194 headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
1195 #else
1196 headers = &plcf->headers;
1197 #endif
1198
1199 if (u->method.len) {
1200 /* HEAD was changed to GET to cache response */
1201 method = u->method;
1202
1203 } else if (plcf->method) {
1204 if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
1205 return NGX_ERROR;
1206 }
1207
1208 } else {
1209 method = r->method_name;
1210 }
1211
1212 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1213
1214 if (method.len == 4
1215 && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
1216 {
1217 ctx->head = 1;
1218 }
1219
1220 len = method.len + 1 + sizeof(ngx_http_proxy_version) - 1
1221 + sizeof(CRLF) - 1;
1222
1223 escape = 0;
1224 loc_len = 0;
1225 unparsed_uri = 0;
1226
1227 if (plcf->proxy_lengths && ctx->vars.uri.len) {
1228 uri_len = ctx->vars.uri.len;
1229
1230 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
1231 unparsed_uri = 1;
1232 uri_len = r->unparsed_uri.len;
1233
1234 } else {
1235 loc_len = (r->valid_location && ctx->vars.uri.len) ?
1236 plcf->location.len : 0;
1237
1238 if (r->quoted_uri || r->space_in_uri || r->internal) {
1239 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1240 r->uri.len - loc_len, NGX_ESCAPE_URI);
1241 }
1242
1243 uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1244 + sizeof("?") - 1 + r->args.len;
1245 }
1246
1247 if (uri_len == 0) {
1248 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1249 "zero length URI to proxy");
1250 return NGX_ERROR;
1251 }
1252
1253 len += uri_len;
1254
1255 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1256
1257 ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
1258 ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);
1259
1260 if (plcf->body_lengths) {
1261 le.ip = plcf->body_lengths->elts;
1262 le.request = r;
1263 le.flushed = 1;
1264 body_len = 0;
1265
1266 while (*(uintptr_t *) le.ip) {
1267 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1268 body_len += lcode(&le);
1269 }
1270
1271 ctx->internal_body_length = body_len;
1272 len += body_len;
1273
1274 } else if (r->headers_in.chunked && r->reading_body) {
1275 ctx->internal_body_length = -1;
1276 ctx->internal_chunked = 1;
1277
1278 } else {
1279 ctx->internal_body_length = r->headers_in.content_length_n;
1280 }
1281
1282 le.ip = headers->lengths->elts;
1283 le.request = r;
1284 le.flushed = 1;
1285
1286 while (*(uintptr_t *) le.ip) {
1287
1288 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1289 key_len = lcode(&le);
1290
1291 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
1292 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1293 }
1294 le.ip += sizeof(uintptr_t);
1295
1296 if (val_len == 0) {
1297 continue;
1298 }
1299
1300 len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
1301 }
1302
1303
1304 if (plcf->upstream.pass_request_headers) {
1305 part = &r->headers_in.headers.part;
1306 header = part->elts;
1307
1308 for (i = 0; /* void */; i++) {
1309
1310 if (i >= part->nelts) {
1311 if (part->next == NULL) {
1312 break;
1313 }
1314
1315 part = part->next;
1316 header = part->elts;
1317 i = 0;
1318 }
1319
1320 if (ngx_hash_find(&headers->hash, header[i].hash,
1321 header[i].lowcase_key, header[i].key.len))
1322 {
1323 continue;
1324 }
1325
1326 len += header[i].key.len + sizeof(": ") - 1
1327 + header[i].value.len + sizeof(CRLF) - 1;
1328 }
1329 }
1330
1331
1332 b = ngx_create_temp_buf(r->pool, len);
1333 if (b == NULL) {
1334 return NGX_ERROR;
1335 }
1336
1337 cl = ngx_alloc_chain_link(r->pool);
1338 if (cl == NULL) {
1339 return NGX_ERROR;
1340 }
1341
1342 cl->buf = b;
1343
1344
1345 /* the request line */
1346
1347 b->last = ngx_copy(b->last, method.data, method.len);
1348 *b->last++ = ' ';
1349
1350 u->uri.data = b->last;
1351
1352 if (plcf->proxy_lengths && ctx->vars.uri.len) {
1353 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1354
1355 } else if (unparsed_uri) {
1356 b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1357
1358 } else {
1359 if (r->valid_location) {
1360 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1361 }
1362
1363 if (escape) {
1364 ngx_escape_uri(b->last, r->uri.data + loc_len,
1365 r->uri.len - loc_len, NGX_ESCAPE_URI);
1366 b->last += r->uri.len - loc_len + escape;
1367
1368 } else {
1369 b->last = ngx_copy(b->last, r->uri.data + loc_len,
1370 r->uri.len - loc_len);
1371 }
1372
1373 if (r->args.len > 0) {
1374 *b->last++ = '?';
1375 b->last = ngx_copy(b->last, r->args.data, r->args.len);
1376 }
1377 }
1378
1379 u->uri.len = b->last - u->uri.data;
1380
1381 if (plcf->http_version == NGX_HTTP_VERSION_11) {
1382 b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1383 sizeof(ngx_http_proxy_version_11) - 1);
1384
1385 } else {
1386 b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1387 sizeof(ngx_http_proxy_version) - 1);
1388 }
1389
1390 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1391
1392 e.ip = headers->values->elts;
1393 e.pos = b->last;
1394 e.request = r;
1395 e.flushed = 1;
1396
1397 le.ip = headers->lengths->elts;
1398
1399 while (*(uintptr_t *) le.ip) {
1400
1401 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1402 (void) lcode(&le);
1403
1404 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
1405 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1406 }
1407 le.ip += sizeof(uintptr_t);
1408
1409 if (val_len == 0) {
1410 e.skip = 1;
1411
1412 while (*(uintptr_t *) e.ip) {
1413 code = *(ngx_http_script_code_pt *) e.ip;
1414 code((ngx_http_script_engine_t *) &e);
1415 }
1416 e.ip += sizeof(uintptr_t);
1417
1418 e.skip = 0;
1419
1420 continue;
1421 }
1422
1423 code = *(ngx_http_script_code_pt *) e.ip;
1424 code((ngx_http_script_engine_t *) &e);
1425
1426 *e.pos++ = ':'; *e.pos++ = ' ';
1427
1428 while (*(uintptr_t *) e.ip) {
1429 code = *(ngx_http_script_code_pt *) e.ip;
1430 code((ngx_http_script_engine_t *) &e);
1431 }
1432 e.ip += sizeof(uintptr_t);
1433
1434 *e.pos++ = CR; *e.pos++ = LF;
1435 }
1436
1437 b->last = e.pos;
1438
1439
1440 if (plcf->upstream.pass_request_headers) {
1441 part = &r->headers_in.headers.part;
1442 header = part->elts;
1443
1444 for (i = 0; /* void */; i++) {
1445
1446 if (i >= part->nelts) {
1447 if (part->next == NULL) {
1448 break;
1449 }
1450
1451 part = part->next;
1452 header = part->elts;
1453 i = 0;
1454 }
1455
1456 if (ngx_hash_find(&headers->hash, header[i].hash,
1457 header[i].lowcase_key, header[i].key.len))
1458 {
1459 continue;
1460 }
1461
1462 b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1463
1464 *b->last++ = ':'; *b->last++ = ' ';
1465
1466 b->last = ngx_copy(b->last, header[i].value.data,
1467 header[i].value.len);
1468
1469 *b->last++ = CR; *b->last++ = LF;
1470
1471 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1472 "http proxy header: \"%V: %V\"",
1473 &header[i].key, &header[i].value);
1474 }
1475 }
1476
1477
1478 /* add "\r\n" at the header end */
1479 *b->last++ = CR; *b->last++ = LF;
1480
1481 if (plcf->body_values) {
1482 e.ip = plcf->body_values->elts;
1483 e.pos = b->last;
1484 e.skip = 0;
1485
1486 while (*(uintptr_t *) e.ip) {
1487 code = *(ngx_http_script_code_pt *) e.ip;
1488 code((ngx_http_script_engine_t *) &e);
1489 }
1490
1491 b->last = e.pos;
1492 }
1493
1494 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1495 "http proxy header:%N\"%*s\"",
1496 (size_t) (b->last - b->pos), b->pos);
1497
1498 if (r->request_body_no_buffering) {
1499
1500 u->request_bufs = cl;
1501
1502 if (ctx->internal_chunked) {
1503 u->output.output_filter = ngx_http_proxy_body_output_filter;
1504 u->output.filter_ctx = r;
1505 }
1506
1507 } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
1508
1509 body = u->request_bufs;
1510 u->request_bufs = cl;
1511
1512 while (body) {
1513 b = ngx_alloc_buf(r->pool);
1514 if (b == NULL) {
1515 return NGX_ERROR;
1516 }
1517
1518 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1519
1520 cl->next = ngx_alloc_chain_link(r->pool);
1521 if (cl->next == NULL) {
1522 return NGX_ERROR;
1523 }
1524
1525 cl = cl->next;
1526 cl->buf = b;
1527
1528 body = body->next;
1529 }
1530
1531 } else {
1532 u->request_bufs = cl;
1533 }
1534
1535 b->flush = 1;
1536 cl->next = NULL;
1537
1538 return NGX_OK;
1539 }
1540
1541
1542 static ngx_int_t
ngx_http_proxy_reinit_request(ngx_http_request_t * r)1543 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1544 {
1545 ngx_http_proxy_ctx_t *ctx;
1546
1547 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1548
1549 if (ctx == NULL) {
1550 return NGX_OK;
1551 }
1552
1553 ctx->status.code = 0;
1554 ctx->status.count = 0;
1555 ctx->status.start = NULL;
1556 ctx->status.end = NULL;
1557 ctx->chunked.state = 0;
1558
1559 r->upstream->process_header = ngx_http_proxy_process_status_line;
1560 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1561 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1562 r->state = 0;
1563
1564 return NGX_OK;
1565 }
1566
1567
1568 static ngx_int_t
ngx_http_proxy_body_output_filter(void * data,ngx_chain_t * in)1569 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
1570 {
1571 ngx_http_request_t *r = data;
1572
1573 off_t size;
1574 u_char *chunk;
1575 ngx_int_t rc;
1576 ngx_buf_t *b;
1577 ngx_chain_t *out, *cl, *tl, **ll, **fl;
1578 ngx_http_proxy_ctx_t *ctx;
1579
1580 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1581 "proxy output filter");
1582
1583 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1584
1585 if (in == NULL) {
1586 out = in;
1587 goto out;
1588 }
1589
1590 out = NULL;
1591 ll = &out;
1592
1593 if (!ctx->header_sent) {
1594 /* first buffer contains headers, pass it unmodified */
1595
1596 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1597 "proxy output header");
1598
1599 ctx->header_sent = 1;
1600
1601 tl = ngx_alloc_chain_link(r->pool);
1602 if (tl == NULL) {
1603 return NGX_ERROR;
1604 }
1605
1606 tl->buf = in->buf;
1607 *ll = tl;
1608 ll = &tl->next;
1609
1610 in = in->next;
1611
1612 if (in == NULL) {
1613 tl->next = NULL;
1614 goto out;
1615 }
1616 }
1617
1618 size = 0;
1619 cl = in;
1620 fl = ll;
1621
1622 for ( ;; ) {
1623 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1624 "proxy output chunk: %O", ngx_buf_size(cl->buf));
1625
1626 size += ngx_buf_size(cl->buf);
1627
1628 if (cl->buf->flush
1629 || cl->buf->sync
1630 || ngx_buf_in_memory(cl->buf)
1631 || cl->buf->in_file)
1632 {
1633 tl = ngx_alloc_chain_link(r->pool);
1634 if (tl == NULL) {
1635 return NGX_ERROR;
1636 }
1637
1638 tl->buf = cl->buf;
1639 *ll = tl;
1640 ll = &tl->next;
1641 }
1642
1643 if (cl->next == NULL) {
1644 break;
1645 }
1646
1647 cl = cl->next;
1648 }
1649
1650 if (size) {
1651 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1652 if (tl == NULL) {
1653 return NGX_ERROR;
1654 }
1655
1656 b = tl->buf;
1657 chunk = b->start;
1658
1659 if (chunk == NULL) {
1660 /* the "0000000000000000" is 64-bit hexadecimal string */
1661
1662 chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
1663 if (chunk == NULL) {
1664 return NGX_ERROR;
1665 }
1666
1667 b->start = chunk;
1668 b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
1669 }
1670
1671 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1672 b->memory = 0;
1673 b->temporary = 1;
1674 b->pos = chunk;
1675 b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
1676
1677 tl->next = *fl;
1678 *fl = tl;
1679 }
1680
1681 if (cl->buf->last_buf) {
1682 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1683 if (tl == NULL) {
1684 return NGX_ERROR;
1685 }
1686
1687 b = tl->buf;
1688
1689 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1690 b->temporary = 0;
1691 b->memory = 1;
1692 b->last_buf = 1;
1693 b->pos = (u_char *) CRLF "0" CRLF CRLF;
1694 b->last = b->pos + 7;
1695
1696 cl->buf->last_buf = 0;
1697
1698 *ll = tl;
1699
1700 if (size == 0) {
1701 b->pos += 2;
1702 }
1703
1704 } else if (size > 0) {
1705 tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1706 if (tl == NULL) {
1707 return NGX_ERROR;
1708 }
1709
1710 b = tl->buf;
1711
1712 b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1713 b->temporary = 0;
1714 b->memory = 1;
1715 b->pos = (u_char *) CRLF;
1716 b->last = b->pos + 2;
1717
1718 *ll = tl;
1719
1720 } else {
1721 *ll = NULL;
1722 }
1723
1724 out:
1725
1726 rc = ngx_chain_writer(&r->upstream->writer, out);
1727
1728 ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1729 (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
1730
1731 return rc;
1732 }
1733
1734
1735 static ngx_int_t
ngx_http_proxy_process_status_line(ngx_http_request_t * r)1736 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1737 {
1738 size_t len;
1739 ngx_int_t rc;
1740 ngx_http_upstream_t *u;
1741 ngx_http_proxy_ctx_t *ctx;
1742
1743 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1744
1745 if (ctx == NULL) {
1746 return NGX_ERROR;
1747 }
1748
1749 u = r->upstream;
1750
1751 rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1752
1753 if (rc == NGX_AGAIN) {
1754 return rc;
1755 }
1756
1757 if (rc == NGX_ERROR) {
1758
1759 #if (NGX_HTTP_CACHE)
1760
1761 if (r->cache) {
1762 r->http_version = NGX_HTTP_VERSION_9;
1763 return NGX_OK;
1764 }
1765
1766 #endif
1767
1768 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1769 "upstream sent no valid HTTP/1.0 header");
1770
1771 #if 0
1772 if (u->accel) {
1773 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1774 }
1775 #endif
1776
1777 r->http_version = NGX_HTTP_VERSION_9;
1778 u->state->status = NGX_HTTP_OK;
1779 u->headers_in.connection_close = 1;
1780
1781 return NGX_OK;
1782 }
1783
1784 if (u->state && u->state->status == 0) {
1785 u->state->status = ctx->status.code;
1786 }
1787
1788 u->headers_in.status_n = ctx->status.code;
1789
1790 len = ctx->status.end - ctx->status.start;
1791 u->headers_in.status_line.len = len;
1792
1793 u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1794 if (u->headers_in.status_line.data == NULL) {
1795 return NGX_ERROR;
1796 }
1797
1798 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1799
1800 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1801 "http proxy status %ui \"%V\"",
1802 u->headers_in.status_n, &u->headers_in.status_line);
1803
1804 if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1805 u->headers_in.connection_close = 1;
1806 }
1807
1808 u->process_header = ngx_http_proxy_process_header;
1809
1810 return ngx_http_proxy_process_header(r);
1811 }
1812
1813
1814 static ngx_int_t
ngx_http_proxy_process_header(ngx_http_request_t * r)1815 ngx_http_proxy_process_header(ngx_http_request_t *r)
1816 {
1817 ngx_int_t rc;
1818 ngx_table_elt_t *h;
1819 ngx_http_upstream_t *u;
1820 ngx_http_proxy_ctx_t *ctx;
1821 ngx_http_upstream_header_t *hh;
1822 ngx_http_upstream_main_conf_t *umcf;
1823
1824 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1825
1826 for ( ;; ) {
1827
1828 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1829
1830 if (rc == NGX_OK) {
1831
1832 /* a header line has been parsed successfully */
1833
1834 h = ngx_list_push(&r->upstream->headers_in.headers);
1835 if (h == NULL) {
1836 return NGX_ERROR;
1837 }
1838
1839 h->hash = r->header_hash;
1840
1841 h->key.len = r->header_name_end - r->header_name_start;
1842 h->value.len = r->header_end - r->header_start;
1843
1844 h->key.data = ngx_pnalloc(r->pool,
1845 h->key.len + 1 + h->value.len + 1 + h->key.len);
1846 if (h->key.data == NULL) {
1847 h->hash = 0;
1848 return NGX_ERROR;
1849 }
1850
1851 h->value.data = h->key.data + h->key.len + 1;
1852 h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1853
1854 ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1855 h->key.data[h->key.len] = '\0';
1856 ngx_memcpy(h->value.data, r->header_start, h->value.len);
1857 h->value.data[h->value.len] = '\0';
1858
1859 if (h->key.len == r->lowcase_index) {
1860 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1861
1862 } else {
1863 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1864 }
1865
1866 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1867 h->lowcase_key, h->key.len);
1868
1869 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1870 return NGX_ERROR;
1871 }
1872
1873 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1874 "http proxy header: \"%V: %V\"",
1875 &h->key, &h->value);
1876
1877 continue;
1878 }
1879
1880 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1881
1882 /* a whole header has been parsed successfully */
1883
1884 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1885 "http proxy header done");
1886
1887 /*
1888 * if no "Server" and "Date" in header line,
1889 * then add the special empty headers
1890 */
1891
1892 if (r->upstream->headers_in.server == NULL) {
1893 h = ngx_list_push(&r->upstream->headers_in.headers);
1894 if (h == NULL) {
1895 return NGX_ERROR;
1896 }
1897
1898 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1899 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1900
1901 ngx_str_set(&h->key, "Server");
1902 ngx_str_null(&h->value);
1903 h->lowcase_key = (u_char *) "server";
1904 }
1905
1906 if (r->upstream->headers_in.date == NULL) {
1907 h = ngx_list_push(&r->upstream->headers_in.headers);
1908 if (h == NULL) {
1909 return NGX_ERROR;
1910 }
1911
1912 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1913
1914 ngx_str_set(&h->key, "Date");
1915 ngx_str_null(&h->value);
1916 h->lowcase_key = (u_char *) "date";
1917 }
1918
1919 /* clear content length if response is chunked */
1920
1921 u = r->upstream;
1922
1923 if (u->headers_in.chunked) {
1924 u->headers_in.content_length_n = -1;
1925 }
1926
1927 /*
1928 * set u->keepalive if response has no body; this allows to keep
1929 * connections alive in case of r->header_only or X-Accel-Redirect
1930 */
1931
1932 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1933
1934 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1935 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1936 || ctx->head
1937 || (!u->headers_in.chunked
1938 && u->headers_in.content_length_n == 0))
1939 {
1940 u->keepalive = !u->headers_in.connection_close;
1941 }
1942
1943 if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1944 u->keepalive = 0;
1945
1946 if (r->headers_in.upgrade) {
1947 u->upgrade = 1;
1948 }
1949 }
1950
1951 return NGX_OK;
1952 }
1953
1954 if (rc == NGX_AGAIN) {
1955 return NGX_AGAIN;
1956 }
1957
1958 /* there was error while a header line parsing */
1959
1960 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1961 "upstream sent invalid header");
1962
1963 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1964 }
1965 }
1966
1967
1968 static ngx_int_t
ngx_http_proxy_input_filter_init(void * data)1969 ngx_http_proxy_input_filter_init(void *data)
1970 {
1971 ngx_http_request_t *r = data;
1972 ngx_http_upstream_t *u;
1973 ngx_http_proxy_ctx_t *ctx;
1974
1975 u = r->upstream;
1976 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1977
1978 if (ctx == NULL) {
1979 return NGX_ERROR;
1980 }
1981
1982 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1983 "http proxy filter init s:%ui h:%d c:%d l:%O",
1984 u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1985 u->headers_in.content_length_n);
1986
1987 /* as per RFC2616, 4.4 Message Length */
1988
1989 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1990 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1991 || ctx->head)
1992 {
1993 /* 1xx, 204, and 304 and replies to HEAD requests */
1994 /* no 1xx since we don't send Expect and Upgrade */
1995
1996 u->pipe->length = 0;
1997 u->length = 0;
1998 u->keepalive = !u->headers_in.connection_close;
1999
2000 } else if (u->headers_in.chunked) {
2001 /* chunked */
2002
2003 u->pipe->input_filter = ngx_http_proxy_chunked_filter;
2004 u->pipe->length = 3; /* "0" LF LF */
2005
2006 u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
2007 u->length = 1;
2008
2009 } else if (u->headers_in.content_length_n == 0) {
2010 /* empty body: special case as filter won't be called */
2011
2012 u->pipe->length = 0;
2013 u->length = 0;
2014 u->keepalive = !u->headers_in.connection_close;
2015
2016 } else {
2017 /* content length or connection close */
2018
2019 u->pipe->length = u->headers_in.content_length_n;
2020 u->length = u->headers_in.content_length_n;
2021 }
2022
2023 return NGX_OK;
2024 }
2025
2026
2027 static ngx_int_t
ngx_http_proxy_copy_filter(ngx_event_pipe_t * p,ngx_buf_t * buf)2028 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2029 {
2030 ngx_buf_t *b;
2031 ngx_chain_t *cl;
2032 ngx_http_request_t *r;
2033
2034 if (buf->pos == buf->last) {
2035 return NGX_OK;
2036 }
2037
2038 cl = ngx_chain_get_free_buf(p->pool, &p->free);
2039 if (cl == NULL) {
2040 return NGX_ERROR;
2041 }
2042
2043 b = cl->buf;
2044
2045 ngx_memcpy(b, buf, sizeof(ngx_buf_t));
2046 b->shadow = buf;
2047 b->tag = p->tag;
2048 b->last_shadow = 1;
2049 b->recycled = 1;
2050 buf->shadow = b;
2051
2052 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
2053
2054 if (p->in) {
2055 *p->last_in = cl;
2056 } else {
2057 p->in = cl;
2058 }
2059 p->last_in = &cl->next;
2060
2061 if (p->length == -1) {
2062 return NGX_OK;
2063 }
2064
2065 p->length -= b->last - b->pos;
2066
2067 if (p->length == 0) {
2068 r = p->input_ctx;
2069 p->upstream_done = 1;
2070 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2071
2072 } else if (p->length < 0) {
2073 r = p->input_ctx;
2074 p->upstream_done = 1;
2075
2076 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
2077 "upstream sent more data than specified in "
2078 "\"Content-Length\" header");
2079 }
2080
2081 return NGX_OK;
2082 }
2083
2084
2085 static ngx_int_t
ngx_http_proxy_chunked_filter(ngx_event_pipe_t * p,ngx_buf_t * buf)2086 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2087 {
2088 ngx_int_t rc;
2089 ngx_buf_t *b, **prev;
2090 ngx_chain_t *cl;
2091 ngx_http_request_t *r;
2092 ngx_http_proxy_ctx_t *ctx;
2093
2094 if (buf->pos == buf->last) {
2095 return NGX_OK;
2096 }
2097
2098 r = p->input_ctx;
2099 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2100
2101 if (ctx == NULL) {
2102 return NGX_ERROR;
2103 }
2104
2105 b = NULL;
2106 prev = &buf->shadow;
2107
2108 for ( ;; ) {
2109
2110 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2111
2112 if (rc == NGX_OK) {
2113
2114 /* a chunk has been parsed successfully */
2115
2116 cl = ngx_chain_get_free_buf(p->pool, &p->free);
2117 if (cl == NULL) {
2118 return NGX_ERROR;
2119 }
2120
2121 b = cl->buf;
2122
2123 ngx_memzero(b, sizeof(ngx_buf_t));
2124
2125 b->pos = buf->pos;
2126 b->start = buf->start;
2127 b->end = buf->end;
2128 b->tag = p->tag;
2129 b->temporary = 1;
2130 b->recycled = 1;
2131
2132 *prev = b;
2133 prev = &b->shadow;
2134
2135 if (p->in) {
2136 *p->last_in = cl;
2137 } else {
2138 p->in = cl;
2139 }
2140 p->last_in = &cl->next;
2141
2142 /* STUB */ b->num = buf->num;
2143
2144 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2145 "input buf #%d %p", b->num, b->pos);
2146
2147 if (buf->last - buf->pos >= ctx->chunked.size) {
2148
2149 buf->pos += (size_t) ctx->chunked.size;
2150 b->last = buf->pos;
2151 ctx->chunked.size = 0;
2152
2153 continue;
2154 }
2155
2156 ctx->chunked.size -= buf->last - buf->pos;
2157 buf->pos = buf->last;
2158 b->last = buf->last;
2159
2160 continue;
2161 }
2162
2163 if (rc == NGX_DONE) {
2164
2165 /* a whole response has been parsed successfully */
2166
2167 p->upstream_done = 1;
2168 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2169
2170 break;
2171 }
2172
2173 if (rc == NGX_AGAIN) {
2174
2175 /* set p->length, minimal amount of data we want to see */
2176
2177 p->length = ctx->chunked.length;
2178
2179 break;
2180 }
2181
2182 /* invalid response */
2183
2184 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2185 "upstream sent invalid chunked response");
2186
2187 return NGX_ERROR;
2188 }
2189
2190 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2191 "http proxy chunked state %ui, length %O",
2192 ctx->chunked.state, p->length);
2193
2194 if (b) {
2195 b->shadow = buf;
2196 b->last_shadow = 1;
2197
2198 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2199 "input buf %p %z", b->pos, b->last - b->pos);
2200
2201 return NGX_OK;
2202 }
2203
2204 /* there is no data record in the buf, add it to free chain */
2205
2206 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2207 return NGX_ERROR;
2208 }
2209
2210 return NGX_OK;
2211 }
2212
2213
2214 static ngx_int_t
ngx_http_proxy_non_buffered_copy_filter(void * data,ssize_t bytes)2215 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
2216 {
2217 ngx_http_request_t *r = data;
2218
2219 ngx_buf_t *b;
2220 ngx_chain_t *cl, **ll;
2221 ngx_http_upstream_t *u;
2222
2223 u = r->upstream;
2224
2225 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2226 ll = &cl->next;
2227 }
2228
2229 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2230 if (cl == NULL) {
2231 return NGX_ERROR;
2232 }
2233
2234 *ll = cl;
2235
2236 cl->buf->flush = 1;
2237 cl->buf->memory = 1;
2238
2239 b = &u->buffer;
2240
2241 cl->buf->pos = b->last;
2242 b->last += bytes;
2243 cl->buf->last = b->last;
2244 cl->buf->tag = u->output.tag;
2245
2246 if (u->length == -1) {
2247 return NGX_OK;
2248 }
2249
2250 u->length -= bytes;
2251
2252 if (u->length == 0) {
2253 u->keepalive = !u->headers_in.connection_close;
2254 }
2255
2256 return NGX_OK;
2257 }
2258
2259
2260 static ngx_int_t
ngx_http_proxy_non_buffered_chunked_filter(void * data,ssize_t bytes)2261 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
2262 {
2263 ngx_http_request_t *r = data;
2264
2265 ngx_int_t rc;
2266 ngx_buf_t *b, *buf;
2267 ngx_chain_t *cl, **ll;
2268 ngx_http_upstream_t *u;
2269 ngx_http_proxy_ctx_t *ctx;
2270
2271 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2272
2273 if (ctx == NULL) {
2274 return NGX_ERROR;
2275 }
2276
2277 u = r->upstream;
2278 buf = &u->buffer;
2279
2280 buf->pos = buf->last;
2281 buf->last += bytes;
2282
2283 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2284 ll = &cl->next;
2285 }
2286
2287 for ( ;; ) {
2288
2289 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2290
2291 if (rc == NGX_OK) {
2292
2293 /* a chunk has been parsed successfully */
2294
2295 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2296 if (cl == NULL) {
2297 return NGX_ERROR;
2298 }
2299
2300 *ll = cl;
2301 ll = &cl->next;
2302
2303 b = cl->buf;
2304
2305 b->flush = 1;
2306 b->memory = 1;
2307
2308 b->pos = buf->pos;
2309 b->tag = u->output.tag;
2310
2311 if (buf->last - buf->pos >= ctx->chunked.size) {
2312 buf->pos += (size_t) ctx->chunked.size;
2313 b->last = buf->pos;
2314 ctx->chunked.size = 0;
2315
2316 } else {
2317 ctx->chunked.size -= buf->last - buf->pos;
2318 buf->pos = buf->last;
2319 b->last = buf->last;
2320 }
2321
2322 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2323 "http proxy out buf %p %z",
2324 b->pos, b->last - b->pos);
2325
2326 continue;
2327 }
2328
2329 if (rc == NGX_DONE) {
2330
2331 /* a whole response has been parsed successfully */
2332
2333 u->keepalive = !u->headers_in.connection_close;
2334 u->length = 0;
2335
2336 break;
2337 }
2338
2339 if (rc == NGX_AGAIN) {
2340 break;
2341 }
2342
2343 /* invalid response */
2344
2345 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2346 "upstream sent invalid chunked response");
2347
2348 return NGX_ERROR;
2349 }
2350
2351 return NGX_OK;
2352 }
2353
2354
2355 static void
ngx_http_proxy_abort_request(ngx_http_request_t * r)2356 ngx_http_proxy_abort_request(ngx_http_request_t *r)
2357 {
2358 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2359 "abort http proxy request");
2360
2361 return;
2362 }
2363
2364
2365 static void
ngx_http_proxy_finalize_request(ngx_http_request_t * r,ngx_int_t rc)2366 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2367 {
2368 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2369 "finalize http proxy request");
2370
2371 return;
2372 }
2373
2374
2375 static ngx_int_t
ngx_http_proxy_host_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2376 ngx_http_proxy_host_variable(ngx_http_request_t *r,
2377 ngx_http_variable_value_t *v, uintptr_t data)
2378 {
2379 ngx_http_proxy_ctx_t *ctx;
2380
2381 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2382
2383 if (ctx == NULL) {
2384 v->not_found = 1;
2385 return NGX_OK;
2386 }
2387
2388 v->len = ctx->vars.host_header.len;
2389 v->valid = 1;
2390 v->no_cacheable = 0;
2391 v->not_found = 0;
2392 v->data = ctx->vars.host_header.data;
2393
2394 return NGX_OK;
2395 }
2396
2397
2398 static ngx_int_t
ngx_http_proxy_port_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2399 ngx_http_proxy_port_variable(ngx_http_request_t *r,
2400 ngx_http_variable_value_t *v, uintptr_t data)
2401 {
2402 ngx_http_proxy_ctx_t *ctx;
2403
2404 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2405
2406 if (ctx == NULL) {
2407 v->not_found = 1;
2408 return NGX_OK;
2409 }
2410
2411 v->len = ctx->vars.port.len;
2412 v->valid = 1;
2413 v->no_cacheable = 0;
2414 v->not_found = 0;
2415 v->data = ctx->vars.port.data;
2416
2417 return NGX_OK;
2418 }
2419
2420
2421 static ngx_int_t
ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2422 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2423 ngx_http_variable_value_t *v, uintptr_t data)
2424 {
2425 size_t len;
2426 u_char *p;
2427 ngx_uint_t i, n;
2428 ngx_table_elt_t **h;
2429
2430 v->valid = 1;
2431 v->no_cacheable = 0;
2432 v->not_found = 0;
2433
2434 n = r->headers_in.x_forwarded_for.nelts;
2435 h = r->headers_in.x_forwarded_for.elts;
2436
2437 len = 0;
2438
2439 for (i = 0; i < n; i++) {
2440 len += h[i]->value.len + sizeof(", ") - 1;
2441 }
2442
2443 if (len == 0) {
2444 v->len = r->connection->addr_text.len;
2445 v->data = r->connection->addr_text.data;
2446 return NGX_OK;
2447 }
2448
2449 len += r->connection->addr_text.len;
2450
2451 p = ngx_pnalloc(r->pool, len);
2452 if (p == NULL) {
2453 return NGX_ERROR;
2454 }
2455
2456 v->len = len;
2457 v->data = p;
2458
2459 for (i = 0; i < n; i++) {
2460 p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2461 *p++ = ','; *p++ = ' ';
2462 }
2463
2464 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2465
2466 return NGX_OK;
2467 }
2468
2469
2470 static ngx_int_t
ngx_http_proxy_internal_body_length_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2471 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2472 ngx_http_variable_value_t *v, uintptr_t data)
2473 {
2474 ngx_http_proxy_ctx_t *ctx;
2475
2476 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2477
2478 if (ctx == NULL || ctx->internal_body_length < 0) {
2479 v->not_found = 1;
2480 return NGX_OK;
2481 }
2482
2483 v->valid = 1;
2484 v->no_cacheable = 0;
2485 v->not_found = 0;
2486
2487 v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
2488
2489 if (v->data == NULL) {
2490 return NGX_ERROR;
2491 }
2492
2493 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2494
2495 return NGX_OK;
2496 }
2497
2498
2499 static ngx_int_t
ngx_http_proxy_internal_chunked_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2500 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
2501 ngx_http_variable_value_t *v, uintptr_t data)
2502 {
2503 ngx_http_proxy_ctx_t *ctx;
2504
2505 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2506
2507 if (ctx == NULL || !ctx->internal_chunked) {
2508 v->not_found = 1;
2509 return NGX_OK;
2510 }
2511
2512 v->valid = 1;
2513 v->no_cacheable = 0;
2514 v->not_found = 0;
2515
2516 v->data = (u_char *) "chunked";
2517 v->len = sizeof("chunked") - 1;
2518
2519 return NGX_OK;
2520 }
2521
2522
2523 static ngx_int_t
ngx_http_proxy_rewrite_redirect(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix)2524 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2525 size_t prefix)
2526 {
2527 size_t len;
2528 ngx_int_t rc;
2529 ngx_uint_t i;
2530 ngx_http_proxy_rewrite_t *pr;
2531 ngx_http_proxy_loc_conf_t *plcf;
2532
2533 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2534
2535 pr = plcf->redirects->elts;
2536
2537 if (pr == NULL) {
2538 return NGX_DECLINED;
2539 }
2540
2541 len = h->value.len - prefix;
2542
2543 for (i = 0; i < plcf->redirects->nelts; i++) {
2544 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2545
2546 if (rc != NGX_DECLINED) {
2547 return rc;
2548 }
2549 }
2550
2551 return NGX_DECLINED;
2552 }
2553
2554
2555 static ngx_int_t
ngx_http_proxy_rewrite_cookie(ngx_http_request_t * r,ngx_table_elt_t * h)2556 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2557 {
2558 size_t prefix;
2559 u_char *p;
2560 ngx_int_t rc, rv;
2561 ngx_http_proxy_loc_conf_t *plcf;
2562
2563 p = (u_char *) ngx_strchr(h->value.data, ';');
2564 if (p == NULL) {
2565 return NGX_DECLINED;
2566 }
2567
2568 prefix = p + 1 - h->value.data;
2569
2570 rv = NGX_DECLINED;
2571
2572 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2573
2574 if (plcf->cookie_domains) {
2575 p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2576
2577 if (p) {
2578 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2579 plcf->cookie_domains);
2580 if (rc == NGX_ERROR) {
2581 return NGX_ERROR;
2582 }
2583
2584 if (rc != NGX_DECLINED) {
2585 rv = rc;
2586 }
2587 }
2588 }
2589
2590 if (plcf->cookie_paths) {
2591 p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2592
2593 if (p) {
2594 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2595 plcf->cookie_paths);
2596 if (rc == NGX_ERROR) {
2597 return NGX_ERROR;
2598 }
2599
2600 if (rc != NGX_DECLINED) {
2601 rv = rc;
2602 }
2603 }
2604 }
2605
2606 return rv;
2607 }
2608
2609
2610 static ngx_int_t
ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t * r,ngx_table_elt_t * h,u_char * value,ngx_array_t * rewrites)2611 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2612 u_char *value, ngx_array_t *rewrites)
2613 {
2614 size_t len, prefix;
2615 u_char *p;
2616 ngx_int_t rc;
2617 ngx_uint_t i;
2618 ngx_http_proxy_rewrite_t *pr;
2619
2620 prefix = value - h->value.data;
2621
2622 p = (u_char *) ngx_strchr(value, ';');
2623
2624 len = p ? (size_t) (p - value) : (h->value.len - prefix);
2625
2626 pr = rewrites->elts;
2627
2628 for (i = 0; i < rewrites->nelts; i++) {
2629 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2630
2631 if (rc != NGX_DECLINED) {
2632 return rc;
2633 }
2634 }
2635
2636 return NGX_DECLINED;
2637 }
2638
2639
2640 static ngx_int_t
ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2641 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2642 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2643 {
2644 ngx_str_t pattern, replacement;
2645
2646 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2647 return NGX_ERROR;
2648 }
2649
2650 if (pattern.len > len
2651 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2652 pattern.len) != 0)
2653 {
2654 return NGX_DECLINED;
2655 }
2656
2657 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2658 return NGX_ERROR;
2659 }
2660
2661 return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2662 }
2663
2664
2665 #if (NGX_PCRE)
2666
2667 static ngx_int_t
ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2668 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2669 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2670 {
2671 ngx_str_t pattern, replacement;
2672
2673 pattern.len = len;
2674 pattern.data = h->value.data + prefix;
2675
2676 if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2677 return NGX_DECLINED;
2678 }
2679
2680 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2681 return NGX_ERROR;
2682 }
2683
2684 if (prefix == 0 && h->value.len == len) {
2685 h->value = replacement;
2686 return NGX_OK;
2687 }
2688
2689 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2690 }
2691
2692 #endif
2693
2694
2695 static ngx_int_t
ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2696 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2697 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2698 {
2699 u_char *p;
2700 ngx_str_t pattern, replacement;
2701
2702 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2703 return NGX_ERROR;
2704 }
2705
2706 p = h->value.data + prefix;
2707
2708 if (p[0] == '.') {
2709 p++;
2710 prefix++;
2711 len--;
2712 }
2713
2714 if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2715 return NGX_DECLINED;
2716 }
2717
2718 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2719 return NGX_ERROR;
2720 }
2721
2722 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2723 }
2724
2725
2726 static ngx_int_t
ngx_http_proxy_rewrite(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_str_t * replacement)2727 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2728 size_t len, ngx_str_t *replacement)
2729 {
2730 u_char *p, *data;
2731 size_t new_len;
2732
2733 new_len = replacement->len + h->value.len - len;
2734
2735 if (replacement->len > len) {
2736
2737 data = ngx_pnalloc(r->pool, new_len + 1);
2738 if (data == NULL) {
2739 return NGX_ERROR;
2740 }
2741
2742 p = ngx_copy(data, h->value.data, prefix);
2743 p = ngx_copy(p, replacement->data, replacement->len);
2744
2745 ngx_memcpy(p, h->value.data + prefix + len,
2746 h->value.len - len - prefix + 1);
2747
2748 h->value.data = data;
2749
2750 } else {
2751 p = ngx_copy(h->value.data + prefix, replacement->data,
2752 replacement->len);
2753
2754 ngx_memmove(p, h->value.data + prefix + len,
2755 h->value.len - len - prefix + 1);
2756 }
2757
2758 h->value.len = new_len;
2759
2760 return NGX_OK;
2761 }
2762
2763
2764 static ngx_int_t
ngx_http_proxy_add_variables(ngx_conf_t * cf)2765 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2766 {
2767 ngx_http_variable_t *var, *v;
2768
2769 for (v = ngx_http_proxy_vars; v->name.len; v++) {
2770 var = ngx_http_add_variable(cf, &v->name, v->flags);
2771 if (var == NULL) {
2772 return NGX_ERROR;
2773 }
2774
2775 var->get_handler = v->get_handler;
2776 var->data = v->data;
2777 }
2778
2779 return NGX_OK;
2780 }
2781
2782
2783 static void *
ngx_http_proxy_create_main_conf(ngx_conf_t * cf)2784 ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
2785 {
2786 ngx_http_proxy_main_conf_t *conf;
2787
2788 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
2789 if (conf == NULL) {
2790 return NULL;
2791 }
2792
2793 #if (NGX_HTTP_CACHE)
2794 if (ngx_array_init(&conf->caches, cf->pool, 4,
2795 sizeof(ngx_http_file_cache_t *))
2796 != NGX_OK)
2797 {
2798 return NULL;
2799 }
2800 #endif
2801
2802 return conf;
2803 }
2804
2805
2806 static void *
ngx_http_proxy_create_loc_conf(ngx_conf_t * cf)2807 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2808 {
2809 ngx_http_proxy_loc_conf_t *conf;
2810
2811 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2812 if (conf == NULL) {
2813 return NULL;
2814 }
2815
2816 /*
2817 * set by ngx_pcalloc():
2818 *
2819 * conf->upstream.bufs.num = 0;
2820 * conf->upstream.ignore_headers = 0;
2821 * conf->upstream.next_upstream = 0;
2822 * conf->upstream.cache_zone = NULL;
2823 * conf->upstream.cache_use_stale = 0;
2824 * conf->upstream.cache_methods = 0;
2825 * conf->upstream.temp_path = NULL;
2826 * conf->upstream.hide_headers_hash = { NULL, 0 };
2827 * conf->upstream.store_lengths = NULL;
2828 * conf->upstream.store_values = NULL;
2829 * conf->upstream.ssl_name = NULL;
2830 *
2831 * conf->method = NULL;
2832 * conf->location = NULL;
2833 * conf->url = { 0, NULL };
2834 * conf->headers_source = NULL;
2835 * conf->headers.lengths = NULL;
2836 * conf->headers.values = NULL;
2837 * conf->headers.hash = { NULL, 0 };
2838 * conf->headers_cache.lengths = NULL;
2839 * conf->headers_cache.values = NULL;
2840 * conf->headers_cache.hash = { NULL, 0 };
2841 * conf->body_lengths = NULL;
2842 * conf->body_values = NULL;
2843 * conf->body_source = { 0, NULL };
2844 * conf->redirects = NULL;
2845 * conf->ssl = 0;
2846 * conf->ssl_protocols = 0;
2847 * conf->ssl_ciphers = { 0, NULL };
2848 * conf->ssl_trusted_certificate = { 0, NULL };
2849 * conf->ssl_crl = { 0, NULL };
2850 * conf->ssl_certificate = { 0, NULL };
2851 * conf->ssl_certificate_key = { 0, NULL };
2852 */
2853
2854 conf->upstream.store = NGX_CONF_UNSET;
2855 conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2856 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2857 conf->upstream.buffering = NGX_CONF_UNSET;
2858 conf->upstream.request_buffering = NGX_CONF_UNSET;
2859 conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2860 conf->upstream.force_ranges = NGX_CONF_UNSET;
2861
2862 conf->upstream.local = NGX_CONF_UNSET_PTR;
2863 conf->upstream.socket_keepalive = NGX_CONF_UNSET;
2864
2865 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2866 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2867 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2868 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2869
2870 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2871 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2872 conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2873
2874 conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2875 conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2876 conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2877
2878 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2879 conf->upstream.pass_request_body = NGX_CONF_UNSET;
2880
2881 #if (NGX_HTTP_CACHE)
2882 conf->upstream.cache = NGX_CONF_UNSET;
2883 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2884 conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2885 conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2886 conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2887 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2888 conf->upstream.cache_lock = NGX_CONF_UNSET;
2889 conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2890 conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2891 conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2892 conf->upstream.cache_convert_head = NGX_CONF_UNSET;
2893 conf->upstream.cache_background_update = NGX_CONF_UNSET;
2894 #endif
2895
2896 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2897 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2898
2899 conf->upstream.intercept_errors = NGX_CONF_UNSET;
2900
2901 #if (NGX_HTTP_SSL)
2902 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2903 conf->upstream.ssl_server_name = NGX_CONF_UNSET;
2904 conf->upstream.ssl_verify = NGX_CONF_UNSET;
2905 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
2906 conf->ssl_passwords = NGX_CONF_UNSET_PTR;
2907 #endif
2908
2909 /* "proxy_cyclic_temp_file" is disabled */
2910 conf->upstream.cyclic_temp_file = 0;
2911
2912 conf->redirect = NGX_CONF_UNSET;
2913 conf->upstream.change_buffering = 1;
2914
2915 conf->cookie_domains = NGX_CONF_UNSET_PTR;
2916 conf->cookie_paths = NGX_CONF_UNSET_PTR;
2917
2918 conf->http_version = NGX_CONF_UNSET_UINT;
2919
2920 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2921 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2922
2923 ngx_str_set(&conf->upstream.module, "proxy");
2924
2925 #if (NGX_HAVE_FSTACK)
2926 conf->kernel_network_stack = NGX_CONF_UNSET;
2927 #endif
2928
2929 return conf;
2930 }
2931
2932
2933 static char *
ngx_http_proxy_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)2934 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2935 {
2936 ngx_http_proxy_loc_conf_t *prev = parent;
2937 ngx_http_proxy_loc_conf_t *conf = child;
2938
2939 u_char *p;
2940 size_t size;
2941 ngx_int_t rc;
2942 ngx_hash_init_t hash;
2943 ngx_http_core_loc_conf_t *clcf;
2944 ngx_http_proxy_rewrite_t *pr;
2945 ngx_http_script_compile_t sc;
2946
2947 #if (NGX_HTTP_CACHE)
2948
2949 if (conf->upstream.store > 0) {
2950 conf->upstream.cache = 0;
2951 }
2952
2953 if (conf->upstream.cache > 0) {
2954 conf->upstream.store = 0;
2955 }
2956
2957 #endif
2958
2959 if (conf->upstream.store == NGX_CONF_UNSET) {
2960 ngx_conf_merge_value(conf->upstream.store,
2961 prev->upstream.store, 0);
2962
2963 conf->upstream.store_lengths = prev->upstream.store_lengths;
2964 conf->upstream.store_values = prev->upstream.store_values;
2965 }
2966
2967 ngx_conf_merge_uint_value(conf->upstream.store_access,
2968 prev->upstream.store_access, 0600);
2969
2970 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2971 prev->upstream.next_upstream_tries, 0);
2972
2973 ngx_conf_merge_value(conf->upstream.buffering,
2974 prev->upstream.buffering, 1);
2975
2976 ngx_conf_merge_value(conf->upstream.request_buffering,
2977 prev->upstream.request_buffering, 1);
2978
2979 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2980 prev->upstream.ignore_client_abort, 0);
2981
2982 ngx_conf_merge_value(conf->upstream.force_ranges,
2983 prev->upstream.force_ranges, 0);
2984
2985 ngx_conf_merge_ptr_value(conf->upstream.local,
2986 prev->upstream.local, NULL);
2987
2988 ngx_conf_merge_value(conf->upstream.socket_keepalive,
2989 prev->upstream.socket_keepalive, 0);
2990
2991 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2992 prev->upstream.connect_timeout, 60000);
2993
2994 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2995 prev->upstream.send_timeout, 60000);
2996
2997 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2998 prev->upstream.read_timeout, 60000);
2999
3000 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
3001 prev->upstream.next_upstream_timeout, 0);
3002
3003 ngx_conf_merge_size_value(conf->upstream.send_lowat,
3004 prev->upstream.send_lowat, 0);
3005
3006 ngx_conf_merge_size_value(conf->upstream.buffer_size,
3007 prev->upstream.buffer_size,
3008 (size_t) ngx_pagesize);
3009
3010 ngx_conf_merge_size_value(conf->upstream.limit_rate,
3011 prev->upstream.limit_rate, 0);
3012
3013 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
3014 8, ngx_pagesize);
3015
3016 if (conf->upstream.bufs.num < 2) {
3017 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3018 "there must be at least 2 \"proxy_buffers\"");
3019 return NGX_CONF_ERROR;
3020 }
3021
3022
3023 size = conf->upstream.buffer_size;
3024 if (size < conf->upstream.bufs.size) {
3025 size = conf->upstream.bufs.size;
3026 }
3027
3028
3029 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
3030 prev->upstream.busy_buffers_size_conf,
3031 NGX_CONF_UNSET_SIZE);
3032
3033 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
3034 conf->upstream.busy_buffers_size = 2 * size;
3035 } else {
3036 conf->upstream.busy_buffers_size =
3037 conf->upstream.busy_buffers_size_conf;
3038 }
3039
3040 if (conf->upstream.busy_buffers_size < size) {
3041 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3042 "\"proxy_busy_buffers_size\" must be equal to or greater than "
3043 "the maximum of the value of \"proxy_buffer_size\" and "
3044 "one of the \"proxy_buffers\"");
3045
3046 return NGX_CONF_ERROR;
3047 }
3048
3049 if (conf->upstream.busy_buffers_size
3050 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
3051 {
3052 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3053 "\"proxy_busy_buffers_size\" must be less than "
3054 "the size of all \"proxy_buffers\" minus one buffer");
3055
3056 return NGX_CONF_ERROR;
3057 }
3058
3059
3060 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
3061 prev->upstream.temp_file_write_size_conf,
3062 NGX_CONF_UNSET_SIZE);
3063
3064 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
3065 conf->upstream.temp_file_write_size = 2 * size;
3066 } else {
3067 conf->upstream.temp_file_write_size =
3068 conf->upstream.temp_file_write_size_conf;
3069 }
3070
3071 if (conf->upstream.temp_file_write_size < size) {
3072 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3073 "\"proxy_temp_file_write_size\" must be equal to or greater "
3074 "than the maximum of the value of \"proxy_buffer_size\" and "
3075 "one of the \"proxy_buffers\"");
3076
3077 return NGX_CONF_ERROR;
3078 }
3079
3080 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
3081 prev->upstream.max_temp_file_size_conf,
3082 NGX_CONF_UNSET_SIZE);
3083
3084 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
3085 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
3086 } else {
3087 conf->upstream.max_temp_file_size =
3088 conf->upstream.max_temp_file_size_conf;
3089 }
3090
3091 if (conf->upstream.max_temp_file_size != 0
3092 && conf->upstream.max_temp_file_size < size)
3093 {
3094 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3095 "\"proxy_max_temp_file_size\" must be equal to zero to disable "
3096 "temporary files usage or must be equal to or greater than "
3097 "the maximum of the value of \"proxy_buffer_size\" and "
3098 "one of the \"proxy_buffers\"");
3099
3100 return NGX_CONF_ERROR;
3101 }
3102
3103
3104 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
3105 prev->upstream.ignore_headers,
3106 NGX_CONF_BITMASK_SET);
3107
3108
3109 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
3110 prev->upstream.next_upstream,
3111 (NGX_CONF_BITMASK_SET
3112 |NGX_HTTP_UPSTREAM_FT_ERROR
3113 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
3114
3115 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
3116 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
3117 |NGX_HTTP_UPSTREAM_FT_OFF;
3118 }
3119
3120 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
3121 prev->upstream.temp_path,
3122 &ngx_http_proxy_temp_path)
3123 != NGX_OK)
3124 {
3125 return NGX_CONF_ERROR;
3126 }
3127
3128
3129 #if (NGX_HTTP_CACHE)
3130
3131 if (conf->upstream.cache == NGX_CONF_UNSET) {
3132 ngx_conf_merge_value(conf->upstream.cache,
3133 prev->upstream.cache, 0);
3134
3135 conf->upstream.cache_zone = prev->upstream.cache_zone;
3136 conf->upstream.cache_value = prev->upstream.cache_value;
3137 }
3138
3139 if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
3140 ngx_shm_zone_t *shm_zone;
3141
3142 shm_zone = conf->upstream.cache_zone;
3143
3144 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3145 "\"proxy_cache\" zone \"%V\" is unknown",
3146 &shm_zone->shm.name);
3147
3148 return NGX_CONF_ERROR;
3149 }
3150
3151 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
3152 prev->upstream.cache_min_uses, 1);
3153
3154 ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
3155 prev->upstream.cache_max_range_offset,
3156 NGX_MAX_OFF_T_VALUE);
3157
3158 ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
3159 prev->upstream.cache_use_stale,
3160 (NGX_CONF_BITMASK_SET
3161 |NGX_HTTP_UPSTREAM_FT_OFF));
3162
3163 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3164 conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3165 |NGX_HTTP_UPSTREAM_FT_OFF;
3166 }
3167
3168 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3169 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3170 }
3171
3172 if (conf->upstream.cache_methods == 0) {
3173 conf->upstream.cache_methods = prev->upstream.cache_methods;
3174 }
3175
3176 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3177
3178 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3179 prev->upstream.cache_bypass, NULL);
3180
3181 ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3182 prev->upstream.no_cache, NULL);
3183
3184 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3185 prev->upstream.cache_valid, NULL);
3186
3187 if (conf->cache_key.value.data == NULL) {
3188 conf->cache_key = prev->cache_key;
3189 }
3190
3191 ngx_conf_merge_value(conf->upstream.cache_lock,
3192 prev->upstream.cache_lock, 0);
3193
3194 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3195 prev->upstream.cache_lock_timeout, 5000);
3196
3197 ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3198 prev->upstream.cache_lock_age, 5000);
3199
3200 ngx_conf_merge_value(conf->upstream.cache_revalidate,
3201 prev->upstream.cache_revalidate, 0);
3202
3203 ngx_conf_merge_value(conf->upstream.cache_convert_head,
3204 prev->upstream.cache_convert_head, 1);
3205
3206 ngx_conf_merge_value(conf->upstream.cache_background_update,
3207 prev->upstream.cache_background_update, 0);
3208
3209 #endif
3210
3211 if (conf->method == NULL) {
3212 conf->method = prev->method;
3213 }
3214
3215 ngx_conf_merge_value(conf->upstream.pass_request_headers,
3216 prev->upstream.pass_request_headers, 1);
3217 ngx_conf_merge_value(conf->upstream.pass_request_body,
3218 prev->upstream.pass_request_body, 1);
3219
3220 ngx_conf_merge_value(conf->upstream.intercept_errors,
3221 prev->upstream.intercept_errors, 0);
3222
3223 #if (NGX_HTTP_SSL)
3224
3225 ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
3226 prev->upstream.ssl_session_reuse, 1);
3227
3228 ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
3229 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
3230 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
3231
3232 ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
3233 "DEFAULT");
3234
3235 if (conf->upstream.ssl_name == NULL) {
3236 conf->upstream.ssl_name = prev->upstream.ssl_name;
3237 }
3238
3239 ngx_conf_merge_value(conf->upstream.ssl_server_name,
3240 prev->upstream.ssl_server_name, 0);
3241 ngx_conf_merge_value(conf->upstream.ssl_verify,
3242 prev->upstream.ssl_verify, 0);
3243 ngx_conf_merge_uint_value(conf->ssl_verify_depth,
3244 prev->ssl_verify_depth, 1);
3245 ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
3246 prev->ssl_trusted_certificate, "");
3247 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
3248
3249 ngx_conf_merge_str_value(conf->ssl_certificate,
3250 prev->ssl_certificate, "");
3251 ngx_conf_merge_str_value(conf->ssl_certificate_key,
3252 prev->ssl_certificate_key, "");
3253 ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
3254
3255 if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
3256 return NGX_CONF_ERROR;
3257 }
3258
3259 #endif
3260
3261 ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
3262
3263 if (conf->redirect) {
3264
3265 if (conf->redirects == NULL) {
3266 conf->redirects = prev->redirects;
3267 }
3268
3269 if (conf->redirects == NULL && conf->url.data) {
3270
3271 conf->redirects = ngx_array_create(cf->pool, 1,
3272 sizeof(ngx_http_proxy_rewrite_t));
3273 if (conf->redirects == NULL) {
3274 return NGX_CONF_ERROR;
3275 }
3276
3277 pr = ngx_array_push(conf->redirects);
3278 if (pr == NULL) {
3279 return NGX_CONF_ERROR;
3280 }
3281
3282 ngx_memzero(&pr->pattern.complex,
3283 sizeof(ngx_http_complex_value_t));
3284
3285 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3286
3287 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3288
3289 if (conf->vars.uri.len) {
3290 pr->pattern.complex.value = conf->url;
3291 pr->replacement.value = conf->location;
3292
3293 } else {
3294 pr->pattern.complex.value.len = conf->url.len
3295 + sizeof("/") - 1;
3296
3297 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3298 if (p == NULL) {
3299 return NGX_CONF_ERROR;
3300 }
3301
3302 pr->pattern.complex.value.data = p;
3303
3304 p = ngx_cpymem(p, conf->url.data, conf->url.len);
3305 *p = '/';
3306
3307 ngx_str_set(&pr->replacement.value, "/");
3308 }
3309 }
3310 }
3311
3312 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
3313
3314 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
3315
3316 ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
3317 NGX_HTTP_VERSION_10);
3318
3319 ngx_conf_merge_uint_value(conf->headers_hash_max_size,
3320 prev->headers_hash_max_size, 512);
3321
3322 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
3323 prev->headers_hash_bucket_size, 64);
3324
3325 conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
3326 ngx_cacheline_size);
3327
3328 hash.max_size = conf->headers_hash_max_size;
3329 hash.bucket_size = conf->headers_hash_bucket_size;
3330 hash.name = "proxy_headers_hash";
3331
3332 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3333 &prev->upstream, ngx_http_proxy_hide_headers, &hash)
3334 != NGX_OK)
3335 {
3336 return NGX_CONF_ERROR;
3337 }
3338
3339 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3340
3341 if (clcf->noname
3342 && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
3343 {
3344 conf->upstream.upstream = prev->upstream.upstream;
3345 conf->location = prev->location;
3346 conf->vars = prev->vars;
3347
3348 conf->proxy_lengths = prev->proxy_lengths;
3349 conf->proxy_values = prev->proxy_values;
3350
3351 #if (NGX_HTTP_SSL)
3352 conf->upstream.ssl = prev->upstream.ssl;
3353 #endif
3354 }
3355
3356 if (clcf->lmt_excpt && clcf->handler == NULL
3357 && (conf->upstream.upstream || conf->proxy_lengths))
3358 {
3359 clcf->handler = ngx_http_proxy_handler;
3360 }
3361
3362 if (conf->body_source.data == NULL) {
3363 conf->body_flushes = prev->body_flushes;
3364 conf->body_source = prev->body_source;
3365 conf->body_lengths = prev->body_lengths;
3366 conf->body_values = prev->body_values;
3367 }
3368
3369 if (conf->body_source.data && conf->body_lengths == NULL) {
3370
3371 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3372
3373 sc.cf = cf;
3374 sc.source = &conf->body_source;
3375 sc.flushes = &conf->body_flushes;
3376 sc.lengths = &conf->body_lengths;
3377 sc.values = &conf->body_values;
3378 sc.complete_lengths = 1;
3379 sc.complete_values = 1;
3380
3381 if (ngx_http_script_compile(&sc) != NGX_OK) {
3382 return NGX_CONF_ERROR;
3383 }
3384 }
3385
3386 if (conf->headers_source == NULL) {
3387 conf->headers = prev->headers;
3388 #if (NGX_HTTP_CACHE)
3389 conf->headers_cache = prev->headers_cache;
3390 #endif
3391 conf->headers_source = prev->headers_source;
3392 }
3393
3394 rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
3395 ngx_http_proxy_headers);
3396 if (rc != NGX_OK) {
3397 return NGX_CONF_ERROR;
3398 }
3399
3400 #if (NGX_HTTP_CACHE)
3401
3402 if (conf->upstream.cache) {
3403 rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
3404 ngx_http_proxy_cache_headers);
3405 if (rc != NGX_OK) {
3406 return NGX_CONF_ERROR;
3407 }
3408 }
3409
3410 #endif
3411
3412 /*
3413 * special handling to preserve conf->headers in the "http" section
3414 * to inherit it to all servers
3415 */
3416
3417 if (prev->headers.hash.buckets == NULL
3418 && conf->headers_source == prev->headers_source)
3419 {
3420 prev->headers = conf->headers;
3421 #if (NGX_HTTP_CACHE)
3422 prev->headers_cache = conf->headers_cache;
3423 #endif
3424 }
3425
3426 #if (NGX_HAVE_FSTACK)
3427 /* By default, we set up a proxy on fstack */
3428 ngx_conf_merge_value(conf->kernel_network_stack,
3429 prev->kernel_network_stack, 0);
3430 #endif
3431
3432 return NGX_CONF_OK;
3433 }
3434
3435
3436 static ngx_int_t
ngx_http_proxy_init_headers(ngx_conf_t * cf,ngx_http_proxy_loc_conf_t * conf,ngx_http_proxy_headers_t * headers,ngx_keyval_t * default_headers)3437 ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
3438 ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
3439 {
3440 u_char *p;
3441 size_t size;
3442 uintptr_t *code;
3443 ngx_uint_t i;
3444 ngx_array_t headers_names, headers_merged;
3445 ngx_keyval_t *src, *s, *h;
3446 ngx_hash_key_t *hk;
3447 ngx_hash_init_t hash;
3448 ngx_http_script_compile_t sc;
3449 ngx_http_script_copy_code_t *copy;
3450
3451 if (headers->hash.buckets) {
3452 return NGX_OK;
3453 }
3454
3455 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3456 != NGX_OK)
3457 {
3458 return NGX_ERROR;
3459 }
3460
3461 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
3462 != NGX_OK)
3463 {
3464 return NGX_ERROR;
3465 }
3466
3467 headers->lengths = ngx_array_create(cf->pool, 64, 1);
3468 if (headers->lengths == NULL) {
3469 return NGX_ERROR;
3470 }
3471
3472 headers->values = ngx_array_create(cf->pool, 512, 1);
3473 if (headers->values == NULL) {
3474 return NGX_ERROR;
3475 }
3476
3477 if (conf->headers_source) {
3478
3479 src = conf->headers_source->elts;
3480 for (i = 0; i < conf->headers_source->nelts; i++) {
3481
3482 s = ngx_array_push(&headers_merged);
3483 if (s == NULL) {
3484 return NGX_ERROR;
3485 }
3486
3487 *s = src[i];
3488 }
3489 }
3490
3491 h = default_headers;
3492
3493 while (h->key.len) {
3494
3495 src = headers_merged.elts;
3496 for (i = 0; i < headers_merged.nelts; i++) {
3497 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3498 goto next;
3499 }
3500 }
3501
3502 s = ngx_array_push(&headers_merged);
3503 if (s == NULL) {
3504 return NGX_ERROR;
3505 }
3506
3507 *s = *h;
3508
3509 next:
3510
3511 h++;
3512 }
3513
3514
3515 src = headers_merged.elts;
3516 for (i = 0; i < headers_merged.nelts; i++) {
3517
3518 hk = ngx_array_push(&headers_names);
3519 if (hk == NULL) {
3520 return NGX_ERROR;
3521 }
3522
3523 hk->key = src[i].key;
3524 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
3525 hk->value = (void *) 1;
3526
3527 if (src[i].value.len == 0) {
3528 continue;
3529 }
3530
3531 copy = ngx_array_push_n(headers->lengths,
3532 sizeof(ngx_http_script_copy_code_t));
3533 if (copy == NULL) {
3534 return NGX_ERROR;
3535 }
3536
3537 copy->code = (ngx_http_script_code_pt) (void *)
3538 ngx_http_script_copy_len_code;
3539 copy->len = src[i].key.len;
3540
3541 size = (sizeof(ngx_http_script_copy_code_t)
3542 + src[i].key.len + sizeof(uintptr_t) - 1)
3543 & ~(sizeof(uintptr_t) - 1);
3544
3545 copy = ngx_array_push_n(headers->values, size);
3546 if (copy == NULL) {
3547 return NGX_ERROR;
3548 }
3549
3550 copy->code = ngx_http_script_copy_code;
3551 copy->len = src[i].key.len;
3552
3553 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3554 ngx_memcpy(p, src[i].key.data, src[i].key.len);
3555
3556 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3557
3558 sc.cf = cf;
3559 sc.source = &src[i].value;
3560 sc.flushes = &headers->flushes;
3561 sc.lengths = &headers->lengths;
3562 sc.values = &headers->values;
3563
3564 if (ngx_http_script_compile(&sc) != NGX_OK) {
3565 return NGX_ERROR;
3566 }
3567
3568 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3569 if (code == NULL) {
3570 return NGX_ERROR;
3571 }
3572
3573 *code = (uintptr_t) NULL;
3574
3575 code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
3576 if (code == NULL) {
3577 return NGX_ERROR;
3578 }
3579
3580 *code = (uintptr_t) NULL;
3581 }
3582
3583 code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3584 if (code == NULL) {
3585 return NGX_ERROR;
3586 }
3587
3588 *code = (uintptr_t) NULL;
3589
3590
3591 hash.hash = &headers->hash;
3592 hash.key = ngx_hash_key_lc;
3593 hash.max_size = conf->headers_hash_max_size;
3594 hash.bucket_size = conf->headers_hash_bucket_size;
3595 hash.name = "proxy_headers_hash";
3596 hash.pool = cf->pool;
3597 hash.temp_pool = NULL;
3598
3599 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3600 }
3601
3602
3603 static char *
ngx_http_proxy_pass(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3604 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3605 {
3606 ngx_http_proxy_loc_conf_t *plcf = conf;
3607
3608 size_t add;
3609 u_short port;
3610 ngx_str_t *value, *url;
3611 ngx_url_t u;
3612 ngx_uint_t n;
3613 ngx_http_core_loc_conf_t *clcf;
3614 ngx_http_script_compile_t sc;
3615
3616 if (plcf->upstream.upstream || plcf->proxy_lengths) {
3617 return "is duplicate";
3618 }
3619
3620 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3621
3622 clcf->handler = ngx_http_proxy_handler;
3623
3624 if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
3625 clcf->auto_redirect = 1;
3626 }
3627
3628 value = cf->args->elts;
3629
3630 url = &value[1];
3631
3632 n = ngx_http_script_variables_count(url);
3633
3634 if (n) {
3635
3636 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3637
3638 sc.cf = cf;
3639 sc.source = url;
3640 sc.lengths = &plcf->proxy_lengths;
3641 sc.values = &plcf->proxy_values;
3642 sc.variables = n;
3643 sc.complete_lengths = 1;
3644 sc.complete_values = 1;
3645
3646 if (ngx_http_script_compile(&sc) != NGX_OK) {
3647 return NGX_CONF_ERROR;
3648 }
3649
3650 #if (NGX_HTTP_SSL)
3651 plcf->ssl = 1;
3652 #endif
3653
3654 return NGX_CONF_OK;
3655 }
3656
3657 if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3658 add = 7;
3659 port = 80;
3660
3661 } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3662
3663 #if (NGX_HTTP_SSL)
3664 plcf->ssl = 1;
3665
3666 add = 8;
3667 port = 443;
3668 #else
3669 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3670 "https protocol requires SSL support");
3671 return NGX_CONF_ERROR;
3672 #endif
3673
3674 } else {
3675 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3676 return NGX_CONF_ERROR;
3677 }
3678
3679 ngx_memzero(&u, sizeof(ngx_url_t));
3680
3681 u.url.len = url->len - add;
3682 u.url.data = url->data + add;
3683 u.default_port = port;
3684 u.uri_part = 1;
3685 u.no_resolve = 1;
3686
3687 plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3688 if (plcf->upstream.upstream == NULL) {
3689 return NGX_CONF_ERROR;
3690 }
3691
3692 plcf->vars.schema.len = add;
3693 plcf->vars.schema.data = url->data;
3694 plcf->vars.key_start = plcf->vars.schema;
3695
3696 ngx_http_proxy_set_vars(&u, &plcf->vars);
3697
3698 plcf->location = clcf->name;
3699
3700 if (clcf->named
3701 #if (NGX_PCRE)
3702 || clcf->regex
3703 #endif
3704 || clcf->noname)
3705 {
3706 if (plcf->vars.uri.len) {
3707 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3708 "\"proxy_pass\" cannot have URI part in "
3709 "location given by regular expression, "
3710 "or inside named location, "
3711 "or inside \"if\" statement, "
3712 "or inside \"limit_except\" block");
3713 return NGX_CONF_ERROR;
3714 }
3715
3716 plcf->location.len = 0;
3717 }
3718
3719 plcf->url = *url;
3720
3721 return NGX_CONF_OK;
3722 }
3723
3724
3725 static char *
ngx_http_proxy_redirect(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3726 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3727 {
3728 ngx_http_proxy_loc_conf_t *plcf = conf;
3729
3730 u_char *p;
3731 ngx_str_t *value;
3732 ngx_http_proxy_rewrite_t *pr;
3733 ngx_http_compile_complex_value_t ccv;
3734
3735 if (plcf->redirect == 0) {
3736 return NGX_CONF_OK;
3737 }
3738
3739 plcf->redirect = 1;
3740
3741 value = cf->args->elts;
3742
3743 if (cf->args->nelts == 2) {
3744 if (ngx_strcmp(value[1].data, "off") == 0) {
3745 plcf->redirect = 0;
3746 plcf->redirects = NULL;
3747 return NGX_CONF_OK;
3748 }
3749
3750 if (ngx_strcmp(value[1].data, "false") == 0) {
3751 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3752 "invalid parameter \"false\", use \"off\" instead");
3753 plcf->redirect = 0;
3754 plcf->redirects = NULL;
3755 return NGX_CONF_OK;
3756 }
3757
3758 if (ngx_strcmp(value[1].data, "default") != 0) {
3759 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3760 "invalid parameter \"%V\"", &value[1]);
3761 return NGX_CONF_ERROR;
3762 }
3763 }
3764
3765 if (plcf->redirects == NULL) {
3766 plcf->redirects = ngx_array_create(cf->pool, 1,
3767 sizeof(ngx_http_proxy_rewrite_t));
3768 if (plcf->redirects == NULL) {
3769 return NGX_CONF_ERROR;
3770 }
3771 }
3772
3773 pr = ngx_array_push(plcf->redirects);
3774 if (pr == NULL) {
3775 return NGX_CONF_ERROR;
3776 }
3777
3778 if (ngx_strcmp(value[1].data, "default") == 0) {
3779 if (plcf->proxy_lengths) {
3780 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3781 "\"proxy_redirect default\" cannot be used "
3782 "with \"proxy_pass\" directive with variables");
3783 return NGX_CONF_ERROR;
3784 }
3785
3786 if (plcf->url.data == NULL) {
3787 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3788 "\"proxy_redirect default\" should be placed "
3789 "after the \"proxy_pass\" directive");
3790 return NGX_CONF_ERROR;
3791 }
3792
3793 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3794
3795 ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3796
3797 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3798
3799 if (plcf->vars.uri.len) {
3800 pr->pattern.complex.value = plcf->url;
3801 pr->replacement.value = plcf->location;
3802
3803 } else {
3804 pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3805
3806 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3807 if (p == NULL) {
3808 return NGX_CONF_ERROR;
3809 }
3810
3811 pr->pattern.complex.value.data = p;
3812
3813 p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3814 *p = '/';
3815
3816 ngx_str_set(&pr->replacement.value, "/");
3817 }
3818
3819 return NGX_CONF_OK;
3820 }
3821
3822
3823 if (value[1].data[0] == '~') {
3824 value[1].len--;
3825 value[1].data++;
3826
3827 if (value[1].data[0] == '*') {
3828 value[1].len--;
3829 value[1].data++;
3830
3831 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3832 return NGX_CONF_ERROR;
3833 }
3834
3835 } else {
3836 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3837 return NGX_CONF_ERROR;
3838 }
3839 }
3840
3841 } else {
3842
3843 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3844
3845 ccv.cf = cf;
3846 ccv.value = &value[1];
3847 ccv.complex_value = &pr->pattern.complex;
3848
3849 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3850 return NGX_CONF_ERROR;
3851 }
3852
3853 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3854 }
3855
3856
3857 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3858
3859 ccv.cf = cf;
3860 ccv.value = &value[2];
3861 ccv.complex_value = &pr->replacement;
3862
3863 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3864 return NGX_CONF_ERROR;
3865 }
3866
3867 return NGX_CONF_OK;
3868 }
3869
3870
3871 static char *
ngx_http_proxy_cookie_domain(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3872 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3873 {
3874 ngx_http_proxy_loc_conf_t *plcf = conf;
3875
3876 ngx_str_t *value;
3877 ngx_http_proxy_rewrite_t *pr;
3878 ngx_http_compile_complex_value_t ccv;
3879
3880 if (plcf->cookie_domains == NULL) {
3881 return NGX_CONF_OK;
3882 }
3883
3884 value = cf->args->elts;
3885
3886 if (cf->args->nelts == 2) {
3887
3888 if (ngx_strcmp(value[1].data, "off") == 0) {
3889 plcf->cookie_domains = NULL;
3890 return NGX_CONF_OK;
3891 }
3892
3893 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3894 "invalid parameter \"%V\"", &value[1]);
3895 return NGX_CONF_ERROR;
3896 }
3897
3898 if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3899 plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3900 sizeof(ngx_http_proxy_rewrite_t));
3901 if (plcf->cookie_domains == NULL) {
3902 return NGX_CONF_ERROR;
3903 }
3904 }
3905
3906 pr = ngx_array_push(plcf->cookie_domains);
3907 if (pr == NULL) {
3908 return NGX_CONF_ERROR;
3909 }
3910
3911 if (value[1].data[0] == '~') {
3912 value[1].len--;
3913 value[1].data++;
3914
3915 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3916 return NGX_CONF_ERROR;
3917 }
3918
3919 } else {
3920
3921 if (value[1].data[0] == '.') {
3922 value[1].len--;
3923 value[1].data++;
3924 }
3925
3926 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3927
3928 ccv.cf = cf;
3929 ccv.value = &value[1];
3930 ccv.complex_value = &pr->pattern.complex;
3931
3932 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3933 return NGX_CONF_ERROR;
3934 }
3935
3936 pr->handler = ngx_http_proxy_rewrite_domain_handler;
3937
3938 if (value[2].data[0] == '.') {
3939 value[2].len--;
3940 value[2].data++;
3941 }
3942 }
3943
3944 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3945
3946 ccv.cf = cf;
3947 ccv.value = &value[2];
3948 ccv.complex_value = &pr->replacement;
3949
3950 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3951 return NGX_CONF_ERROR;
3952 }
3953
3954 return NGX_CONF_OK;
3955 }
3956
3957
3958 static char *
ngx_http_proxy_cookie_path(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3959 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3960 {
3961 ngx_http_proxy_loc_conf_t *plcf = conf;
3962
3963 ngx_str_t *value;
3964 ngx_http_proxy_rewrite_t *pr;
3965 ngx_http_compile_complex_value_t ccv;
3966
3967 if (plcf->cookie_paths == NULL) {
3968 return NGX_CONF_OK;
3969 }
3970
3971 value = cf->args->elts;
3972
3973 if (cf->args->nelts == 2) {
3974
3975 if (ngx_strcmp(value[1].data, "off") == 0) {
3976 plcf->cookie_paths = NULL;
3977 return NGX_CONF_OK;
3978 }
3979
3980 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3981 "invalid parameter \"%V\"", &value[1]);
3982 return NGX_CONF_ERROR;
3983 }
3984
3985 if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3986 plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3987 sizeof(ngx_http_proxy_rewrite_t));
3988 if (plcf->cookie_paths == NULL) {
3989 return NGX_CONF_ERROR;
3990 }
3991 }
3992
3993 pr = ngx_array_push(plcf->cookie_paths);
3994 if (pr == NULL) {
3995 return NGX_CONF_ERROR;
3996 }
3997
3998 if (value[1].data[0] == '~') {
3999 value[1].len--;
4000 value[1].data++;
4001
4002 if (value[1].data[0] == '*') {
4003 value[1].len--;
4004 value[1].data++;
4005
4006 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
4007 return NGX_CONF_ERROR;
4008 }
4009
4010 } else {
4011 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
4012 return NGX_CONF_ERROR;
4013 }
4014 }
4015
4016 } else {
4017
4018 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4019
4020 ccv.cf = cf;
4021 ccv.value = &value[1];
4022 ccv.complex_value = &pr->pattern.complex;
4023
4024 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4025 return NGX_CONF_ERROR;
4026 }
4027
4028 pr->handler = ngx_http_proxy_rewrite_complex_handler;
4029 }
4030
4031 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4032
4033 ccv.cf = cf;
4034 ccv.value = &value[2];
4035 ccv.complex_value = &pr->replacement;
4036
4037 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4038 return NGX_CONF_ERROR;
4039 }
4040
4041 return NGX_CONF_OK;
4042 }
4043
4044
4045 static ngx_int_t
ngx_http_proxy_rewrite_regex(ngx_conf_t * cf,ngx_http_proxy_rewrite_t * pr,ngx_str_t * regex,ngx_uint_t caseless)4046 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
4047 ngx_str_t *regex, ngx_uint_t caseless)
4048 {
4049 #if (NGX_PCRE)
4050 u_char errstr[NGX_MAX_CONF_ERRSTR];
4051 ngx_regex_compile_t rc;
4052
4053 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
4054
4055 rc.pattern = *regex;
4056 rc.err.len = NGX_MAX_CONF_ERRSTR;
4057 rc.err.data = errstr;
4058
4059 if (caseless) {
4060 rc.options = NGX_REGEX_CASELESS;
4061 }
4062
4063 pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
4064 if (pr->pattern.regex == NULL) {
4065 return NGX_ERROR;
4066 }
4067
4068 pr->handler = ngx_http_proxy_rewrite_regex_handler;
4069
4070 return NGX_OK;
4071
4072 #else
4073
4074 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4075 "using regex \"%V\" requires PCRE library", regex);
4076 return NGX_ERROR;
4077
4078 #endif
4079 }
4080
4081
4082 static char *
ngx_http_proxy_store(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4083 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4084 {
4085 ngx_http_proxy_loc_conf_t *plcf = conf;
4086
4087 ngx_str_t *value;
4088 ngx_http_script_compile_t sc;
4089
4090 if (plcf->upstream.store != NGX_CONF_UNSET) {
4091 return "is duplicate";
4092 }
4093
4094 value = cf->args->elts;
4095
4096 if (ngx_strcmp(value[1].data, "off") == 0) {
4097 plcf->upstream.store = 0;
4098 return NGX_CONF_OK;
4099 }
4100
4101 #if (NGX_HTTP_CACHE)
4102 if (plcf->upstream.cache > 0) {
4103 return "is incompatible with \"proxy_cache\"";
4104 }
4105 #endif
4106
4107 plcf->upstream.store = 1;
4108
4109 if (ngx_strcmp(value[1].data, "on") == 0) {
4110 return NGX_CONF_OK;
4111 }
4112
4113 /* include the terminating '\0' into script */
4114 value[1].len++;
4115
4116 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4117
4118 sc.cf = cf;
4119 sc.source = &value[1];
4120 sc.lengths = &plcf->upstream.store_lengths;
4121 sc.values = &plcf->upstream.store_values;
4122 sc.variables = ngx_http_script_variables_count(&value[1]);
4123 sc.complete_lengths = 1;
4124 sc.complete_values = 1;
4125
4126 if (ngx_http_script_compile(&sc) != NGX_OK) {
4127 return NGX_CONF_ERROR;
4128 }
4129
4130 return NGX_CONF_OK;
4131 }
4132
4133
4134 #if (NGX_HTTP_CACHE)
4135
4136 static char *
ngx_http_proxy_cache(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4137 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4138 {
4139 ngx_http_proxy_loc_conf_t *plcf = conf;
4140
4141 ngx_str_t *value;
4142 ngx_http_complex_value_t cv;
4143 ngx_http_compile_complex_value_t ccv;
4144
4145 value = cf->args->elts;
4146
4147 if (plcf->upstream.cache != NGX_CONF_UNSET) {
4148 return "is duplicate";
4149 }
4150
4151 if (ngx_strcmp(value[1].data, "off") == 0) {
4152 plcf->upstream.cache = 0;
4153 return NGX_CONF_OK;
4154 }
4155
4156 if (plcf->upstream.store > 0) {
4157 return "is incompatible with \"proxy_store\"";
4158 }
4159
4160 plcf->upstream.cache = 1;
4161
4162 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4163
4164 ccv.cf = cf;
4165 ccv.value = &value[1];
4166 ccv.complex_value = &cv;
4167
4168 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4169 return NGX_CONF_ERROR;
4170 }
4171
4172 if (cv.lengths != NULL) {
4173
4174 plcf->upstream.cache_value = ngx_palloc(cf->pool,
4175 sizeof(ngx_http_complex_value_t));
4176 if (plcf->upstream.cache_value == NULL) {
4177 return NGX_CONF_ERROR;
4178 }
4179
4180 *plcf->upstream.cache_value = cv;
4181
4182 return NGX_CONF_OK;
4183 }
4184
4185 plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
4186 &ngx_http_proxy_module);
4187 if (plcf->upstream.cache_zone == NULL) {
4188 return NGX_CONF_ERROR;
4189 }
4190
4191 return NGX_CONF_OK;
4192 }
4193
4194
4195 static char *
ngx_http_proxy_cache_key(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4196 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4197 {
4198 ngx_http_proxy_loc_conf_t *plcf = conf;
4199
4200 ngx_str_t *value;
4201 ngx_http_compile_complex_value_t ccv;
4202
4203 value = cf->args->elts;
4204
4205 if (plcf->cache_key.value.data) {
4206 return "is duplicate";
4207 }
4208
4209 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4210
4211 ccv.cf = cf;
4212 ccv.value = &value[1];
4213 ccv.complex_value = &plcf->cache_key;
4214
4215 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4216 return NGX_CONF_ERROR;
4217 }
4218
4219 return NGX_CONF_OK;
4220 }
4221
4222 #endif
4223
4224
4225 #if (NGX_HTTP_SSL)
4226
4227 static char *
ngx_http_proxy_ssl_password_file(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4228 ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4229 {
4230 ngx_http_proxy_loc_conf_t *plcf = conf;
4231
4232 ngx_str_t *value;
4233
4234 if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
4235 return "is duplicate";
4236 }
4237
4238 value = cf->args->elts;
4239
4240 plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
4241
4242 if (plcf->ssl_passwords == NULL) {
4243 return NGX_CONF_ERROR;
4244 }
4245
4246 return NGX_CONF_OK;
4247 }
4248
4249 #endif
4250
4251
4252 static char *
ngx_http_proxy_lowat_check(ngx_conf_t * cf,void * post,void * data)4253 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
4254 {
4255 #if (NGX_FREEBSD)
4256 ssize_t *np = data;
4257
4258 if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
4259 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4260 "\"proxy_send_lowat\" must be less than %d "
4261 "(sysctl net.inet.tcp.sendspace)",
4262 ngx_freebsd_net_inet_tcp_sendspace);
4263
4264 return NGX_CONF_ERROR;
4265 }
4266
4267 #elif !(NGX_HAVE_SO_SNDLOWAT)
4268 ssize_t *np = data;
4269
4270 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
4271 "\"proxy_send_lowat\" is not supported, ignored");
4272
4273 *np = 0;
4274
4275 #endif
4276
4277 return NGX_CONF_OK;
4278 }
4279
4280
4281 #if (NGX_HTTP_SSL)
4282
4283 static ngx_int_t
ngx_http_proxy_set_ssl(ngx_conf_t * cf,ngx_http_proxy_loc_conf_t * plcf)4284 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
4285 {
4286 ngx_pool_cleanup_t *cln;
4287
4288 plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
4289 if (plcf->upstream.ssl == NULL) {
4290 return NGX_ERROR;
4291 }
4292
4293 plcf->upstream.ssl->log = cf->log;
4294
4295 if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
4296 != NGX_OK)
4297 {
4298 return NGX_ERROR;
4299 }
4300
4301 cln = ngx_pool_cleanup_add(cf->pool, 0);
4302 if (cln == NULL) {
4303 ngx_ssl_cleanup_ctx(plcf->upstream.ssl);
4304 return NGX_ERROR;
4305 }
4306
4307 cln->handler = ngx_ssl_cleanup_ctx;
4308 cln->data = plcf->upstream.ssl;
4309
4310 if (plcf->ssl_certificate.len) {
4311
4312 if (plcf->ssl_certificate_key.len == 0) {
4313 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4314 "no \"proxy_ssl_certificate_key\" is defined "
4315 "for certificate \"%V\"", &plcf->ssl_certificate);
4316 return NGX_ERROR;
4317 }
4318
4319 if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate,
4320 &plcf->ssl_certificate_key, plcf->ssl_passwords)
4321 != NGX_OK)
4322 {
4323 return NGX_ERROR;
4324 }
4325 }
4326
4327 if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0)
4328 != NGX_OK)
4329 {
4330 return NGX_ERROR;
4331 }
4332
4333 if (plcf->upstream.ssl_verify) {
4334 if (plcf->ssl_trusted_certificate.len == 0) {
4335 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4336 "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
4337 return NGX_ERROR;
4338 }
4339
4340 if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
4341 &plcf->ssl_trusted_certificate,
4342 plcf->ssl_verify_depth)
4343 != NGX_OK)
4344 {
4345 return NGX_ERROR;
4346 }
4347
4348 if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
4349 return NGX_ERROR;
4350 }
4351 }
4352
4353 if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl,
4354 plcf->upstream.ssl_session_reuse)
4355 != NGX_OK)
4356 {
4357 return NGX_ERROR;
4358 }
4359
4360 return NGX_OK;
4361 }
4362
4363 #endif
4364
4365
4366 static void
ngx_http_proxy_set_vars(ngx_url_t * u,ngx_http_proxy_vars_t * v)4367 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
4368 {
4369 if (u->family != AF_UNIX) {
4370
4371 if (u->no_port || u->port == u->default_port) {
4372
4373 v->host_header = u->host;
4374
4375 if (u->default_port == 80) {
4376 ngx_str_set(&v->port, "80");
4377
4378 } else {
4379 ngx_str_set(&v->port, "443");
4380 }
4381
4382 } else {
4383 v->host_header.len = u->host.len + 1 + u->port_text.len;
4384 v->host_header.data = u->host.data;
4385 v->port = u->port_text;
4386 }
4387
4388 v->key_start.len += v->host_header.len;
4389
4390 } else {
4391 ngx_str_set(&v->host_header, "localhost");
4392 ngx_str_null(&v->port);
4393 v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
4394 }
4395
4396 v->uri = u->uri;
4397 }
4398