3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.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
;
23 ngx_http_complex_value_t
complex;
25 ngx_http_regex_t
*regex
;
29 ngx_http_complex_value_t replacement
;
36 ngx_str_t host_header
;
39 } ngx_http_proxy_vars_t
;
43 ngx_http_upstream_conf_t upstream
;
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
;
68 ngx_http_complex_value_t cache_key
;
71 ngx_http_proxy_vars_t vars
;
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
;
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
);
95 static ngx_int_t
ngx_http_proxy_create_key(ngx_http_request_t
*r
);
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
,
104 static ngx_int_t
ngx_http_proxy_chunked_filter(ngx_event_pipe_t
*p
,
106 static ngx_int_t
ngx_http_proxy_non_buffered_copy_filter(void *data
,
108 static ngx_int_t
ngx_http_proxy_non_buffered_chunked_filter(void *data
,
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
,
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
);
119 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t
*r
,
120 ngx_http_variable_value_t
*v
, uintptr_t data
);
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
,
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
,
142 static char *ngx_http_proxy_redirect(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
144 static char *ngx_http_proxy_cookie_domain(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
146 static char *ngx_http_proxy_cookie_path(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
148 static char *ngx_http_proxy_store(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
151 static char *ngx_http_proxy_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
153 static char *ngx_http_proxy_cache_key(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
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
);
163 static ngx_int_t
ngx_http_proxy_set_ssl(ngx_conf_t
*cf
,
164 ngx_http_proxy_loc_conf_t
*plcf
);
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
,
203 NGX_HTTP_LOC_CONF_OFFSET
,
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
,
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
,
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
,
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
,
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
,
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
,
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
),
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
},
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
),
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
= {
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
[] = {
569 ngx_string("Server"),
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"),
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
}
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 },
614 { ngx_string("proxy_add_via"), NULL
, NULL
, 0, NGX_HTTP_VAR_NOHASH
, 0 },
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 }
630 ngx_http_proxy_handler(ngx_http_request_t
*r
)
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
));
646 ngx_http_set_ctx(r
, ctx
, ngx_http_proxy_module
);
648 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
652 if (plcf
->proxy_lengths
== NULL
) {
653 ctx
->vars
= plcf
->vars
;
654 u
->schema
= plcf
->vars
.schema
;
656 u
->ssl
= (plcf
->upstream
.ssl
!= NULL
);
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
;
670 u
->create_key
= ngx_http_proxy_create_key
;
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
;
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
;
703 rc
= ngx_http_read_client_request_body(r
, ngx_http_upstream_init
);
705 if (rc
>= NGX_HTTP_SPECIAL_RESPONSE
) {
714 ngx_http_proxy_eval(ngx_http_request_t
*r
, ngx_http_proxy_ctx_t
*ctx
,
715 ngx_http_proxy_loc_conf_t
*plcf
)
722 ngx_http_upstream_t
*u
;
724 if (ngx_http_script_run(r
, &proxy
, plcf
->proxy_lengths
->elts
, 0,
725 plcf
->proxy_values
->elts
)
732 && ngx_strncasecmp(proxy
.data
, (u_char
*) "http://", 7) == 0)
739 } else if (proxy
.len
> 8
740 && ngx_strncasecmp(proxy
.data
, (u_char
*) "https://", 8) == 0)
744 r
->upstream
->ssl
= 1;
749 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
750 "invalid URL prefix in \"%V\"", &proxy
);
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
;
767 if (ngx_parse_url(r
->pool
, &url
) != NGX_OK
) {
769 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
770 "%s in upstream \"%V\"", url
.err
, &url
.url
);
777 if (url
.uri
.data
[0] == '?') {
778 p
= ngx_pnalloc(r
->pool
, url
.uri
.len
+ 1);
784 ngx_memcpy(p
, url
.uri
.data
, 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
) {
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
;
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
;
819 ngx_http_proxy_create_key(ngx_http_request_t
*r
)
825 ngx_http_upstream_t
*u
;
826 ngx_http_proxy_ctx_t
*ctx
;
827 ngx_http_proxy_loc_conf_t
*plcf
;
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
);
840 if (plcf
->cache_key
.value
.data
) {
842 if (ngx_http_complex_value(r
, &plcf
->cache_key
, key
) != NGX_OK
) {
849 *key
= ctx
->vars
.key_start
;
851 key
= ngx_array_push(&r
->cache
->keys
);
856 if (plcf
->proxy_lengths
&& ctx
->vars
.uri
.len
) {
858 *key
= ctx
->vars
.uri
;
859 u
->uri
= ctx
->vars
.uri
;
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
;
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
);
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
);
890 if (r
->valid_location
) {
891 p
= ngx_copy(p
, ctx
->vars
.uri
.data
, ctx
->vars
.uri
.len
);
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
;
900 p
= ngx_copy(p
, r
->uri
.data
+ loc_len
, r
->uri
.len
- loc_len
);
903 if (r
->args
.len
> 0) {
905 p
= ngx_copy(p
, r
->args
.data
, r
->args
.len
);
908 key
->len
= p
- key
->data
;
918 ngx_http_proxy_create_request(ngx_http_request_t
*r
)
920 size_t len
, uri_len
, loc_len
, body_len
;
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
;
937 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
940 /* HEAD was changed to GET to cache response */
944 } else if (plcf
->method
.len
) {
945 method
= plcf
->method
;
948 method
= r
->method_name
;
952 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
955 && ngx_strncasecmp(method
.data
, (u_char
*) "HEAD ", 5) == 0)
960 len
= method
.len
+ sizeof(ngx_http_proxy_version
) - 1 + sizeof(CRLF
) - 1;
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
)
972 uri_len
= r
->unparsed_uri
.len
;
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
;
988 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
989 "zero length URI to proxy");
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
;
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
;
1012 ctx
->internal_body_length
= r
->headers_in
.content_length_n
;
1015 le
.ip
= plcf
->headers_set_len
->elts
;
1019 while (*(uintptr_t *) le
.ip
) {
1020 while (*(uintptr_t *) le
.ip
) {
1021 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
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
) {
1040 header
= part
->elts
;
1044 if (ngx_hash_find(&plcf
->headers_set_hash
, header
[i
].hash
,
1045 header
[i
].lowcase_key
, header
[i
].key
.len
))
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
);
1061 cl
= ngx_alloc_chain_link(r
->pool
);
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
);
1082 if (r
->valid_location
) {
1083 b
->last
= ngx_copy(b
->last
, ctx
->vars
.uri
.data
, ctx
->vars
.uri
.len
);
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
;
1092 b
->last
= ngx_copy(b
->last
, r
->uri
.data
+ loc_len
,
1093 r
->uri
.len
- loc_len
);
1096 if (r
->args
.len
> 0) {
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);
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
;
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 */
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;
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);
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
) {
1164 header
= part
->elts
;
1168 if (ngx_hash_find(&plcf
->headers_set_hash
, header
[i
].hash
,
1169 header
[i
].lowcase_key
, header
[i
].key
.len
))
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
;
1197 while (*(uintptr_t *) e
.ip
) {
1198 code
= *(ngx_http_script_code_pt
*) e
.ip
;
1199 code((ngx_http_script_engine_t
*) &e
);
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
;
1215 b
= ngx_alloc_buf(r
->pool
);
1220 ngx_memcpy(b
, body
->buf
, sizeof(ngx_buf_t
));
1222 cl
->next
= ngx_alloc_chain_link(r
->pool
);
1223 if (cl
->next
== NULL
) {
1234 u
->request_bufs
= cl
;
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
);
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
;
1271 ngx_http_proxy_process_status_line(ngx_http_request_t
*r
)
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
);
1286 rc
= ngx_http_parse_status_line(r
, &u
->buffer
, &ctx
->status
);
1288 if (rc
== NGX_AGAIN
) {
1292 if (rc
== NGX_ERROR
) {
1294 #if (NGX_HTTP_CACHE)
1297 r
->http_version
= NGX_HTTP_VERSION_9
;
1303 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1304 "upstream sent no valid HTTP/1.0 header");
1308 return NGX_HTTP_UPSTREAM_INVALID_HEADER
;
1312 r
->http_version
= NGX_HTTP_VERSION_9
;
1313 u
->state
->status
= NGX_HTTP_OK
;
1314 u
->headers_in
.connection_close
= 1;
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
) {
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
);
1350 ngx_http_proxy_process_header(ngx_http_request_t
*r
)
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
);
1363 rc
= ngx_http_parse_header_line(r
, &r
->upstream
->buffer
, 1);
1367 /* a header line has been parsed successfully */
1369 h
= ngx_list_push(&r
->upstream
->headers_in
.headers
);
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
) {
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
);
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
) {
1407 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1408 "http proxy header: \"%V: %V\"",
1409 &h
->key
, &h
->value
);
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
);
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
);
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 */
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
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
) {
1480 if (r
->headers_in
.upgrade
) {
1488 if (rc
== 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
;
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
;
1510 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
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
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;
1532 u
->keepalive
= !u
->headers_in
.connection_close
;
1534 } else if (u
->headers_in
.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
;
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;
1548 u
->keepalive
= !u
->headers_in
.connection_close
;
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
;
1562 ngx_http_proxy_copy_filter(ngx_event_pipe_t
*p
, ngx_buf_t
*buf
)
1566 ngx_http_request_t
*r
;
1568 if (buf
->pos
== buf
->last
) {
1576 ngx_free_chain(p
->pool
, cl
);
1579 b
= ngx_alloc_buf(p
->pool
);
1585 ngx_memcpy(b
, buf
, sizeof(ngx_buf_t
));
1592 cl
= ngx_alloc_chain_link(p
->pool
);
1600 ngx_log_debug1(NGX_LOG_DEBUG_EVENT
, p
->log
, 0, "input buf #%d", b
->num
);
1607 p
->last_in
= &cl
->next
;
1609 if (p
->length
== -1) {
1613 p
->length
-= b
->last
- b
->pos
;
1615 if (p
->length
== 0) {
1617 p
->upstream_done
= 1;
1618 r
->upstream
->keepalive
= !r
->upstream
->headers_in
.connection_close
;
1620 } else if (p
->length
< 0) {
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");
1634 ngx_http_proxy_chunked_filter(ngx_event_pipe_t
*p
, ngx_buf_t
*buf
)
1637 ngx_buf_t
*b
, **prev
;
1639 ngx_http_request_t
*r
;
1640 ngx_http_proxy_ctx_t
*ctx
;
1642 if (buf
->pos
== buf
->last
) {
1647 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1654 prev
= &buf
->shadow
;
1658 rc
= ngx_http_parse_chunked(r
, buf
, &ctx
->chunked
);
1662 /* a chunk has been parsed successfully */
1668 ngx_free_chain(p
->pool
, cl
);
1671 b
= ngx_alloc_buf(p
->pool
);
1677 ngx_memzero(b
, sizeof(ngx_buf_t
));
1680 b
->start
= buf
->start
;
1689 cl
= ngx_alloc_chain_link(p
->pool
);
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
;
1713 ctx
->chunked
.size
= 0;
1718 ctx
->chunked
.size
-= buf
->last
- buf
->pos
;
1719 buf
->pos
= buf
->last
;
1720 b
->last
= buf
->last
;
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
;
1735 if (rc
== NGX_AGAIN
) {
1737 /* set p->length, minimal amount of data we want to see */
1739 p
->length
= ctx
->chunked
.length
;
1744 /* invalid response */
1746 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1747 "upstream sent invalid chunked response");
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
);
1760 ngx_log_debug2(NGX_LOG_DEBUG_EVENT
, p
->log
, 0,
1761 "input buf %p %z", b
->pos
, b
->last
- b
->pos
);
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
) {
1777 ngx_http_proxy_non_buffered_copy_filter(void *data
, ssize_t bytes
)
1779 ngx_http_request_t
*r
= data
;
1782 ngx_chain_t
*cl
, **ll
;
1783 ngx_http_upstream_t
*u
;
1787 for (cl
= u
->out_bufs
, ll
= &u
->out_bufs
; cl
; cl
= cl
->next
) {
1791 cl
= ngx_chain_get_free_buf(r
->pool
, &u
->free_bufs
);
1799 cl
->buf
->memory
= 1;
1803 cl
->buf
->pos
= b
->last
;
1805 cl
->buf
->last
= b
->last
;
1806 cl
->buf
->tag
= u
->output
.tag
;
1808 if (u
->length
== -1) {
1814 if (u
->length
== 0) {
1815 u
->keepalive
= !u
->headers_in
.connection_close
;
1823 ngx_http_proxy_non_buffered_chunked_filter(void *data
, ssize_t bytes
)
1825 ngx_http_request_t
*r
= data
;
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
);
1842 buf
->pos
= buf
->last
;
1845 for (cl
= u
->out_bufs
, ll
= &u
->out_bufs
; cl
; cl
= cl
->next
) {
1851 rc
= ngx_http_parse_chunked(r
, buf
, &ctx
->chunked
);
1855 /* a chunk has been parsed successfully */
1857 cl
= ngx_chain_get_free_buf(r
->pool
, &u
->free_bufs
);
1871 b
->tag
= u
->output
.tag
;
1873 if (buf
->last
- buf
->pos
>= ctx
->chunked
.size
) {
1874 buf
->pos
+= ctx
->chunked
.size
;
1876 ctx
->chunked
.size
= 0;
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
);
1891 if (rc
== NGX_DONE
) {
1893 /* a whole response has been parsed successfully */
1895 u
->keepalive
= !u
->headers_in
.connection_close
;
1901 if (rc
== NGX_AGAIN
) {
1905 /* invalid response */
1907 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1908 "upstream sent invalid chunked response");
1913 /* provide continuous buffer for subrequests in memory */
1915 if (r
->subrequest_in_memory
) {
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
;
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
;
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");
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");
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
);
1980 v
->len
= ctx
->vars
.host_header
.len
;
1982 v
->no_cacheable
= 0;
1984 v
->data
= ctx
->vars
.host_header
.data
;
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
);
2003 v
->len
= ctx
->vars
.port
.len
;
2005 v
->no_cacheable
= 0;
2007 v
->data
= ctx
->vars
.port
.data
;
2014 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t
*r
,
2015 ngx_http_variable_value_t
*v
, uintptr_t data
)
2020 ngx_table_elt_t
**h
;
2023 v
->no_cacheable
= 0;
2026 n
= r
->headers_in
.x_forwarded_for
.nelts
;
2027 h
= r
->headers_in
.x_forwarded_for
.elts
;
2031 for (i
= 0; i
< n
; i
++) {
2032 len
+= h
[i
]->value
.len
+ sizeof(", ") - 1;
2036 v
->len
= r
->connection
->addr_text
.len
;
2037 v
->data
= r
->connection
->addr_text
.data
;
2041 len
+= r
->connection
->addr_text
.len
;
2043 p
= ngx_pnalloc(r
->pool
, len
);
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
);
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) {
2076 v
->no_cacheable
= 0;
2079 v
->data
= ngx_pnalloc(r
->connection
->pool
, NGX_OFF_T_LEN
);
2081 if (v
->data
== NULL
) {
2085 v
->len
= ngx_sprintf(v
->data
, "%O", ctx
->internal_body_length
) - v
->data
;
2092 ngx_http_proxy_rewrite_redirect(ngx_http_request_t
*r
, ngx_table_elt_t
*h
,
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
;
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
) {
2119 return NGX_DECLINED
;
2124 ngx_http_proxy_rewrite_cookie(ngx_http_request_t
*r
, ngx_table_elt_t
*h
)
2129 ngx_http_proxy_loc_conf_t
*plcf
;
2131 p
= (u_char
*) ngx_strchr(h
->value
.data
, ';');
2133 return NGX_DECLINED
;
2136 prefix
= p
+ 1 - h
->value
.data
;
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);
2146 rc
= ngx_http_proxy_rewrite_cookie_value(r
, h
, p
+ 7,
2147 plcf
->cookie_domains
);
2148 if (rc
== NGX_ERROR
) {
2152 if (rc
!= NGX_DECLINED
) {
2158 if (plcf
->cookie_paths
) {
2159 p
= ngx_strcasestrn(h
->value
.data
+ prefix
, "path=", 5 - 1);
2162 rc
= ngx_http_proxy_rewrite_cookie_value(r
, h
, p
+ 5,
2163 plcf
->cookie_paths
);
2164 if (rc
== NGX_ERROR
) {
2168 if (rc
!= NGX_DECLINED
) {
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
)
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
) {
2204 return NGX_DECLINED
;
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
) {
2218 if (pattern
.len
> len
2219 || ngx_rstrncmp(h
->value
.data
+ prefix
, pattern
.data
,
2222 return NGX_DECLINED
;
2225 if (ngx_http_complex_value(r
, &pr
->replacement
, &replacement
) != NGX_OK
) {
2229 return ngx_http_proxy_rewrite(r
, h
, prefix
, pattern
.len
, &replacement
);
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
;
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
) {
2252 if (prefix
== 0 && h
->value
.len
== len
) {
2253 h
->value
= replacement
;
2257 return ngx_http_proxy_rewrite(r
, h
, prefix
, len
, &replacement
);
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
)
2268 ngx_str_t pattern
, replacement
;
2270 if (ngx_http_complex_value(r
, &pr
->pattern
.complex, &pattern
) != NGX_OK
) {
2274 p
= h
->value
.data
+ prefix
;
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
) {
2290 return ngx_http_proxy_rewrite(r
, h
, prefix
, len
, &replacement
);
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
)
2301 new_len
= replacement
->len
+ h
->value
.len
- len
;
2303 if (replacement
->len
> len
) {
2305 data
= ngx_pnalloc(r
->pool
, new_len
);
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
;
2319 p
= ngx_copy(h
->value
.data
+ prefix
, replacement
->data
,
2322 ngx_memmove(p
, h
->value
.data
+ prefix
+ len
,
2323 h
->value
.len
- len
- prefix
);
2326 h
->value
.len
= new_len
;
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
);
2343 var
->get_handler
= v
->get_handler
;
2344 var
->data
= v
->data
;
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
));
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
;
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
;
2423 conf
->upstream
.ssl_session_reuse
= NGX_CONF_UNSET
;
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");
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
;
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
,
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
;
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
;
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;
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
)
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);
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
] = ' ';
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);
2698 ngx_conf_merge_value(conf
->upstream
.ssl_session_reuse
,
2699 prev
->upstream
.ssl_session_reuse
, 1);
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
);
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
;
2735 pr
->pattern
.complex.value
.len
= conf
->url
.len
2738 p
= ngx_pnalloc(cf
->pool
, pr
->pattern
.complex.value
.len
);
2740 return NGX_CONF_ERROR
;
2743 pr
->pattern
.complex.value
.data
= p
;
2745 p
= ngx_cpymem(p
, conf
->url
.data
, conf
->url
.len
);
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
);
2758 if (conf
->upstream
.ssl
== NULL
) {
2759 conf
->upstream
.ssl
= prev
->upstream
.ssl
;
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
)
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
));
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
;
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
)
2843 ngx_array_t headers_names
, headers_merged
;
2844 ngx_keyval_t
*src
, *s
, *h
;
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
))
2868 if (ngx_array_init(&headers_names
, cf
->temp_pool
, 4, sizeof(ngx_hash_key_t
))
2874 if (ngx_array_init(&headers_merged
, cf
->temp_pool
, 4, sizeof(ngx_keyval_t
))
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
) {
2888 conf
->headers_set_len
= ngx_array_create(cf
->pool
, 64, 1);
2889 if (conf
->headers_set_len
== NULL
) {
2893 conf
->headers_set
= ngx_array_create(cf
->pool
, 512, 1);
2894 if (conf
->headers_set
== NULL
) {
2899 #if (NGX_HTTP_CACHE)
2901 h
= conf
->upstream
.cache
? ngx_http_proxy_cache_headers
:
2902 ngx_http_proxy_headers
;
2905 h
= ngx_http_proxy_headers
;
2909 src
= conf
->headers_source
->elts
;
2910 for (i
= 0; i
< conf
->headers_source
->nelts
; i
++) {
2912 s
= ngx_array_push(&headers_merged
);
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) {
2929 s
= ngx_array_push(&headers_merged
);
2942 src
= headers_merged
.elts
;
2943 for (i
= 0; i
< headers_merged
.nelts
; i
++) {
2945 hk
= ngx_array_push(&headers_names
);
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) {
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
));
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
);
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
);
2994 copy
= ngx_array_push_n(conf
->headers_set_len
,
2995 sizeof(ngx_http_script_copy_code_t
));
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
);
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
));
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
) {
3035 copy
= ngx_array_push_n(conf
->headers_set_len
,
3036 sizeof(ngx_http_script_copy_code_t
));
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
);
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
);
3062 code
= ngx_array_push_n(conf
->headers_set_len
, sizeof(uintptr_t));
3067 *code
= (uintptr_t) NULL
;
3069 code
= ngx_array_push_n(conf
->headers_set
, sizeof(uintptr_t));
3074 *code
= (uintptr_t) NULL
;
3077 code
= ngx_array_push_n(conf
->headers_set_len
, sizeof(uintptr_t));
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
);
3098 ngx_http_proxy_pass(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
3100 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
3104 ngx_str_t
*value
, *url
;
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
;
3126 n
= ngx_http_script_variables_count(url
);
3130 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
3134 sc
.lengths
= &plcf
->proxy_lengths
;
3135 sc
.values
= &plcf
->proxy_values
;
3137 sc
.complete_lengths
= 1;
3138 sc
.complete_values
= 1;
3140 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
3141 return NGX_CONF_ERROR
;
3145 if (ngx_http_proxy_set_ssl(cf
, plcf
) != NGX_OK
) {
3146 return NGX_CONF_ERROR
;
3153 if (ngx_strncasecmp(url
->data
, (u_char
*) "http://", 7) == 0) {
3157 } else if (ngx_strncasecmp(url
->data
, (u_char
*) "https://", 8) == 0) {
3160 if (ngx_http_proxy_set_ssl(cf
, plcf
) != NGX_OK
) {
3161 return NGX_CONF_ERROR
;
3167 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
3168 "https protocol requires SSL support");
3169 return NGX_CONF_ERROR
;
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
;
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
;
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;
3224 ngx_http_proxy_redirect(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
3226 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
3230 ngx_http_proxy_rewrite_t
*pr
;
3231 ngx_http_compile_complex_value_t ccv
;
3233 if (plcf
->redirect
== 0) {
3239 value
= cf
->args
->elts
;
3241 if (cf
->args
->nelts
== 2) {
3242 if (ngx_strcmp(value
[1].data
, "off") == 0) {
3244 plcf
->redirects
= NULL
;
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");
3252 plcf
->redirects
= NULL
;
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
);
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
;
3302 pr
->pattern
.complex.value
.len
= plcf
->url
.len
+ sizeof("/") - 1;
3304 p
= ngx_pnalloc(cf
->pool
, pr
->pattern
.complex.value
.len
);
3306 return NGX_CONF_ERROR
;
3309 pr
->pattern
.complex.value
.data
= p
;
3311 p
= ngx_cpymem(p
, plcf
->url
.data
, plcf
->url
.len
);
3314 ngx_str_set(&pr
->replacement
.value
, "/");
3321 if (value
[1].data
[0] == '~') {
3325 if (value
[1].data
[0] == '*') {
3329 if (ngx_http_proxy_rewrite_regex(cf
, pr
, &value
[1], 1) != NGX_OK
) {
3330 return NGX_CONF_ERROR
;
3334 if (ngx_http_proxy_rewrite_regex(cf
, pr
, &value
[1], 0) != NGX_OK
) {
3335 return NGX_CONF_ERROR
;
3341 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
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
));
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
;
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
;
3375 ngx_http_proxy_rewrite_t
*pr
;
3376 ngx_http_compile_complex_value_t ccv
;
3378 if (plcf
->cookie_domains
== NULL
) {
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
;
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
);
3406 return NGX_CONF_ERROR
;
3409 if (value
[1].data
[0] == '~') {
3413 if (ngx_http_proxy_rewrite_regex(cf
, pr
, &value
[1], 1) != NGX_OK
) {
3414 return NGX_CONF_ERROR
;
3419 if (value
[1].data
[0] == '.') {
3424 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
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] == '.') {
3442 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
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
;
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
;
3462 ngx_http_proxy_rewrite_t
*pr
;
3463 ngx_http_compile_complex_value_t ccv
;
3465 if (plcf
->cookie_paths
== NULL
) {
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
;
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
);
3493 return NGX_CONF_ERROR
;
3496 if (value
[1].data
[0] == '~') {
3500 if (value
[1].data
[0] == '*') {
3504 if (ngx_http_proxy_rewrite_regex(cf
, pr
, &value
[1], 1) != NGX_OK
) {
3505 return NGX_CONF_ERROR
;
3509 if (ngx_http_proxy_rewrite_regex(cf
, pr
, &value
[1], 0) != NGX_OK
) {
3510 return NGX_CONF_ERROR
;
3516 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
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
));
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
;
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
)
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
;
3558 rc
.options
= NGX_REGEX_CASELESS
;
3561 pr
->pattern
.regex
= ngx_http_regex_compile(cf
, &rc
);
3562 if (pr
->pattern
.regex
== NULL
) {
3566 pr
->handler
= ngx_http_proxy_rewrite_regex_handler
;
3572 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
3573 "using regex \"%V\" requires PCRE library", regex
);
3581 ngx_http_proxy_store(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
3583 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
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;
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\"";
3611 if (ngx_strcmp(value
[1].data
, "on") == 0) {
3612 plcf
->upstream
.store
= 1;
3616 /* include the terminating '\0' into script */
3619 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
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
;
3637 #if (NGX_HTTP_CACHE)
3640 ngx_http_proxy_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
3642 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
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
;
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
;
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
;
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
));
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
;
3702 ngx_http_proxy_lowat_check(ngx_conf_t
*cf
, void *post
, void *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)
3719 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
3720 "\"proxy_send_lowat\" is not supported, ignored");
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
) {
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
,
3753 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
3758 cln
->handler
= ngx_ssl_cleanup_ctx
;
3759 cln
->data
= plcf
->upstream
.ssl
;
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");
3780 ngx_str_set(&v
->port
, "443");
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
;
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;