3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t
;
14 typedef ngx_int_t (*ngx_http_proxy_redirect_pt
)(ngx_http_request_t
*r
,
15 ngx_table_elt_t
*h
, size_t prefix
, ngx_http_proxy_redirect_t
*pr
);
17 struct ngx_http_proxy_redirect_s
{
18 ngx_http_proxy_redirect_pt handler
;
37 ngx_str_t host_header
;
40 } ngx_http_proxy_vars_t
;
44 ngx_http_upstream_conf_t upstream
;
47 ngx_array_t
*body_set_len
;
48 ngx_array_t
*body_set
;
49 ngx_array_t
*headers_set_len
;
50 ngx_array_t
*headers_set
;
51 ngx_hash_t headers_set_hash
;
53 ngx_array_t
*headers_source
;
54 ngx_array_t
*headers_names
;
56 ngx_array_t
*proxy_lengths
;
57 ngx_array_t
*proxy_values
;
59 ngx_array_t
*redirects
;
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 headers_hash_max_size
;
76 ngx_uint_t headers_hash_bucket_size
;
77 } ngx_http_proxy_loc_conf_t
;
82 ngx_uint_t status_count
;
86 ngx_http_proxy_vars_t vars
;
88 size_t internal_body_length
;
89 } ngx_http_proxy_ctx_t
;
92 #define NGX_HTTP_PROXY_PARSE_NO_HEADER 20
95 static ngx_int_t
ngx_http_proxy_eval(ngx_http_request_t
*r
,
96 ngx_http_proxy_ctx_t
*ctx
, ngx_http_proxy_loc_conf_t
*plcf
);
98 static ngx_int_t
ngx_http_proxy_create_key(ngx_http_request_t
*r
);
100 static ngx_int_t
ngx_http_proxy_create_request(ngx_http_request_t
*r
);
101 static ngx_int_t
ngx_http_proxy_reinit_request(ngx_http_request_t
*r
);
102 static ngx_int_t
ngx_http_proxy_process_status_line(ngx_http_request_t
*r
);
103 static ngx_int_t
ngx_http_proxy_parse_status_line(ngx_http_request_t
*r
,
104 ngx_http_proxy_ctx_t
*ctx
);
105 static ngx_int_t
ngx_http_proxy_process_header(ngx_http_request_t
*r
);
106 static void ngx_http_proxy_abort_request(ngx_http_request_t
*r
);
107 static void ngx_http_proxy_finalize_request(ngx_http_request_t
*r
,
110 static ngx_int_t
ngx_http_proxy_host_variable(ngx_http_request_t
*r
,
111 ngx_http_variable_value_t
*v
, uintptr_t data
);
112 static ngx_int_t
ngx_http_proxy_port_variable(ngx_http_request_t
*r
,
113 ngx_http_variable_value_t
*v
, uintptr_t data
);
115 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t
*r
,
116 ngx_http_variable_value_t
*v
, uintptr_t data
);
118 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t
*r
,
119 ngx_http_variable_value_t
*v
, uintptr_t data
);
120 static ngx_int_t
ngx_http_proxy_rewrite_redirect(ngx_http_request_t
*r
,
121 ngx_table_elt_t
*h
, size_t prefix
);
123 static ngx_int_t
ngx_http_proxy_add_variables(ngx_conf_t
*cf
);
124 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t
*cf
);
125 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t
*cf
,
126 void *parent
, void *child
);
127 static ngx_int_t
ngx_http_proxy_merge_headers(ngx_conf_t
*cf
,
128 ngx_http_proxy_loc_conf_t
*conf
, ngx_http_proxy_loc_conf_t
*prev
);
130 static char *ngx_http_proxy_pass(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
132 static char *ngx_http_proxy_redirect(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
134 static char *ngx_http_proxy_store(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
137 static char *ngx_http_proxy_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
139 static char *ngx_http_proxy_cache_key(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
143 static char *ngx_http_proxy_lowat_check(ngx_conf_t
*cf
, void *post
, void *data
);
145 static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t
*cf
,
146 ngx_command_t
*cmd
, void *conf
);
147 static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t
*cf
,
148 ngx_command_t
*cmd
, void *conf
);
151 static ngx_int_t
ngx_http_proxy_set_ssl(ngx_conf_t
*cf
,
152 ngx_http_proxy_loc_conf_t
*plcf
);
154 static void ngx_http_proxy_set_vars(ngx_url_t
*u
, ngx_http_proxy_vars_t
*v
);
157 static ngx_conf_post_t ngx_http_proxy_lowat_post
=
158 { ngx_http_proxy_lowat_check
};
161 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks
[] = {
162 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR
},
163 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT
},
164 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER
},
165 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500
},
166 { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502
},
167 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503
},
168 { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504
},
169 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404
},
170 { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING
},
171 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF
},
172 { ngx_null_string
, 0 }
176 static ngx_conf_bitmask_t ngx_http_proxy_ignore_headers_masks
[] = {
177 { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT
},
178 { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES
},
179 { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES
},
180 { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL
},
181 { ngx_null_string
, 0 }
185 ngx_module_t ngx_http_proxy_module
;
188 static ngx_command_t ngx_http_proxy_commands
[] = {
190 { ngx_string("proxy_pass"),
191 NGX_HTTP_LOC_CONF
|NGX_HTTP_LIF_CONF
|NGX_HTTP_LMT_CONF
|NGX_CONF_TAKE1
,
193 NGX_HTTP_LOC_CONF_OFFSET
,
197 { ngx_string("proxy_redirect"),
198 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE12
,
199 ngx_http_proxy_redirect
,
200 NGX_HTTP_LOC_CONF_OFFSET
,
204 { ngx_string("proxy_store"),
205 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
206 ngx_http_proxy_store
,
207 NGX_HTTP_LOC_CONF_OFFSET
,
211 { ngx_string("proxy_store_access"),
212 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE123
,
213 ngx_conf_set_access_slot
,
214 NGX_HTTP_LOC_CONF_OFFSET
,
215 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.store_access
),
218 { ngx_string("proxy_buffering"),
219 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
220 ngx_conf_set_flag_slot
,
221 NGX_HTTP_LOC_CONF_OFFSET
,
222 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.buffering
),
225 { ngx_string("proxy_ignore_client_abort"),
226 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
227 ngx_conf_set_flag_slot
,
228 NGX_HTTP_LOC_CONF_OFFSET
,
229 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.ignore_client_abort
),
232 { ngx_string("proxy_bind"),
233 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
234 ngx_http_upstream_bind_set_slot
,
235 NGX_HTTP_LOC_CONF_OFFSET
,
236 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.local
),
239 { ngx_string("proxy_connect_timeout"),
240 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
241 ngx_conf_set_msec_slot
,
242 NGX_HTTP_LOC_CONF_OFFSET
,
243 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.connect_timeout
),
246 { ngx_string("proxy_send_timeout"),
247 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
248 ngx_conf_set_msec_slot
,
249 NGX_HTTP_LOC_CONF_OFFSET
,
250 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.send_timeout
),
253 { ngx_string("proxy_send_lowat"),
254 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
255 ngx_conf_set_size_slot
,
256 NGX_HTTP_LOC_CONF_OFFSET
,
257 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.send_lowat
),
258 &ngx_http_proxy_lowat_post
},
260 { ngx_string("proxy_intercept_errors"),
261 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
262 ngx_conf_set_flag_slot
,
263 NGX_HTTP_LOC_CONF_OFFSET
,
264 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.intercept_errors
),
267 { ngx_string("proxy_set_header"),
268 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE2
,
269 ngx_conf_set_keyval_slot
,
270 NGX_HTTP_LOC_CONF_OFFSET
,
271 offsetof(ngx_http_proxy_loc_conf_t
, headers_source
),
274 { ngx_string("proxy_headers_hash_max_size"),
275 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
276 ngx_conf_set_num_slot
,
277 NGX_HTTP_LOC_CONF_OFFSET
,
278 offsetof(ngx_http_proxy_loc_conf_t
, headers_hash_max_size
),
281 { ngx_string("proxy_headers_hash_bucket_size"),
282 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
283 ngx_conf_set_num_slot
,
284 NGX_HTTP_LOC_CONF_OFFSET
,
285 offsetof(ngx_http_proxy_loc_conf_t
, headers_hash_bucket_size
),
288 { ngx_string("proxy_set_body"),
289 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
290 ngx_conf_set_str_slot
,
291 NGX_HTTP_LOC_CONF_OFFSET
,
292 offsetof(ngx_http_proxy_loc_conf_t
, body_source
),
295 { ngx_string("proxy_method"),
296 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
297 ngx_conf_set_str_slot
,
298 NGX_HTTP_LOC_CONF_OFFSET
,
299 offsetof(ngx_http_proxy_loc_conf_t
, method
),
302 { ngx_string("proxy_pass_request_headers"),
303 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
304 ngx_conf_set_flag_slot
,
305 NGX_HTTP_LOC_CONF_OFFSET
,
306 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.pass_request_headers
),
309 { ngx_string("proxy_pass_request_body"),
310 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
311 ngx_conf_set_flag_slot
,
312 NGX_HTTP_LOC_CONF_OFFSET
,
313 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.pass_request_body
),
316 { ngx_string("proxy_buffer_size"),
317 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
318 ngx_conf_set_size_slot
,
319 NGX_HTTP_LOC_CONF_OFFSET
,
320 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.buffer_size
),
323 { ngx_string("proxy_read_timeout"),
324 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
325 ngx_conf_set_msec_slot
,
326 NGX_HTTP_LOC_CONF_OFFSET
,
327 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.read_timeout
),
330 { ngx_string("proxy_buffers"),
331 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE2
,
332 ngx_conf_set_bufs_slot
,
333 NGX_HTTP_LOC_CONF_OFFSET
,
334 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.bufs
),
337 { ngx_string("proxy_busy_buffers_size"),
338 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
339 ngx_conf_set_size_slot
,
340 NGX_HTTP_LOC_CONF_OFFSET
,
341 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.busy_buffers_size_conf
),
346 { ngx_string("proxy_cache"),
347 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
348 ngx_http_proxy_cache
,
349 NGX_HTTP_LOC_CONF_OFFSET
,
353 { ngx_string("proxy_cache_key"),
354 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
355 ngx_http_proxy_cache_key
,
356 NGX_HTTP_LOC_CONF_OFFSET
,
360 { ngx_string("proxy_cache_path"),
361 NGX_HTTP_MAIN_CONF
|NGX_CONF_2MORE
,
362 ngx_http_file_cache_set_slot
,
365 &ngx_http_proxy_module
},
367 { ngx_string("proxy_cache_valid"),
368 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
369 ngx_http_file_cache_valid_set_slot
,
370 NGX_HTTP_LOC_CONF_OFFSET
,
371 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.cache_valid
),
374 { ngx_string("proxy_cache_min_uses"),
375 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
376 ngx_conf_set_num_slot
,
377 NGX_HTTP_LOC_CONF_OFFSET
,
378 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.cache_min_uses
),
381 { ngx_string("proxy_cache_use_stale"),
382 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
383 ngx_conf_set_bitmask_slot
,
384 NGX_HTTP_LOC_CONF_OFFSET
,
385 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.cache_use_stale
),
386 &ngx_http_proxy_next_upstream_masks
},
388 { ngx_string("proxy_cache_methods"),
389 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
390 ngx_conf_set_bitmask_slot
,
391 NGX_HTTP_LOC_CONF_OFFSET
,
392 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.cache_methods
),
393 &ngx_http_upstream_cache_method_mask
},
397 { ngx_string("proxy_temp_path"),
398 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1234
,
399 ngx_conf_set_path_slot
,
400 NGX_HTTP_LOC_CONF_OFFSET
,
401 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.temp_path
),
404 { ngx_string("proxy_max_temp_file_size"),
405 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
406 ngx_conf_set_size_slot
,
407 NGX_HTTP_LOC_CONF_OFFSET
,
408 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.max_temp_file_size_conf
),
411 { ngx_string("proxy_temp_file_write_size"),
412 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
413 ngx_conf_set_size_slot
,
414 NGX_HTTP_LOC_CONF_OFFSET
,
415 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.temp_file_write_size_conf
),
418 { ngx_string("proxy_next_upstream"),
419 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
420 ngx_conf_set_bitmask_slot
,
421 NGX_HTTP_LOC_CONF_OFFSET
,
422 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.next_upstream
),
423 &ngx_http_proxy_next_upstream_masks
},
425 { ngx_string("proxy_upstream_max_fails"),
426 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
427 ngx_http_proxy_upstream_max_fails_unsupported
,
432 { ngx_string("proxy_upstream_fail_timeout"),
433 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
434 ngx_http_proxy_upstream_fail_timeout_unsupported
,
439 { ngx_string("proxy_pass_header"),
440 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
441 ngx_conf_set_str_array_slot
,
442 NGX_HTTP_LOC_CONF_OFFSET
,
443 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.pass_headers
),
446 { ngx_string("proxy_hide_header"),
447 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
448 ngx_conf_set_str_array_slot
,
449 NGX_HTTP_LOC_CONF_OFFSET
,
450 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.hide_headers
),
453 { ngx_string("proxy_ignore_headers"),
454 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_1MORE
,
455 ngx_conf_set_bitmask_slot
,
456 NGX_HTTP_LOC_CONF_OFFSET
,
457 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.ignore_headers
),
458 &ngx_http_proxy_ignore_headers_masks
},
462 { ngx_string("proxy_ssl_session_reuse"),
463 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
464 ngx_conf_set_flag_slot
,
465 NGX_HTTP_LOC_CONF_OFFSET
,
466 offsetof(ngx_http_proxy_loc_conf_t
, upstream
.ssl_session_reuse
),
475 static ngx_http_module_t ngx_http_proxy_module_ctx
= {
476 ngx_http_proxy_add_variables
, /* preconfiguration */
477 NULL
, /* postconfiguration */
479 NULL
, /* create main configuration */
480 NULL
, /* init main configuration */
482 NULL
, /* create server configuration */
483 NULL
, /* merge server configuration */
485 ngx_http_proxy_create_loc_conf
, /* create location configration */
486 ngx_http_proxy_merge_loc_conf
/* merge location configration */
490 ngx_module_t ngx_http_proxy_module
= {
492 &ngx_http_proxy_module_ctx
, /* module context */
493 ngx_http_proxy_commands
, /* module directives */
494 NGX_HTTP_MODULE
, /* module type */
495 NULL
, /* init master */
496 NULL
, /* init module */
497 NULL
, /* init process */
498 NULL
, /* init thread */
499 NULL
, /* exit thread */
500 NULL
, /* exit process */
501 NULL
, /* exit master */
502 NGX_MODULE_V1_PADDING
506 static char ngx_http_proxy_version
[] = " HTTP/1.0" CRLF
;
509 static ngx_keyval_t ngx_http_proxy_headers
[] = {
510 { ngx_string("Host"), ngx_string("$proxy_host") },
511 { ngx_string("Connection"), ngx_string("close") },
512 { ngx_string("Keep-Alive"), ngx_string("") },
513 { ngx_string("Expect"), ngx_string("") },
514 { ngx_null_string
, ngx_null_string
}
518 static ngx_str_t ngx_http_proxy_hide_headers
[] = {
520 ngx_string("Server"),
522 ngx_string("X-Accel-Expires"),
523 ngx_string("X-Accel-Redirect"),
524 ngx_string("X-Accel-Limit-Rate"),
525 ngx_string("X-Accel-Buffering"),
526 ngx_string("X-Accel-Charset"),
533 static ngx_keyval_t ngx_http_proxy_cache_headers
[] = {
534 { ngx_string("Host"), ngx_string("$proxy_host") },
535 { ngx_string("Connection"), ngx_string("close") },
536 { ngx_string("Keep-Alive"), ngx_string("") },
537 { ngx_string("Expect"), ngx_string("") },
538 { ngx_string("If-Modified-Since"), ngx_string("") },
539 { ngx_string("If-Unmodified-Since"), ngx_string("") },
540 { ngx_string("If-None-Match"), ngx_string("") },
541 { ngx_string("If-Match"), ngx_string("") },
542 { ngx_string("Range"), ngx_string("") },
543 { ngx_string("If-Range"), ngx_string("") },
544 { ngx_null_string
, ngx_null_string
}
548 static ngx_str_t ngx_http_proxy_hide_cache_headers
[] = {
550 ngx_string("Server"),
552 ngx_string("X-Accel-Expires"),
553 ngx_string("X-Accel-Redirect"),
554 ngx_string("X-Accel-Limit-Rate"),
555 ngx_string("X-Accel-Buffering"),
556 ngx_string("X-Accel-Charset"),
557 ngx_string("Set-Cookie"),
565 static ngx_http_variable_t ngx_http_proxy_vars
[] = {
567 { ngx_string("proxy_host"), NULL
, ngx_http_proxy_host_variable
, 0,
568 NGX_HTTP_VAR_CHANGEABLE
|NGX_HTTP_VAR_NOCACHEABLE
|NGX_HTTP_VAR_NOHASH
, 0 },
570 { ngx_string("proxy_port"), NULL
, ngx_http_proxy_port_variable
, 0,
571 NGX_HTTP_VAR_CHANGEABLE
|NGX_HTTP_VAR_NOCACHEABLE
|NGX_HTTP_VAR_NOHASH
, 0 },
573 { ngx_string("proxy_add_x_forwarded_for"), NULL
,
574 ngx_http_proxy_add_x_forwarded_for_variable
, 0, NGX_HTTP_VAR_NOHASH
, 0 },
577 { ngx_string("proxy_add_via"), NULL
, NULL
, 0, NGX_HTTP_VAR_NOHASH
, 0 },
580 { ngx_string("proxy_internal_body_length"), NULL
,
581 ngx_http_proxy_internal_body_length_variable
, 0, NGX_HTTP_VAR_NOHASH
, 0 },
583 { ngx_null_string
, NULL
, NULL
, 0, 0, 0 }
587 static ngx_path_init_t ngx_http_proxy_temp_path
= {
588 ngx_string(NGX_HTTP_PROXY_TEMP_PATH
), { 1, 2, 0 }
593 ngx_http_proxy_handler(ngx_http_request_t
*r
)
596 ngx_http_upstream_t
*u
;
597 ngx_http_proxy_ctx_t
*ctx
;
598 ngx_http_proxy_loc_conf_t
*plcf
;
600 if (ngx_http_upstream_create(r
) != NGX_OK
) {
601 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
604 ctx
= ngx_pcalloc(r
->pool
, sizeof(ngx_http_proxy_ctx_t
));
609 ngx_http_set_ctx(r
, ctx
, ngx_http_proxy_module
);
611 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
615 if (plcf
->proxy_lengths
== 0) {
616 ctx
->vars
= plcf
->vars
;
617 u
->schema
= plcf
->vars
.schema
;
619 u
->ssl
= (plcf
->upstream
.ssl
!= NULL
);
623 if (ngx_http_proxy_eval(r
, ctx
, plcf
) != NGX_OK
) {
624 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
628 u
->output
.tag
= (ngx_buf_tag_t
) &ngx_http_proxy_module
;
630 u
->conf
= &plcf
->upstream
;
633 u
->create_key
= ngx_http_proxy_create_key
;
635 u
->create_request
= ngx_http_proxy_create_request
;
636 u
->reinit_request
= ngx_http_proxy_reinit_request
;
637 u
->process_header
= ngx_http_proxy_process_status_line
;
638 u
->abort_request
= ngx_http_proxy_abort_request
;
639 u
->finalize_request
= ngx_http_proxy_finalize_request
;
642 if (plcf
->redirects
) {
643 u
->rewrite_redirect
= ngx_http_proxy_rewrite_redirect
;
646 u
->buffering
= plcf
->upstream
.buffering
;
648 u
->pipe
= ngx_pcalloc(r
->pool
, sizeof(ngx_event_pipe_t
));
649 if (u
->pipe
== NULL
) {
650 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
653 u
->pipe
->input_filter
= ngx_event_pipe_copy_input_filter
;
657 rc
= ngx_http_read_client_request_body(r
, ngx_http_upstream_init
);
659 if (rc
>= NGX_HTTP_SPECIAL_RESPONSE
) {
668 ngx_http_proxy_eval(ngx_http_request_t
*r
, ngx_http_proxy_ctx_t
*ctx
,
669 ngx_http_proxy_loc_conf_t
*plcf
)
676 ngx_http_upstream_t
*u
;
678 if (ngx_http_script_run(r
, &proxy
, plcf
->proxy_lengths
->elts
, 0,
679 plcf
->proxy_values
->elts
)
685 if (ngx_strncasecmp(proxy
.data
, (u_char
*) "http://", 7) == 0) {
692 } else if (ngx_strncasecmp(proxy
.data
, (u_char
*) "https://", 8) == 0) {
696 r
->upstream
->ssl
= 1;
701 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
702 "invalid URL prefix in \"%V\"", &proxy
);
709 u
->schema
.data
= proxy
.data
;
711 ngx_memzero(&url
, sizeof(ngx_url_t
));
713 url
.url
.len
= proxy
.len
- add
;
714 url
.url
.data
= proxy
.data
+ add
;
715 url
.default_port
= port
;
719 if (ngx_parse_url(r
->pool
, &url
) != NGX_OK
) {
721 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
722 "%s in upstream \"%V\"", url
.err
, &url
.url
);
729 if (url
.uri
.data
[0] == '?') {
730 p
= ngx_pnalloc(r
->pool
, url
.uri
.len
+ 1);
736 ngx_memcpy(p
, url
.uri
.data
, url
.uri
.len
);
739 url
.uri
.data
= p
- 1;
743 url
.uri
= r
->unparsed_uri
;
746 ctx
->vars
.key_start
= u
->schema
;
748 ngx_http_proxy_set_vars(&url
, &ctx
->vars
);
750 u
->resolved
= ngx_pcalloc(r
->pool
, sizeof(ngx_http_upstream_resolved_t
));
751 if (u
->resolved
== NULL
) {
755 if (url
.addrs
&& url
.addrs
[0].sockaddr
) {
756 u
->resolved
->sockaddr
= url
.addrs
[0].sockaddr
;
757 u
->resolved
->socklen
= url
.addrs
[0].socklen
;
758 u
->resolved
->naddrs
= 1;
759 u
->resolved
->host
= url
.addrs
[0].name
;
762 u
->resolved
->host
= url
.host
;
763 u
->resolved
->port
= (in_port_t
) (url
.no_port
? port
: url
.port
);
764 u
->resolved
->no_port
= url
.no_port
;
774 ngx_http_proxy_create_key(ngx_http_request_t
*r
)
780 ngx_http_upstream_t
*u
;
781 ngx_http_proxy_ctx_t
*ctx
;
782 ngx_http_proxy_loc_conf_t
*plcf
;
786 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
788 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
790 key
= ngx_array_push(&r
->cache
->keys
);
795 if (plcf
->cache_key
.value
.len
) {
797 if (ngx_http_complex_value(r
, &plcf
->cache_key
, key
) != NGX_OK
) {
804 *key
= ctx
->vars
.key_start
;
806 key
= ngx_array_push(&r
->cache
->keys
);
811 if (plcf
->proxy_lengths
) {
813 *key
= ctx
->vars
.uri
;
814 u
->uri
= ctx
->vars
.uri
;
818 } else if (ctx
->vars
.uri
.len
== 0 && r
->valid_unparsed_uri
&& r
== r
->main
)
820 *key
= r
->unparsed_uri
;
821 u
->uri
= r
->unparsed_uri
;
826 loc_len
= (r
->valid_location
&& ctx
->vars
.uri
.len
) ? plcf
->location
.len
: 0;
828 if (r
->quoted_uri
|| r
->internal
) {
829 escape
= 2 * ngx_escape_uri(NULL
, r
->uri
.data
+ loc_len
,
830 r
->uri
.len
- loc_len
, NGX_ESCAPE_URI
);
835 len
= ctx
->vars
.uri
.len
+ r
->uri
.len
- loc_len
+ escape
836 + sizeof("?") - 1 + r
->args
.len
;
838 p
= ngx_pnalloc(r
->pool
, len
);
845 if (r
->valid_location
) {
846 p
= ngx_copy(p
, ctx
->vars
.uri
.data
, ctx
->vars
.uri
.len
);
850 ngx_escape_uri(p
, r
->uri
.data
+ loc_len
,
851 r
->uri
.len
- loc_len
, NGX_ESCAPE_URI
);
852 p
+= r
->uri
.len
- loc_len
+ escape
;
855 p
= ngx_copy(p
, r
->uri
.data
+ loc_len
, r
->uri
.len
- loc_len
);
858 if (r
->args
.len
> 0) {
860 p
= ngx_copy(p
, r
->args
.data
, r
->args
.len
);
863 key
->len
= p
- key
->data
;
873 ngx_http_proxy_create_request(ngx_http_request_t
*r
)
875 size_t len
, uri_len
, loc_len
, body_len
;
879 ngx_uint_t i
, unparsed_uri
;
880 ngx_chain_t
*cl
, *body
;
881 ngx_list_part_t
*part
;
882 ngx_table_elt_t
*header
;
883 ngx_http_upstream_t
*u
;
884 ngx_http_proxy_ctx_t
*ctx
;
885 ngx_http_script_code_pt code
;
886 ngx_http_script_engine_t e
, le
;
887 ngx_http_proxy_loc_conf_t
*plcf
;
888 ngx_http_script_len_code_pt lcode
;
892 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
895 /* HEAD was changed to GET to cache response */
899 } else if (plcf
->method
.len
) {
900 method
= plcf
->method
;
903 method
= r
->method_name
;
907 len
= method
.len
+ sizeof(ngx_http_proxy_version
) - 1 + sizeof(CRLF
) - 1;
913 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
915 if (plcf
->proxy_lengths
) {
916 uri_len
= ctx
->vars
.uri
.len
;
918 } else if (ctx
->vars
.uri
.len
== 0 && r
->valid_unparsed_uri
&& r
== r
->main
)
921 uri_len
= r
->unparsed_uri
.len
;
924 loc_len
= (r
->valid_location
&& ctx
->vars
.uri
.len
) ?
925 plcf
->location
.len
: 0;
927 if (r
->quoted_uri
|| r
->internal
) {
928 escape
= 2 * ngx_escape_uri(NULL
, r
->uri
.data
+ loc_len
,
929 r
->uri
.len
- loc_len
, NGX_ESCAPE_URI
);
932 uri_len
= ctx
->vars
.uri
.len
+ r
->uri
.len
- loc_len
+ escape
933 + sizeof("?") - 1 + r
->args
.len
;
937 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
938 "zero length URI to proxy");
944 ngx_http_script_flush_no_cacheable_variables(r
, plcf
->flushes
);
946 if (plcf
->body_set_len
) {
947 le
.ip
= plcf
->body_set_len
->elts
;
952 while (*(uintptr_t *) le
.ip
) {
953 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
954 body_len
+= lcode(&le
);
957 ctx
->internal_body_length
= body_len
;
961 le
.ip
= plcf
->headers_set_len
->elts
;
965 while (*(uintptr_t *) le
.ip
) {
966 while (*(uintptr_t *) le
.ip
) {
967 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
970 le
.ip
+= sizeof(uintptr_t);
974 if (plcf
->upstream
.pass_request_headers
) {
975 part
= &r
->headers_in
.headers
.part
;
978 for (i
= 0; /* void */; i
++) {
980 if (i
>= part
->nelts
) {
981 if (part
->next
== NULL
) {
990 if (ngx_hash_find(&plcf
->headers_set_hash
, header
[i
].hash
,
991 header
[i
].lowcase_key
, header
[i
].key
.len
))
996 len
+= header
[i
].key
.len
+ sizeof(": ") - 1
997 + header
[i
].value
.len
+ sizeof(CRLF
) - 1;
1002 b
= ngx_create_temp_buf(r
->pool
, len
);
1007 cl
= ngx_alloc_chain_link(r
->pool
);
1015 /* the request line */
1017 b
->last
= ngx_copy(b
->last
, method
.data
, method
.len
);
1019 u
->uri
.data
= b
->last
;
1021 if (plcf
->proxy_lengths
) {
1022 b
->last
= ngx_copy(b
->last
, ctx
->vars
.uri
.data
, ctx
->vars
.uri
.len
);
1024 } else if (unparsed_uri
) {
1025 b
->last
= ngx_copy(b
->last
, r
->unparsed_uri
.data
, r
->unparsed_uri
.len
);
1028 if (r
->valid_location
) {
1029 b
->last
= ngx_copy(b
->last
, ctx
->vars
.uri
.data
, ctx
->vars
.uri
.len
);
1033 ngx_escape_uri(b
->last
, r
->uri
.data
+ loc_len
,
1034 r
->uri
.len
- loc_len
, NGX_ESCAPE_URI
);
1035 b
->last
+= r
->uri
.len
- loc_len
+ escape
;
1038 b
->last
= ngx_copy(b
->last
, r
->uri
.data
+ loc_len
,
1039 r
->uri
.len
- loc_len
);
1042 if (r
->args
.len
> 0) {
1044 b
->last
= ngx_copy(b
->last
, r
->args
.data
, r
->args
.len
);
1048 u
->uri
.len
= b
->last
- u
->uri
.data
;
1050 b
->last
= ngx_cpymem(b
->last
, ngx_http_proxy_version
,
1051 sizeof(ngx_http_proxy_version
) - 1);
1053 ngx_memzero(&e
, sizeof(ngx_http_script_engine_t
));
1055 e
.ip
= plcf
->headers_set
->elts
;
1060 le
.ip
= plcf
->headers_set_len
->elts
;
1062 while (*(uintptr_t *) le
.ip
) {
1063 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
1065 /* skip the header line name length */
1068 if (*(ngx_http_script_len_code_pt
*) le
.ip
) {
1070 for (len
= 0; *(uintptr_t *) le
.ip
; len
+= lcode(&le
)) {
1071 lcode
= *(ngx_http_script_len_code_pt
*) le
.ip
;
1074 e
.skip
= (len
== sizeof(CRLF
) - 1) ? 1 : 0;
1080 le
.ip
+= sizeof(uintptr_t);
1082 while (*(uintptr_t *) e
.ip
) {
1083 code
= *(ngx_http_script_code_pt
*) e
.ip
;
1084 code((ngx_http_script_engine_t
*) &e
);
1086 e
.ip
+= sizeof(uintptr_t);
1092 if (plcf
->upstream
.pass_request_headers
) {
1093 part
= &r
->headers_in
.headers
.part
;
1094 header
= part
->elts
;
1096 for (i
= 0; /* void */; i
++) {
1098 if (i
>= part
->nelts
) {
1099 if (part
->next
== NULL
) {
1104 header
= part
->elts
;
1108 if (ngx_hash_find(&plcf
->headers_set_hash
, header
[i
].hash
,
1109 header
[i
].lowcase_key
, header
[i
].key
.len
))
1114 b
->last
= ngx_copy(b
->last
, header
[i
].key
.data
, header
[i
].key
.len
);
1116 *b
->last
++ = ':'; *b
->last
++ = ' ';
1118 b
->last
= ngx_copy(b
->last
, header
[i
].value
.data
,
1119 header
[i
].value
.len
);
1121 *b
->last
++ = CR
; *b
->last
++ = LF
;
1123 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1124 "http proxy header: \"%V: %V\"",
1125 &header
[i
].key
, &header
[i
].value
);
1130 /* add "\r\n" at the header end */
1131 *b
->last
++ = CR
; *b
->last
++ = LF
;
1133 if (plcf
->body_set
) {
1134 e
.ip
= plcf
->body_set
->elts
;
1137 while (*(uintptr_t *) e
.ip
) {
1138 code
= *(ngx_http_script_code_pt
*) e
.ip
;
1139 code((ngx_http_script_engine_t
*) &e
);
1145 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1146 "http proxy header:\n\"%*s\"",
1147 (size_t) (b
->last
- b
->pos
), b
->pos
);
1149 if (plcf
->body_set
== NULL
&& plcf
->upstream
.pass_request_body
) {
1151 body
= u
->request_bufs
;
1152 u
->request_bufs
= cl
;
1155 b
= ngx_alloc_buf(r
->pool
);
1160 ngx_memcpy(b
, body
->buf
, sizeof(ngx_buf_t
));
1162 cl
->next
= ngx_alloc_chain_link(r
->pool
);
1163 if (cl
->next
== NULL
) {
1176 u
->request_bufs
= cl
;
1186 ngx_http_proxy_reinit_request(ngx_http_request_t
*r
)
1188 ngx_http_proxy_ctx_t
*ctx
;
1190 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1197 ctx
->status_count
= 0;
1198 ctx
->status_start
= NULL
;
1199 ctx
->status_end
= NULL
;
1201 r
->upstream
->process_header
= ngx_http_proxy_process_status_line
;
1209 ngx_http_proxy_process_status_line(ngx_http_request_t
*r
)
1212 ngx_http_upstream_t
*u
;
1213 ngx_http_proxy_ctx_t
*ctx
;
1215 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1221 rc
= ngx_http_proxy_parse_status_line(r
, ctx
);
1223 if (rc
== NGX_AGAIN
) {
1229 if (rc
== NGX_HTTP_PROXY_PARSE_NO_HEADER
) {
1231 #if (NGX_HTTP_CACHE)
1234 r
->http_version
= NGX_HTTP_VERSION_9
;
1240 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1241 "upstream sent no valid HTTP/1.0 header");
1245 return NGX_HTTP_UPSTREAM_INVALID_HEADER
;
1249 r
->http_version
= NGX_HTTP_VERSION_9
;
1250 u
->state
->status
= NGX_HTTP_OK
;
1256 u
->state
->status
= ctx
->status
;
1259 u
->headers_in
.status_n
= ctx
->status
;
1261 u
->headers_in
.status_line
.len
= ctx
->status_end
- ctx
->status_start
;
1262 u
->headers_in
.status_line
.data
= ngx_pnalloc(r
->pool
,
1263 u
->headers_in
.status_line
.len
);
1264 if (u
->headers_in
.status_line
.data
== NULL
) {
1268 ngx_memcpy(u
->headers_in
.status_line
.data
, ctx
->status_start
,
1269 u
->headers_in
.status_line
.len
);
1271 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1272 "http proxy status %ui \"%V\"",
1273 u
->headers_in
.status_n
, &u
->headers_in
.status_line
);
1275 u
->process_header
= ngx_http_proxy_process_header
;
1277 return ngx_http_proxy_process_header(r
);
1282 ngx_http_proxy_parse_status_line(ngx_http_request_t
*r
,
1283 ngx_http_proxy_ctx_t
*ctx
)
1287 ngx_http_upstream_t
*u
;
1294 sw_first_major_digit
,
1296 sw_first_minor_digit
,
1299 sw_space_after_status
,
1308 for (p
= u
->buffer
.pos
; p
< u
->buffer
.last
; p
++) {
1320 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1330 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1340 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1350 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1357 state
= sw_first_major_digit
;
1360 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1364 /* the first digit of major HTTP version */
1365 case sw_first_major_digit
:
1366 if (ch
< '1' || ch
> '9') {
1367 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1370 state
= sw_major_digit
;
1373 /* the major HTTP version or dot */
1374 case sw_major_digit
:
1376 state
= sw_first_minor_digit
;
1380 if (ch
< '0' || ch
> '9') {
1381 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1386 /* the first digit of minor HTTP version */
1387 case sw_first_minor_digit
:
1388 if (ch
< '0' || ch
> '9') {
1389 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1392 state
= sw_minor_digit
;
1395 /* the minor HTTP version or the end of the request line */
1396 case sw_minor_digit
:
1402 if (ch
< '0' || ch
> '9') {
1403 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1408 /* HTTP status code */
1414 if (ch
< '0' || ch
> '9') {
1415 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1418 ctx
->status
= ctx
->status
* 10 + ch
- '0';
1420 if (++ctx
->status_count
== 3) {
1421 state
= sw_space_after_status
;
1422 ctx
->status_start
= p
- 2;
1427 /* space or end of line */
1428 case sw_space_after_status
:
1431 state
= sw_status_text
;
1433 case '.': /* IIS may send 403.1, 403.2, etc */
1434 state
= sw_status_text
;
1437 state
= sw_almost_done
;
1442 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1446 /* any text until end of line */
1447 case sw_status_text
:
1450 state
= sw_almost_done
;
1458 /* end of status line */
1459 case sw_almost_done
:
1460 ctx
->status_end
= p
- 1;
1465 return NGX_HTTP_PROXY_PARSE_NO_HEADER
;
1477 u
->buffer
.pos
= p
+ 1;
1479 if (ctx
->status_end
== NULL
) {
1480 ctx
->status_end
= p
;
1483 r
->state
= sw_start
;
1490 ngx_http_proxy_process_header(ngx_http_request_t
*r
)
1494 ngx_http_upstream_header_t
*hh
;
1495 ngx_http_upstream_main_conf_t
*umcf
;
1497 umcf
= ngx_http_get_module_main_conf(r
, ngx_http_upstream_module
);
1501 rc
= ngx_http_parse_header_line(r
, &r
->upstream
->buffer
, 1);
1505 /* a header line has been parsed successfully */
1507 h
= ngx_list_push(&r
->upstream
->headers_in
.headers
);
1512 h
->hash
= r
->header_hash
;
1514 h
->key
.len
= r
->header_name_end
- r
->header_name_start
;
1515 h
->value
.len
= r
->header_end
- r
->header_start
;
1517 h
->key
.data
= ngx_pnalloc(r
->pool
,
1518 h
->key
.len
+ 1 + h
->value
.len
+ 1 + h
->key
.len
);
1519 if (h
->key
.data
== NULL
) {
1523 h
->value
.data
= h
->key
.data
+ h
->key
.len
+ 1;
1524 h
->lowcase_key
= h
->key
.data
+ h
->key
.len
+ 1 + h
->value
.len
+ 1;
1526 ngx_cpystrn(h
->key
.data
, r
->header_name_start
, h
->key
.len
+ 1);
1527 ngx_cpystrn(h
->value
.data
, r
->header_start
, h
->value
.len
+ 1);
1529 if (h
->key
.len
== r
->lowcase_index
) {
1530 ngx_memcpy(h
->lowcase_key
, r
->lowcase_header
, h
->key
.len
);
1533 ngx_strlow(h
->lowcase_key
, h
->key
.data
, h
->key
.len
);
1536 hh
= ngx_hash_find(&umcf
->headers_in_hash
, h
->hash
,
1537 h
->lowcase_key
, h
->key
.len
);
1539 if (hh
&& hh
->handler(r
, h
, hh
->offset
) != NGX_OK
) {
1543 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1544 "http proxy header: \"%V: %V\"",
1545 &h
->key
, &h
->value
);
1550 if (rc
== NGX_HTTP_PARSE_HEADER_DONE
) {
1552 /* a whole header has been parsed successfully */
1554 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1555 "http proxy header done");
1558 * if no "Server" and "Date" in header line,
1559 * then add the special empty headers
1562 if (r
->upstream
->headers_in
.server
== NULL
) {
1563 h
= ngx_list_push(&r
->upstream
->headers_in
.headers
);
1568 h
->hash
= ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1569 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1571 h
->key
.len
= sizeof("Server") - 1;
1572 h
->key
.data
= (u_char
*) "Server";
1574 h
->value
.data
= NULL
;
1575 h
->lowcase_key
= (u_char
*) "server";
1578 if (r
->upstream
->headers_in
.date
== NULL
) {
1579 h
= ngx_list_push(&r
->upstream
->headers_in
.headers
);
1584 h
->hash
= ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1586 h
->key
.len
= sizeof("Date") - 1;
1587 h
->key
.data
= (u_char
*) "Date";
1589 h
->value
.data
= NULL
;
1590 h
->lowcase_key
= (u_char
*) "date";
1596 if (rc
== NGX_AGAIN
) {
1600 /* there was error while a header line parsing */
1602 ngx_log_error(NGX_LOG_ERR
, r
->connection
->log
, 0,
1603 "upstream sent invalid header");
1605 return NGX_HTTP_UPSTREAM_INVALID_HEADER
;
1611 ngx_http_proxy_abort_request(ngx_http_request_t
*r
)
1613 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1614 "abort http proxy request");
1621 ngx_http_proxy_finalize_request(ngx_http_request_t
*r
, ngx_int_t rc
)
1623 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
1624 "finalize http proxy request");
1631 ngx_http_proxy_host_variable(ngx_http_request_t
*r
,
1632 ngx_http_variable_value_t
*v
, uintptr_t data
)
1634 ngx_http_proxy_ctx_t
*ctx
;
1636 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1643 v
->len
= ctx
->vars
.host_header
.len
;
1645 v
->no_cacheable
= 0;
1647 v
->data
= ctx
->vars
.host_header
.data
;
1654 ngx_http_proxy_port_variable(ngx_http_request_t
*r
,
1655 ngx_http_variable_value_t
*v
, uintptr_t data
)
1657 ngx_http_proxy_ctx_t
*ctx
;
1659 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1666 v
->len
= ctx
->vars
.port
.len
;
1668 v
->no_cacheable
= 0;
1670 v
->data
= ctx
->vars
.port
.data
;
1677 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t
*r
,
1678 ngx_http_variable_value_t
*v
, uintptr_t data
)
1683 v
->no_cacheable
= 0;
1686 if (r
->headers_in
.x_forwarded_for
== NULL
) {
1687 v
->len
= r
->connection
->addr_text
.len
;
1688 v
->data
= r
->connection
->addr_text
.data
;
1692 v
->len
= r
->headers_in
.x_forwarded_for
->value
.len
1693 + sizeof(", ") - 1 + r
->connection
->addr_text
.len
;
1695 p
= ngx_pnalloc(r
->pool
, v
->len
);
1702 p
= ngx_copy(p
, r
->headers_in
.x_forwarded_for
->value
.data
,
1703 r
->headers_in
.x_forwarded_for
->value
.len
);
1705 *p
++ = ','; *p
++ = ' ';
1707 ngx_memcpy(p
, r
->connection
->addr_text
.data
, r
->connection
->addr_text
.len
);
1714 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t
*r
,
1715 ngx_http_variable_value_t
*v
, uintptr_t data
)
1717 ngx_http_proxy_ctx_t
*ctx
;
1719 ctx
= ngx_http_get_module_ctx(r
, ngx_http_proxy_module
);
1727 v
->no_cacheable
= 0;
1730 v
->data
= ngx_pnalloc(r
->connection
->pool
, NGX_SIZE_T_LEN
);
1732 if (v
->data
== NULL
) {
1736 v
->len
= ngx_sprintf(v
->data
, "%uz", ctx
->internal_body_length
) - v
->data
;
1743 ngx_http_proxy_rewrite_redirect(ngx_http_request_t
*r
, ngx_table_elt_t
*h
,
1748 ngx_http_proxy_loc_conf_t
*plcf
;
1749 ngx_http_proxy_redirect_t
*pr
;
1751 plcf
= ngx_http_get_module_loc_conf(r
, ngx_http_proxy_module
);
1753 pr
= plcf
->redirects
->elts
;
1756 return NGX_DECLINED
;
1759 for (i
= 0; i
< plcf
->redirects
->nelts
; i
++) {
1760 rc
= pr
[i
].handler(r
, h
, prefix
, &pr
[i
]);
1762 if (rc
!= NGX_DECLINED
) {
1767 return NGX_DECLINED
;
1772 ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t
*r
, ngx_table_elt_t
*h
,
1773 size_t prefix
, ngx_http_proxy_redirect_t
*pr
)
1778 if (pr
->redirect
.len
> h
->value
.len
- prefix
1779 || ngx_rstrncmp(h
->value
.data
+ prefix
, pr
->redirect
.data
,
1780 pr
->redirect
.len
) != 0)
1782 return NGX_DECLINED
;
1785 len
= prefix
+ pr
->replacement
.text
.len
+ h
->value
.len
- pr
->redirect
.len
;
1787 data
= ngx_pnalloc(r
->pool
, len
);
1794 p
= ngx_copy(p
, h
->value
.data
, prefix
);
1796 if (pr
->replacement
.text
.len
) {
1797 p
= ngx_copy(p
, pr
->replacement
.text
.data
, pr
->replacement
.text
.len
);
1800 ngx_memcpy(p
, h
->value
.data
+ prefix
+ pr
->redirect
.len
,
1801 h
->value
.len
- pr
->redirect
.len
- prefix
);
1804 h
->value
.data
= data
;
1811 ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t
*r
, ngx_table_elt_t
*h
,
1812 size_t prefix
, ngx_http_proxy_redirect_t
*pr
)
1816 ngx_http_script_code_pt code
;
1817 ngx_http_script_engine_t e
;
1818 ngx_http_script_len_code_pt lcode
;
1820 if (pr
->redirect
.len
> h
->value
.len
- prefix
1821 || ngx_rstrncmp(h
->value
.data
+ prefix
, pr
->redirect
.data
,
1822 pr
->redirect
.len
) != 0)
1824 return NGX_DECLINED
;
1827 ngx_memzero(&e
, sizeof(ngx_http_script_engine_t
));
1829 e
.ip
= pr
->replacement
.vars
.lengths
;
1832 len
= prefix
+ h
->value
.len
- pr
->redirect
.len
;
1834 while (*(uintptr_t *) e
.ip
) {
1835 lcode
= *(ngx_http_script_len_code_pt
*) e
.ip
;
1839 data
= ngx_pnalloc(r
->pool
, len
);
1846 p
= ngx_copy(p
, h
->value
.data
, prefix
);
1848 e
.ip
= pr
->replacement
.vars
.values
;
1851 while (*(uintptr_t *) e
.ip
) {
1852 code
= *(ngx_http_script_code_pt
*) e
.ip
;
1856 ngx_memcpy(e
.pos
, h
->value
.data
+ prefix
+ pr
->redirect
.len
,
1857 h
->value
.len
- pr
->redirect
.len
- prefix
);
1860 h
->value
.data
= data
;
1867 ngx_http_proxy_add_variables(ngx_conf_t
*cf
)
1869 ngx_http_variable_t
*var
, *v
;
1871 for (v
= ngx_http_proxy_vars
; v
->name
.len
; v
++) {
1872 var
= ngx_http_add_variable(cf
, &v
->name
, v
->flags
);
1877 var
->get_handler
= v
->get_handler
;
1878 var
->data
= v
->data
;
1886 ngx_http_proxy_create_loc_conf(ngx_conf_t
*cf
)
1888 ngx_http_proxy_loc_conf_t
*conf
;
1890 conf
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_proxy_loc_conf_t
));
1896 * set by ngx_pcalloc():
1898 * conf->upstream.bufs.num = 0;
1899 * conf->upstream.ignore_headers = 0;
1900 * conf->upstream.next_upstream = 0;
1901 * conf->upstream.cache_use_stale = 0;
1902 * conf->upstream.cache_methods = 0;
1903 * conf->upstream.temp_path = NULL;
1904 * conf->upstream.hide_headers_hash = { NULL, 0 };
1905 * conf->upstream.uri = { 0, NULL };
1906 * conf->upstream.location = NULL;
1907 * conf->upstream.store_lengths = NULL;
1908 * conf->upstream.store_values = NULL;
1910 * conf->method = NULL;
1911 * conf->headers_source = NULL;
1912 * conf->headers_set_len = NULL;
1913 * conf->headers_set = NULL;
1914 * conf->headers_set_hash = NULL;
1915 * conf->body_set_len = NULL;
1916 * conf->body_set = NULL;
1917 * conf->body_source = { 0, NULL };
1918 * conf->redirects = NULL;
1921 conf
->upstream
.store
= NGX_CONF_UNSET
;
1922 conf
->upstream
.store_access
= NGX_CONF_UNSET_UINT
;
1923 conf
->upstream
.buffering
= NGX_CONF_UNSET
;
1924 conf
->upstream
.ignore_client_abort
= NGX_CONF_UNSET
;
1926 conf
->upstream
.connect_timeout
= NGX_CONF_UNSET_MSEC
;
1927 conf
->upstream
.send_timeout
= NGX_CONF_UNSET_MSEC
;
1928 conf
->upstream
.read_timeout
= NGX_CONF_UNSET_MSEC
;
1930 conf
->upstream
.send_lowat
= NGX_CONF_UNSET_SIZE
;
1931 conf
->upstream
.buffer_size
= NGX_CONF_UNSET_SIZE
;
1933 conf
->upstream
.busy_buffers_size_conf
= NGX_CONF_UNSET_SIZE
;
1934 conf
->upstream
.max_temp_file_size_conf
= NGX_CONF_UNSET_SIZE
;
1935 conf
->upstream
.temp_file_write_size_conf
= NGX_CONF_UNSET_SIZE
;
1937 conf
->upstream
.pass_request_headers
= NGX_CONF_UNSET
;
1938 conf
->upstream
.pass_request_body
= NGX_CONF_UNSET
;
1940 #if (NGX_HTTP_CACHE)
1941 conf
->upstream
.cache
= NGX_CONF_UNSET_PTR
;
1942 conf
->upstream
.cache_min_uses
= NGX_CONF_UNSET_UINT
;
1943 conf
->upstream
.cache_valid
= NGX_CONF_UNSET_PTR
;
1946 conf
->upstream
.hide_headers
= NGX_CONF_UNSET_PTR
;
1947 conf
->upstream
.pass_headers
= NGX_CONF_UNSET_PTR
;
1949 conf
->upstream
.intercept_errors
= NGX_CONF_UNSET
;
1951 conf
->upstream
.ssl_session_reuse
= NGX_CONF_UNSET
;
1954 /* "proxy_cyclic_temp_file" is disabled */
1955 conf
->upstream
.cyclic_temp_file
= 0;
1957 conf
->redirect
= NGX_CONF_UNSET
;
1958 conf
->upstream
.change_buffering
= 1;
1960 conf
->headers_hash_max_size
= NGX_CONF_UNSET_UINT
;
1961 conf
->headers_hash_bucket_size
= NGX_CONF_UNSET_UINT
;
1968 ngx_http_proxy_merge_loc_conf(ngx_conf_t
*cf
, void *parent
, void *child
)
1970 ngx_http_proxy_loc_conf_t
*prev
= parent
;
1971 ngx_http_proxy_loc_conf_t
*conf
= child
;
1976 ngx_hash_init_t hash
;
1977 ngx_http_proxy_redirect_t
*pr
;
1978 ngx_http_script_compile_t sc
;
1980 if (conf
->upstream
.store
!= 0) {
1981 ngx_conf_merge_value(conf
->upstream
.store
,
1982 prev
->upstream
.store
, 0);
1984 if (conf
->upstream
.store_lengths
== NULL
) {
1985 conf
->upstream
.store_lengths
= prev
->upstream
.store_lengths
;
1986 conf
->upstream
.store_values
= prev
->upstream
.store_values
;
1990 ngx_conf_merge_uint_value(conf
->upstream
.store_access
,
1991 prev
->upstream
.store_access
, 0600);
1993 ngx_conf_merge_value(conf
->upstream
.buffering
,
1994 prev
->upstream
.buffering
, 1);
1996 ngx_conf_merge_value(conf
->upstream
.ignore_client_abort
,
1997 prev
->upstream
.ignore_client_abort
, 0);
1999 ngx_conf_merge_msec_value(conf
->upstream
.connect_timeout
,
2000 prev
->upstream
.connect_timeout
, 60000);
2002 ngx_conf_merge_msec_value(conf
->upstream
.send_timeout
,
2003 prev
->upstream
.send_timeout
, 60000);
2005 ngx_conf_merge_msec_value(conf
->upstream
.read_timeout
,
2006 prev
->upstream
.read_timeout
, 60000);
2008 ngx_conf_merge_size_value(conf
->upstream
.send_lowat
,
2009 prev
->upstream
.send_lowat
, 0);
2011 ngx_conf_merge_size_value(conf
->upstream
.buffer_size
,
2012 prev
->upstream
.buffer_size
,
2013 (size_t) ngx_pagesize
);
2015 ngx_conf_merge_bufs_value(conf
->upstream
.bufs
, prev
->upstream
.bufs
,
2018 if (conf
->upstream
.bufs
.num
< 2) {
2019 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2020 "there must be at least 2 \"proxy_buffers\"");
2021 return NGX_CONF_ERROR
;
2025 size
= conf
->upstream
.buffer_size
;
2026 if (size
< conf
->upstream
.bufs
.size
) {
2027 size
= conf
->upstream
.bufs
.size
;
2031 ngx_conf_merge_size_value(conf
->upstream
.busy_buffers_size_conf
,
2032 prev
->upstream
.busy_buffers_size_conf
,
2033 NGX_CONF_UNSET_SIZE
);
2035 if (conf
->upstream
.busy_buffers_size_conf
== NGX_CONF_UNSET_SIZE
) {
2036 conf
->upstream
.busy_buffers_size
= 2 * size
;
2038 conf
->upstream
.busy_buffers_size
=
2039 conf
->upstream
.busy_buffers_size_conf
;
2042 if (conf
->upstream
.busy_buffers_size
< size
) {
2043 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2044 "\"proxy_busy_buffers_size\" must be equal or bigger than "
2045 "maximum of the value of \"proxy_buffer_size\" and "
2046 "one of the \"proxy_buffers\"");
2048 return NGX_CONF_ERROR
;
2051 if (conf
->upstream
.busy_buffers_size
2052 > (conf
->upstream
.bufs
.num
- 1) * conf
->upstream
.bufs
.size
)
2054 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2055 "\"proxy_busy_buffers_size\" must be less than "
2056 "the size of all \"proxy_buffers\" minus one buffer");
2058 return NGX_CONF_ERROR
;
2062 ngx_conf_merge_size_value(conf
->upstream
.temp_file_write_size_conf
,
2063 prev
->upstream
.temp_file_write_size_conf
,
2064 NGX_CONF_UNSET_SIZE
);
2066 if (conf
->upstream
.temp_file_write_size_conf
== NGX_CONF_UNSET_SIZE
) {
2067 conf
->upstream
.temp_file_write_size
= 2 * size
;
2069 conf
->upstream
.temp_file_write_size
=
2070 conf
->upstream
.temp_file_write_size_conf
;
2073 if (conf
->upstream
.temp_file_write_size
< size
) {
2074 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2075 "\"proxy_temp_file_write_size\" must be equal or bigger than "
2076 "maximum of the value of \"proxy_buffer_size\" and "
2077 "one of the \"proxy_buffers\"");
2079 return NGX_CONF_ERROR
;
2082 ngx_conf_merge_size_value(conf
->upstream
.max_temp_file_size_conf
,
2083 prev
->upstream
.max_temp_file_size_conf
,
2084 NGX_CONF_UNSET_SIZE
);
2086 if (conf
->upstream
.max_temp_file_size_conf
== NGX_CONF_UNSET_SIZE
) {
2087 conf
->upstream
.max_temp_file_size
= 1024 * 1024 * 1024;
2089 conf
->upstream
.max_temp_file_size
=
2090 conf
->upstream
.max_temp_file_size_conf
;
2093 if (conf
->upstream
.max_temp_file_size
!= 0
2094 && conf
->upstream
.max_temp_file_size
< size
)
2096 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2097 "\"proxy_max_temp_file_size\" must be equal to zero to disable "
2098 "the temporary files usage or must be equal or bigger than "
2099 "maximum of the value of \"proxy_buffer_size\" and "
2100 "one of the \"proxy_buffers\"");
2102 return NGX_CONF_ERROR
;
2106 ngx_conf_merge_bitmask_value(conf
->upstream
.ignore_headers
,
2107 prev
->upstream
.ignore_headers
,
2108 NGX_CONF_BITMASK_SET
);
2111 ngx_conf_merge_bitmask_value(conf
->upstream
.next_upstream
,
2112 prev
->upstream
.next_upstream
,
2113 (NGX_CONF_BITMASK_SET
2114 |NGX_HTTP_UPSTREAM_FT_ERROR
2115 |NGX_HTTP_UPSTREAM_FT_TIMEOUT
));
2117 if (conf
->upstream
.next_upstream
& NGX_HTTP_UPSTREAM_FT_OFF
) {
2118 conf
->upstream
.next_upstream
= NGX_CONF_BITMASK_SET
2119 |NGX_HTTP_UPSTREAM_FT_OFF
;
2122 if (ngx_conf_merge_path_value(cf
, &conf
->upstream
.temp_path
,
2123 prev
->upstream
.temp_path
,
2124 &ngx_http_proxy_temp_path
)
2127 return NGX_CONF_ERROR
;
2131 #if (NGX_HTTP_CACHE)
2133 ngx_conf_merge_ptr_value(conf
->upstream
.cache
,
2134 prev
->upstream
.cache
, NULL
);
2136 if (conf
->upstream
.cache
&& conf
->upstream
.cache
->data
== NULL
) {
2137 ngx_shm_zone_t
*shm_zone
;
2139 shm_zone
= conf
->upstream
.cache
;
2141 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2142 "\"proxy_cache\" zone \"%V\" is unknown",
2143 &shm_zone
->shm
.name
);
2145 return NGX_CONF_ERROR
;
2148 ngx_conf_merge_uint_value(conf
->upstream
.cache_min_uses
,
2149 prev
->upstream
.cache_min_uses
, 1);
2151 ngx_conf_merge_bitmask_value(conf
->upstream
.cache_use_stale
,
2152 prev
->upstream
.cache_use_stale
,
2153 (NGX_CONF_BITMASK_SET
2154 |NGX_HTTP_UPSTREAM_FT_OFF
));
2156 if (conf
->upstream
.cache_methods
== 0) {
2157 conf
->upstream
.cache_methods
= prev
->upstream
.cache_methods
;
2160 conf
->upstream
.cache_methods
|= NGX_HTTP_GET
|NGX_HTTP_HEAD
;
2162 if (conf
->upstream
.cache_use_stale
& NGX_HTTP_UPSTREAM_FT_OFF
) {
2163 conf
->upstream
.cache_use_stale
= NGX_CONF_BITMASK_SET
2164 |NGX_HTTP_UPSTREAM_FT_OFF
;
2167 ngx_conf_merge_ptr_value(conf
->upstream
.cache_valid
,
2168 prev
->upstream
.cache_valid
, NULL
);
2170 if (conf
->cache_key
.value
.data
== NULL
) {
2171 conf
->cache_key
= prev
->cache_key
;
2176 if (conf
->method
.len
== 0) {
2177 conf
->method
= prev
->method
;
2180 conf
->method
.data
[conf
->method
.len
] = ' ';
2184 ngx_conf_merge_value(conf
->upstream
.pass_request_headers
,
2185 prev
->upstream
.pass_request_headers
, 1);
2186 ngx_conf_merge_value(conf
->upstream
.pass_request_body
,
2187 prev
->upstream
.pass_request_body
, 1);
2189 ngx_conf_merge_value(conf
->upstream
.intercept_errors
,
2190 prev
->upstream
.intercept_errors
, 0);
2193 ngx_conf_merge_value(conf
->upstream
.ssl_session_reuse
,
2194 prev
->upstream
.ssl_session_reuse
, 1);
2197 ngx_conf_merge_value(conf
->redirect
, prev
->redirect
, 1);
2199 if (conf
->redirect
) {
2201 if (conf
->redirects
== NULL
) {
2202 conf
->redirects
= prev
->redirects
;
2205 if (conf
->redirects
== NULL
&& conf
->url
.data
) {
2207 conf
->redirects
= ngx_array_create(cf
->pool
, 1,
2208 sizeof(ngx_http_proxy_redirect_t
));
2209 if (conf
->redirects
== NULL
) {
2210 return NGX_CONF_ERROR
;
2213 pr
= ngx_array_push(conf
->redirects
);
2215 return NGX_CONF_ERROR
;
2218 pr
->handler
= ngx_http_proxy_rewrite_redirect_text
;
2219 pr
->redirect
= conf
->url
;
2221 if (conf
->vars
.uri
.len
) {
2222 pr
->replacement
.text
= conf
->location
;
2225 pr
->replacement
.text
.len
= 0;
2226 pr
->replacement
.text
.data
= NULL
;
2232 if (prev
->proxy_lengths
) {
2233 conf
->proxy_lengths
= prev
->proxy_lengths
;
2234 conf
->proxy_values
= prev
->proxy_values
;
2238 if (conf
->upstream
.ssl
== NULL
) {
2239 conf
->upstream
.ssl
= prev
->upstream
.ssl
;
2243 ngx_conf_merge_uint_value(conf
->headers_hash_max_size
,
2244 prev
->headers_hash_max_size
, 512);
2246 ngx_conf_merge_uint_value(conf
->headers_hash_bucket_size
,
2247 prev
->headers_hash_bucket_size
, 64);
2249 conf
->headers_hash_bucket_size
= ngx_align(conf
->headers_hash_bucket_size
,
2250 ngx_cacheline_size
);
2252 hash
.max_size
= conf
->headers_hash_max_size
;
2253 hash
.bucket_size
= conf
->headers_hash_bucket_size
;
2254 hash
.name
= "proxy_headers_hash";
2256 #if (NGX_HTTP_CACHE)
2258 h
= conf
->upstream
.cache
? ngx_http_proxy_hide_cache_headers
:
2259 ngx_http_proxy_hide_headers
;
2262 h
= ngx_http_proxy_hide_headers
;
2266 if (ngx_http_upstream_hide_headers_hash(cf
, &conf
->upstream
,
2267 &prev
->upstream
, h
, &hash
)
2270 return NGX_CONF_ERROR
;
2273 if (conf
->upstream
.upstream
== NULL
) {
2274 conf
->upstream
.upstream
= prev
->upstream
.upstream
;
2275 conf
->vars
= prev
->vars
;
2279 if (conf
->body_source
.data
== NULL
) {
2280 conf
->body_source
= prev
->body_source
;
2281 conf
->body_set_len
= prev
->body_set_len
;
2282 conf
->body_set
= prev
->body_set
;
2285 if (conf
->body_source
.data
&& conf
->body_set_len
== NULL
) {
2287 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
2290 sc
.source
= &conf
->body_source
;
2291 sc
.flushes
= &conf
->flushes
;
2292 sc
.lengths
= &conf
->body_set_len
;
2293 sc
.values
= &conf
->body_set
;
2294 sc
.complete_lengths
= 1;
2295 sc
.complete_values
= 1;
2297 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
2298 return NGX_CONF_ERROR
;
2301 if (conf
->headers_source
== NULL
) {
2302 conf
->headers_source
= ngx_array_create(cf
->pool
, 4,
2303 sizeof(ngx_keyval_t
));
2304 if (conf
->headers_source
== NULL
) {
2305 return NGX_CONF_ERROR
;
2309 s
= ngx_array_push(conf
->headers_source
);
2311 return NGX_CONF_ERROR
;
2314 s
->key
.len
= sizeof("Content-Length") - 1;
2315 s
->key
.data
= (u_char
*) "Content-Length";
2316 s
->value
.len
= sizeof("$proxy_internal_body_length") - 1;
2317 s
->value
.data
= (u_char
*) "$proxy_internal_body_length";
2320 if (ngx_http_proxy_merge_headers(cf
, conf
, prev
) != NGX_OK
) {
2321 return NGX_CONF_ERROR
;
2329 ngx_http_proxy_merge_headers(ngx_conf_t
*cf
, ngx_http_proxy_loc_conf_t
*conf
,
2330 ngx_http_proxy_loc_conf_t
*prev
)
2336 ngx_keyval_t
*src
, *s
, *h
;
2338 ngx_hash_init_t hash
;
2339 ngx_http_script_compile_t sc
;
2340 ngx_http_script_copy_code_t
*copy
;
2342 if (conf
->headers_source
== NULL
) {
2343 conf
->flushes
= prev
->flushes
;
2344 conf
->headers_set_len
= prev
->headers_set_len
;
2345 conf
->headers_set
= prev
->headers_set
;
2346 conf
->headers_set_hash
= prev
->headers_set_hash
;
2347 conf
->headers_source
= prev
->headers_source
;
2350 if (conf
->headers_set_hash
.buckets
2351 #if (NGX_HTTP_CACHE)
2352 && ((conf
->upstream
.cache
== NULL
) == (prev
->upstream
.cache
== NULL
))
2360 conf
->headers_names
= ngx_array_create(cf
->pool
, 4, sizeof(ngx_hash_key_t
));
2361 if (conf
->headers_names
== NULL
) {
2365 if (conf
->headers_source
== NULL
) {
2366 conf
->headers_source
= ngx_array_create(cf
->pool
, 4,
2367 sizeof(ngx_keyval_t
));
2368 if (conf
->headers_source
== NULL
) {
2373 conf
->headers_set_len
= ngx_array_create(cf
->pool
, 64, 1);
2374 if (conf
->headers_set_len
== NULL
) {
2378 conf
->headers_set
= ngx_array_create(cf
->pool
, 512, 1);
2379 if (conf
->headers_set
== NULL
) {
2384 src
= conf
->headers_source
->elts
;
2386 #if (NGX_HTTP_CACHE)
2388 h
= conf
->upstream
.cache
? ngx_http_proxy_cache_headers
:
2389 ngx_http_proxy_headers
;
2392 h
= ngx_http_proxy_headers
;
2396 while (h
->key
.len
) {
2398 for (i
= 0; i
< conf
->headers_source
->nelts
; i
++) {
2399 if (ngx_strcasecmp(h
->key
.data
, src
[i
].key
.data
) == 0) {
2404 s
= ngx_array_push(conf
->headers_source
);
2411 src
= conf
->headers_source
->elts
;
2419 src
= conf
->headers_source
->elts
;
2420 for (i
= 0; i
< conf
->headers_source
->nelts
; i
++) {
2422 hk
= ngx_array_push(conf
->headers_names
);
2427 hk
->key
= src
[i
].key
;
2428 hk
->key_hash
= ngx_hash_key_lc(src
[i
].key
.data
, src
[i
].key
.len
);
2429 hk
->value
= (void *) 1;
2431 if (src
[i
].value
.len
== 0) {
2435 if (ngx_http_script_variables_count(&src
[i
].value
) == 0) {
2436 copy
= ngx_array_push_n(conf
->headers_set_len
,
2437 sizeof(ngx_http_script_copy_code_t
));
2442 copy
->code
= (ngx_http_script_code_pt
)
2443 ngx_http_script_copy_len_code
;
2444 copy
->len
= src
[i
].key
.len
+ sizeof(": ") - 1
2445 + src
[i
].value
.len
+ sizeof(CRLF
) - 1;
2448 size
= (sizeof(ngx_http_script_copy_code_t
)
2449 + src
[i
].key
.len
+ sizeof(": ") - 1
2450 + src
[i
].value
.len
+ sizeof(CRLF
) - 1
2451 + sizeof(uintptr_t) - 1)
2452 & ~(sizeof(uintptr_t) - 1);
2454 copy
= ngx_array_push_n(conf
->headers_set
, size
);
2459 copy
->code
= ngx_http_script_copy_code
;
2460 copy
->len
= src
[i
].key
.len
+ sizeof(": ") - 1
2461 + src
[i
].value
.len
+ sizeof(CRLF
) - 1;
2463 p
= (u_char
*) copy
+ sizeof(ngx_http_script_copy_code_t
);
2465 p
= ngx_cpymem(p
, src
[i
].key
.data
, src
[i
].key
.len
);
2466 *p
++ = ':'; *p
++ = ' ';
2467 p
= ngx_cpymem(p
, src
[i
].value
.data
, src
[i
].value
.len
);
2471 copy
= ngx_array_push_n(conf
->headers_set_len
,
2472 sizeof(ngx_http_script_copy_code_t
));
2477 copy
->code
= (ngx_http_script_code_pt
)
2478 ngx_http_script_copy_len_code
;
2479 copy
->len
= src
[i
].key
.len
+ sizeof(": ") - 1;
2482 size
= (sizeof(ngx_http_script_copy_code_t
)
2483 + src
[i
].key
.len
+ sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
2484 & ~(sizeof(uintptr_t) - 1);
2486 copy
= ngx_array_push_n(conf
->headers_set
, size
);
2491 copy
->code
= ngx_http_script_copy_code
;
2492 copy
->len
= src
[i
].key
.len
+ sizeof(": ") - 1;
2494 p
= (u_char
*) copy
+ sizeof(ngx_http_script_copy_code_t
);
2495 p
= ngx_cpymem(p
, src
[i
].key
.data
, src
[i
].key
.len
);
2496 *p
++ = ':'; *p
= ' ';
2499 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
2502 sc
.source
= &src
[i
].value
;
2503 sc
.flushes
= &conf
->flushes
;
2504 sc
.lengths
= &conf
->headers_set_len
;
2505 sc
.values
= &conf
->headers_set
;
2507 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
2512 copy
= ngx_array_push_n(conf
->headers_set_len
,
2513 sizeof(ngx_http_script_copy_code_t
));
2518 copy
->code
= (ngx_http_script_code_pt
)
2519 ngx_http_script_copy_len_code
;
2520 copy
->len
= sizeof(CRLF
) - 1;
2523 size
= (sizeof(ngx_http_script_copy_code_t
)
2524 + sizeof(CRLF
) - 1 + sizeof(uintptr_t) - 1)
2525 & ~(sizeof(uintptr_t) - 1);
2527 copy
= ngx_array_push_n(conf
->headers_set
, size
);
2532 copy
->code
= ngx_http_script_copy_code
;
2533 copy
->len
= sizeof(CRLF
) - 1;
2535 p
= (u_char
*) copy
+ sizeof(ngx_http_script_copy_code_t
);
2539 code
= ngx_array_push_n(conf
->headers_set_len
, sizeof(uintptr_t));
2544 *code
= (uintptr_t) NULL
;
2546 code
= ngx_array_push_n(conf
->headers_set
, sizeof(uintptr_t));
2551 *code
= (uintptr_t) NULL
;
2554 code
= ngx_array_push_n(conf
->headers_set_len
, sizeof(uintptr_t));
2559 *code
= (uintptr_t) NULL
;
2562 hash
.hash
= &conf
->headers_set_hash
;
2563 hash
.key
= ngx_hash_key_lc
;
2564 hash
.max_size
= conf
->headers_hash_max_size
;
2565 hash
.bucket_size
= conf
->headers_hash_bucket_size
;
2566 hash
.name
= "proxy_headers_hash";
2567 hash
.pool
= cf
->pool
;
2568 hash
.temp_pool
= NULL
;
2570 if (ngx_hash_init(&hash
, conf
->headers_names
->elts
,
2571 conf
->headers_names
->nelts
)
2582 ngx_http_proxy_pass(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
2584 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
2588 ngx_str_t
*value
, *url
;
2591 ngx_http_core_loc_conf_t
*clcf
;
2592 ngx_http_script_compile_t sc
;
2594 if (plcf
->upstream
.upstream
|| plcf
->proxy_lengths
) {
2595 return "is duplicate";
2598 clcf
= ngx_http_conf_get_module_loc_conf(cf
, ngx_http_core_module
);
2600 clcf
->handler
= ngx_http_proxy_handler
;
2602 if (clcf
->name
.data
[clcf
->name
.len
- 1] == '/') {
2603 clcf
->auto_redirect
= 1;
2606 value
= cf
->args
->elts
;
2610 n
= ngx_http_script_variables_count(url
);
2614 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
2618 sc
.lengths
= &plcf
->proxy_lengths
;
2619 sc
.values
= &plcf
->proxy_values
;
2621 sc
.complete_lengths
= 1;
2622 sc
.complete_values
= 1;
2624 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
2625 return NGX_CONF_ERROR
;
2629 if (ngx_http_proxy_set_ssl(cf
, plcf
) != NGX_OK
) {
2630 return NGX_CONF_ERROR
;
2637 if (ngx_strncasecmp(url
->data
, (u_char
*) "http://", 7) == 0) {
2641 } else if (ngx_strncasecmp(url
->data
, (u_char
*) "https://", 8) == 0) {
2644 if (ngx_http_proxy_set_ssl(cf
, plcf
) != NGX_OK
) {
2645 return NGX_CONF_ERROR
;
2651 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2652 "https protocol requires SSL support");
2653 return NGX_CONF_ERROR
;
2657 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0, "invalid URL prefix");
2658 return NGX_CONF_ERROR
;
2661 ngx_memzero(&u
, sizeof(ngx_url_t
));
2663 u
.url
.len
= url
->len
- add
;
2664 u
.url
.data
= url
->data
+ add
;
2665 u
.default_port
= port
;
2669 plcf
->upstream
.upstream
= ngx_http_upstream_add(cf
, &u
, 0);
2670 if (plcf
->upstream
.upstream
== NULL
) {
2671 return NGX_CONF_ERROR
;
2674 plcf
->vars
.schema
.len
= add
;
2675 plcf
->vars
.schema
.data
= url
->data
;
2676 plcf
->vars
.key_start
= plcf
->vars
.schema
;
2678 ngx_http_proxy_set_vars(&u
, &plcf
->vars
);
2680 plcf
->location
= clcf
->name
;
2688 if (plcf
->vars
.uri
.len
) {
2689 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2690 "\"proxy_pass\" may not have URI part in "
2691 "location given by regular expression, "
2692 "or inside named location, "
2693 "or inside the \"if\" statement, "
2694 "or inside the \"limit_except\" block");
2695 return NGX_CONF_ERROR
;
2698 plcf
->location
.len
= 0;
2708 ngx_http_proxy_redirect(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
2710 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
2713 ngx_array_t
*vars_lengths
, *vars_values
;
2714 ngx_http_script_compile_t sc
;
2715 ngx_http_proxy_redirect_t
*pr
;
2717 if (plcf
->redirect
== 0) {
2721 value
= cf
->args
->elts
;
2723 if (cf
->args
->nelts
== 2) {
2724 if (ngx_strcmp(value
[1].data
, "off") == 0) {
2726 plcf
->redirects
= NULL
;
2730 if (ngx_strcmp(value
[1].data
, "false") == 0) {
2731 ngx_conf_log_error(NGX_LOG_ERR
, cf
, 0,
2732 "invalid parameter \"false\", use \"off\" instead");
2734 plcf
->redirects
= NULL
;
2738 if (ngx_strcmp(value
[1].data
, "default") != 0) {
2739 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2740 "invalid parameter \"%V\"", &value
[1]);
2741 return NGX_CONF_ERROR
;
2745 if (plcf
->redirects
== NULL
) {
2746 plcf
->redirects
= ngx_array_create(cf
->pool
, 1,
2747 sizeof(ngx_http_proxy_redirect_t
));
2748 if (plcf
->redirects
== NULL
) {
2749 return NGX_CONF_ERROR
;
2753 pr
= ngx_array_push(plcf
->redirects
);
2755 return NGX_CONF_ERROR
;
2758 if (ngx_strcmp(value
[1].data
, "default") == 0) {
2759 if (plcf
->proxy_lengths
) {
2760 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2761 "\"proxy_redirect default\" may not be used "
2762 "with \"proxy_pass\" directive with variables");
2763 return NGX_CONF_ERROR
;
2766 if (plcf
->url
.data
== NULL
) {
2767 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2768 "\"proxy_redirect default\" must go "
2769 "after the \"proxy_pass\" directive");
2770 return NGX_CONF_ERROR
;
2773 pr
->handler
= ngx_http_proxy_rewrite_redirect_text
;
2774 pr
->redirect
= plcf
->url
;
2776 if (plcf
->vars
.uri
.len
) {
2777 pr
->replacement
.text
= plcf
->location
;
2780 pr
->replacement
.text
.len
= 0;
2781 pr
->replacement
.text
.data
= NULL
;
2787 if (ngx_http_script_variables_count(&value
[2]) == 0) {
2788 pr
->handler
= ngx_http_proxy_rewrite_redirect_text
;
2789 pr
->redirect
= value
[1];
2790 pr
->replacement
.text
= value
[2];
2795 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
2797 vars_lengths
= NULL
;
2801 sc
.source
= &value
[2];
2802 sc
.lengths
= &vars_lengths
;
2803 sc
.values
= &vars_values
;
2804 sc
.complete_lengths
= 1;
2805 sc
.complete_values
= 1;
2807 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
2808 return NGX_CONF_ERROR
;
2811 pr
->handler
= ngx_http_proxy_rewrite_redirect_vars
;
2812 pr
->redirect
= value
[1];
2813 pr
->replacement
.vars
.lengths
= vars_lengths
->elts
;
2814 pr
->replacement
.vars
.values
= vars_values
->elts
;
2821 ngx_http_proxy_store(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
2823 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
2826 ngx_http_script_compile_t sc
;
2828 if (plcf
->upstream
.store
!= NGX_CONF_UNSET
2829 || plcf
->upstream
.store_lengths
)
2831 return "is duplicate";
2834 value
= cf
->args
->elts
;
2836 if (ngx_strcmp(value
[1].data
, "off") == 0) {
2837 plcf
->upstream
.store
= 0;
2841 #if (NGX_HTTP_CACHE)
2843 if (plcf
->upstream
.cache
!= NGX_CONF_UNSET_PTR
2844 && plcf
->upstream
.cache
!= NULL
)
2846 return "is incompatible with \"proxy_cache\"";
2851 if (ngx_strcmp(value
[1].data
, "on") == 0) {
2852 plcf
->upstream
.store
= 1;
2856 /* include the terminating '\0' into script */
2859 ngx_memzero(&sc
, sizeof(ngx_http_script_compile_t
));
2862 sc
.source
= &value
[1];
2863 sc
.lengths
= &plcf
->upstream
.store_lengths
;
2864 sc
.values
= &plcf
->upstream
.store_values
;
2865 sc
.variables
= ngx_http_script_variables_count(&value
[1]);
2866 sc
.complete_lengths
= 1;
2867 sc
.complete_values
= 1;
2869 if (ngx_http_script_compile(&sc
) != NGX_OK
) {
2870 return NGX_CONF_ERROR
;
2877 #if (NGX_HTTP_CACHE)
2880 ngx_http_proxy_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
2882 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
2886 value
= cf
->args
->elts
;
2888 if (plcf
->upstream
.cache
!= NGX_CONF_UNSET_PTR
) {
2889 return "is duplicate";
2892 if (ngx_strcmp(value
[1].data
, "off") == 0) {
2893 plcf
->upstream
.cache
= NULL
;
2897 if (plcf
->upstream
.store
> 0 || plcf
->upstream
.store_lengths
) {
2898 return "is incompatible with \"proxy_store\"";
2901 plcf
->upstream
.cache
= ngx_shared_memory_add(cf
, &value
[1], 0,
2902 &ngx_http_proxy_module
);
2903 if (plcf
->upstream
.cache
== NULL
) {
2904 return NGX_CONF_ERROR
;
2912 ngx_http_proxy_cache_key(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
2914 ngx_http_proxy_loc_conf_t
*plcf
= conf
;
2917 ngx_http_compile_complex_value_t ccv
;
2919 value
= cf
->args
->elts
;
2921 if (plcf
->cache_key
.value
.len
) {
2922 return "is duplicate";
2925 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
2928 ccv
.value
= &value
[1];
2929 ccv
.complex_value
= &plcf
->cache_key
;
2931 if (ngx_http_compile_complex_value(&ccv
) != NGX_OK
) {
2932 return NGX_CONF_ERROR
;
2942 ngx_http_proxy_lowat_check(ngx_conf_t
*cf
, void *post
, void *data
)
2947 if ((u_long
) *np
>= ngx_freebsd_net_inet_tcp_sendspace
) {
2948 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2949 "\"proxy_send_lowat\" must be less than %d "
2950 "(sysctl net.inet.tcp.sendspace)",
2951 ngx_freebsd_net_inet_tcp_sendspace
);
2953 return NGX_CONF_ERROR
;
2956 #elif !(NGX_HAVE_SO_SNDLOWAT)
2959 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
2960 "\"proxy_send_lowat\" is not supported, ignored");
2971 ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t
*cf
,
2972 ngx_command_t
*cmd
, void *conf
)
2974 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2975 "\"proxy_upstream_max_fails\" is not supported, "
2976 "use the \"max_fails\" parameter of the \"server\" directive ",
2977 "inside the \"upstream\" block");
2979 return NGX_CONF_ERROR
;
2984 ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t
*cf
,
2985 ngx_command_t
*cmd
, void *conf
)
2987 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
2988 "\"proxy_upstream_fail_timeout\" is not supported, "
2989 "use the \"fail_timeout\" parameter of the \"server\" directive ",
2990 "inside the \"upstream\" block");
2992 return NGX_CONF_ERROR
;
2999 ngx_http_proxy_set_ssl(ngx_conf_t
*cf
, ngx_http_proxy_loc_conf_t
*plcf
)
3001 ngx_pool_cleanup_t
*cln
;
3003 plcf
->upstream
.ssl
= ngx_pcalloc(cf
->pool
, sizeof(ngx_ssl_t
));
3004 if (plcf
->upstream
.ssl
== NULL
) {
3008 plcf
->upstream
.ssl
->log
= cf
->log
;
3010 if (ngx_ssl_create(plcf
->upstream
.ssl
,
3011 NGX_SSL_SSLv2
|NGX_SSL_SSLv3
|NGX_SSL_TLSv1
, NULL
)
3017 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
3022 cln
->handler
= ngx_ssl_cleanup_ctx
;
3023 cln
->data
= plcf
->upstream
.ssl
;
3032 ngx_http_proxy_set_vars(ngx_url_t
*u
, ngx_http_proxy_vars_t
*v
)
3034 if (u
->family
!= AF_UNIX
) {
3036 if (u
->no_port
|| u
->port
== u
->default_port
) {
3038 v
->host_header
= u
->host
;
3040 if (u
->default_port
== 80) {
3041 v
->port
.len
= sizeof("80") - 1;
3042 v
->port
.data
= (u_char
*) "80";
3045 v
->port
.len
= sizeof("443") - 1;
3046 v
->port
.data
= (u_char
*) "443";
3050 v
->host_header
.len
= u
->host
.len
+ 1 + u
->port_text
.len
;
3051 v
->host_header
.data
= u
->host
.data
;
3052 v
->port
= u
->port_text
;
3055 v
->key_start
.len
+= v
->host_header
.len
;
3058 v
->host_header
.len
= sizeof("localhost") - 1;
3059 v
->host_header
.data
= (u_char
*) "localhost";
3061 v
->port
.data
= (u_char
*) "";
3062 v
->key_start
.len
+= sizeof("unix:") - 1 + u
->host
.len
+ 1;