Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / modules / ngx_http_proxy_module.c
blobeadc8c480bbef442c2593a08b191a2c50f3a4793
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
13 typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
15 typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
16 ngx_table_elt_t *h, size_t prefix, size_t len,
17 ngx_http_proxy_rewrite_t *pr);
19 struct ngx_http_proxy_rewrite_s {
20 ngx_http_proxy_rewrite_pt handler;
22 union {
23 ngx_http_complex_value_t complex;
24 #if (NGX_PCRE)
25 ngx_http_regex_t *regex;
26 #endif
27 } pattern;
29 ngx_http_complex_value_t replacement;
33 typedef struct {
34 ngx_str_t key_start;
35 ngx_str_t schema;
36 ngx_str_t host_header;
37 ngx_str_t port;
38 ngx_str_t uri;
39 } ngx_http_proxy_vars_t;
42 typedef struct {
43 ngx_http_upstream_conf_t upstream;
45 ngx_array_t *flushes;
46 ngx_array_t *body_set_len;
47 ngx_array_t *body_set;
48 ngx_array_t *headers_set_len;
49 ngx_array_t *headers_set;
50 ngx_hash_t headers_set_hash;
52 ngx_array_t *headers_source;
54 ngx_array_t *proxy_lengths;
55 ngx_array_t *proxy_values;
57 ngx_array_t *redirects;
58 ngx_array_t *cookie_domains;
59 ngx_array_t *cookie_paths;
61 ngx_str_t body_source;
63 ngx_str_t method;
64 ngx_str_t location;
65 ngx_str_t url;
67 #if (NGX_HTTP_CACHE)
68 ngx_http_complex_value_t cache_key;
69 #endif
71 ngx_http_proxy_vars_t vars;
73 ngx_flag_t redirect;
75 ngx_uint_t http_version;
77 ngx_uint_t headers_hash_max_size;
78 ngx_uint_t headers_hash_bucket_size;
79 } ngx_http_proxy_loc_conf_t;
82 typedef struct {
83 ngx_http_status_t status;
84 ngx_http_chunked_t chunked;
85 ngx_http_proxy_vars_t vars;
86 off_t internal_body_length;
88 ngx_uint_t head; /* unsigned head:1 */
89 } ngx_http_proxy_ctx_t;
92 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
93 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
94 #if (NGX_HTTP_CACHE)
95 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
96 #endif
97 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
98 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
99 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
100 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
101 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
102 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
103 ngx_buf_t *buf);
104 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
105 ngx_buf_t *buf);
106 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
107 ssize_t bytes);
108 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
109 ssize_t bytes);
110 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
111 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
112 ngx_int_t rc);
114 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
115 ngx_http_variable_value_t *v, uintptr_t data);
116 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
117 ngx_http_variable_value_t *v, uintptr_t data);
118 static ngx_int_t
119 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
120 ngx_http_variable_value_t *v, uintptr_t data);
121 static ngx_int_t
122 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
123 ngx_http_variable_value_t *v, uintptr_t data);
124 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
125 ngx_table_elt_t *h, size_t prefix);
126 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
127 ngx_table_elt_t *h);
128 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
129 ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
130 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
131 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
133 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
134 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
135 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
136 void *parent, void *child);
137 static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
138 ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
140 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
141 void *conf);
142 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
143 void *conf);
144 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
145 void *conf);
146 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
147 void *conf);
148 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
149 void *conf);
150 #if (NGX_HTTP_CACHE)
151 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
152 void *conf);
153 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
154 void *conf);
155 #endif
157 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
159 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
160 ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
162 #if (NGX_HTTP_SSL)
163 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
164 ngx_http_proxy_loc_conf_t *plcf);
165 #endif
166 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
169 static ngx_conf_post_t ngx_http_proxy_lowat_post =
170 { ngx_http_proxy_lowat_check };
173 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
174 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
175 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
176 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
177 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
178 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
179 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
180 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
181 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
182 { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
183 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
184 { ngx_null_string, 0 }
188 static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
189 { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
190 { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
191 { ngx_null_string, 0 }
195 ngx_module_t ngx_http_proxy_module;
198 static ngx_command_t ngx_http_proxy_commands[] = {
200 { ngx_string("proxy_pass"),
201 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
202 ngx_http_proxy_pass,
203 NGX_HTTP_LOC_CONF_OFFSET,
205 NULL },
207 { ngx_string("proxy_redirect"),
208 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
209 ngx_http_proxy_redirect,
210 NGX_HTTP_LOC_CONF_OFFSET,
212 NULL },
214 { ngx_string("proxy_cookie_domain"),
215 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
216 ngx_http_proxy_cookie_domain,
217 NGX_HTTP_LOC_CONF_OFFSET,
219 NULL },
221 { ngx_string("proxy_cookie_path"),
222 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
223 ngx_http_proxy_cookie_path,
224 NGX_HTTP_LOC_CONF_OFFSET,
226 NULL },
228 { ngx_string("proxy_store"),
229 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
230 ngx_http_proxy_store,
231 NGX_HTTP_LOC_CONF_OFFSET,
233 NULL },
235 { ngx_string("proxy_store_access"),
236 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
237 ngx_conf_set_access_slot,
238 NGX_HTTP_LOC_CONF_OFFSET,
239 offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
240 NULL },
242 { ngx_string("proxy_buffering"),
243 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
244 ngx_conf_set_flag_slot,
245 NGX_HTTP_LOC_CONF_OFFSET,
246 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
247 NULL },
249 { ngx_string("proxy_ignore_client_abort"),
250 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
251 ngx_conf_set_flag_slot,
252 NGX_HTTP_LOC_CONF_OFFSET,
253 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
254 NULL },
256 { ngx_string("proxy_bind"),
257 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
258 ngx_http_upstream_bind_set_slot,
259 NGX_HTTP_LOC_CONF_OFFSET,
260 offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
261 NULL },
263 { ngx_string("proxy_connect_timeout"),
264 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
265 ngx_conf_set_msec_slot,
266 NGX_HTTP_LOC_CONF_OFFSET,
267 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
268 NULL },
270 { ngx_string("proxy_send_timeout"),
271 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
272 ngx_conf_set_msec_slot,
273 NGX_HTTP_LOC_CONF_OFFSET,
274 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
275 NULL },
277 { ngx_string("proxy_send_lowat"),
278 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
279 ngx_conf_set_size_slot,
280 NGX_HTTP_LOC_CONF_OFFSET,
281 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
282 &ngx_http_proxy_lowat_post },
284 { ngx_string("proxy_intercept_errors"),
285 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
286 ngx_conf_set_flag_slot,
287 NGX_HTTP_LOC_CONF_OFFSET,
288 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
289 NULL },
291 { ngx_string("proxy_set_header"),
292 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
293 ngx_conf_set_keyval_slot,
294 NGX_HTTP_LOC_CONF_OFFSET,
295 offsetof(ngx_http_proxy_loc_conf_t, headers_source),
296 NULL },
298 { ngx_string("proxy_headers_hash_max_size"),
299 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
300 ngx_conf_set_num_slot,
301 NGX_HTTP_LOC_CONF_OFFSET,
302 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
303 NULL },
305 { ngx_string("proxy_headers_hash_bucket_size"),
306 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
307 ngx_conf_set_num_slot,
308 NGX_HTTP_LOC_CONF_OFFSET,
309 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
310 NULL },
312 { ngx_string("proxy_set_body"),
313 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
314 ngx_conf_set_str_slot,
315 NGX_HTTP_LOC_CONF_OFFSET,
316 offsetof(ngx_http_proxy_loc_conf_t, body_source),
317 NULL },
319 { ngx_string("proxy_method"),
320 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
321 ngx_conf_set_str_slot,
322 NGX_HTTP_LOC_CONF_OFFSET,
323 offsetof(ngx_http_proxy_loc_conf_t, method),
324 NULL },
326 { ngx_string("proxy_pass_request_headers"),
327 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
328 ngx_conf_set_flag_slot,
329 NGX_HTTP_LOC_CONF_OFFSET,
330 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
331 NULL },
333 { ngx_string("proxy_pass_request_body"),
334 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
335 ngx_conf_set_flag_slot,
336 NGX_HTTP_LOC_CONF_OFFSET,
337 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
338 NULL },
340 { ngx_string("proxy_buffer_size"),
341 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
342 ngx_conf_set_size_slot,
343 NGX_HTTP_LOC_CONF_OFFSET,
344 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
345 NULL },
347 { ngx_string("proxy_read_timeout"),
348 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
349 ngx_conf_set_msec_slot,
350 NGX_HTTP_LOC_CONF_OFFSET,
351 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
352 NULL },
354 { ngx_string("proxy_buffers"),
355 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
356 ngx_conf_set_bufs_slot,
357 NGX_HTTP_LOC_CONF_OFFSET,
358 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
359 NULL },
361 { ngx_string("proxy_busy_buffers_size"),
362 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
363 ngx_conf_set_size_slot,
364 NGX_HTTP_LOC_CONF_OFFSET,
365 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
366 NULL },
368 #if (NGX_HTTP_CACHE)
370 { ngx_string("proxy_cache"),
371 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
372 ngx_http_proxy_cache,
373 NGX_HTTP_LOC_CONF_OFFSET,
375 NULL },
377 { ngx_string("proxy_cache_key"),
378 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
379 ngx_http_proxy_cache_key,
380 NGX_HTTP_LOC_CONF_OFFSET,
382 NULL },
384 { ngx_string("proxy_cache_path"),
385 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
386 ngx_http_file_cache_set_slot,
389 &ngx_http_proxy_module },
391 { ngx_string("proxy_cache_bypass"),
392 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
393 ngx_http_set_predicate_slot,
394 NGX_HTTP_LOC_CONF_OFFSET,
395 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
396 NULL },
398 { ngx_string("proxy_no_cache"),
399 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
400 ngx_http_set_predicate_slot,
401 NGX_HTTP_LOC_CONF_OFFSET,
402 offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
403 NULL },
405 { ngx_string("proxy_cache_valid"),
406 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
407 ngx_http_file_cache_valid_set_slot,
408 NGX_HTTP_LOC_CONF_OFFSET,
409 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
410 NULL },
412 { ngx_string("proxy_cache_min_uses"),
413 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
414 ngx_conf_set_num_slot,
415 NGX_HTTP_LOC_CONF_OFFSET,
416 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
417 NULL },
419 { ngx_string("proxy_cache_use_stale"),
420 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
421 ngx_conf_set_bitmask_slot,
422 NGX_HTTP_LOC_CONF_OFFSET,
423 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
424 &ngx_http_proxy_next_upstream_masks },
426 { ngx_string("proxy_cache_methods"),
427 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
428 ngx_conf_set_bitmask_slot,
429 NGX_HTTP_LOC_CONF_OFFSET,
430 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
431 &ngx_http_upstream_cache_method_mask },
433 { ngx_string("proxy_cache_lock"),
434 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
435 ngx_conf_set_flag_slot,
436 NGX_HTTP_LOC_CONF_OFFSET,
437 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
438 NULL },
440 { ngx_string("proxy_cache_lock_timeout"),
441 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
442 ngx_conf_set_msec_slot,
443 NGX_HTTP_LOC_CONF_OFFSET,
444 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
445 NULL },
447 #endif
449 { ngx_string("proxy_temp_path"),
450 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
451 ngx_conf_set_path_slot,
452 NGX_HTTP_LOC_CONF_OFFSET,
453 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
454 NULL },
456 { ngx_string("proxy_max_temp_file_size"),
457 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
458 ngx_conf_set_size_slot,
459 NGX_HTTP_LOC_CONF_OFFSET,
460 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
461 NULL },
463 { ngx_string("proxy_temp_file_write_size"),
464 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
465 ngx_conf_set_size_slot,
466 NGX_HTTP_LOC_CONF_OFFSET,
467 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
468 NULL },
470 { ngx_string("proxy_next_upstream"),
471 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
472 ngx_conf_set_bitmask_slot,
473 NGX_HTTP_LOC_CONF_OFFSET,
474 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
475 &ngx_http_proxy_next_upstream_masks },
477 { ngx_string("proxy_pass_header"),
478 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
479 ngx_conf_set_str_array_slot,
480 NGX_HTTP_LOC_CONF_OFFSET,
481 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
482 NULL },
484 { ngx_string("proxy_hide_header"),
485 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
486 ngx_conf_set_str_array_slot,
487 NGX_HTTP_LOC_CONF_OFFSET,
488 offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
489 NULL },
491 { ngx_string("proxy_ignore_headers"),
492 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
493 ngx_conf_set_bitmask_slot,
494 NGX_HTTP_LOC_CONF_OFFSET,
495 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
496 &ngx_http_upstream_ignore_headers_masks },
498 { ngx_string("proxy_http_version"),
499 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
500 ngx_conf_set_enum_slot,
501 NGX_HTTP_LOC_CONF_OFFSET,
502 offsetof(ngx_http_proxy_loc_conf_t, http_version),
503 &ngx_http_proxy_http_version },
505 #if (NGX_HTTP_SSL)
507 { ngx_string("proxy_ssl_session_reuse"),
508 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
509 ngx_conf_set_flag_slot,
510 NGX_HTTP_LOC_CONF_OFFSET,
511 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
512 NULL },
514 #endif
516 ngx_null_command
520 static ngx_http_module_t ngx_http_proxy_module_ctx = {
521 ngx_http_proxy_add_variables, /* preconfiguration */
522 NULL, /* postconfiguration */
524 NULL, /* create main configuration */
525 NULL, /* init main configuration */
527 NULL, /* create server configuration */
528 NULL, /* merge server configuration */
530 ngx_http_proxy_create_loc_conf, /* create location configuration */
531 ngx_http_proxy_merge_loc_conf /* merge location configuration */
535 ngx_module_t ngx_http_proxy_module = {
536 NGX_MODULE_V1,
537 &ngx_http_proxy_module_ctx, /* module context */
538 ngx_http_proxy_commands, /* module directives */
539 NGX_HTTP_MODULE, /* module type */
540 NULL, /* init master */
541 NULL, /* init module */
542 NULL, /* init process */
543 NULL, /* init thread */
544 NULL, /* exit thread */
545 NULL, /* exit process */
546 NULL, /* exit master */
547 NGX_MODULE_V1_PADDING
551 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
552 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
555 static ngx_keyval_t ngx_http_proxy_headers[] = {
556 { ngx_string("Host"), ngx_string("$proxy_host") },
557 { ngx_string("Connection"), ngx_string("close") },
558 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
559 { ngx_string("Transfer-Encoding"), ngx_string("") },
560 { ngx_string("Keep-Alive"), ngx_string("") },
561 { ngx_string("Expect"), ngx_string("") },
562 { ngx_string("Upgrade"), ngx_string("") },
563 { ngx_null_string, ngx_null_string }
567 static ngx_str_t ngx_http_proxy_hide_headers[] = {
568 ngx_string("Date"),
569 ngx_string("Server"),
570 ngx_string("X-Pad"),
571 ngx_string("X-Accel-Expires"),
572 ngx_string("X-Accel-Redirect"),
573 ngx_string("X-Accel-Limit-Rate"),
574 ngx_string("X-Accel-Buffering"),
575 ngx_string("X-Accel-Charset"),
576 ngx_null_string
580 #if (NGX_HTTP_CACHE)
582 static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
583 { ngx_string("Host"), ngx_string("$proxy_host") },
584 { ngx_string("Connection"), ngx_string("close") },
585 { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
586 { ngx_string("Transfer-Encoding"), ngx_string("") },
587 { ngx_string("Keep-Alive"), ngx_string("") },
588 { ngx_string("Expect"), ngx_string("") },
589 { ngx_string("Upgrade"), ngx_string("") },
590 { ngx_string("If-Modified-Since"), ngx_string("") },
591 { ngx_string("If-Unmodified-Since"), ngx_string("") },
592 { ngx_string("If-None-Match"), ngx_string("") },
593 { ngx_string("If-Match"), ngx_string("") },
594 { ngx_string("Range"), ngx_string("") },
595 { ngx_string("If-Range"), ngx_string("") },
596 { ngx_null_string, ngx_null_string }
599 #endif
602 static ngx_http_variable_t ngx_http_proxy_vars[] = {
604 { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
605 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
607 { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
608 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
610 { ngx_string("proxy_add_x_forwarded_for"), NULL,
611 ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
613 #if 0
614 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
615 #endif
617 { ngx_string("proxy_internal_body_length"), NULL,
618 ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
620 { ngx_null_string, NULL, NULL, 0, 0, 0 }
624 static ngx_path_init_t ngx_http_proxy_temp_path = {
625 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
629 static ngx_int_t
630 ngx_http_proxy_handler(ngx_http_request_t *r)
632 ngx_int_t rc;
633 ngx_http_upstream_t *u;
634 ngx_http_proxy_ctx_t *ctx;
635 ngx_http_proxy_loc_conf_t *plcf;
637 if (ngx_http_upstream_create(r) != NGX_OK) {
638 return NGX_HTTP_INTERNAL_SERVER_ERROR;
641 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
642 if (ctx == NULL) {
643 return NGX_ERROR;
646 ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
648 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
650 u = r->upstream;
652 if (plcf->proxy_lengths == NULL) {
653 ctx->vars = plcf->vars;
654 u->schema = plcf->vars.schema;
655 #if (NGX_HTTP_SSL)
656 u->ssl = (plcf->upstream.ssl != NULL);
657 #endif
659 } else {
660 if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
661 return NGX_HTTP_INTERNAL_SERVER_ERROR;
665 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
667 u->conf = &plcf->upstream;
669 #if (NGX_HTTP_CACHE)
670 u->create_key = ngx_http_proxy_create_key;
671 #endif
672 u->create_request = ngx_http_proxy_create_request;
673 u->reinit_request = ngx_http_proxy_reinit_request;
674 u->process_header = ngx_http_proxy_process_status_line;
675 u->abort_request = ngx_http_proxy_abort_request;
676 u->finalize_request = ngx_http_proxy_finalize_request;
677 r->state = 0;
679 if (plcf->redirects) {
680 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
683 if (plcf->cookie_domains || plcf->cookie_paths) {
684 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
687 u->buffering = plcf->upstream.buffering;
689 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
690 if (u->pipe == NULL) {
691 return NGX_HTTP_INTERNAL_SERVER_ERROR;
694 u->pipe->input_filter = ngx_http_proxy_copy_filter;
695 u->pipe->input_ctx = r;
697 u->input_filter_init = ngx_http_proxy_input_filter_init;
698 u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
699 u->input_filter_ctx = r;
701 u->accel = 1;
703 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
705 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
706 return rc;
709 return NGX_DONE;
713 static ngx_int_t
714 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
715 ngx_http_proxy_loc_conf_t *plcf)
717 u_char *p;
718 size_t add;
719 u_short port;
720 ngx_str_t proxy;
721 ngx_url_t url;
722 ngx_http_upstream_t *u;
724 if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
725 plcf->proxy_values->elts)
726 == NULL)
728 return NGX_ERROR;
731 if (proxy.len > 7
732 && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
734 add = 7;
735 port = 80;
737 #if (NGX_HTTP_SSL)
739 } else if (proxy.len > 8
740 && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
742 add = 8;
743 port = 443;
744 r->upstream->ssl = 1;
746 #endif
748 } else {
749 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
750 "invalid URL prefix in \"%V\"", &proxy);
751 return NGX_ERROR;
754 u = r->upstream;
756 u->schema.len = add;
757 u->schema.data = proxy.data;
759 ngx_memzero(&url, sizeof(ngx_url_t));
761 url.url.len = proxy.len - add;
762 url.url.data = proxy.data + add;
763 url.default_port = port;
764 url.uri_part = 1;
765 url.no_resolve = 1;
767 if (ngx_parse_url(r->pool, &url) != NGX_OK) {
768 if (url.err) {
769 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
770 "%s in upstream \"%V\"", url.err, &url.url);
773 return NGX_ERROR;
776 if (url.uri.len) {
777 if (url.uri.data[0] == '?') {
778 p = ngx_pnalloc(r->pool, url.uri.len + 1);
779 if (p == NULL) {
780 return NGX_ERROR;
783 *p++ = '/';
784 ngx_memcpy(p, url.uri.data, url.uri.len);
786 url.uri.len++;
787 url.uri.data = p - 1;
791 ctx->vars.key_start = u->schema;
793 ngx_http_proxy_set_vars(&url, &ctx->vars);
795 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
796 if (u->resolved == NULL) {
797 return NGX_ERROR;
800 if (url.addrs && url.addrs[0].sockaddr) {
801 u->resolved->sockaddr = url.addrs[0].sockaddr;
802 u->resolved->socklen = url.addrs[0].socklen;
803 u->resolved->naddrs = 1;
804 u->resolved->host = url.addrs[0].name;
806 } else {
807 u->resolved->host = url.host;
808 u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
809 u->resolved->no_port = url.no_port;
812 return NGX_OK;
816 #if (NGX_HTTP_CACHE)
818 static ngx_int_t
819 ngx_http_proxy_create_key(ngx_http_request_t *r)
821 size_t len, loc_len;
822 u_char *p;
823 uintptr_t escape;
824 ngx_str_t *key;
825 ngx_http_upstream_t *u;
826 ngx_http_proxy_ctx_t *ctx;
827 ngx_http_proxy_loc_conf_t *plcf;
829 u = r->upstream;
831 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
833 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
835 key = ngx_array_push(&r->cache->keys);
836 if (key == NULL) {
837 return NGX_ERROR;
840 if (plcf->cache_key.value.data) {
842 if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
843 return NGX_ERROR;
846 return NGX_OK;
849 *key = ctx->vars.key_start;
851 key = ngx_array_push(&r->cache->keys);
852 if (key == NULL) {
853 return NGX_ERROR;
856 if (plcf->proxy_lengths && ctx->vars.uri.len) {
858 *key = ctx->vars.uri;
859 u->uri = ctx->vars.uri;
861 return NGX_OK;
863 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
865 *key = r->unparsed_uri;
866 u->uri = r->unparsed_uri;
868 return NGX_OK;
871 loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
873 if (r->quoted_uri || r->internal) {
874 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
875 r->uri.len - loc_len, NGX_ESCAPE_URI);
876 } else {
877 escape = 0;
880 len = ctx->vars.uri.len + r->uri.len - loc_len + escape
881 + sizeof("?") - 1 + r->args.len;
883 p = ngx_pnalloc(r->pool, len);
884 if (p == NULL) {
885 return NGX_ERROR;
888 key->data = p;
890 if (r->valid_location) {
891 p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
894 if (escape) {
895 ngx_escape_uri(p, r->uri.data + loc_len,
896 r->uri.len - loc_len, NGX_ESCAPE_URI);
897 p += r->uri.len - loc_len + escape;
899 } else {
900 p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
903 if (r->args.len > 0) {
904 *p++ = '?';
905 p = ngx_copy(p, r->args.data, r->args.len);
908 key->len = p - key->data;
909 u->uri = *key;
911 return NGX_OK;
914 #endif
917 static ngx_int_t
918 ngx_http_proxy_create_request(ngx_http_request_t *r)
920 size_t len, uri_len, loc_len, body_len;
921 uintptr_t escape;
922 ngx_buf_t *b;
923 ngx_str_t method;
924 ngx_uint_t i, unparsed_uri;
925 ngx_chain_t *cl, *body;
926 ngx_list_part_t *part;
927 ngx_table_elt_t *header;
928 ngx_http_upstream_t *u;
929 ngx_http_proxy_ctx_t *ctx;
930 ngx_http_script_code_pt code;
931 ngx_http_script_engine_t e, le;
932 ngx_http_proxy_loc_conf_t *plcf;
933 ngx_http_script_len_code_pt lcode;
935 u = r->upstream;
937 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
939 if (u->method.len) {
940 /* HEAD was changed to GET to cache response */
941 method = u->method;
942 method.len++;
944 } else if (plcf->method.len) {
945 method = plcf->method;
947 } else {
948 method = r->method_name;
949 method.len++;
952 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
954 if (method.len == 5
955 && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
957 ctx->head = 1;
960 len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
962 escape = 0;
963 loc_len = 0;
964 unparsed_uri = 0;
966 if (plcf->proxy_lengths && ctx->vars.uri.len) {
967 uri_len = ctx->vars.uri.len;
969 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
971 unparsed_uri = 1;
972 uri_len = r->unparsed_uri.len;
974 } else {
975 loc_len = (r->valid_location && ctx->vars.uri.len) ?
976 plcf->location.len : 0;
978 if (r->quoted_uri || r->space_in_uri || r->internal) {
979 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
980 r->uri.len - loc_len, NGX_ESCAPE_URI);
983 uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
984 + sizeof("?") - 1 + r->args.len;
987 if (uri_len == 0) {
988 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
989 "zero length URI to proxy");
990 return NGX_ERROR;
993 len += uri_len;
995 ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
997 if (plcf->body_set_len) {
998 le.ip = plcf->body_set_len->elts;
999 le.request = r;
1000 le.flushed = 1;
1001 body_len = 0;
1003 while (*(uintptr_t *) le.ip) {
1004 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1005 body_len += lcode(&le);
1008 ctx->internal_body_length = body_len;
1009 len += body_len;
1011 } else {
1012 ctx->internal_body_length = r->headers_in.content_length_n;
1015 le.ip = plcf->headers_set_len->elts;
1016 le.request = r;
1017 le.flushed = 1;
1019 while (*(uintptr_t *) le.ip) {
1020 while (*(uintptr_t *) le.ip) {
1021 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1022 len += lcode(&le);
1024 le.ip += sizeof(uintptr_t);
1028 if (plcf->upstream.pass_request_headers) {
1029 part = &r->headers_in.headers.part;
1030 header = part->elts;
1032 for (i = 0; /* void */; i++) {
1034 if (i >= part->nelts) {
1035 if (part->next == NULL) {
1036 break;
1039 part = part->next;
1040 header = part->elts;
1041 i = 0;
1044 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1045 header[i].lowcase_key, header[i].key.len))
1047 continue;
1050 len += header[i].key.len + sizeof(": ") - 1
1051 + header[i].value.len + sizeof(CRLF) - 1;
1056 b = ngx_create_temp_buf(r->pool, len);
1057 if (b == NULL) {
1058 return NGX_ERROR;
1061 cl = ngx_alloc_chain_link(r->pool);
1062 if (cl == NULL) {
1063 return NGX_ERROR;
1066 cl->buf = b;
1069 /* the request line */
1071 b->last = ngx_copy(b->last, method.data, method.len);
1073 u->uri.data = b->last;
1075 if (plcf->proxy_lengths && ctx->vars.uri.len) {
1076 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1078 } else if (unparsed_uri) {
1079 b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1081 } else {
1082 if (r->valid_location) {
1083 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1086 if (escape) {
1087 ngx_escape_uri(b->last, r->uri.data + loc_len,
1088 r->uri.len - loc_len, NGX_ESCAPE_URI);
1089 b->last += r->uri.len - loc_len + escape;
1091 } else {
1092 b->last = ngx_copy(b->last, r->uri.data + loc_len,
1093 r->uri.len - loc_len);
1096 if (r->args.len > 0) {
1097 *b->last++ = '?';
1098 b->last = ngx_copy(b->last, r->args.data, r->args.len);
1102 u->uri.len = b->last - u->uri.data;
1104 if (plcf->http_version == NGX_HTTP_VERSION_11) {
1105 b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1106 sizeof(ngx_http_proxy_version_11) - 1);
1108 } else {
1109 b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1110 sizeof(ngx_http_proxy_version) - 1);
1113 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1115 e.ip = plcf->headers_set->elts;
1116 e.pos = b->last;
1117 e.request = r;
1118 e.flushed = 1;
1120 le.ip = plcf->headers_set_len->elts;
1122 while (*(uintptr_t *) le.ip) {
1123 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1125 /* skip the header line name length */
1126 (void) lcode(&le);
1128 if (*(ngx_http_script_len_code_pt *) le.ip) {
1130 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1131 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1134 e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1136 } else {
1137 e.skip = 0;
1140 le.ip += sizeof(uintptr_t);
1142 while (*(uintptr_t *) e.ip) {
1143 code = *(ngx_http_script_code_pt *) e.ip;
1144 code((ngx_http_script_engine_t *) &e);
1146 e.ip += sizeof(uintptr_t);
1149 b->last = e.pos;
1152 if (plcf->upstream.pass_request_headers) {
1153 part = &r->headers_in.headers.part;
1154 header = part->elts;
1156 for (i = 0; /* void */; i++) {
1158 if (i >= part->nelts) {
1159 if (part->next == NULL) {
1160 break;
1163 part = part->next;
1164 header = part->elts;
1165 i = 0;
1168 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1169 header[i].lowcase_key, header[i].key.len))
1171 continue;
1174 b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1176 *b->last++ = ':'; *b->last++ = ' ';
1178 b->last = ngx_copy(b->last, header[i].value.data,
1179 header[i].value.len);
1181 *b->last++ = CR; *b->last++ = LF;
1183 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1184 "http proxy header: \"%V: %V\"",
1185 &header[i].key, &header[i].value);
1190 /* add "\r\n" at the header end */
1191 *b->last++ = CR; *b->last++ = LF;
1193 if (plcf->body_set) {
1194 e.ip = plcf->body_set->elts;
1195 e.pos = b->last;
1197 while (*(uintptr_t *) e.ip) {
1198 code = *(ngx_http_script_code_pt *) e.ip;
1199 code((ngx_http_script_engine_t *) &e);
1202 b->last = e.pos;
1205 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1206 "http proxy header:\n\"%*s\"",
1207 (size_t) (b->last - b->pos), b->pos);
1209 if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
1211 body = u->request_bufs;
1212 u->request_bufs = cl;
1214 while (body) {
1215 b = ngx_alloc_buf(r->pool);
1216 if (b == NULL) {
1217 return NGX_ERROR;
1220 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1222 cl->next = ngx_alloc_chain_link(r->pool);
1223 if (cl->next == NULL) {
1224 return NGX_ERROR;
1227 cl = cl->next;
1228 cl->buf = b;
1230 body = body->next;
1233 } else {
1234 u->request_bufs = cl;
1237 b->flush = 1;
1238 cl->next = NULL;
1240 return NGX_OK;
1244 static ngx_int_t
1245 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1247 ngx_http_proxy_ctx_t *ctx;
1249 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1251 if (ctx == NULL) {
1252 return NGX_OK;
1255 ctx->status.code = 0;
1256 ctx->status.count = 0;
1257 ctx->status.start = NULL;
1258 ctx->status.end = NULL;
1259 ctx->chunked.state = 0;
1261 r->upstream->process_header = ngx_http_proxy_process_status_line;
1262 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1263 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1264 r->state = 0;
1266 return NGX_OK;
1270 static ngx_int_t
1271 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1273 size_t len;
1274 ngx_int_t rc;
1275 ngx_http_upstream_t *u;
1276 ngx_http_proxy_ctx_t *ctx;
1278 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1280 if (ctx == NULL) {
1281 return NGX_ERROR;
1284 u = r->upstream;
1286 rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1288 if (rc == NGX_AGAIN) {
1289 return rc;
1292 if (rc == NGX_ERROR) {
1294 #if (NGX_HTTP_CACHE)
1296 if (r->cache) {
1297 r->http_version = NGX_HTTP_VERSION_9;
1298 return NGX_OK;
1301 #endif
1303 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1304 "upstream sent no valid HTTP/1.0 header");
1306 #if 0
1307 if (u->accel) {
1308 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1310 #endif
1312 r->http_version = NGX_HTTP_VERSION_9;
1313 u->state->status = NGX_HTTP_OK;
1314 u->headers_in.connection_close = 1;
1316 return NGX_OK;
1319 if (u->state) {
1320 u->state->status = ctx->status.code;
1323 u->headers_in.status_n = ctx->status.code;
1325 len = ctx->status.end - ctx->status.start;
1326 u->headers_in.status_line.len = len;
1328 u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1329 if (u->headers_in.status_line.data == NULL) {
1330 return NGX_ERROR;
1333 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1335 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1336 "http proxy status %ui \"%V\"",
1337 u->headers_in.status_n, &u->headers_in.status_line);
1339 if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1340 u->headers_in.connection_close = 1;
1343 u->process_header = ngx_http_proxy_process_header;
1345 return ngx_http_proxy_process_header(r);
1349 static ngx_int_t
1350 ngx_http_proxy_process_header(ngx_http_request_t *r)
1352 ngx_int_t rc;
1353 ngx_table_elt_t *h;
1354 ngx_http_upstream_t *u;
1355 ngx_http_proxy_ctx_t *ctx;
1356 ngx_http_upstream_header_t *hh;
1357 ngx_http_upstream_main_conf_t *umcf;
1359 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1361 for ( ;; ) {
1363 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1365 if (rc == NGX_OK) {
1367 /* a header line has been parsed successfully */
1369 h = ngx_list_push(&r->upstream->headers_in.headers);
1370 if (h == NULL) {
1371 return NGX_ERROR;
1374 h->hash = r->header_hash;
1376 h->key.len = r->header_name_end - r->header_name_start;
1377 h->value.len = r->header_end - r->header_start;
1379 h->key.data = ngx_pnalloc(r->pool,
1380 h->key.len + 1 + h->value.len + 1 + h->key.len);
1381 if (h->key.data == NULL) {
1382 return NGX_ERROR;
1385 h->value.data = h->key.data + h->key.len + 1;
1386 h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1388 ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1389 h->key.data[h->key.len] = '\0';
1390 ngx_memcpy(h->value.data, r->header_start, h->value.len);
1391 h->value.data[h->value.len] = '\0';
1393 if (h->key.len == r->lowcase_index) {
1394 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1396 } else {
1397 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1400 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1401 h->lowcase_key, h->key.len);
1403 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1404 return NGX_ERROR;
1407 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1408 "http proxy header: \"%V: %V\"",
1409 &h->key, &h->value);
1411 continue;
1414 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1416 /* a whole header has been parsed successfully */
1418 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1419 "http proxy header done");
1422 * if no "Server" and "Date" in header line,
1423 * then add the special empty headers
1426 if (r->upstream->headers_in.server == NULL) {
1427 h = ngx_list_push(&r->upstream->headers_in.headers);
1428 if (h == NULL) {
1429 return NGX_ERROR;
1432 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1433 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1435 ngx_str_set(&h->key, "Server");
1436 ngx_str_null(&h->value);
1437 h->lowcase_key = (u_char *) "server";
1440 if (r->upstream->headers_in.date == NULL) {
1441 h = ngx_list_push(&r->upstream->headers_in.headers);
1442 if (h == NULL) {
1443 return NGX_ERROR;
1446 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1448 ngx_str_set(&h->key, "Date");
1449 ngx_str_null(&h->value);
1450 h->lowcase_key = (u_char *) "date";
1453 /* clear content length if response is chunked */
1455 u = r->upstream;
1457 if (u->headers_in.chunked) {
1458 u->headers_in.content_length_n = -1;
1462 * set u->keepalive if response has no body; this allows to keep
1463 * connections alive in case of r->header_only or X-Accel-Redirect
1466 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1468 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1469 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1470 || ctx->head
1471 || (!u->headers_in.chunked
1472 && u->headers_in.content_length_n == 0))
1474 u->keepalive = !u->headers_in.connection_close;
1477 if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1478 u->keepalive = 0;
1480 if (r->headers_in.upgrade) {
1481 u->upgrade = 1;
1485 return NGX_OK;
1488 if (rc == NGX_AGAIN) {
1489 return NGX_AGAIN;
1492 /* there was error while a header line parsing */
1494 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1495 "upstream sent invalid header");
1497 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1502 static ngx_int_t
1503 ngx_http_proxy_input_filter_init(void *data)
1505 ngx_http_request_t *r = data;
1506 ngx_http_upstream_t *u;
1507 ngx_http_proxy_ctx_t *ctx;
1509 u = r->upstream;
1510 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1512 if (ctx == NULL) {
1513 return NGX_ERROR;
1516 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1517 "http proxy filter init s:%d h:%d c:%d l:%O",
1518 u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1519 u->headers_in.content_length_n);
1521 /* as per RFC2616, 4.4 Message Length */
1523 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1524 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1525 || ctx->head)
1527 /* 1xx, 204, and 304 and replies to HEAD requests */
1528 /* no 1xx since we don't send Expect and Upgrade */
1530 u->pipe->length = 0;
1531 u->length = 0;
1532 u->keepalive = !u->headers_in.connection_close;
1534 } else if (u->headers_in.chunked) {
1535 /* chunked */
1537 u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1538 u->pipe->length = 3; /* "0" LF LF */
1540 u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1541 u->length = -1;
1543 } else if (u->headers_in.content_length_n == 0) {
1544 /* empty body: special case as filter won't be called */
1546 u->pipe->length = 0;
1547 u->length = 0;
1548 u->keepalive = !u->headers_in.connection_close;
1550 } else {
1551 /* content length or connection close */
1553 u->pipe->length = u->headers_in.content_length_n;
1554 u->length = u->headers_in.content_length_n;
1557 return NGX_OK;
1561 static ngx_int_t
1562 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1564 ngx_buf_t *b;
1565 ngx_chain_t *cl;
1566 ngx_http_request_t *r;
1568 if (buf->pos == buf->last) {
1569 return NGX_OK;
1572 if (p->free) {
1573 cl = p->free;
1574 b = cl->buf;
1575 p->free = cl->next;
1576 ngx_free_chain(p->pool, cl);
1578 } else {
1579 b = ngx_alloc_buf(p->pool);
1580 if (b == NULL) {
1581 return NGX_ERROR;
1585 ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1586 b->shadow = buf;
1587 b->tag = p->tag;
1588 b->last_shadow = 1;
1589 b->recycled = 1;
1590 buf->shadow = b;
1592 cl = ngx_alloc_chain_link(p->pool);
1593 if (cl == NULL) {
1594 return NGX_ERROR;
1597 cl->buf = b;
1598 cl->next = NULL;
1600 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1602 if (p->in) {
1603 *p->last_in = cl;
1604 } else {
1605 p->in = cl;
1607 p->last_in = &cl->next;
1609 if (p->length == -1) {
1610 return NGX_OK;
1613 p->length -= b->last - b->pos;
1615 if (p->length == 0) {
1616 r = p->input_ctx;
1617 p->upstream_done = 1;
1618 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1620 } else if (p->length < 0) {
1621 r = p->input_ctx;
1622 p->upstream_done = 1;
1624 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
1625 "upstream sent more data than specified in "
1626 "\"Content-Length\" header");
1629 return NGX_OK;
1633 static ngx_int_t
1634 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1636 ngx_int_t rc;
1637 ngx_buf_t *b, **prev;
1638 ngx_chain_t *cl;
1639 ngx_http_request_t *r;
1640 ngx_http_proxy_ctx_t *ctx;
1642 if (buf->pos == buf->last) {
1643 return NGX_OK;
1646 r = p->input_ctx;
1647 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1649 if (ctx == NULL) {
1650 return NGX_ERROR;
1653 b = NULL;
1654 prev = &buf->shadow;
1656 for ( ;; ) {
1658 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1660 if (rc == NGX_OK) {
1662 /* a chunk has been parsed successfully */
1664 if (p->free) {
1665 cl = p->free;
1666 b = cl->buf;
1667 p->free = cl->next;
1668 ngx_free_chain(p->pool, cl);
1670 } else {
1671 b = ngx_alloc_buf(p->pool);
1672 if (b == NULL) {
1673 return NGX_ERROR;
1677 ngx_memzero(b, sizeof(ngx_buf_t));
1679 b->pos = buf->pos;
1680 b->start = buf->start;
1681 b->end = buf->end;
1682 b->tag = p->tag;
1683 b->temporary = 1;
1684 b->recycled = 1;
1686 *prev = b;
1687 prev = &b->shadow;
1689 cl = ngx_alloc_chain_link(p->pool);
1690 if (cl == NULL) {
1691 return NGX_ERROR;
1694 cl->buf = b;
1695 cl->next = NULL;
1697 if (p->in) {
1698 *p->last_in = cl;
1699 } else {
1700 p->in = cl;
1702 p->last_in = &cl->next;
1704 /* STUB */ b->num = buf->num;
1706 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1707 "input buf #%d %p", b->num, b->pos);
1709 if (buf->last - buf->pos >= ctx->chunked.size) {
1711 buf->pos += ctx->chunked.size;
1712 b->last = buf->pos;
1713 ctx->chunked.size = 0;
1715 continue;
1718 ctx->chunked.size -= buf->last - buf->pos;
1719 buf->pos = buf->last;
1720 b->last = buf->last;
1722 continue;
1725 if (rc == NGX_DONE) {
1727 /* a whole response has been parsed successfully */
1729 p->upstream_done = 1;
1730 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1732 break;
1735 if (rc == NGX_AGAIN) {
1737 /* set p->length, minimal amount of data we want to see */
1739 p->length = ctx->chunked.length;
1741 break;
1744 /* invalid response */
1746 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1747 "upstream sent invalid chunked response");
1749 return NGX_ERROR;
1752 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1753 "http proxy chunked state %d, length %d",
1754 ctx->chunked.state, p->length);
1756 if (b) {
1757 b->shadow = buf;
1758 b->last_shadow = 1;
1760 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1761 "input buf %p %z", b->pos, b->last - b->pos);
1763 return NGX_OK;
1766 /* there is no data record in the buf, add it to free chain */
1768 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1769 return NGX_ERROR;
1772 return NGX_OK;
1776 static ngx_int_t
1777 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
1779 ngx_http_request_t *r = data;
1781 ngx_buf_t *b;
1782 ngx_chain_t *cl, **ll;
1783 ngx_http_upstream_t *u;
1785 u = r->upstream;
1787 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1788 ll = &cl->next;
1791 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1792 if (cl == NULL) {
1793 return NGX_ERROR;
1796 *ll = cl;
1798 cl->buf->flush = 1;
1799 cl->buf->memory = 1;
1801 b = &u->buffer;
1803 cl->buf->pos = b->last;
1804 b->last += bytes;
1805 cl->buf->last = b->last;
1806 cl->buf->tag = u->output.tag;
1808 if (u->length == -1) {
1809 return NGX_OK;
1812 u->length -= bytes;
1814 if (u->length == 0) {
1815 u->keepalive = !u->headers_in.connection_close;
1818 return NGX_OK;
1822 static ngx_int_t
1823 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
1825 ngx_http_request_t *r = data;
1827 ngx_int_t rc;
1828 ngx_buf_t *b, *buf;
1829 ngx_chain_t *cl, **ll;
1830 ngx_http_upstream_t *u;
1831 ngx_http_proxy_ctx_t *ctx;
1833 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1835 if (ctx == NULL) {
1836 return NGX_ERROR;
1839 u = r->upstream;
1840 buf = &u->buffer;
1842 buf->pos = buf->last;
1843 buf->last += bytes;
1845 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1846 ll = &cl->next;
1849 for ( ;; ) {
1851 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1853 if (rc == NGX_OK) {
1855 /* a chunk has been parsed successfully */
1857 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1858 if (cl == NULL) {
1859 return NGX_ERROR;
1862 *ll = cl;
1863 ll = &cl->next;
1865 b = cl->buf;
1867 b->flush = 1;
1868 b->memory = 1;
1870 b->pos = buf->pos;
1871 b->tag = u->output.tag;
1873 if (buf->last - buf->pos >= ctx->chunked.size) {
1874 buf->pos += ctx->chunked.size;
1875 b->last = buf->pos;
1876 ctx->chunked.size = 0;
1878 } else {
1879 ctx->chunked.size -= buf->last - buf->pos;
1880 buf->pos = buf->last;
1881 b->last = buf->last;
1884 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1885 "http proxy out buf %p %z",
1886 b->pos, b->last - b->pos);
1888 continue;
1891 if (rc == NGX_DONE) {
1893 /* a whole response has been parsed successfully */
1895 u->keepalive = !u->headers_in.connection_close;
1896 u->length = 0;
1898 break;
1901 if (rc == NGX_AGAIN) {
1902 break;
1905 /* invalid response */
1907 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1908 "upstream sent invalid chunked response");
1910 return NGX_ERROR;
1913 /* provide continuous buffer for subrequests in memory */
1915 if (r->subrequest_in_memory) {
1917 cl = u->out_bufs;
1919 if (cl) {
1920 buf->pos = cl->buf->pos;
1923 buf->last = buf->pos;
1925 for (cl = u->out_bufs; cl; cl = cl->next) {
1926 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1927 "http proxy in memory %p-%p %uz",
1928 cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
1930 if (buf->last == cl->buf->pos) {
1931 buf->last = cl->buf->last;
1932 continue;
1935 buf->last = ngx_movemem(buf->last, cl->buf->pos,
1936 cl->buf->last - cl->buf->pos);
1938 cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
1939 cl->buf->last = buf->last;
1943 return NGX_OK;
1947 static void
1948 ngx_http_proxy_abort_request(ngx_http_request_t *r)
1950 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1951 "abort http proxy request");
1953 return;
1957 static void
1958 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1960 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1961 "finalize http proxy request");
1963 return;
1967 static ngx_int_t
1968 ngx_http_proxy_host_variable(ngx_http_request_t *r,
1969 ngx_http_variable_value_t *v, uintptr_t data)
1971 ngx_http_proxy_ctx_t *ctx;
1973 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1975 if (ctx == NULL) {
1976 v->not_found = 1;
1977 return NGX_OK;
1980 v->len = ctx->vars.host_header.len;
1981 v->valid = 1;
1982 v->no_cacheable = 0;
1983 v->not_found = 0;
1984 v->data = ctx->vars.host_header.data;
1986 return NGX_OK;
1990 static ngx_int_t
1991 ngx_http_proxy_port_variable(ngx_http_request_t *r,
1992 ngx_http_variable_value_t *v, uintptr_t data)
1994 ngx_http_proxy_ctx_t *ctx;
1996 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1998 if (ctx == NULL) {
1999 v->not_found = 1;
2000 return NGX_OK;
2003 v->len = ctx->vars.port.len;
2004 v->valid = 1;
2005 v->no_cacheable = 0;
2006 v->not_found = 0;
2007 v->data = ctx->vars.port.data;
2009 return NGX_OK;
2013 static ngx_int_t
2014 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2015 ngx_http_variable_value_t *v, uintptr_t data)
2017 size_t len;
2018 u_char *p;
2019 ngx_uint_t i, n;
2020 ngx_table_elt_t **h;
2022 v->valid = 1;
2023 v->no_cacheable = 0;
2024 v->not_found = 0;
2026 n = r->headers_in.x_forwarded_for.nelts;
2027 h = r->headers_in.x_forwarded_for.elts;
2029 len = 0;
2031 for (i = 0; i < n; i++) {
2032 len += h[i]->value.len + sizeof(", ") - 1;
2035 if (len == 0) {
2036 v->len = r->connection->addr_text.len;
2037 v->data = r->connection->addr_text.data;
2038 return NGX_OK;
2041 len += r->connection->addr_text.len;
2043 p = ngx_pnalloc(r->pool, len);
2044 if (p == NULL) {
2045 return NGX_ERROR;
2048 v->len = len;
2049 v->data = p;
2051 for (i = 0; i < n; i++) {
2052 p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2053 *p++ = ','; *p++ = ' ';
2056 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2058 return NGX_OK;
2062 static ngx_int_t
2063 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2064 ngx_http_variable_value_t *v, uintptr_t data)
2066 ngx_http_proxy_ctx_t *ctx;
2068 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2070 if (ctx == NULL || ctx->internal_body_length < 0) {
2071 v->not_found = 1;
2072 return NGX_OK;
2075 v->valid = 1;
2076 v->no_cacheable = 0;
2077 v->not_found = 0;
2079 v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
2081 if (v->data == NULL) {
2082 return NGX_ERROR;
2085 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2087 return NGX_OK;
2091 static ngx_int_t
2092 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2093 size_t prefix)
2095 size_t len;
2096 ngx_int_t rc;
2097 ngx_uint_t i;
2098 ngx_http_proxy_rewrite_t *pr;
2099 ngx_http_proxy_loc_conf_t *plcf;
2101 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2103 pr = plcf->redirects->elts;
2105 if (pr == NULL) {
2106 return NGX_DECLINED;
2109 len = h->value.len - prefix;
2111 for (i = 0; i < plcf->redirects->nelts; i++) {
2112 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2114 if (rc != NGX_DECLINED) {
2115 return rc;
2119 return NGX_DECLINED;
2123 static ngx_int_t
2124 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2126 size_t prefix;
2127 u_char *p;
2128 ngx_int_t rc, rv;
2129 ngx_http_proxy_loc_conf_t *plcf;
2131 p = (u_char *) ngx_strchr(h->value.data, ';');
2132 if (p == NULL) {
2133 return NGX_DECLINED;
2136 prefix = p + 1 - h->value.data;
2138 rv = NGX_DECLINED;
2140 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2142 if (plcf->cookie_domains) {
2143 p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2145 if (p) {
2146 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2147 plcf->cookie_domains);
2148 if (rc == NGX_ERROR) {
2149 return NGX_ERROR;
2152 if (rc != NGX_DECLINED) {
2153 rv = rc;
2158 if (plcf->cookie_paths) {
2159 p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2161 if (p) {
2162 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2163 plcf->cookie_paths);
2164 if (rc == NGX_ERROR) {
2165 return NGX_ERROR;
2168 if (rc != NGX_DECLINED) {
2169 rv = rc;
2174 return rv;
2178 static ngx_int_t
2179 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2180 u_char *value, ngx_array_t *rewrites)
2182 size_t len, prefix;
2183 u_char *p;
2184 ngx_int_t rc;
2185 ngx_uint_t i;
2186 ngx_http_proxy_rewrite_t *pr;
2188 prefix = value - h->value.data;
2190 p = (u_char *) ngx_strchr(value, ';');
2192 len = p ? (size_t) (p - value) : (h->value.len - prefix);
2194 pr = rewrites->elts;
2196 for (i = 0; i < rewrites->nelts; i++) {
2197 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2199 if (rc != NGX_DECLINED) {
2200 return rc;
2204 return NGX_DECLINED;
2208 static ngx_int_t
2209 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2210 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2212 ngx_str_t pattern, replacement;
2214 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2215 return NGX_ERROR;
2218 if (pattern.len > len
2219 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2220 pattern.len) != 0)
2222 return NGX_DECLINED;
2225 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2226 return NGX_ERROR;
2229 return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2233 #if (NGX_PCRE)
2235 static ngx_int_t
2236 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2237 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2239 ngx_str_t pattern, replacement;
2241 pattern.len = len;
2242 pattern.data = h->value.data + prefix;
2244 if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2245 return NGX_DECLINED;
2248 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2249 return NGX_ERROR;
2252 if (prefix == 0 && h->value.len == len) {
2253 h->value = replacement;
2254 return NGX_OK;
2257 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2260 #endif
2263 static ngx_int_t
2264 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2265 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2267 u_char *p;
2268 ngx_str_t pattern, replacement;
2270 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2271 return NGX_ERROR;
2274 p = h->value.data + prefix;
2276 if (p[0] == '.') {
2277 p++;
2278 prefix++;
2279 len--;
2282 if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2283 return NGX_DECLINED;
2286 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2287 return NGX_ERROR;
2290 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2294 static ngx_int_t
2295 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2296 size_t len, ngx_str_t *replacement)
2298 u_char *p, *data;
2299 size_t new_len;
2301 new_len = replacement->len + h->value.len - len;
2303 if (replacement->len > len) {
2305 data = ngx_pnalloc(r->pool, new_len);
2306 if (data == NULL) {
2307 return NGX_ERROR;
2310 p = ngx_copy(data, h->value.data, prefix);
2311 p = ngx_copy(p, replacement->data, replacement->len);
2313 ngx_memcpy(p, h->value.data + prefix + len,
2314 h->value.len - len - prefix);
2316 h->value.data = data;
2318 } else {
2319 p = ngx_copy(h->value.data + prefix, replacement->data,
2320 replacement->len);
2322 ngx_memmove(p, h->value.data + prefix + len,
2323 h->value.len - len - prefix);
2326 h->value.len = new_len;
2328 return NGX_OK;
2332 static ngx_int_t
2333 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2335 ngx_http_variable_t *var, *v;
2337 for (v = ngx_http_proxy_vars; v->name.len; v++) {
2338 var = ngx_http_add_variable(cf, &v->name, v->flags);
2339 if (var == NULL) {
2340 return NGX_ERROR;
2343 var->get_handler = v->get_handler;
2344 var->data = v->data;
2347 return NGX_OK;
2351 static void *
2352 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2354 ngx_http_proxy_loc_conf_t *conf;
2356 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2357 if (conf == NULL) {
2358 return NULL;
2362 * set by ngx_pcalloc():
2364 * conf->upstream.bufs.num = 0;
2365 * conf->upstream.ignore_headers = 0;
2366 * conf->upstream.next_upstream = 0;
2367 * conf->upstream.cache_use_stale = 0;
2368 * conf->upstream.cache_methods = 0;
2369 * conf->upstream.temp_path = NULL;
2370 * conf->upstream.hide_headers_hash = { NULL, 0 };
2371 * conf->upstream.uri = { 0, NULL };
2372 * conf->upstream.location = NULL;
2373 * conf->upstream.store_lengths = NULL;
2374 * conf->upstream.store_values = NULL;
2376 * conf->method = { 0, NULL };
2377 * conf->headers_source = NULL;
2378 * conf->headers_set_len = NULL;
2379 * conf->headers_set = NULL;
2380 * conf->headers_set_hash = NULL;
2381 * conf->body_set_len = NULL;
2382 * conf->body_set = NULL;
2383 * conf->body_source = { 0, NULL };
2384 * conf->redirects = NULL;
2387 conf->upstream.store = NGX_CONF_UNSET;
2388 conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2389 conf->upstream.buffering = NGX_CONF_UNSET;
2390 conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2392 conf->upstream.local = NGX_CONF_UNSET_PTR;
2394 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2395 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2396 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2398 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2399 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2401 conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2402 conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2403 conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2405 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2406 conf->upstream.pass_request_body = NGX_CONF_UNSET;
2408 #if (NGX_HTTP_CACHE)
2409 conf->upstream.cache = NGX_CONF_UNSET_PTR;
2410 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2411 conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2412 conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2413 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2414 conf->upstream.cache_lock = NGX_CONF_UNSET;
2415 conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2416 #endif
2418 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2419 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2421 conf->upstream.intercept_errors = NGX_CONF_UNSET;
2422 #if (NGX_HTTP_SSL)
2423 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2424 #endif
2426 /* "proxy_cyclic_temp_file" is disabled */
2427 conf->upstream.cyclic_temp_file = 0;
2429 conf->redirect = NGX_CONF_UNSET;
2430 conf->upstream.change_buffering = 1;
2432 conf->cookie_domains = NGX_CONF_UNSET_PTR;
2433 conf->cookie_paths = NGX_CONF_UNSET_PTR;
2435 conf->http_version = NGX_CONF_UNSET_UINT;
2437 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2438 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2440 ngx_str_set(&conf->upstream.module, "proxy");
2442 return conf;
2446 static char *
2447 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2449 ngx_http_proxy_loc_conf_t *prev = parent;
2450 ngx_http_proxy_loc_conf_t *conf = child;
2452 u_char *p;
2453 size_t size;
2454 ngx_hash_init_t hash;
2455 ngx_http_core_loc_conf_t *clcf;
2456 ngx_http_proxy_rewrite_t *pr;
2457 ngx_http_script_compile_t sc;
2459 if (conf->upstream.store != 0) {
2460 ngx_conf_merge_value(conf->upstream.store,
2461 prev->upstream.store, 0);
2463 if (conf->upstream.store_lengths == NULL) {
2464 conf->upstream.store_lengths = prev->upstream.store_lengths;
2465 conf->upstream.store_values = prev->upstream.store_values;
2469 ngx_conf_merge_uint_value(conf->upstream.store_access,
2470 prev->upstream.store_access, 0600);
2472 ngx_conf_merge_value(conf->upstream.buffering,
2473 prev->upstream.buffering, 1);
2475 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2476 prev->upstream.ignore_client_abort, 0);
2478 ngx_conf_merge_ptr_value(conf->upstream.local,
2479 prev->upstream.local, NULL);
2481 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2482 prev->upstream.connect_timeout, 60000);
2484 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2485 prev->upstream.send_timeout, 60000);
2487 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2488 prev->upstream.read_timeout, 60000);
2490 ngx_conf_merge_size_value(conf->upstream.send_lowat,
2491 prev->upstream.send_lowat, 0);
2493 ngx_conf_merge_size_value(conf->upstream.buffer_size,
2494 prev->upstream.buffer_size,
2495 (size_t) ngx_pagesize);
2497 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2498 8, ngx_pagesize);
2500 if (conf->upstream.bufs.num < 2) {
2501 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2502 "there must be at least 2 \"proxy_buffers\"");
2503 return NGX_CONF_ERROR;
2507 size = conf->upstream.buffer_size;
2508 if (size < conf->upstream.bufs.size) {
2509 size = conf->upstream.bufs.size;
2513 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2514 prev->upstream.busy_buffers_size_conf,
2515 NGX_CONF_UNSET_SIZE);
2517 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2518 conf->upstream.busy_buffers_size = 2 * size;
2519 } else {
2520 conf->upstream.busy_buffers_size =
2521 conf->upstream.busy_buffers_size_conf;
2524 if (conf->upstream.busy_buffers_size < size) {
2525 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2526 "\"proxy_busy_buffers_size\" must be equal to or greater than "
2527 "the maximum of the value of \"proxy_buffer_size\" and "
2528 "one of the \"proxy_buffers\"");
2530 return NGX_CONF_ERROR;
2533 if (conf->upstream.busy_buffers_size
2534 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2536 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2537 "\"proxy_busy_buffers_size\" must be less than "
2538 "the size of all \"proxy_buffers\" minus one buffer");
2540 return NGX_CONF_ERROR;
2544 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2545 prev->upstream.temp_file_write_size_conf,
2546 NGX_CONF_UNSET_SIZE);
2548 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2549 conf->upstream.temp_file_write_size = 2 * size;
2550 } else {
2551 conf->upstream.temp_file_write_size =
2552 conf->upstream.temp_file_write_size_conf;
2555 if (conf->upstream.temp_file_write_size < size) {
2556 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2557 "\"proxy_temp_file_write_size\" must be equal to or greater "
2558 "than the maximum of the value of \"proxy_buffer_size\" and "
2559 "one of the \"proxy_buffers\"");
2561 return NGX_CONF_ERROR;
2564 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2565 prev->upstream.max_temp_file_size_conf,
2566 NGX_CONF_UNSET_SIZE);
2568 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2569 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2570 } else {
2571 conf->upstream.max_temp_file_size =
2572 conf->upstream.max_temp_file_size_conf;
2575 if (conf->upstream.max_temp_file_size != 0
2576 && conf->upstream.max_temp_file_size < size)
2578 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2579 "\"proxy_max_temp_file_size\" must be equal to zero to disable "
2580 "temporary files usage or must be equal to or greater than "
2581 "the maximum of the value of \"proxy_buffer_size\" and "
2582 "one of the \"proxy_buffers\"");
2584 return NGX_CONF_ERROR;
2588 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2589 prev->upstream.ignore_headers,
2590 NGX_CONF_BITMASK_SET);
2593 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2594 prev->upstream.next_upstream,
2595 (NGX_CONF_BITMASK_SET
2596 |NGX_HTTP_UPSTREAM_FT_ERROR
2597 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2599 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2600 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2601 |NGX_HTTP_UPSTREAM_FT_OFF;
2604 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2605 prev->upstream.temp_path,
2606 &ngx_http_proxy_temp_path)
2607 != NGX_OK)
2609 return NGX_CONF_ERROR;
2613 #if (NGX_HTTP_CACHE)
2615 ngx_conf_merge_ptr_value(conf->upstream.cache,
2616 prev->upstream.cache, NULL);
2618 if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2619 ngx_shm_zone_t *shm_zone;
2621 shm_zone = conf->upstream.cache;
2623 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2624 "\"proxy_cache\" zone \"%V\" is unknown",
2625 &shm_zone->shm.name);
2627 return NGX_CONF_ERROR;
2630 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2631 prev->upstream.cache_min_uses, 1);
2633 ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2634 prev->upstream.cache_use_stale,
2635 (NGX_CONF_BITMASK_SET
2636 |NGX_HTTP_UPSTREAM_FT_OFF));
2638 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2639 conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2640 |NGX_HTTP_UPSTREAM_FT_OFF;
2643 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2644 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2647 if (conf->upstream.cache_methods == 0) {
2648 conf->upstream.cache_methods = prev->upstream.cache_methods;
2651 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2653 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2654 prev->upstream.cache_bypass, NULL);
2656 ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2657 prev->upstream.no_cache, NULL);
2659 if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
2660 ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2661 "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
2662 "now it should be used together with \"proxy_cache_bypass\"");
2665 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2666 prev->upstream.cache_valid, NULL);
2668 if (conf->cache_key.value.data == NULL) {
2669 conf->cache_key = prev->cache_key;
2672 ngx_conf_merge_value(conf->upstream.cache_lock,
2673 prev->upstream.cache_lock, 0);
2675 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2676 prev->upstream.cache_lock_timeout, 5000);
2678 #endif
2680 ngx_conf_merge_str_value(conf->method, prev->method, "");
2682 if (conf->method.len
2683 && conf->method.data[conf->method.len - 1] != ' ')
2685 conf->method.data[conf->method.len] = ' ';
2686 conf->method.len++;
2689 ngx_conf_merge_value(conf->upstream.pass_request_headers,
2690 prev->upstream.pass_request_headers, 1);
2691 ngx_conf_merge_value(conf->upstream.pass_request_body,
2692 prev->upstream.pass_request_body, 1);
2694 ngx_conf_merge_value(conf->upstream.intercept_errors,
2695 prev->upstream.intercept_errors, 0);
2697 #if (NGX_HTTP_SSL)
2698 ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
2699 prev->upstream.ssl_session_reuse, 1);
2700 #endif
2702 ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
2704 if (conf->redirect) {
2706 if (conf->redirects == NULL) {
2707 conf->redirects = prev->redirects;
2710 if (conf->redirects == NULL && conf->url.data) {
2712 conf->redirects = ngx_array_create(cf->pool, 1,
2713 sizeof(ngx_http_proxy_rewrite_t));
2714 if (conf->redirects == NULL) {
2715 return NGX_CONF_ERROR;
2718 pr = ngx_array_push(conf->redirects);
2719 if (pr == NULL) {
2720 return NGX_CONF_ERROR;
2723 ngx_memzero(&pr->pattern.complex,
2724 sizeof(ngx_http_complex_value_t));
2726 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
2728 pr->handler = ngx_http_proxy_rewrite_complex_handler;
2730 if (conf->vars.uri.len) {
2731 pr->pattern.complex.value = conf->url;
2732 pr->replacement.value = conf->location;
2734 } else {
2735 pr->pattern.complex.value.len = conf->url.len
2736 + sizeof("/") - 1;
2738 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
2739 if (p == NULL) {
2740 return NGX_CONF_ERROR;
2743 pr->pattern.complex.value.data = p;
2745 p = ngx_cpymem(p, conf->url.data, conf->url.len);
2746 *p = '/';
2748 ngx_str_set(&pr->replacement.value, "/");
2753 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
2755 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
2757 #if (NGX_HTTP_SSL)
2758 if (conf->upstream.ssl == NULL) {
2759 conf->upstream.ssl = prev->upstream.ssl;
2761 #endif
2763 ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
2764 NGX_HTTP_VERSION_10);
2766 ngx_conf_merge_uint_value(conf->headers_hash_max_size,
2767 prev->headers_hash_max_size, 512);
2769 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
2770 prev->headers_hash_bucket_size, 64);
2772 conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
2773 ngx_cacheline_size);
2775 hash.max_size = conf->headers_hash_max_size;
2776 hash.bucket_size = conf->headers_hash_bucket_size;
2777 hash.name = "proxy_headers_hash";
2779 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
2780 &prev->upstream, ngx_http_proxy_hide_headers, &hash)
2781 != NGX_OK)
2783 return NGX_CONF_ERROR;
2786 if (conf->upstream.upstream == NULL) {
2787 conf->upstream.upstream = prev->upstream.upstream;
2788 conf->vars = prev->vars;
2791 if (conf->proxy_lengths == NULL) {
2792 conf->proxy_lengths = prev->proxy_lengths;
2793 conf->proxy_values = prev->proxy_values;
2796 if (conf->upstream.upstream || conf->proxy_lengths) {
2797 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2798 if (clcf->handler == NULL && clcf->lmt_excpt) {
2799 clcf->handler = ngx_http_proxy_handler;
2800 conf->location = prev->location;
2804 if (conf->body_source.data == NULL) {
2805 conf->body_source = prev->body_source;
2806 conf->body_set_len = prev->body_set_len;
2807 conf->body_set = prev->body_set;
2810 if (conf->body_source.data && conf->body_set_len == NULL) {
2812 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2814 sc.cf = cf;
2815 sc.source = &conf->body_source;
2816 sc.flushes = &conf->flushes;
2817 sc.lengths = &conf->body_set_len;
2818 sc.values = &conf->body_set;
2819 sc.complete_lengths = 1;
2820 sc.complete_values = 1;
2822 if (ngx_http_script_compile(&sc) != NGX_OK) {
2823 return NGX_CONF_ERROR;
2827 if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
2828 return NGX_CONF_ERROR;
2831 return NGX_CONF_OK;
2835 static ngx_int_t
2836 ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
2837 ngx_http_proxy_loc_conf_t *prev)
2839 u_char *p;
2840 size_t size;
2841 uintptr_t *code;
2842 ngx_uint_t i;
2843 ngx_array_t headers_names, headers_merged;
2844 ngx_keyval_t *src, *s, *h;
2845 ngx_hash_key_t *hk;
2846 ngx_hash_init_t hash;
2847 ngx_http_script_compile_t sc;
2848 ngx_http_script_copy_code_t *copy;
2850 if (conf->headers_source == NULL) {
2851 conf->flushes = prev->flushes;
2852 conf->headers_set_len = prev->headers_set_len;
2853 conf->headers_set = prev->headers_set;
2854 conf->headers_set_hash = prev->headers_set_hash;
2855 conf->headers_source = prev->headers_source;
2858 if (conf->headers_set_hash.buckets
2859 #if (NGX_HTTP_CACHE)
2860 && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
2861 #endif
2864 return NGX_OK;
2868 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2869 != NGX_OK)
2871 return NGX_ERROR;
2874 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
2875 != NGX_OK)
2877 return NGX_ERROR;
2880 if (conf->headers_source == NULL) {
2881 conf->headers_source = ngx_array_create(cf->pool, 4,
2882 sizeof(ngx_keyval_t));
2883 if (conf->headers_source == NULL) {
2884 return NGX_ERROR;
2888 conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
2889 if (conf->headers_set_len == NULL) {
2890 return NGX_ERROR;
2893 conf->headers_set = ngx_array_create(cf->pool, 512, 1);
2894 if (conf->headers_set == NULL) {
2895 return NGX_ERROR;
2899 #if (NGX_HTTP_CACHE)
2901 h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
2902 ngx_http_proxy_headers;
2903 #else
2905 h = ngx_http_proxy_headers;
2907 #endif
2909 src = conf->headers_source->elts;
2910 for (i = 0; i < conf->headers_source->nelts; i++) {
2912 s = ngx_array_push(&headers_merged);
2913 if (s == NULL) {
2914 return NGX_ERROR;
2917 *s = src[i];
2920 while (h->key.len) {
2922 src = headers_merged.elts;
2923 for (i = 0; i < headers_merged.nelts; i++) {
2924 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2925 goto next;
2929 s = ngx_array_push(&headers_merged);
2930 if (s == NULL) {
2931 return NGX_ERROR;
2934 *s = *h;
2936 next:
2938 h++;
2942 src = headers_merged.elts;
2943 for (i = 0; i < headers_merged.nelts; i++) {
2945 hk = ngx_array_push(&headers_names);
2946 if (hk == NULL) {
2947 return NGX_ERROR;
2950 hk->key = src[i].key;
2951 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
2952 hk->value = (void *) 1;
2954 if (src[i].value.len == 0) {
2955 continue;
2958 if (ngx_http_script_variables_count(&src[i].value) == 0) {
2959 copy = ngx_array_push_n(conf->headers_set_len,
2960 sizeof(ngx_http_script_copy_code_t));
2961 if (copy == NULL) {
2962 return NGX_ERROR;
2965 copy->code = (ngx_http_script_code_pt)
2966 ngx_http_script_copy_len_code;
2967 copy->len = src[i].key.len + sizeof(": ") - 1
2968 + src[i].value.len + sizeof(CRLF) - 1;
2971 size = (sizeof(ngx_http_script_copy_code_t)
2972 + src[i].key.len + sizeof(": ") - 1
2973 + src[i].value.len + sizeof(CRLF) - 1
2974 + sizeof(uintptr_t) - 1)
2975 & ~(sizeof(uintptr_t) - 1);
2977 copy = ngx_array_push_n(conf->headers_set, size);
2978 if (copy == NULL) {
2979 return NGX_ERROR;
2982 copy->code = ngx_http_script_copy_code;
2983 copy->len = src[i].key.len + sizeof(": ") - 1
2984 + src[i].value.len + sizeof(CRLF) - 1;
2986 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2988 p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2989 *p++ = ':'; *p++ = ' ';
2990 p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
2991 *p++ = CR; *p = LF;
2993 } else {
2994 copy = ngx_array_push_n(conf->headers_set_len,
2995 sizeof(ngx_http_script_copy_code_t));
2996 if (copy == NULL) {
2997 return NGX_ERROR;
3000 copy->code = (ngx_http_script_code_pt)
3001 ngx_http_script_copy_len_code;
3002 copy->len = src[i].key.len + sizeof(": ") - 1;
3005 size = (sizeof(ngx_http_script_copy_code_t)
3006 + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
3007 & ~(sizeof(uintptr_t) - 1);
3009 copy = ngx_array_push_n(conf->headers_set, size);
3010 if (copy == NULL) {
3011 return NGX_ERROR;
3014 copy->code = ngx_http_script_copy_code;
3015 copy->len = src[i].key.len + sizeof(": ") - 1;
3017 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3018 p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3019 *p++ = ':'; *p = ' ';
3022 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3024 sc.cf = cf;
3025 sc.source = &src[i].value;
3026 sc.flushes = &conf->flushes;
3027 sc.lengths = &conf->headers_set_len;
3028 sc.values = &conf->headers_set;
3030 if (ngx_http_script_compile(&sc) != NGX_OK) {
3031 return NGX_ERROR;
3035 copy = ngx_array_push_n(conf->headers_set_len,
3036 sizeof(ngx_http_script_copy_code_t));
3037 if (copy == NULL) {
3038 return NGX_ERROR;
3041 copy->code = (ngx_http_script_code_pt)
3042 ngx_http_script_copy_len_code;
3043 copy->len = sizeof(CRLF) - 1;
3046 size = (sizeof(ngx_http_script_copy_code_t)
3047 + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3048 & ~(sizeof(uintptr_t) - 1);
3050 copy = ngx_array_push_n(conf->headers_set, size);
3051 if (copy == NULL) {
3052 return NGX_ERROR;
3055 copy->code = ngx_http_script_copy_code;
3056 copy->len = sizeof(CRLF) - 1;
3058 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3059 *p++ = CR; *p = LF;
3062 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3063 if (code == NULL) {
3064 return NGX_ERROR;
3067 *code = (uintptr_t) NULL;
3069 code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
3070 if (code == NULL) {
3071 return NGX_ERROR;
3074 *code = (uintptr_t) NULL;
3077 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3078 if (code == NULL) {
3079 return NGX_ERROR;
3082 *code = (uintptr_t) NULL;
3085 hash.hash = &conf->headers_set_hash;
3086 hash.key = ngx_hash_key_lc;
3087 hash.max_size = conf->headers_hash_max_size;
3088 hash.bucket_size = conf->headers_hash_bucket_size;
3089 hash.name = "proxy_headers_hash";
3090 hash.pool = cf->pool;
3091 hash.temp_pool = NULL;
3093 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3097 static char *
3098 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3100 ngx_http_proxy_loc_conf_t *plcf = conf;
3102 size_t add;
3103 u_short port;
3104 ngx_str_t *value, *url;
3105 ngx_url_t u;
3106 ngx_uint_t n;
3107 ngx_http_core_loc_conf_t *clcf;
3108 ngx_http_script_compile_t sc;
3110 if (plcf->upstream.upstream || plcf->proxy_lengths) {
3111 return "is duplicate";
3114 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3116 clcf->handler = ngx_http_proxy_handler;
3118 if (clcf->name.data[clcf->name.len - 1] == '/') {
3119 clcf->auto_redirect = 1;
3122 value = cf->args->elts;
3124 url = &value[1];
3126 n = ngx_http_script_variables_count(url);
3128 if (n) {
3130 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3132 sc.cf = cf;
3133 sc.source = url;
3134 sc.lengths = &plcf->proxy_lengths;
3135 sc.values = &plcf->proxy_values;
3136 sc.variables = n;
3137 sc.complete_lengths = 1;
3138 sc.complete_values = 1;
3140 if (ngx_http_script_compile(&sc) != NGX_OK) {
3141 return NGX_CONF_ERROR;
3144 #if (NGX_HTTP_SSL)
3145 if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3146 return NGX_CONF_ERROR;
3148 #endif
3150 return NGX_CONF_OK;
3153 if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3154 add = 7;
3155 port = 80;
3157 } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3159 #if (NGX_HTTP_SSL)
3160 if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3161 return NGX_CONF_ERROR;
3164 add = 8;
3165 port = 443;
3166 #else
3167 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3168 "https protocol requires SSL support");
3169 return NGX_CONF_ERROR;
3170 #endif
3172 } else {
3173 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3174 return NGX_CONF_ERROR;
3177 ngx_memzero(&u, sizeof(ngx_url_t));
3179 u.url.len = url->len - add;
3180 u.url.data = url->data + add;
3181 u.default_port = port;
3182 u.uri_part = 1;
3183 u.no_resolve = 1;
3185 plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3186 if (plcf->upstream.upstream == NULL) {
3187 return NGX_CONF_ERROR;
3190 plcf->vars.schema.len = add;
3191 plcf->vars.schema.data = url->data;
3192 plcf->vars.key_start = plcf->vars.schema;
3194 ngx_http_proxy_set_vars(&u, &plcf->vars);
3196 plcf->location = clcf->name;
3198 if (clcf->named
3199 #if (NGX_PCRE)
3200 || clcf->regex
3201 #endif
3202 || clcf->noname)
3204 if (plcf->vars.uri.len) {
3205 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3206 "\"proxy_pass\" cannot have URI part in "
3207 "location given by regular expression, "
3208 "or inside named location, "
3209 "or inside \"if\" statement, "
3210 "or inside \"limit_except\" block");
3211 return NGX_CONF_ERROR;
3214 plcf->location.len = 0;
3217 plcf->url = *url;
3219 return NGX_CONF_OK;
3223 static char *
3224 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3226 ngx_http_proxy_loc_conf_t *plcf = conf;
3228 u_char *p;
3229 ngx_str_t *value;
3230 ngx_http_proxy_rewrite_t *pr;
3231 ngx_http_compile_complex_value_t ccv;
3233 if (plcf->redirect == 0) {
3234 return NGX_CONF_OK;
3237 plcf->redirect = 1;
3239 value = cf->args->elts;
3241 if (cf->args->nelts == 2) {
3242 if (ngx_strcmp(value[1].data, "off") == 0) {
3243 plcf->redirect = 0;
3244 plcf->redirects = NULL;
3245 return NGX_CONF_OK;
3248 if (ngx_strcmp(value[1].data, "false") == 0) {
3249 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3250 "invalid parameter \"false\", use \"off\" instead");
3251 plcf->redirect = 0;
3252 plcf->redirects = NULL;
3253 return NGX_CONF_OK;
3256 if (ngx_strcmp(value[1].data, "default") != 0) {
3257 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3258 "invalid parameter \"%V\"", &value[1]);
3259 return NGX_CONF_ERROR;
3263 if (plcf->redirects == NULL) {
3264 plcf->redirects = ngx_array_create(cf->pool, 1,
3265 sizeof(ngx_http_proxy_rewrite_t));
3266 if (plcf->redirects == NULL) {
3267 return NGX_CONF_ERROR;
3271 pr = ngx_array_push(plcf->redirects);
3272 if (pr == NULL) {
3273 return NGX_CONF_ERROR;
3276 if (ngx_strcmp(value[1].data, "default") == 0) {
3277 if (plcf->proxy_lengths) {
3278 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3279 "\"proxy_redirect default\" cannot be used "
3280 "with \"proxy_pass\" directive with variables");
3281 return NGX_CONF_ERROR;
3284 if (plcf->url.data == NULL) {
3285 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3286 "\"proxy_redirect default\" should be placed "
3287 "after the \"proxy_pass\" directive");
3288 return NGX_CONF_ERROR;
3291 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3293 ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3295 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3297 if (plcf->vars.uri.len) {
3298 pr->pattern.complex.value = plcf->url;
3299 pr->replacement.value = plcf->location;
3301 } else {
3302 pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3304 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3305 if (p == NULL) {
3306 return NGX_CONF_ERROR;
3309 pr->pattern.complex.value.data = p;
3311 p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3312 *p = '/';
3314 ngx_str_set(&pr->replacement.value, "/");
3317 return NGX_CONF_OK;
3321 if (value[1].data[0] == '~') {
3322 value[1].len--;
3323 value[1].data++;
3325 if (value[1].data[0] == '*') {
3326 value[1].len--;
3327 value[1].data++;
3329 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3330 return NGX_CONF_ERROR;
3333 } else {
3334 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3335 return NGX_CONF_ERROR;
3339 } else {
3341 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3343 ccv.cf = cf;
3344 ccv.value = &value[1];
3345 ccv.complex_value = &pr->pattern.complex;
3347 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3348 return NGX_CONF_ERROR;
3351 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3355 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3357 ccv.cf = cf;
3358 ccv.value = &value[2];
3359 ccv.complex_value = &pr->replacement;
3361 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3362 return NGX_CONF_ERROR;
3365 return NGX_CONF_OK;
3369 static char *
3370 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3372 ngx_http_proxy_loc_conf_t *plcf = conf;
3374 ngx_str_t *value;
3375 ngx_http_proxy_rewrite_t *pr;
3376 ngx_http_compile_complex_value_t ccv;
3378 if (plcf->cookie_domains == NULL) {
3379 return NGX_CONF_OK;
3382 value = cf->args->elts;
3384 if (cf->args->nelts == 2) {
3386 if (ngx_strcmp(value[1].data, "off") == 0) {
3387 plcf->cookie_domains = NULL;
3388 return NGX_CONF_OK;
3391 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3392 "invalid parameter \"%V\"", &value[1]);
3393 return NGX_CONF_ERROR;
3396 if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3397 plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3398 sizeof(ngx_http_proxy_rewrite_t));
3399 if (plcf->cookie_domains == NULL) {
3400 return NGX_CONF_ERROR;
3404 pr = ngx_array_push(plcf->cookie_domains);
3405 if (pr == NULL) {
3406 return NGX_CONF_ERROR;
3409 if (value[1].data[0] == '~') {
3410 value[1].len--;
3411 value[1].data++;
3413 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3414 return NGX_CONF_ERROR;
3417 } else {
3419 if (value[1].data[0] == '.') {
3420 value[1].len--;
3421 value[1].data++;
3424 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3426 ccv.cf = cf;
3427 ccv.value = &value[1];
3428 ccv.complex_value = &pr->pattern.complex;
3430 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3431 return NGX_CONF_ERROR;
3434 pr->handler = ngx_http_proxy_rewrite_domain_handler;
3436 if (value[2].data[0] == '.') {
3437 value[2].len--;
3438 value[2].data++;
3442 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3444 ccv.cf = cf;
3445 ccv.value = &value[2];
3446 ccv.complex_value = &pr->replacement;
3448 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3449 return NGX_CONF_ERROR;
3452 return NGX_CONF_OK;
3456 static char *
3457 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3459 ngx_http_proxy_loc_conf_t *plcf = conf;
3461 ngx_str_t *value;
3462 ngx_http_proxy_rewrite_t *pr;
3463 ngx_http_compile_complex_value_t ccv;
3465 if (plcf->cookie_paths == NULL) {
3466 return NGX_CONF_OK;
3469 value = cf->args->elts;
3471 if (cf->args->nelts == 2) {
3473 if (ngx_strcmp(value[1].data, "off") == 0) {
3474 plcf->cookie_paths = NULL;
3475 return NGX_CONF_OK;
3478 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3479 "invalid parameter \"%V\"", &value[1]);
3480 return NGX_CONF_ERROR;
3483 if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3484 plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3485 sizeof(ngx_http_proxy_rewrite_t));
3486 if (plcf->cookie_paths == NULL) {
3487 return NGX_CONF_ERROR;
3491 pr = ngx_array_push(plcf->cookie_paths);
3492 if (pr == NULL) {
3493 return NGX_CONF_ERROR;
3496 if (value[1].data[0] == '~') {
3497 value[1].len--;
3498 value[1].data++;
3500 if (value[1].data[0] == '*') {
3501 value[1].len--;
3502 value[1].data++;
3504 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3505 return NGX_CONF_ERROR;
3508 } else {
3509 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3510 return NGX_CONF_ERROR;
3514 } else {
3516 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3518 ccv.cf = cf;
3519 ccv.value = &value[1];
3520 ccv.complex_value = &pr->pattern.complex;
3522 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3523 return NGX_CONF_ERROR;
3526 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3529 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3531 ccv.cf = cf;
3532 ccv.value = &value[2];
3533 ccv.complex_value = &pr->replacement;
3535 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3536 return NGX_CONF_ERROR;
3539 return NGX_CONF_OK;
3543 static ngx_int_t
3544 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
3545 ngx_str_t *regex, ngx_uint_t caseless)
3547 #if (NGX_PCRE)
3548 u_char errstr[NGX_MAX_CONF_ERRSTR];
3549 ngx_regex_compile_t rc;
3551 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3553 rc.pattern = *regex;
3554 rc.err.len = NGX_MAX_CONF_ERRSTR;
3555 rc.err.data = errstr;
3557 if (caseless) {
3558 rc.options = NGX_REGEX_CASELESS;
3561 pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
3562 if (pr->pattern.regex == NULL) {
3563 return NGX_ERROR;
3566 pr->handler = ngx_http_proxy_rewrite_regex_handler;
3568 return NGX_OK;
3570 #else
3572 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3573 "using regex \"%V\" requires PCRE library", regex);
3574 return NGX_ERROR;
3576 #endif
3580 static char *
3581 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3583 ngx_http_proxy_loc_conf_t *plcf = conf;
3585 ngx_str_t *value;
3586 ngx_http_script_compile_t sc;
3588 if (plcf->upstream.store != NGX_CONF_UNSET
3589 || plcf->upstream.store_lengths)
3591 return "is duplicate";
3594 value = cf->args->elts;
3596 if (ngx_strcmp(value[1].data, "off") == 0) {
3597 plcf->upstream.store = 0;
3598 return NGX_CONF_OK;
3601 #if (NGX_HTTP_CACHE)
3603 if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
3604 && plcf->upstream.cache != NULL)
3606 return "is incompatible with \"proxy_cache\"";
3609 #endif
3611 if (ngx_strcmp(value[1].data, "on") == 0) {
3612 plcf->upstream.store = 1;
3613 return NGX_CONF_OK;
3616 /* include the terminating '\0' into script */
3617 value[1].len++;
3619 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3621 sc.cf = cf;
3622 sc.source = &value[1];
3623 sc.lengths = &plcf->upstream.store_lengths;
3624 sc.values = &plcf->upstream.store_values;
3625 sc.variables = ngx_http_script_variables_count(&value[1]);
3626 sc.complete_lengths = 1;
3627 sc.complete_values = 1;
3629 if (ngx_http_script_compile(&sc) != NGX_OK) {
3630 return NGX_CONF_ERROR;
3633 return NGX_CONF_OK;
3637 #if (NGX_HTTP_CACHE)
3639 static char *
3640 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3642 ngx_http_proxy_loc_conf_t *plcf = conf;
3644 ngx_str_t *value;
3646 value = cf->args->elts;
3648 if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
3649 return "is duplicate";
3652 if (ngx_strcmp(value[1].data, "off") == 0) {
3653 plcf->upstream.cache = NULL;
3654 return NGX_CONF_OK;
3657 if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
3658 return "is incompatible with \"proxy_store\"";
3661 plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
3662 &ngx_http_proxy_module);
3663 if (plcf->upstream.cache == NULL) {
3664 return NGX_CONF_ERROR;
3667 return NGX_CONF_OK;
3671 static char *
3672 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3674 ngx_http_proxy_loc_conf_t *plcf = conf;
3676 ngx_str_t *value;
3677 ngx_http_compile_complex_value_t ccv;
3679 value = cf->args->elts;
3681 if (plcf->cache_key.value.data) {
3682 return "is duplicate";
3685 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3687 ccv.cf = cf;
3688 ccv.value = &value[1];
3689 ccv.complex_value = &plcf->cache_key;
3691 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3692 return NGX_CONF_ERROR;
3695 return NGX_CONF_OK;
3698 #endif
3701 static char *
3702 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
3704 #if (NGX_FREEBSD)
3705 ssize_t *np = data;
3707 if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3708 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3709 "\"proxy_send_lowat\" must be less than %d "
3710 "(sysctl net.inet.tcp.sendspace)",
3711 ngx_freebsd_net_inet_tcp_sendspace);
3713 return NGX_CONF_ERROR;
3716 #elif !(NGX_HAVE_SO_SNDLOWAT)
3717 ssize_t *np = data;
3719 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3720 "\"proxy_send_lowat\" is not supported, ignored");
3722 *np = 0;
3724 #endif
3726 return NGX_CONF_OK;
3730 #if (NGX_HTTP_SSL)
3732 static ngx_int_t
3733 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
3735 ngx_pool_cleanup_t *cln;
3737 plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
3738 if (plcf->upstream.ssl == NULL) {
3739 return NGX_ERROR;
3742 plcf->upstream.ssl->log = cf->log;
3744 if (ngx_ssl_create(plcf->upstream.ssl,
3745 NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
3746 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
3747 NULL)
3748 != NGX_OK)
3750 return NGX_ERROR;
3753 cln = ngx_pool_cleanup_add(cf->pool, 0);
3754 if (cln == NULL) {
3755 return NGX_ERROR;
3758 cln->handler = ngx_ssl_cleanup_ctx;
3759 cln->data = plcf->upstream.ssl;
3761 return NGX_OK;
3764 #endif
3767 static void
3768 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
3770 if (u->family != AF_UNIX) {
3772 if (u->no_port || u->port == u->default_port) {
3774 v->host_header = u->host;
3776 if (u->default_port == 80) {
3777 ngx_str_set(&v->port, "80");
3779 } else {
3780 ngx_str_set(&v->port, "443");
3783 } else {
3784 v->host_header.len = u->host.len + 1 + u->port_text.len;
3785 v->host_header.data = u->host.data;
3786 v->port = u->port_text;
3789 v->key_start.len += v->host_header.len;
3791 } else {
3792 ngx_str_set(&v->host_header, "localhost");
3793 ngx_str_null(&v->port);
3794 v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
3797 v->uri = u->uri;