1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11
12
13 typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
14
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);
18
19 struct ngx_http_proxy_rewrite_s {
20 ngx_http_proxy_rewrite_pt handler;
21
22 union {
23 ngx_http_complex_value_t complex;
24 #if (NGX_PCRE)
25 ngx_http_regex_t *regex;
26 #endif
27 } pattern;
28
29 ngx_http_complex_value_t replacement;
30 };
31
32
33 typedef struct {
34 ngx_str_t key_start;
35 ngx_str_t schema;
36 ngx_str_t host_header;
37 ngx_str_t port;
38 ngx_str_t uri;
39 } ngx_http_proxy_vars_t;
40
41
42 typedef struct {
43 ngx_http_upstream_conf_t upstream;
44
45 ngx_array_t *flushes;
46 ngx_array_t *body_set_len;
47 ngx_array_t *body_set;
48 ngx_array_t *headers_set_len;
49 ngx_array_t *headers_set;
50 ngx_hash_t headers_set_hash;
51
52 ngx_array_t *headers_source;
53
54 ngx_array_t *proxy_lengths;
55 ngx_array_t *proxy_values;
56
57 ngx_array_t *redirects;
58 ngx_array_t *cookie_domains;
59 ngx_array_t *cookie_paths;
60
61 ngx_str_t body_source;
62
63 ngx_str_t method;
64 ngx_str_t location;
65 ngx_str_t url;
66
67 #if (NGX_HTTP_CACHE)
68 ngx_http_complex_value_t cache_key;
69 #endif
70
71 ngx_http_proxy_vars_t vars;
72
73 ngx_flag_t redirect;
74
75 ngx_uint_t http_version;
76
77 ngx_uint_t headers_hash_max_size;
78 ngx_uint_t headers_hash_bucket_size;
79 } ngx_http_proxy_loc_conf_t;
80
81
82 typedef struct {
83 ngx_http_status_t status;
84 ngx_http_chunked_t chunked;
85 ngx_http_proxy_vars_t vars;
86 off_t internal_body_length;
87
88 ngx_uint_t head; /* unsigned head:1 */
89 } ngx_http_proxy_ctx_t;
90
91
92 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
93 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
94 #if (NGX_HTTP_CACHE)
95 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
96 #endif
97 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
98 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
99 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
100 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
101 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
102 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
103 ngx_buf_t *buf);
104 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
105 ngx_buf_t *buf);
106 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
107 ssize_t bytes);
108 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
109 ssize_t bytes);
110 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
111 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
112 ngx_int_t rc);
113
114 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
115 ngx_http_variable_value_t *v, uintptr_t data);
116 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
117 ngx_http_variable_value_t *v, uintptr_t data);
118 static ngx_int_t
119 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
120 ngx_http_variable_value_t *v, uintptr_t data);
121 static ngx_int_t
122 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
123 ngx_http_variable_value_t *v, uintptr_t data);
124 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
125 ngx_table_elt_t *h, size_t prefix);
126 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
127 ngx_table_elt_t *h);
128 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
129 ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
130 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
131 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
132
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);
139
140 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
141 void *conf);
142 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
143 void *conf);
144 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
145 void *conf);
146 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
147 void *conf);
148 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
149 void *conf);
150 #if (NGX_HTTP_CACHE)
151 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
152 void *conf);
153 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
154 void *conf);
155 #endif
156
157 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
158
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);
161
162 #if (NGX_HTTP_SSL)
163 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
164 ngx_http_proxy_loc_conf_t *plcf);
165 #endif
166 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
167
168
169 static ngx_conf_post_t ngx_http_proxy_lowat_post =
170 { ngx_http_proxy_lowat_check };
171
172
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 }
185 };
186
187
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 }
192 };
193
194
195 ngx_module_t ngx_http_proxy_module;
196
197
198 static ngx_command_t ngx_http_proxy_commands[] = {
199
200 { ngx_string("proxy_pass"),
201 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
202 ngx_http_proxy_pass,
203 NGX_HTTP_LOC_CONF_OFFSET,
204 0,
205 NULL },
206
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,
211 0,
212 NULL },
213
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,
218 0,
219 NULL },
220
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,
225 0,
226 NULL },
227
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,
232 0,
233 NULL },
234
235 { ngx_string("proxy_store_access"),
236 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
237 ngx_conf_set_access_slot,
238 NGX_HTTP_LOC_CONF_OFFSET,
239 offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
240 NULL },
241
242 { ngx_string("proxy_buffering"),
243 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
244 ngx_conf_set_flag_slot,
245 NGX_HTTP_LOC_CONF_OFFSET,
246 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
247 NULL },
248
249 { ngx_string("proxy_ignore_client_abort"),
250 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
251 ngx_conf_set_flag_slot,
252 NGX_HTTP_LOC_CONF_OFFSET,
253 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
254 NULL },
255
256 { ngx_string("proxy_bind"),
257 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
258 ngx_http_upstream_bind_set_slot,
259 NGX_HTTP_LOC_CONF_OFFSET,
260 offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
261 NULL },
262
263 { ngx_string("proxy_connect_timeout"),
264 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
265 ngx_conf_set_msec_slot,
266 NGX_HTTP_LOC_CONF_OFFSET,
267 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
268 NULL },
269
270 { ngx_string("proxy_send_timeout"),
271 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
272 ngx_conf_set_msec_slot,
273 NGX_HTTP_LOC_CONF_OFFSET,
274 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
275 NULL },
276
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 },
283
284 { ngx_string("proxy_intercept_errors"),
285 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
286 ngx_conf_set_flag_slot,
287 NGX_HTTP_LOC_CONF_OFFSET,
288 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
289 NULL },
290
291 { ngx_string("proxy_set_header"),
292 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
293 ngx_conf_set_keyval_slot,
294 NGX_HTTP_LOC_CONF_OFFSET,
295 offsetof(ngx_http_proxy_loc_conf_t, headers_source),
296 NULL },
297
298 { ngx_string("proxy_headers_hash_max_size"),
299 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
300 ngx_conf_set_num_slot,
301 NGX_HTTP_LOC_CONF_OFFSET,
302 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
303 NULL },
304
305 { ngx_string("proxy_headers_hash_bucket_size"),
306 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
307 ngx_conf_set_num_slot,
308 NGX_HTTP_LOC_CONF_OFFSET,
309 offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
310 NULL },
311
312 { ngx_string("proxy_set_body"),
313 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
314 ngx_conf_set_str_slot,
315 NGX_HTTP_LOC_CONF_OFFSET,
316 offsetof(ngx_http_proxy_loc_conf_t, body_source),
317 NULL },
318
319 { ngx_string("proxy_method"),
320 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
321 ngx_conf_set_str_slot,
322 NGX_HTTP_LOC_CONF_OFFSET,
323 offsetof(ngx_http_proxy_loc_conf_t, method),
324 NULL },
325
326 { ngx_string("proxy_pass_request_headers"),
327 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
328 ngx_conf_set_flag_slot,
329 NGX_HTTP_LOC_CONF_OFFSET,
330 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
331 NULL },
332
333 { ngx_string("proxy_pass_request_body"),
334 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
335 ngx_conf_set_flag_slot,
336 NGX_HTTP_LOC_CONF_OFFSET,
337 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
338 NULL },
339
340 { ngx_string("proxy_buffer_size"),
341 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
342 ngx_conf_set_size_slot,
343 NGX_HTTP_LOC_CONF_OFFSET,
344 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
345 NULL },
346
347 { ngx_string("proxy_read_timeout"),
348 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
349 ngx_conf_set_msec_slot,
350 NGX_HTTP_LOC_CONF_OFFSET,
351 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
352 NULL },
353
354 { ngx_string("proxy_buffers"),
355 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
356 ngx_conf_set_bufs_slot,
357 NGX_HTTP_LOC_CONF_OFFSET,
358 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
359 NULL },
360
361 { ngx_string("proxy_busy_buffers_size"),
362 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
363 ngx_conf_set_size_slot,
364 NGX_HTTP_LOC_CONF_OFFSET,
365 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
366 NULL },
367
368 #if (NGX_HTTP_CACHE)
369
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,
374 0,
375 NULL },
376
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,
381 0,
382 NULL },
383
384 { ngx_string("proxy_cache_path"),
385 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
386 ngx_http_file_cache_set_slot,
387 0,
388 0,
389 &ngx_http_proxy_module },
390
391 { ngx_string("proxy_cache_bypass"),
392 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
393 ngx_http_set_predicate_slot,
394 NGX_HTTP_LOC_CONF_OFFSET,
395 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
396 NULL },
397
398 { ngx_string("proxy_no_cache"),
399 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
400 ngx_http_set_predicate_slot,
401 NGX_HTTP_LOC_CONF_OFFSET,
402 offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
403 NULL },
404
405 { ngx_string("proxy_cache_valid"),
406 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
407 ngx_http_file_cache_valid_set_slot,
408 NGX_HTTP_LOC_CONF_OFFSET,
409 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
410 NULL },
411
412 { ngx_string("proxy_cache_min_uses"),
413 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
414 ngx_conf_set_num_slot,
415 NGX_HTTP_LOC_CONF_OFFSET,
416 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
417 NULL },
418
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 },
425
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 },
432
433 { ngx_string("proxy_cache_lock"),
434 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
435 ngx_conf_set_flag_slot,
436 NGX_HTTP_LOC_CONF_OFFSET,
437 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
438 NULL },
439
440 { ngx_string("proxy_cache_lock_timeout"),
441 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
442 ngx_conf_set_msec_slot,
443 NGX_HTTP_LOC_CONF_OFFSET,
444 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
445 NULL },
446
447 #endif
448
449 { ngx_string("proxy_temp_path"),
450 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
451 ngx_conf_set_path_slot,
452 NGX_HTTP_LOC_CONF_OFFSET,
453 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
454 NULL },
455
456 { ngx_string("proxy_max_temp_file_size"),
457 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
458 ngx_conf_set_size_slot,
459 NGX_HTTP_LOC_CONF_OFFSET,
460 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
461 NULL },
462
463 { ngx_string("proxy_temp_file_write_size"),
464 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
465 ngx_conf_set_size_slot,
466 NGX_HTTP_LOC_CONF_OFFSET,
467 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
468 NULL },
469
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 },
476
477 { ngx_string("proxy_pass_header"),
478 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
479 ngx_conf_set_str_array_slot,
480 NGX_HTTP_LOC_CONF_OFFSET,
481 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
482 NULL },
483
484 { ngx_string("proxy_hide_header"),
485 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
486 ngx_conf_set_str_array_slot,
487 NGX_HTTP_LOC_CONF_OFFSET,
488 offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
489 NULL },
490
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 },
497
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 },
504
505 #if (NGX_HTTP_SSL)
506
507 { ngx_string("proxy_ssl_session_reuse"),
508 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
509 ngx_conf_set_flag_slot,
510 NGX_HTTP_LOC_CONF_OFFSET,
511 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
512 NULL },
513
514 #endif
515
516 ngx_null_command
517 };
518
519
520 static ngx_http_module_t ngx_http_proxy_module_ctx = {
521 ngx_http_proxy_add_variables, /* preconfiguration */
522 NULL, /* postconfiguration */
523
524 NULL, /* create main configuration */
525 NULL, /* init main configuration */
526
527 NULL, /* create server configuration */
528 NULL, /* merge server configuration */
529
530 ngx_http_proxy_create_loc_conf, /* create location configuration */
531 ngx_http_proxy_merge_loc_conf /* merge location configuration */
532 };
533
534
535 ngx_module_t ngx_http_proxy_module = {
536 NGX_MODULE_V1,
537 &ngx_http_proxy_module_ctx, /* module context */
538 ngx_http_proxy_commands, /* module directives */
539 NGX_HTTP_MODULE, /* module type */
540 NULL, /* init master */
541 NULL, /* init module */
542 NULL, /* init process */
543 NULL, /* init thread */
544 NULL, /* exit thread */
545 NULL, /* exit process */
546 NULL, /* exit master */
547 NGX_MODULE_V1_PADDING
548 };
549
550
551 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
552 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
553
554
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 }
564 };
565
566
567 static ngx_str_t ngx_http_proxy_hide_headers[] = {
568 ngx_string("Date"),
569 ngx_string("Server"),
570 ngx_string("X-Pad"),
571 ngx_string("X-Accel-Expires"),
572 ngx_string("X-Accel-Redirect"),
573 ngx_string("X-Accel-Limit-Rate"),
574 ngx_string("X-Accel-Buffering"),
575 ngx_string("X-Accel-Charset"),
576 ngx_null_string
577 };
578
579
580 #if (NGX_HTTP_CACHE)
581
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 }
597 };
598
599 #endif
600
601
602 static ngx_http_variable_t ngx_http_proxy_vars[] = {
603
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 },
606
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 },
609
610 { ngx_string("proxy_add_x_forwarded_for"), NULL,
611 ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
612
613 #if 0
614 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
615 #endif
616
617 { ngx_string("proxy_internal_body_length"), NULL,
618 ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
619
620 { ngx_null_string, NULL, NULL, 0, 0, 0 }
621 };
622
623
624 static ngx_path_init_t ngx_http_proxy_temp_path = {
625 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
626 };
627
628
629 static ngx_int_t
630 ngx_http_proxy_handler(ngx_http_request_t *r)
631 {
632 ngx_int_t rc;
633 ngx_http_upstream_t *u;
634 ngx_http_proxy_ctx_t *ctx;
635 ngx_http_proxy_loc_conf_t *plcf;
636
637 if (ngx_http_upstream_create(r) != NGX_OK) {
638 return NGX_HTTP_INTERNAL_SERVER_ERROR;
639 }
640
641 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
642 if (ctx == NULL) {
643 return NGX_ERROR;
644 }
645
646 ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
647
648 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
649
650 u = r->upstream;
651
652 if (plcf->proxy_lengths == NULL) {
653 ctx->vars = plcf->vars;
654 u->schema = plcf->vars.schema;
655 #if (NGX_HTTP_SSL)
656 u->ssl = (plcf->upstream.ssl != NULL);
657 #endif
658
659 } else {
660 if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
661 return NGX_HTTP_INTERNAL_SERVER_ERROR;
662 }
663 }
664
665 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
666
667 u->conf = &plcf->upstream;
668
669 #if (NGX_HTTP_CACHE)
670 u->create_key = ngx_http_proxy_create_key;
671 #endif
672 u->create_request = ngx_http_proxy_create_request;
673 u->reinit_request = ngx_http_proxy_reinit_request;
674 u->process_header = ngx_http_proxy_process_status_line;
675 u->abort_request = ngx_http_proxy_abort_request;
676 u->finalize_request = ngx_http_proxy_finalize_request;
677 r->state = 0;
678
679 if (plcf->redirects) {
680 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
681 }
682
683 if (plcf->cookie_domains || plcf->cookie_paths) {
684 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
685 }
686
687 u->buffering = plcf->upstream.buffering;
688
689 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
690 if (u->pipe == NULL) {
691 return NGX_HTTP_INTERNAL_SERVER_ERROR;
692 }
693
694 u->pipe->input_filter = ngx_http_proxy_copy_filter;
695 u->pipe->input_ctx = r;
696
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;
700
701 u->accel = 1;
702
703 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
704
705 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
706 return rc;
707 }
708
709 return NGX_DONE;
710 }
711
712
713 static ngx_int_t
714 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
715 ngx_http_proxy_loc_conf_t *plcf)
716 {
717 u_char *p;
718 size_t add;
719 u_short port;
720 ngx_str_t proxy;
721 ngx_url_t url;
722 ngx_http_upstream_t *u;
723
724 if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
725 plcf->proxy_values->elts)
726 == NULL)
727 {
728 return NGX_ERROR;
729 }
730
731 if (proxy.len > 7
732 && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
733 {
734 add = 7;
735 port = 80;
736
737 #if (NGX_HTTP_SSL)
738
739 } else if (proxy.len > 8
740 && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
741 {
742 add = 8;
743 port = 443;
744 r->upstream->ssl = 1;
745
746 #endif
747
748 } else {
749 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
750 "invalid URL prefix in \"%V\"", &proxy);
751 return NGX_ERROR;
752 }
753
754 u = r->upstream;
755
756 u->schema.len = add;
757 u->schema.data = proxy.data;
758
759 ngx_memzero(&url, sizeof(ngx_url_t));
760
761 url.url.len = proxy.len - add;
762 url.url.data = proxy.data + add;
763 url.default_port = port;
764 url.uri_part = 1;
765 url.no_resolve = 1;
766
767 if (ngx_parse_url(r->pool, &url) != NGX_OK) {
768 if (url.err) {
769 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
770 "%s in upstream \"%V\"", url.err, &url.url);
771 }
772
773 return NGX_ERROR;
774 }
775
776 if (url.uri.len) {
777 if (url.uri.data[0] == '?') {
778 p = ngx_pnalloc(r->pool, url.uri.len + 1);
779 if (p == NULL) {
780 return NGX_ERROR;
781 }
782
783 *p++ = '/';
784 ngx_memcpy(p, url.uri.data, url.uri.len);
785
786 url.uri.len++;
787 url.uri.data = p - 1;
788 }
789 }
790
791 ctx->vars.key_start = u->schema;
792
793 ngx_http_proxy_set_vars(&url, &ctx->vars);
794
795 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
796 if (u->resolved == NULL) {
797 return NGX_ERROR;
798 }
799
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;
805
806 } else {
807 u->resolved->host = url.host;
808 u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
809 u->resolved->no_port = url.no_port;
810 }
811
812 return NGX_OK;
813 }
814
815
816 #if (NGX_HTTP_CACHE)
817
818 static ngx_int_t
819 ngx_http_proxy_create_key(ngx_http_request_t *r)
820 {
821 size_t len, loc_len;
822 u_char *p;
823 uintptr_t escape;
824 ngx_str_t *key;
825 ngx_http_upstream_t *u;
826 ngx_http_proxy_ctx_t *ctx;
827 ngx_http_proxy_loc_conf_t *plcf;
828
829 u = r->upstream;
830
831 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
832
833 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
834
835 key = ngx_array_push(&r->cache->keys);
836 if (key == NULL) {
837 return NGX_ERROR;
838 }
839
840 if (plcf->cache_key.value.data) {
841
842 if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
843 return NGX_ERROR;
844 }
845
846 return NGX_OK;
847 }
848
849 *key = ctx->vars.key_start;
850
851 key = ngx_array_push(&r->cache->keys);
852 if (key == NULL) {
853 return NGX_ERROR;
854 }
855
856 if (plcf->proxy_lengths && ctx->vars.uri.len) {
857
858 *key = ctx->vars.uri;
859 u->uri = ctx->vars.uri;
860
861 return NGX_OK;
862
863 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
864 {
865 *key = r->unparsed_uri;
866 u->uri = r->unparsed_uri;
867
868 return NGX_OK;
869 }
870
871 loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
872
873 if (r->quoted_uri || r->internal) {
874 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
875 r->uri.len - loc_len, NGX_ESCAPE_URI);
876 } else {
877 escape = 0;
878 }
879
880 len = ctx->vars.uri.len + r->uri.len - loc_len + escape
881 + sizeof("?") - 1 + r->args.len;
882
883 p = ngx_pnalloc(r->pool, len);
884 if (p == NULL) {
885 return NGX_ERROR;
886 }
887
888 key->data = p;
889
890 if (r->valid_location) {
891 p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
892 }
893
894 if (escape) {
895 ngx_escape_uri(p, r->uri.data + loc_len,
896 r->uri.len - loc_len, NGX_ESCAPE_URI);
897 p += r->uri.len - loc_len + escape;
898
899 } else {
900 p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
901 }
902
903 if (r->args.len > 0) {
904 *p++ = '?';
905 p = ngx_copy(p, r->args.data, r->args.len);
906 }
907
908 key->len = p - key->data;
909 u->uri = *key;
910
911 return NGX_OK;
912 }
913
914 #endif
915
916
917 static ngx_int_t
918 ngx_http_proxy_create_request(ngx_http_request_t *r)
919 {
920 size_t len, uri_len, loc_len, body_len;
921 uintptr_t escape;
922 ngx_buf_t *b;
923 ngx_str_t method;
924 ngx_uint_t i, unparsed_uri;
925 ngx_chain_t *cl, *body;
926 ngx_list_part_t *part;
927 ngx_table_elt_t *header;
928 ngx_http_upstream_t *u;
929 ngx_http_proxy_ctx_t *ctx;
930 ngx_http_script_code_pt code;
931 ngx_http_script_engine_t e, le;
932 ngx_http_proxy_loc_conf_t *plcf;
933 ngx_http_script_len_code_pt lcode;
934
935 u = r->upstream;
936
937 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
938
939 if (u->method.len) {
940 /* HEAD was changed to GET to cache response */
941 method = u->method;
942 method.len++;
943
944 } else if (plcf->method.len) {
945 method = plcf->method;
946
947 } else {
948 method = r->method_name;
949 method.len++;
950 }
951
952 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
953
954 if (method.len == 5
955 && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
956 {
957 ctx->head = 1;
958 }
959
960 len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
961
962 escape = 0;
963 loc_len = 0;
964 unparsed_uri = 0;
965
966 if (plcf->proxy_lengths && ctx->vars.uri.len) {
967 uri_len = ctx->vars.uri.len;
968
969 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
970 {
971 unparsed_uri = 1;
972 uri_len = r->unparsed_uri.len;
973
974 } else {
975 loc_len = (r->valid_location && ctx->vars.uri.len) ?
976 plcf->location.len : 0;
977
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);
981 }
982
983 uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
984 + sizeof("?") - 1 + r->args.len;
985 }
986
987 if (uri_len == 0) {
988 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
989 "zero length URI to proxy");
990 return NGX_ERROR;
991 }
992
993 len += uri_len;
994
995 ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
996
997 if (plcf->body_set_len) {
998 le.ip = plcf->body_set_len->elts;
999 le.request = r;
1000 le.flushed = 1;
1001 body_len = 0;
1002
1003 while (*(uintptr_t *) le.ip) {
1004 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1005 body_len += lcode(&le);
1006 }
1007
1008 ctx->internal_body_length = body_len;
1009 len += body_len;
1010
1011 } else {
1012 ctx->internal_body_length = r->headers_in.content_length_n;
1013 }
1014
1015 le.ip = plcf->headers_set_len->elts;
1016 le.request = r;
1017 le.flushed = 1;
1018
1019 while (*(uintptr_t *) le.ip) {
1020 while (*(uintptr_t *) le.ip) {
1021 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1022 len += lcode(&le);
1023 }
1024 le.ip += sizeof(uintptr_t);
1025 }
1026
1027
1028 if (plcf->upstream.pass_request_headers) {
1029 part = &r->headers_in.headers.part;
1030 header = part->elts;
1031
1032 for (i = 0; /* void */; i++) {
1033
1034 if (i >= part->nelts) {
1035 if (part->next == NULL) {
1036 break;
1037 }
1038
1039 part = part->next;
1040 header = part->elts;
1041 i = 0;
1042 }
1043
1044 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1045 header[i].lowcase_key, header[i].key.len))
1046 {
1047 continue;
1048 }
1049
1050 len += header[i].key.len + sizeof(": ") - 1
1051 + header[i].value.len + sizeof(CRLF) - 1;
1052 }
1053 }
1054
1055
1056 b = ngx_create_temp_buf(r->pool, len);
1057 if (b == NULL) {
1058 return NGX_ERROR;
1059 }
1060
1061 cl = ngx_alloc_chain_link(r->pool);
1062 if (cl == NULL) {
1063 return NGX_ERROR;
1064 }
1065
1066 cl->buf = b;
1067
1068
1069 /* the request line */
1070
1071 b->last = ngx_copy(b->last, method.data, method.len);
1072
1073 u->uri.data = b->last;
1074
1075 if (plcf->proxy_lengths && ctx->vars.uri.len) {
1076 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1077
1078 } else if (unparsed_uri) {
1079 b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1080
1081 } else {
1082 if (r->valid_location) {
1083 b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1084 }
1085
1086 if (escape) {
1087 ngx_escape_uri(b->last, r->uri.data + loc_len,
1088 r->uri.len - loc_len, NGX_ESCAPE_URI);
1089 b->last += r->uri.len - loc_len + escape;
1090
1091 } else {
1092 b->last = ngx_copy(b->last, r->uri.data + loc_len,
1093 r->uri.len - loc_len);
1094 }
1095
1096 if (r->args.len > 0) {
1097 *b->last++ = '?';
1098 b->last = ngx_copy(b->last, r->args.data, r->args.len);
1099 }
1100 }
1101
1102 u->uri.len = b->last - u->uri.data;
1103
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);
1107
1108 } else {
1109 b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1110 sizeof(ngx_http_proxy_version) - 1);
1111 }
1112
1113 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1114
1115 e.ip = plcf->headers_set->elts;
1116 e.pos = b->last;
1117 e.request = r;
1118 e.flushed = 1;
1119
1120 le.ip = plcf->headers_set_len->elts;
1121
1122 while (*(uintptr_t *) le.ip) {
1123 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1124
1125 /* skip the header line name length */
1126 (void) lcode(&le);
1127
1128 if (*(ngx_http_script_len_code_pt *) le.ip) {
1129
1130 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1131 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1132 }
1133
1134 e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1135
1136 } else {
1137 e.skip = 0;
1138 }
1139
1140 le.ip += sizeof(uintptr_t);
1141
1142 while (*(uintptr_t *) e.ip) {
1143 code = *(ngx_http_script_code_pt *) e.ip;
1144 code((ngx_http_script_engine_t *) &e);
1145 }
1146 e.ip += sizeof(uintptr_t);
1147 }
1148
1149 b->last = e.pos;
1150
1151
1152 if (plcf->upstream.pass_request_headers) {
1153 part = &r->headers_in.headers.part;
1154 header = part->elts;
1155
1156 for (i = 0; /* void */; i++) {
1157
1158 if (i >= part->nelts) {
1159 if (part->next == NULL) {
1160 break;
1161 }
1162
1163 part = part->next;
1164 header = part->elts;
1165 i = 0;
1166 }
1167
1168 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1169 header[i].lowcase_key, header[i].key.len))
1170 {
1171 continue;
1172 }
1173
1174 b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1175
1176 *b->last++ = ':'; *b->last++ = ' ';
1177
1178 b->last = ngx_copy(b->last, header[i].value.data,
1179 header[i].value.len);
1180
1181 *b->last++ = CR; *b->last++ = LF;
1182
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);
1186 }
1187 }
1188
1189
1190 /* add "\r\n" at the header end */
1191 *b->last++ = CR; *b->last++ = LF;
1192
1193 if (plcf->body_set) {
1194 e.ip = plcf->body_set->elts;
1195 e.pos = b->last;
1196
1197 while (*(uintptr_t *) e.ip) {
1198 code = *(ngx_http_script_code_pt *) e.ip;
1199 code((ngx_http_script_engine_t *) &e);
1200 }
1201
1202 b->last = e.pos;
1203 }
1204
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);
1208
1209 if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
1210
1211 body = u->request_bufs;
1212 u->request_bufs = cl;
1213
1214 while (body) {
1215 b = ngx_alloc_buf(r->pool);
1216 if (b == NULL) {
1217 return NGX_ERROR;
1218 }
1219
1220 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1221
1222 cl->next = ngx_alloc_chain_link(r->pool);
1223 if (cl->next == NULL) {
1224 return NGX_ERROR;
1225 }
1226
1227 cl = cl->next;
1228 cl->buf = b;
1229
1230 body = body->next;
1231 }
1232
1233 } else {
1234 u->request_bufs = cl;
1235 }
1236
1237 b->flush = 1;
1238 cl->next = NULL;
1239
1240 return NGX_OK;
1241 }
1242
1243
1244 static ngx_int_t
1245 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1246 {
1247 ngx_http_proxy_ctx_t *ctx;
1248
1249 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1250
1251 if (ctx == NULL) {
1252 return NGX_OK;
1253 }
1254
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;
1260
1261 r->upstream->process_header = ngx_http_proxy_process_status_line;
1262 r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1263 r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1264 r->state = 0;
1265
1266 return NGX_OK;
1267 }
1268
1269
1270 static ngx_int_t
1271 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1272 {
1273 size_t len;
1274 ngx_int_t rc;
1275 ngx_http_upstream_t *u;
1276 ngx_http_proxy_ctx_t *ctx;
1277
1278 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1279
1280 if (ctx == NULL) {
1281 return NGX_ERROR;
1282 }
1283
1284 u = r->upstream;
1285
1286 rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1287
1288 if (rc == NGX_AGAIN) {
1289 return rc;
1290 }
1291
1292 if (rc == NGX_ERROR) {
1293
1294 #if (NGX_HTTP_CACHE)
1295
1296 if (r->cache) {
1297 r->http_version = NGX_HTTP_VERSION_9;
1298 return NGX_OK;
1299 }
1300
1301 #endif
1302
1303 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1304 "upstream sent no valid HTTP/1.0 header");
1305
1306 #if 0
1307 if (u->accel) {
1308 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1309 }
1310 #endif
1311
1312 r->http_version = NGX_HTTP_VERSION_9;
1313 u->state->status = NGX_HTTP_OK;
1314 u->headers_in.connection_close = 1;
1315
1316 return NGX_OK;
1317 }
1318
1319 if (u->state) {
1320 u->state->status = ctx->status.code;
1321 }
1322
1323 u->headers_in.status_n = ctx->status.code;
1324
1325 len = ctx->status.end - ctx->status.start;
1326 u->headers_in.status_line.len = len;
1327
1328 u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1329 if (u->headers_in.status_line.data == NULL) {
1330 return NGX_ERROR;
1331 }
1332
1333 ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1334
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);
1338
1339 if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1340 u->headers_in.connection_close = 1;
1341 }
1342
1343 u->process_header = ngx_http_proxy_process_header;
1344
1345 return ngx_http_proxy_process_header(r);
1346 }
1347
1348
1349 static ngx_int_t
1350 ngx_http_proxy_process_header(ngx_http_request_t *r)
1351 {
1352 ngx_int_t rc;
1353 ngx_table_elt_t *h;
1354 ngx_http_upstream_t *u;
1355 ngx_http_proxy_ctx_t *ctx;
1356 ngx_http_upstream_header_t *hh;
1357 ngx_http_upstream_main_conf_t *umcf;
1358
1359 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1360
1361 for ( ;; ) {
1362
1363 rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1364
1365 if (rc == NGX_OK) {
1366
1367 /* a header line has been parsed successfully */
1368
1369 h = ngx_list_push(&r->upstream->headers_in.headers);
1370 if (h == NULL) {
1371 return NGX_ERROR;
1372 }
1373
1374 h->hash = r->header_hash;
1375
1376 h->key.len = r->header_name_end - r->header_name_start;
1377 h->value.len = r->header_end - r->header_start;
1378
1379 h->key.data = ngx_pnalloc(r->pool,
1380 h->key.len + 1 + h->value.len + 1 + h->key.len);
1381 if (h->key.data == NULL) {
1382 return NGX_ERROR;
1383 }
1384
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;
1387
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';
1392
1393 if (h->key.len == r->lowcase_index) {
1394 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1395
1396 } else {
1397 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1398 }
1399
1400 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1401 h->lowcase_key, h->key.len);
1402
1403 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1404 return NGX_ERROR;
1405 }
1406
1407 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1408 "http proxy header: \"%V: %V\"",
1409 &h->key, &h->value);
1410
1411 continue;
1412 }
1413
1414 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1415
1416 /* a whole header has been parsed successfully */
1417
1418 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1419 "http proxy header done");
1420
1421 /*
1422 * if no "Server" and "Date" in header line,
1423 * then add the special empty headers
1424 */
1425
1426 if (r->upstream->headers_in.server == NULL) {
1427 h = ngx_list_push(&r->upstream->headers_in.headers);
1428 if (h == NULL) {
1429 return NGX_ERROR;
1430 }
1431
1432 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1433 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1434
1435 ngx_str_set(&h->key, "Server");
1436 ngx_str_null(&h->value);
1437 h->lowcase_key = (u_char *) "server";
1438 }
1439
1440 if (r->upstream->headers_in.date == NULL) {
1441 h = ngx_list_push(&r->upstream->headers_in.headers);
1442 if (h == NULL) {
1443 return NGX_ERROR;
1444 }
1445
1446 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1447
1448 ngx_str_set(&h->key, "Date");
1449 ngx_str_null(&h->value);
1450 h->lowcase_key = (u_char *) "date";
1451 }
1452
1453 /* clear content length if response is chunked */
1454
1455 u = r->upstream;
1456
1457 if (u->headers_in.chunked) {
1458 u->headers_in.content_length_n = -1;
1459 }
1460
1461 /*
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
1464 */
1465
1466 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1467
1468 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1469 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1470 || ctx->head
1471 || (!u->headers_in.chunked
1472 && u->headers_in.content_length_n == 0))
1473 {
1474 u->keepalive = !u->headers_in.connection_close;
1475 }
1476
1477 if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1478 u->keepalive = 0;
1479
1480 if (r->headers_in.upgrade) {
1481 u->upgrade = 1;
1482 }
1483 }
1484
1485 return NGX_OK;
1486 }
1487
1488 if (rc == NGX_AGAIN) {
1489 return NGX_AGAIN;
1490 }
1491
1492 /* there was error while a header line parsing */
1493
1494 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1495 "upstream sent invalid header");
1496
1497 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1498 }
1499 }
1500
1501
1502 static ngx_int_t
1503 ngx_http_proxy_input_filter_init(void *data)
1504 {
1505 ngx_http_request_t *r = data;
1506 ngx_http_upstream_t *u;
1507 ngx_http_proxy_ctx_t *ctx;
1508
1509 u = r->upstream;
1510 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1511
1512 if (ctx == NULL) {
1513 return NGX_ERROR;
1514 }
1515
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);
1520
1521 /* as per RFC2616, 4.4 Message Length */
1522
1523 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1524 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1525 || ctx->head)
1526 {
1527 /* 1xx, 204, and 304 and replies to HEAD requests */
1528 /* no 1xx since we don't send Expect and Upgrade */
1529
1530 u->pipe->length = 0;
1531 u->length = 0;
1532 u->keepalive = !u->headers_in.connection_close;
1533
1534 } else if (u->headers_in.chunked) {
1535 /* chunked */
1536
1537 u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1538 u->pipe->length = 3; /* "" LF LF */
1539
1540 u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1541 u->length = -1;
1542
1543 } else if (u->headers_in.content_length_n == 0) {
1544 /* empty body: special case as filter won't be called */
1545
1546 u->pipe->length = 0;
1547 u->length = 0;
1548 u->keepalive = !u->headers_in.connection_close;
1549
1550 } else {
1551 /* content length or connection close */
1552
1553 u->pipe->length = u->headers_in.content_length_n;
1554 u->length = u->headers_in.content_length_n;
1555 }
1556
1557 return NGX_OK;
1558 }
1559
1560
1561 static ngx_int_t
1562 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1563 {
1564 ngx_buf_t *b;
1565 ngx_chain_t *cl;
1566 ngx_http_request_t *r;
1567
1568 if (buf->pos == buf->last) {
1569 return NGX_OK;
1570 }
1571
1572 if (p->free) {
1573 cl = p->free;
1574 b = cl->buf;
1575 p->free = cl->next;
1576 ngx_free_chain(p->pool, cl);
1577
1578 } else {
1579 b = ngx_alloc_buf(p->pool);
1580 if (b == NULL) {
1581 return NGX_ERROR;
1582 }
1583 }
1584
1585 ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1586 b->shadow = buf;
1587 b->tag = p->tag;
1588 b->last_shadow = 1;
1589 b->recycled = 1;
1590 buf->shadow = b;
1591
1592 cl = ngx_alloc_chain_link(p->pool);
1593 if (cl == NULL) {
1594 return NGX_ERROR;
1595 }
1596
1597 cl->buf = b;
1598 cl->next = NULL;
1599
1600 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1601
1602 if (p->in) {
1603 *p->last_in = cl;
1604 } else {
1605 p->in = cl;
1606 }
1607 p->last_in = &cl->next;
1608
1609 if (p->length == -1) {
1610 return NGX_OK;
1611 }
1612
1613 p->length -= b->last - b->pos;
1614
1615 if (p->length == 0) {
1616 r = p->input_ctx;
1617 p->upstream_done = 1;
1618 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1619
1620 } else if (p->length < 0) {
1621 r = p->input_ctx;
1622 p->upstream_done = 1;
1623
1624 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
1625 "upstream sent more data than specified in "
1626 "\"Content-Length\" header");
1627 }
1628
1629 return NGX_OK;
1630 }
1631
1632
1633 static ngx_int_t
1634 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1635 {
1636 ngx_int_t rc;
1637 ngx_buf_t *b, **prev;
1638 ngx_chain_t *cl;
1639 ngx_http_request_t *r;
1640 ngx_http_proxy_ctx_t *ctx;
1641
1642 if (buf->pos == buf->last) {
1643 return NGX_OK;
1644 }
1645
1646 r = p->input_ctx;
1647 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1648
1649 if (ctx == NULL) {
1650 return NGX_ERROR;
1651 }
1652
1653 b = NULL;
1654 prev = &buf->shadow;
1655
1656 for ( ;; ) {
1657
1658 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1659
1660 if (rc == NGX_OK) {
1661
1662 /* a chunk has been parsed successfully */
1663
1664 if (p->free) {
1665 cl = p->free;
1666 b = cl->buf;
1667 p->free = cl->next;
1668 ngx_free_chain(p->pool, cl);
1669
1670 } else {
1671 b = ngx_alloc_buf(p->pool);
1672 if (b == NULL) {
1673 return NGX_ERROR;
1674 }
1675 }
1676
1677 ngx_memzero(b, sizeof(ngx_buf_t));
1678
1679 b->pos = buf->pos;
1680 b->start = buf->start;
1681 b->end = buf->end;
1682 b->tag = p->tag;
1683 b->temporary = 1;
1684 b->recycled = 1;
1685
1686 *prev = b;
1687 prev = &b->shadow;
1688
1689 cl = ngx_alloc_chain_link(p->pool);
1690 if (cl == NULL) {
1691 return NGX_ERROR;
1692 }
1693
1694 cl->buf = b;
1695 cl->next = NULL;
1696
1697 if (p->in) {
1698 *p->last_in = cl;
1699 } else {
1700 p->in = cl;
1701 }
1702 p->last_in = &cl->next;
1703
1704 /* STUB */ b->num = buf->num;
1705
1706 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1707 "input buf #%d %p", b->num, b->pos);
1708
1709 if (buf->last - buf->pos >= ctx->chunked.size) {
1710
1711 buf->pos += ctx->chunked.size;
1712 b->last = buf->pos;
1713 ctx->chunked.size = 0;
1714
1715 continue;
1716 }
1717
1718 ctx->chunked.size -= buf->last - buf->pos;
1719 buf->pos = buf->last;
1720 b->last = buf->last;
1721
1722 continue;
1723 }
1724
1725 if (rc == NGX_DONE) {
1726
1727 /* a whole response has been parsed successfully */
1728
1729 p->upstream_done = 1;
1730 r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1731
1732 break;
1733 }
1734
1735 if (rc == NGX_AGAIN) {
1736
1737 /* set p->length, minimal amount of data we want to see */
1738
1739 p->length = ctx->chunked.length;
1740
1741 break;
1742 }
1743
1744 /* invalid response */
1745
1746 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1747 "upstream sent invalid chunked response");
1748
1749 return NGX_ERROR;
1750 }
1751
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);
1755
1756 if (b) {
1757 b->shadow = buf;
1758 b->last_shadow = 1;
1759
1760 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1761 "input buf %p %z", b->pos, b->last - b->pos);
1762
1763 return NGX_OK;
1764 }
1765
1766 /* there is no data record in the buf, add it to free chain */
1767
1768 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1769 return NGX_ERROR;
1770 }
1771
1772 return NGX_OK;
1773 }
1774
1775
1776 static ngx_int_t
1777 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
1778 {
1779 ngx_http_request_t *r = data;
1780
1781 ngx_buf_t *b;
1782 ngx_chain_t *cl, **ll;
1783 ngx_http_upstream_t *u;
1784
1785 u = r->upstream;
1786
1787 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1788 ll = &cl->next;
1789 }
1790
1791 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1792 if (cl == NULL) {
1793 return NGX_ERROR;
1794 }
1795
1796 *ll = cl;
1797
1798 cl->buf->flush = 1;
1799 cl->buf->memory = 1;
1800
1801 b = &u->buffer;
1802
1803 cl->buf->pos = b->last;
1804 b->last += bytes;
1805 cl->buf->last = b->last;
1806 cl->buf->tag = u->output.tag;
1807
1808 if (u->length == -1) {
1809 return NGX_OK;
1810 }
1811
1812 u->length -= bytes;
1813
1814 if (u->length == 0) {
1815 u->keepalive = !u->headers_in.connection_close;
1816 }
1817
1818 return NGX_OK;
1819 }
1820
1821
1822 static ngx_int_t
1823 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
1824 {
1825 ngx_http_request_t *r = data;
1826
1827 ngx_int_t rc;
1828 ngx_buf_t *b, *buf;
1829 ngx_chain_t *cl, **ll;
1830 ngx_http_upstream_t *u;
1831 ngx_http_proxy_ctx_t *ctx;
1832
1833 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1834
1835 if (ctx == NULL) {
1836 return NGX_ERROR;
1837 }
1838
1839 u = r->upstream;
1840 buf = &u->buffer;
1841
1842 buf->pos = buf->last;
1843 buf->last += bytes;
1844
1845 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1846 ll = &cl->next;
1847 }
1848
1849 for ( ;; ) {
1850
1851 rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1852
1853 if (rc == NGX_OK) {
1854
1855 /* a chunk has been parsed successfully */
1856
1857 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1858 if (cl == NULL) {
1859 return NGX_ERROR;
1860 }
1861
1862 *ll = cl;
1863 ll = &cl->next;
1864
1865 b = cl->buf;
1866
1867 b->flush = 1;
1868 b->memory = 1;
1869
1870 b->pos = buf->pos;
1871 b->tag = u->output.tag;
1872
1873 if (buf->last - buf->pos >= ctx->chunked.size) {
1874 buf->pos += ctx->chunked.size;
1875 b->last = buf->pos;
1876 ctx->chunked.size = 0;
1877
1878 } else {
1879 ctx->chunked.size -= buf->last - buf->pos;
1880 buf->pos = buf->last;
1881 b->last = buf->last;
1882 }
1883
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);
1887
1888 continue;
1889 }
1890
1891 if (rc == NGX_DONE) {
1892
1893 /* a whole response has been parsed successfully */
1894
1895 u->keepalive = !u->headers_in.connection_close;
1896 u->length = 0;
1897
1898 break;
1899 }
1900
1901 if (rc == NGX_AGAIN) {
1902 break;
1903 }
1904
1905 /* invalid response */
1906
1907 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1908 "upstream sent invalid chunked response");
1909
1910 return NGX_ERROR;
1911 }
1912
1913 /* provide continuous buffer for subrequests in memory */
1914
1915 if (r->subrequest_in_memory) {
1916
1917 cl = u->out_bufs;
1918
1919 if (cl) {
1920 buf->pos = cl->buf->pos;
1921 }
1922
1923 buf->last = buf->pos;
1924
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));
1929
1930 if (buf->last == cl->buf->pos) {
1931 buf->last = cl->buf->last;
1932 continue;
1933 }
1934
1935 buf->last = ngx_movemem(buf->last, cl->buf->pos,
1936 cl->buf->last - cl->buf->pos);
1937
1938 cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
1939 cl->buf->last = buf->last;
1940 }
1941 }
1942
1943 return NGX_OK;
1944 }
1945
1946
1947 static void
1948 ngx_http_proxy_abort_request(ngx_http_request_t *r)
1949 {
1950 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1951 "abort http proxy request");
1952
1953 return;
1954 }
1955
1956
1957 static void
1958 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1959 {
1960 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1961 "finalize http proxy request");
1962
1963 return;
1964 }
1965
1966
1967 static ngx_int_t
1968 ngx_http_proxy_host_variable(ngx_http_request_t *r,
1969 ngx_http_variable_value_t *v, uintptr_t data)
1970 {
1971 ngx_http_proxy_ctx_t *ctx;
1972
1973 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1974
1975 if (ctx == NULL) {
1976 v->not_found = 1;
1977 return NGX_OK;
1978 }
1979
1980 v->len = ctx->vars.host_header.len;
1981 v->valid = 1;
1982 v->no_cacheable = 0;
1983 v->not_found = 0;
1984 v->data = ctx->vars.host_header.data;
1985
1986 return NGX_OK;
1987 }
1988
1989
1990 static ngx_int_t
1991 ngx_http_proxy_port_variable(ngx_http_request_t *r,
1992 ngx_http_variable_value_t *v, uintptr_t data)
1993 {
1994 ngx_http_proxy_ctx_t *ctx;
1995
1996 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1997
1998 if (ctx == NULL) {
1999 v->not_found = 1;
2000 return NGX_OK;
2001 }
2002
2003 v->len = ctx->vars.port.len;
2004 v->valid = 1;
2005 v->no_cacheable = 0;
2006 v->not_found = 0;
2007 v->data = ctx->vars.port.data;
2008
2009 return NGX_OK;
2010 }
2011
2012
2013 static ngx_int_t
2014 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2015 ngx_http_variable_value_t *v, uintptr_t data)
2016 {
2017 size_t len;
2018 u_char *p;
2019 ngx_uint_t i, n;
2020 ngx_table_elt_t **h;
2021
2022 v->valid = 1;
2023 v->no_cacheable = 0;
2024 v->not_found = 0;
2025
2026 n = r->headers_in.x_forwarded_for.nelts;
2027 h = r->headers_in.x_forwarded_for.elts;
2028
2029 len = 0;
2030
2031 for (i = 0; i < n; i++) {
2032 len += h[i]->value.len + sizeof(", ") - 1;
2033 }
2034
2035 if (len == 0) {
2036 v->len = r->connection->addr_text.len;
2037 v->data = r->connection->addr_text.data;
2038 return NGX_OK;
2039 }
2040
2041 len += r->connection->addr_text.len;
2042
2043 p = ngx_pnalloc(r->pool, len);
2044 if (p == NULL) {
2045 return NGX_ERROR;
2046 }
2047
2048 v->len = len;
2049 v->data = p;
2050
2051 for (i = 0; i < n; i++) {
2052 p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2053 *p++ = ','; *p++ = ' ';
2054 }
2055
2056 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2057
2058 return NGX_OK;
2059 }
2060
2061
2062 static ngx_int_t
2063 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2064 ngx_http_variable_value_t *v, uintptr_t data)
2065 {
2066 ngx_http_proxy_ctx_t *ctx;
2067
2068 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2069
2070 if (ctx == NULL || ctx->internal_body_length < 0) {
2071 v->not_found = 1;
2072 return NGX_OK;
2073 }
2074
2075 v->valid = 1;
2076 v->no_cacheable = 0;
2077 v->not_found = 0;
2078
2079 v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
2080
2081 if (v->data == NULL) {
2082 return NGX_ERROR;
2083 }
2084
2085 v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2086
2087 return NGX_OK;
2088 }
2089
2090
2091 static ngx_int_t
2092 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2093 size_t prefix)
2094 {
2095 size_t len;
2096 ngx_int_t rc;
2097 ngx_uint_t i;
2098 ngx_http_proxy_rewrite_t *pr;
2099 ngx_http_proxy_loc_conf_t *plcf;
2100
2101 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2102
2103 pr = plcf->redirects->elts;
2104
2105 if (pr == NULL) {
2106 return NGX_DECLINED;
2107 }
2108
2109 len = h->value.len - prefix;
2110
2111 for (i = 0; i < plcf->redirects->nelts; i++) {
2112 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2113
2114 if (rc != NGX_DECLINED) {
2115 return rc;
2116 }
2117 }
2118
2119 return NGX_DECLINED;
2120 }
2121
2122
2123 static ngx_int_t
2124 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2125 {
2126 size_t prefix;
2127 u_char *p;
2128 ngx_int_t rc, rv;
2129 ngx_http_proxy_loc_conf_t *plcf;
2130
2131 p = (u_char *) ngx_strchr(h->value.data, ';');
2132 if (p == NULL) {
2133 return NGX_DECLINED;
2134 }
2135
2136 prefix = p + 1 - h->value.data;
2137
2138 rv = NGX_DECLINED;
2139
2140 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2141
2142 if (plcf->cookie_domains) {
2143 p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2144
2145 if (p) {
2146 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2147 plcf->cookie_domains);
2148 if (rc == NGX_ERROR) {
2149 return NGX_ERROR;
2150 }
2151
2152 if (rc != NGX_DECLINED) {
2153 rv = rc;
2154 }
2155 }
2156 }
2157
2158 if (plcf->cookie_paths) {
2159 p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2160
2161 if (p) {
2162 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2163 plcf->cookie_paths);
2164 if (rc == NGX_ERROR) {
2165 return NGX_ERROR;
2166 }
2167
2168 if (rc != NGX_DECLINED) {
2169 rv = rc;
2170 }
2171 }
2172 }
2173
2174 return rv;
2175 }
2176
2177
2178 static ngx_int_t
2179 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2180 u_char *value, ngx_array_t *rewrites)
2181 {
2182 size_t len, prefix;
2183 u_char *p;
2184 ngx_int_t rc;
2185 ngx_uint_t i;
2186 ngx_http_proxy_rewrite_t *pr;
2187
2188 prefix = value - h->value.data;
2189
2190 p = (u_char *) ngx_strchr(value, ';');
2191
2192 len = p ? (size_t) (p - value) : (h->value.len - prefix);
2193
2194 pr = rewrites->elts;
2195
2196 for (i = 0; i < rewrites->nelts; i++) {
2197 rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2198
2199 if (rc != NGX_DECLINED) {
2200 return rc;
2201 }
2202 }
2203
2204 return NGX_DECLINED;
2205 }
2206
2207
2208 static ngx_int_t
2209 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2210 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2211 {
2212 ngx_str_t pattern, replacement;
2213
2214 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2215 return NGX_ERROR;
2216 }
2217
2218 if (pattern.len > len
2219 || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2220 pattern.len) != 0)
2221 {
2222 return NGX_DECLINED;
2223 }
2224
2225 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2226 return NGX_ERROR;
2227 }
2228
2229 return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2230 }
2231
2232
2233 #if (NGX_PCRE)
2234
2235 static ngx_int_t
2236 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2237 size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2238 {
2239 ngx_str_t pattern, replacement;
2240
2241 pattern.len = len;
2242 pattern.data = h->value.data + prefix;
2243
2244 if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2245 return NGX_DECLINED;
2246 }
2247
2248 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2249 return NGX_ERROR;
2250 }
2251
2252 if (prefix == 0 && h->value.len == len) {
2253 h->value = replacement;
2254 return NGX_OK;
2255 }
2256
2257 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2258 }
2259
2260 #endif
2261
2262
2263 static ngx_int_t
2264 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2265 ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2266 {
2267 u_char *p;
2268 ngx_str_t pattern, replacement;
2269
2270 if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2271 return NGX_ERROR;
2272 }
2273
2274 p = h->value.data + prefix;
2275
2276 if (p[0] == '.') {
2277 p++;
2278 prefix++;
2279 len--;
2280 }
2281
2282 if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2283 return NGX_DECLINED;
2284 }
2285
2286 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2287 return NGX_ERROR;
2288 }
2289
2290 return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2291 }
2292
2293
2294 static ngx_int_t
2295 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2296 size_t len, ngx_str_t *replacement)
2297 {
2298 u_char *p, *data;
2299 size_t new_len;
2300
2301 new_len = replacement->len + h->value.len - len;
2302
2303 if (replacement->len > len) {
2304
2305 data = ngx_pnalloc(r->pool, new_len);
2306 if (data == NULL) {
2307 return NGX_ERROR;
2308 }
2309
2310 p = ngx_copy(data, h->value.data, prefix);
2311 p = ngx_copy(p, replacement->data, replacement->len);
2312
2313 ngx_memcpy(p, h->value.data + prefix + len,
2314 h->value.len - len - prefix);
2315
2316 h->value.data = data;
2317
2318 } else {
2319 p = ngx_copy(h->value.data + prefix, replacement->data,
2320 replacement->len);
2321
2322 ngx_memmove(p, h->value.data + prefix + len,
2323 h->value.len - len - prefix);
2324 }
2325
2326 h->value.len = new_len;
2327
2328 return NGX_OK;
2329 }
2330
2331
2332 static ngx_int_t
2333 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2334 {
2335 ngx_http_variable_t *var, *v;
2336
2337 for (v = ngx_http_proxy_vars; v->name.len; v++) {
2338 var = ngx_http_add_variable(cf, &v->name, v->flags);
2339 if (var == NULL) {
2340 return NGX_ERROR;
2341 }
2342
2343 var->get_handler = v->get_handler;
2344 var->data = v->data;
2345 }
2346
2347 return NGX_OK;
2348 }
2349
2350
2351 static void *
2352 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2353 {
2354 ngx_http_proxy_loc_conf_t *conf;
2355
2356 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2357 if (conf == NULL) {
2358 return NULL;
2359 }
2360
2361 /*
2362 * set by ngx_pcalloc():
2363 *
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;
2375 *
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;
2385 */
2386
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;
2391
2392 conf->upstream.local = NGX_CONF_UNSET_PTR;
2393
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;
2397
2398 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2399 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2400
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;
2404
2405 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2406 conf->upstream.pass_request_body = NGX_CONF_UNSET;
2407
2408 #if (NGX_HTTP_CACHE)
2409 conf->upstream.cache = NGX_CONF_UNSET_PTR;
2410 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2411 conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2412 conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2413 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2414 conf->upstream.cache_lock = NGX_CONF_UNSET;
2415 conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2416 #endif
2417
2418 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2419 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2420
2421 conf->upstream.intercept_errors = NGX_CONF_UNSET;
2422 #if (NGX_HTTP_SSL)
2423 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2424 #endif
2425
2426 /* "proxy_cyclic_temp_file" is disabled */
2427 conf->upstream.cyclic_temp_file = 0;
2428
2429 conf->redirect = NGX_CONF_UNSET;
2430 conf->upstream.change_buffering = 1;
2431
2432 conf->cookie_domains = NGX_CONF_UNSET_PTR;
2433 conf->cookie_paths = NGX_CONF_UNSET_PTR;
2434
2435 conf->http_version = NGX_CONF_UNSET_UINT;
2436
2437 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2438 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2439
2440 ngx_str_set(&conf->upstream.module, "proxy");
2441
2442 return conf;
2443 }
2444
2445
2446 static char *
2447 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2448 {
2449 ngx_http_proxy_loc_conf_t *prev = parent;
2450 ngx_http_proxy_loc_conf_t *conf = child;
2451
2452 u_char *p;
2453 size_t size;
2454 ngx_hash_init_t hash;
2455 ngx_http_core_loc_conf_t *clcf;
2456 ngx_http_proxy_rewrite_t *pr;
2457 ngx_http_script_compile_t sc;
2458
2459 if (conf->upstream.store != 0) {
2460 ngx_conf_merge_value(conf->upstream.store,
2461 prev->upstream.store, 0);
2462
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;
2466 }
2467 }
2468
2469 ngx_conf_merge_uint_value(conf->upstream.store_access,
2470 prev->upstream.store_access, 0600);
2471
2472 ngx_conf_merge_value(conf->upstream.buffering,
2473 prev->upstream.buffering, 1);
2474
2475 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2476 prev->upstream.ignore_client_abort, 0);
2477
2478 ngx_conf_merge_ptr_value(conf->upstream.local,
2479 prev->upstream.local, NULL);
2480
2481 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2482 prev->upstream.connect_timeout, 60000);
2483
2484 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2485 prev->upstream.send_timeout, 60000);
2486
2487 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2488 prev->upstream.read_timeout, 60000);
2489
2490 ngx_conf_merge_size_value(conf->upstream.send_lowat,
2491 prev->upstream.send_lowat, 0);
2492
2493 ngx_conf_merge_size_value(conf->upstream.buffer_size,
2494 prev->upstream.buffer_size,
2495 (size_t) ngx_pagesize);
2496
2497 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2498 8, ngx_pagesize);
2499
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;
2504 }
2505
2506
2507 size = conf->upstream.buffer_size;
2508 if (size < conf->upstream.bufs.size) {
2509 size = conf->upstream.bufs.size;
2510 }
2511
2512
2513 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2514 prev->upstream.busy_buffers_size_conf,
2515 NGX_CONF_UNSET_SIZE);
2516
2517 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2518 conf->upstream.busy_buffers_size = 2 * size;
2519 } else {
2520 conf->upstream.busy_buffers_size =
2521 conf->upstream.busy_buffers_size_conf;
2522 }
2523
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\"");
2529
2530 return NGX_CONF_ERROR;
2531 }
2532
2533 if (conf->upstream.busy_buffers_size
2534 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2535 {
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");
2539
2540 return NGX_CONF_ERROR;
2541 }
2542
2543
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);
2547
2548 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2549 conf->upstream.temp_file_write_size = 2 * size;
2550 } else {
2551 conf->upstream.temp_file_write_size =
2552 conf->upstream.temp_file_write_size_conf;
2553 }
2554
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\"");
2560
2561 return NGX_CONF_ERROR;
2562 }
2563
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);
2567
2568 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2569 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2570 } else {
2571 conf->upstream.max_temp_file_size =
2572 conf->upstream.max_temp_file_size_conf;
2573 }
2574
2575 if (conf->upstream.max_temp_file_size != 0
2576 && conf->upstream.max_temp_file_size < size)
2577 {
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\"");
2583
2584 return NGX_CONF_ERROR;
2585 }
2586
2587
2588 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2589 prev->upstream.ignore_headers,
2590 NGX_CONF_BITMASK_SET);
2591
2592
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));
2598
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;
2602 }
2603
2604 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2605 prev->upstream.temp_path,
2606 &ngx_http_proxy_temp_path)
2607 != NGX_OK)
2608 {
2609 return NGX_CONF_ERROR;
2610 }
2611
2612
2613 #if (NGX_HTTP_CACHE)
2614
2615 ngx_conf_merge_ptr_value(conf->upstream.cache,
2616 prev->upstream.cache, NULL);
2617
2618 if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2619 ngx_shm_zone_t *shm_zone;
2620
2621 shm_zone = conf->upstream.cache;
2622
2623 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2624 "\"proxy_cache\" zone \"%V\" is unknown",
2625 &shm_zone->shm.name);
2626
2627 return NGX_CONF_ERROR;
2628 }
2629
2630 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2631 prev->upstream.cache_min_uses, 1);
2632
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));
2637
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;
2641 }
2642
2643 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2644 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2645 }
2646
2647 if (conf->upstream.cache_methods == 0) {
2648 conf->upstream.cache_methods = prev->upstream.cache_methods;
2649 }
2650
2651 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2652
2653 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2654 prev->upstream.cache_bypass, NULL);
2655
2656 ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2657 prev->upstream.no_cache, NULL);
2658
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\"");
2663 }
2664
2665 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2666 prev->upstream.cache_valid, NULL);
2667
2668 if (conf->cache_key.value.data == NULL) {
2669 conf->cache_key = prev->cache_key;
2670 }
2671
2672 ngx_conf_merge_value(conf->upstream.cache_lock,
2673 prev->upstream.cache_lock, 0);
2674
2675 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2676 prev->upstream.cache_lock_timeout, 5000);
2677
2678 #endif
2679
2680 ngx_conf_merge_str_value(conf->method, prev->method, "");
2681
2682 if (conf->method.len
2683 && conf->method.data[conf->method.len - 1] != ' ')
2684 {
2685 conf->method.data[conf->method.len] = ' ';
2686 conf->method.len++;
2687 }
2688
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);
2693
2694 ngx_conf_merge_value(conf->upstream.intercept_errors,
2695 prev->upstream.intercept_errors, 0);
2696
2697 #if (NGX_HTTP_SSL)
2698 ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
2699 prev->upstream.ssl_session_reuse, 1);
2700 #endif
2701
2702 ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
2703
2704 if (conf->redirect) {
2705
2706 if (conf->redirects == NULL) {
2707 conf->redirects = prev->redirects;
2708 }
2709
2710 if (conf->redirects == NULL && conf->url.data) {
2711
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;
2716 }
2717
2718 pr = ngx_array_push(conf->redirects);
2719 if (pr == NULL) {
2720 return NGX_CONF_ERROR;
2721 }
2722
2723 ngx_memzero(&pr->pattern.complex,
2724 sizeof(ngx_http_complex_value_t));
2725
2726 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
2727
2728 pr->handler = ngx_http_proxy_rewrite_complex_handler;
2729
2730 if (conf->vars.uri.len) {
2731 pr->pattern.complex.value = conf->url;
2732 pr->replacement.value = conf->location;
2733
2734 } else {
2735 pr->pattern.complex.value.len = conf->url.len
2736 + sizeof("/") - 1;
2737
2738 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
2739 if (p == NULL) {
2740 return NGX_CONF_ERROR;
2741 }
2742
2743 pr->pattern.complex.value.data = p;
2744
2745 p = ngx_cpymem(p, conf->url.data, conf->url.len);
2746 *p = '/';
2747
2748 ngx_str_set(&pr->replacement.value, "/");
2749 }
2750 }
2751 }
2752
2753 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
2754
2755 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
2756
2757 #if (NGX_HTTP_SSL)
2758 if (conf->upstream.ssl == NULL) {
2759 conf->upstream.ssl = prev->upstream.ssl;
2760 }
2761 #endif
2762
2763 ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
2764 NGX_HTTP_VERSION_10);
2765
2766 ngx_conf_merge_uint_value(conf->headers_hash_max_size,
2767 prev->headers_hash_max_size, 512);
2768
2769 ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
2770 prev->headers_hash_bucket_size, 64);
2771
2772 conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
2773 ngx_cacheline_size);
2774
2775 hash.max_size = conf->headers_hash_max_size;
2776 hash.bucket_size = conf->headers_hash_bucket_size;
2777 hash.name = "proxy_headers_hash";
2778
2779 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
2780 &prev->upstream, ngx_http_proxy_hide_headers, &hash)
2781 != NGX_OK)
2782 {
2783 return NGX_CONF_ERROR;
2784 }
2785
2786 if (conf->upstream.upstream == NULL) {
2787 conf->upstream.upstream = prev->upstream.upstream;
2788 conf->vars = prev->vars;
2789 }
2790
2791 if (conf->proxy_lengths == NULL) {
2792 conf->proxy_lengths = prev->proxy_lengths;
2793 conf->proxy_values = prev->proxy_values;
2794 }
2795
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;
2801 }
2802 }
2803
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;
2808 }
2809
2810 if (conf->body_source.data && conf->body_set_len == NULL) {
2811
2812 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2813
2814 sc.cf = cf;
2815 sc.source = &conf->body_source;
2816 sc.flushes = &conf->flushes;
2817 sc.lengths = &conf->body_set_len;
2818 sc.values = &conf->body_set;
2819 sc.complete_lengths = 1;
2820 sc.complete_values = 1;
2821
2822 if (ngx_http_script_compile(&sc) != NGX_OK) {
2823 return NGX_CONF_ERROR;
2824 }
2825 }
2826
2827 if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
2828 return NGX_CONF_ERROR;
2829 }
2830
2831 return NGX_CONF_OK;
2832 }
2833
2834
2835 static ngx_int_t
2836 ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
2837 ngx_http_proxy_loc_conf_t *prev)
2838 {
2839 u_char *p;
2840 size_t size;
2841 uintptr_t *code;
2842 ngx_uint_t i;
2843 ngx_array_t headers_names, headers_merged;
2844 ngx_keyval_t *src, *s, *h;
2845 ngx_hash_key_t *hk;
2846 ngx_hash_init_t hash;
2847 ngx_http_script_compile_t sc;
2848 ngx_http_script_copy_code_t *copy;
2849
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;
2856 }
2857
2858 if (conf->headers_set_hash.buckets
2859 #if (NGX_HTTP_CACHE)
2860 && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
2861 #endif
2862 )
2863 {
2864 return NGX_OK;
2865 }
2866
2867
2868 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2869 != NGX_OK)
2870 {
2871 return NGX_ERROR;
2872 }
2873
2874 if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
2875 != NGX_OK)
2876 {
2877 return NGX_ERROR;
2878 }
2879
2880 if (conf->headers_source == NULL) {
2881 conf->headers_source = ngx_array_create(cf->pool, 4,
2882 sizeof(ngx_keyval_t));
2883 if (conf->headers_source == NULL) {
2884 return NGX_ERROR;
2885 }
2886 }
2887
2888 conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
2889 if (conf->headers_set_len == NULL) {
2890 return NGX_ERROR;
2891 }
2892
2893 conf->headers_set = ngx_array_create(cf->pool, 512, 1);
2894 if (conf->headers_set == NULL) {
2895 return NGX_ERROR;
2896 }
2897
2898
2899 #if (NGX_HTTP_CACHE)
2900
2901 h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
2902 ngx_http_proxy_headers;
2903 #else
2904
2905 h = ngx_http_proxy_headers;
2906
2907 #endif
2908
2909 src = conf->headers_source->elts;
2910 for (i = 0; i < conf->headers_source->nelts; i++) {
2911
2912 s = ngx_array_push(&headers_merged);
2913 if (s == NULL) {
2914 return NGX_ERROR;
2915 }
2916
2917 *s = src[i];
2918 }
2919
2920 while (h->key.len) {
2921
2922 src = headers_merged.elts;
2923 for (i = 0; i < headers_merged.nelts; i++) {
2924 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2925 goto next;
2926 }
2927 }
2928
2929 s = ngx_array_push(&headers_merged);
2930 if (s == NULL) {
2931 return NGX_ERROR;
2932 }
2933
2934 *s = *h;
2935
2936 next:
2937
2938 h++;
2939 }
2940
2941
2942 src = headers_merged.elts;
2943 for (i = 0; i < headers_merged.nelts; i++) {
2944
2945 hk = ngx_array_push(&headers_names);
2946 if (hk == NULL) {
2947 return NGX_ERROR;
2948 }
2949
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;
2953
2954 if (src[i].value.len == 0) {
2955 continue;
2956 }
2957
2958 if (ngx_http_script_variables_count(&src[i].value) == 0) {
2959 copy = ngx_array_push_n(conf->headers_set_len,
2960 sizeof(ngx_http_script_copy_code_t));
2961 if (copy == NULL) {
2962 return NGX_ERROR;
2963 }
2964
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;
2969
2970
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);
2976
2977 copy = ngx_array_push_n(conf->headers_set, size);
2978 if (copy == NULL) {
2979 return NGX_ERROR;
2980 }
2981
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;
2985
2986 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2987
2988 p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2989 *p++ = ':'; *p++ = ' ';
2990 p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
2991 *p++ = CR; *p = LF;
2992
2993 } else {
2994 copy = ngx_array_push_n(conf->headers_set_len,
2995 sizeof(ngx_http_script_copy_code_t));
2996 if (copy == NULL) {
2997 return NGX_ERROR;
2998 }
2999
3000 copy->code = (ngx_http_script_code_pt)
3001 ngx_http_script_copy_len_code;
3002 copy->len = src[i].key.len + sizeof(": ") - 1;
3003
3004
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);
3008
3009 copy = ngx_array_push_n(conf->headers_set, size);
3010 if (copy == NULL) {
3011 return NGX_ERROR;
3012 }
3013
3014 copy->code = ngx_http_script_copy_code;
3015 copy->len = src[i].key.len + sizeof(": ") - 1;
3016
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 = ' ';
3020
3021
3022 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3023
3024 sc.cf = cf;
3025 sc.source = &src[i].value;
3026 sc.flushes = &conf->flushes;
3027 sc.lengths = &conf->headers_set_len;
3028 sc.values = &conf->headers_set;
3029
3030 if (ngx_http_script_compile(&sc) != NGX_OK) {
3031 return NGX_ERROR;
3032 }
3033
3034
3035 copy = ngx_array_push_n(conf->headers_set_len,
3036 sizeof(ngx_http_script_copy_code_t));
3037 if (copy == NULL) {
3038 return NGX_ERROR;
3039 }
3040
3041 copy->code = (ngx_http_script_code_pt)
3042 ngx_http_script_copy_len_code;
3043 copy->len = sizeof(CRLF) - 1;
3044
3045
3046 size = (sizeof(ngx_http_script_copy_code_t)
3047 + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3048 & ~(sizeof(uintptr_t) - 1);
3049
3050 copy = ngx_array_push_n(conf->headers_set, size);
3051 if (copy == NULL) {
3052 return NGX_ERROR;
3053 }
3054
3055 copy->code = ngx_http_script_copy_code;
3056 copy->len = sizeof(CRLF) - 1;
3057
3058 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3059 *p++ = CR; *p = LF;
3060 }
3061
3062 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3063 if (code == NULL) {
3064 return NGX_ERROR;
3065 }
3066
3067 *code = (uintptr_t) NULL;
3068
3069 code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
3070 if (code == NULL) {
3071 return NGX_ERROR;
3072 }
3073
3074 *code = (uintptr_t) NULL;
3075 }
3076
3077 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3078 if (code == NULL) {
3079 return NGX_ERROR;
3080 }
3081
3082 *code = (uintptr_t) NULL;
3083
3084
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;
3092
3093 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3094 }
3095
3096
3097 static char *
3098 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3099 {
3100 ngx_http_proxy_loc_conf_t *plcf = conf;
3101
3102 size_t add;
3103 u_short port;
3104 ngx_str_t *value, *url;
3105 ngx_url_t u;
3106 ngx_uint_t n;
3107 ngx_http_core_loc_conf_t *clcf;
3108 ngx_http_script_compile_t sc;
3109
3110 if (plcf->upstream.upstream || plcf->proxy_lengths) {
3111 return "is duplicate";
3112 }
3113
3114 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3115
3116 clcf->handler = ngx_http_proxy_handler;
3117
3118 if (clcf->name.data[clcf->name.len - 1] == '/') {
3119 clcf->auto_redirect = 1;
3120 }
3121
3122 value = cf->args->elts;
3123
3124 url = &value[1];
3125
3126 n = ngx_http_script_variables_count(url);
3127
3128 if (n) {
3129
3130 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3131
3132 sc.cf = cf;
3133 sc.source = url;
3134 sc.lengths = &plcf->proxy_lengths;
3135 sc.values = &plcf->proxy_values;
3136 sc.variables = n;
3137 sc.complete_lengths = 1;
3138 sc.complete_values = 1;
3139
3140 if (ngx_http_script_compile(&sc) != NGX_OK) {
3141 return NGX_CONF_ERROR;
3142 }
3143
3144 #if (NGX_HTTP_SSL)
3145 if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3146 return NGX_CONF_ERROR;
3147 }
3148 #endif
3149
3150 return NGX_CONF_OK;
3151 }
3152
3153 if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3154 add = 7;
3155 port = 80;
3156
3157 } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3158
3159 #if (NGX_HTTP_SSL)
3160 if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3161 return NGX_CONF_ERROR;
3162 }
3163
3164 add = 8;
3165 port = 443;
3166 #else
3167 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3168 "https protocol requires SSL support");
3169 return NGX_CONF_ERROR;
3170 #endif
3171
3172 } else {
3173 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3174 return NGX_CONF_ERROR;
3175 }
3176
3177 ngx_memzero(&u, sizeof(ngx_url_t));
3178
3179 u.url.len = url->len - add;
3180 u.url.data = url->data + add;
3181 u.default_port = port;
3182 u.uri_part = 1;
3183 u.no_resolve = 1;
3184
3185 plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3186 if (plcf->upstream.upstream == NULL) {
3187 return NGX_CONF_ERROR;
3188 }
3189
3190 plcf->vars.schema.len = add;
3191 plcf->vars.schema.data = url->data;
3192 plcf->vars.key_start = plcf->vars.schema;
3193
3194 ngx_http_proxy_set_vars(&u, &plcf->vars);
3195
3196 plcf->location = clcf->name;
3197
3198 if (clcf->named
3199 #if (NGX_PCRE)
3200 || clcf->regex
3201 #endif
3202 || clcf->noname)
3203 {
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;
3212 }
3213
3214 plcf->location.len = 0;
3215 }
3216
3217 plcf->url = *url;
3218
3219 return NGX_CONF_OK;
3220 }
3221
3222
3223 static char *
3224 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3225 {
3226 ngx_http_proxy_loc_conf_t *plcf = conf;
3227
3228 u_char *p;
3229 ngx_str_t *value;
3230 ngx_http_proxy_rewrite_t *pr;
3231 ngx_http_compile_complex_value_t ccv;
3232
3233 if (plcf->redirect == 0) {
3234 return NGX_CONF_OK;
3235 }
3236
3237 plcf->redirect = 1;
3238
3239 value = cf->args->elts;
3240
3241 if (cf->args->nelts == 2) {
3242 if (ngx_strcmp(value[1].data, "off") == 0) {
3243 plcf->redirect = 0;
3244 plcf->redirects = NULL;
3245 return NGX_CONF_OK;
3246 }
3247
3248 if (ngx_strcmp(value[1].data, "false") == 0) {
3249 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3250 "invalid parameter \"false\", use \"off\" instead");
3251 plcf->redirect = 0;
3252 plcf->redirects = NULL;
3253 return NGX_CONF_OK;
3254 }
3255
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;
3260 }
3261 }
3262
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;
3268 }
3269 }
3270
3271 pr = ngx_array_push(plcf->redirects);
3272 if (pr == NULL) {
3273 return NGX_CONF_ERROR;
3274 }
3275
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;
3282 }
3283
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;
3289 }
3290
3291 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3292
3293 ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3294
3295 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3296
3297 if (plcf->vars.uri.len) {
3298 pr->pattern.complex.value = plcf->url;
3299 pr->replacement.value = plcf->location;
3300
3301 } else {
3302 pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3303
3304 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3305 if (p == NULL) {
3306 return NGX_CONF_ERROR;
3307 }
3308
3309 pr->pattern.complex.value.data = p;
3310
3311 p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3312 *p = '/';
3313
3314 ngx_str_set(&pr->replacement.value, "/");
3315 }
3316
3317 return NGX_CONF_OK;
3318 }
3319
3320
3321 if (value[1].data[0] == '~') {
3322 value[1].len--;
3323 value[1].data++;
3324
3325 if (value[1].data[0] == '*') {
3326 value[1].len--;
3327 value[1].data++;
3328
3329 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3330 return NGX_CONF_ERROR;
3331 }
3332
3333 } else {
3334 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3335 return NGX_CONF_ERROR;
3336 }
3337 }
3338
3339 } else {
3340
3341 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3342
3343 ccv.cf = cf;
3344 ccv.value = &value[1];
3345 ccv.complex_value = &pr->pattern.complex;
3346
3347 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3348 return NGX_CONF_ERROR;
3349 }
3350
3351 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3352 }
3353
3354
3355 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3356
3357 ccv.cf = cf;
3358 ccv.value = &value[2];
3359 ccv.complex_value = &pr->replacement;
3360
3361 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3362 return NGX_CONF_ERROR;
3363 }
3364
3365 return NGX_CONF_OK;
3366 }
3367
3368
3369 static char *
3370 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3371 {
3372 ngx_http_proxy_loc_conf_t *plcf = conf;
3373
3374 ngx_str_t *value;
3375 ngx_http_proxy_rewrite_t *pr;
3376 ngx_http_compile_complex_value_t ccv;
3377
3378 if (plcf->cookie_domains == NULL) {
3379 return NGX_CONF_OK;
3380 }
3381
3382 value = cf->args->elts;
3383
3384 if (cf->args->nelts == 2) {
3385
3386 if (ngx_strcmp(value[1].data, "off") == 0) {
3387 plcf->cookie_domains = NULL;
3388 return NGX_CONF_OK;
3389 }
3390
3391 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3392 "invalid parameter \"%V\"", &value[1]);
3393 return NGX_CONF_ERROR;
3394 }
3395
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;
3401 }
3402 }
3403
3404 pr = ngx_array_push(plcf->cookie_domains);
3405 if (pr == NULL) {
3406 return NGX_CONF_ERROR;
3407 }
3408
3409 if (value[1].data[0] == '~') {
3410 value[1].len--;
3411 value[1].data++;
3412
3413 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3414 return NGX_CONF_ERROR;
3415 }
3416
3417 } else {
3418
3419 if (value[1].data[0] == '.') {
3420 value[1].len--;
3421 value[1].data++;
3422 }
3423
3424 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3425
3426 ccv.cf = cf;
3427 ccv.value = &value[1];
3428 ccv.complex_value = &pr->pattern.complex;
3429
3430 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3431 return NGX_CONF_ERROR;
3432 }
3433
3434 pr->handler = ngx_http_proxy_rewrite_domain_handler;
3435
3436 if (value[2].data[0] == '.') {
3437 value[2].len--;
3438 value[2].data++;
3439 }
3440 }
3441
3442 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3443
3444 ccv.cf = cf;
3445 ccv.value = &value[2];
3446 ccv.complex_value = &pr->replacement;
3447
3448 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3449 return NGX_CONF_ERROR;
3450 }
3451
3452 return NGX_CONF_OK;
3453 }
3454
3455
3456 static char *
3457 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3458 {
3459 ngx_http_proxy_loc_conf_t *plcf = conf;
3460
3461 ngx_str_t *value;
3462 ngx_http_proxy_rewrite_t *pr;
3463 ngx_http_compile_complex_value_t ccv;
3464
3465 if (plcf->cookie_paths == NULL) {
3466 return NGX_CONF_OK;
3467 }
3468
3469 value = cf->args->elts;
3470
3471 if (cf->args->nelts == 2) {
3472
3473 if (ngx_strcmp(value[1].data, "off") == 0) {
3474 plcf->cookie_paths = NULL;
3475 return NGX_CONF_OK;
3476 }
3477
3478 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3479 "invalid parameter \"%V\"", &value[1]);
3480 return NGX_CONF_ERROR;
3481 }
3482
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;
3488 }
3489 }
3490
3491 pr = ngx_array_push(plcf->cookie_paths);
3492 if (pr == NULL) {
3493 return NGX_CONF_ERROR;
3494 }
3495
3496 if (value[1].data[0] == '~') {
3497 value[1].len--;
3498 value[1].data++;
3499
3500 if (value[1].data[0] == '*') {
3501 value[1].len--;
3502 value[1].data++;
3503
3504 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3505 return NGX_CONF_ERROR;
3506 }
3507
3508 } else {
3509 if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3510 return NGX_CONF_ERROR;
3511 }
3512 }
3513
3514 } else {
3515
3516 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3517
3518 ccv.cf = cf;
3519 ccv.value = &value[1];
3520 ccv.complex_value = &pr->pattern.complex;
3521
3522 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3523 return NGX_CONF_ERROR;
3524 }
3525
3526 pr->handler = ngx_http_proxy_rewrite_complex_handler;
3527 }
3528
3529 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3530
3531 ccv.cf = cf;
3532 ccv.value = &value[2];
3533 ccv.complex_value = &pr->replacement;
3534
3535 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3536 return NGX_CONF_ERROR;
3537 }
3538
3539 return NGX_CONF_OK;
3540 }
3541
3542
3543 static ngx_int_t
3544 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
3545 ngx_str_t *regex, ngx_uint_t caseless)
3546 {
3547 #if (NGX_PCRE)
3548 u_char errstr[NGX_MAX_CONF_ERRSTR];
3549 ngx_regex_compile_t rc;
3550
3551 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3552
3553 rc.pattern = *regex;
3554 rc.err.len = NGX_MAX_CONF_ERRSTR;
3555 rc.err.data = errstr;
3556
3557 if (caseless) {
3558 rc.options = NGX_REGEX_CASELESS;
3559 }
3560
3561 pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
3562 if (pr->pattern.regex == NULL) {
3563 return NGX_ERROR;
3564 }
3565
3566 pr->handler = ngx_http_proxy_rewrite_regex_handler;
3567
3568 return NGX_OK;
3569
3570 #else
3571
3572 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3573 "using regex \"%V\" requires PCRE library", regex);
3574 return NGX_ERROR;
3575
3576 #endif
3577 }
3578
3579
3580 static char *
3581 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3582 {
3583 ngx_http_proxy_loc_conf_t *plcf = conf;
3584
3585 ngx_str_t *value;
3586 ngx_http_script_compile_t sc;
3587
3588 if (plcf->upstream.store != NGX_CONF_UNSET
3589 || plcf->upstream.store_lengths)
3590 {
3591 return "is duplicate";
3592 }
3593
3594 value = cf->args->elts;
3595
3596 if (ngx_strcmp(value[1].data, "off") == 0) {
3597 plcf->upstream.store = 0;
3598 return NGX_CONF_OK;
3599 }
3600
3601 #if (NGX_HTTP_CACHE)
3602
3603 if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
3604 && plcf->upstream.cache != NULL)
3605 {
3606 return "is incompatible with \"proxy_cache\"";
3607 }
3608
3609 #endif
3610
3611 if (ngx_strcmp(value[1].data, "on") == 0) {
3612 plcf->upstream.store = 1;
3613 return NGX_CONF_OK;
3614 }
3615
3616 /* include the terminating '\0' into script */
3617 value[1].len++;
3618
3619 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3620
3621 sc.cf = cf;
3622 sc.source = &value[1];
3623 sc.lengths = &plcf->upstream.store_lengths;
3624 sc.values = &plcf->upstream.store_values;
3625 sc.variables = ngx_http_script_variables_count(&value[1]);
3626 sc.complete_lengths = 1;
3627 sc.complete_values = 1;
3628
3629 if (ngx_http_script_compile(&sc) != NGX_OK) {
3630 return NGX_CONF_ERROR;
3631 }
3632
3633 return NGX_CONF_OK;
3634 }
3635
3636
3637 #if (NGX_HTTP_CACHE)
3638
3639 static char *
3640 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3641 {
3642 ngx_http_proxy_loc_conf_t *plcf = conf;
3643
3644 ngx_str_t *value;
3645
3646 value = cf->args->elts;
3647
3648 if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
3649 return "is duplicate";
3650 }
3651
3652 if (ngx_strcmp(value[1].data, "off") == 0) {
3653 plcf->upstream.cache = NULL;
3654 return NGX_CONF_OK;
3655 }
3656
3657 if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
3658 return "is incompatible with \"proxy_store\"";
3659 }
3660
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;
3665 }
3666
3667 return NGX_CONF_OK;
3668 }
3669
3670
3671 static char *
3672 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3673 {
3674 ngx_http_proxy_loc_conf_t *plcf = conf;
3675
3676 ngx_str_t *value;
3677 ngx_http_compile_complex_value_t ccv;
3678
3679 value = cf->args->elts;
3680
3681 if (plcf->cache_key.value.data) {
3682 return "is duplicate";
3683 }
3684
3685 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3686
3687 ccv.cf = cf;
3688 ccv.value = &value[1];
3689 ccv.complex_value = &plcf->cache_key;
3690
3691 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3692 return NGX_CONF_ERROR;
3693 }
3694
3695 return NGX_CONF_OK;
3696 }
3697
3698 #endif
3699
3700
3701 static char *
3702 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
3703 {
3704 #if (NGX_FREEBSD)
3705 ssize_t *np = data;
3706
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);
3712
3713 return NGX_CONF_ERROR;
3714 }
3715
3716 #elif !(NGX_HAVE_SO_SNDLOWAT)
3717 ssize_t *np = data;
3718
3719 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3720 "\"proxy_send_lowat\" is not supported, ignored");
3721
3722 *np = 0;
3723
3724 #endif
3725
3726 return NGX_CONF_OK;
3727 }
3728
3729
3730 #if (NGX_HTTP_SSL)
3731
3732 static ngx_int_t
3733 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
3734 {
3735 ngx_pool_cleanup_t *cln;
3736
3737 plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
3738 if (plcf->upstream.ssl == NULL) {
3739 return NGX_ERROR;
3740 }
3741
3742 plcf->upstream.ssl->log = cf->log;
3743
3744 if (ngx_ssl_create(plcf->upstream.ssl,
3745 NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
3746 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
3747 NULL)
3748 != NGX_OK)
3749 {
3750 return NGX_ERROR;
3751 }
3752
3753 cln = ngx_pool_cleanup_add(cf->pool, 0);
3754 if (cln == NULL) {
3755 return NGX_ERROR;
3756 }
3757
3758 cln->handler = ngx_ssl_cleanup_ctx;
3759 cln->data = plcf->upstream.ssl;
3760
3761 return NGX_OK;
3762 }
3763
3764 #endif
3765
3766
3767 static void
3768 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
3769 {
3770 if (u->family != AF_UNIX) {
3771
3772 if (u->no_port || u->port == u->default_port) {
3773
3774 v->host_header = u->host;
3775
3776 if (u->default_port == 80) {
3777 ngx_str_set(&v->port, "80");
3778
3779 } else {
3780 ngx_str_set(&v->port, "443");
3781 }
3782
3783 } else {
3784 v->host_header.len = u->host.len + 1 + u->port_text.len;
3785 v->host_header.data = u->host.data;
3786 v->port = u->port_text;
3787 }
3788
3789 v->key_start.len += v->host_header.len;
3790
3791 } else {
3792 ngx_str_set(&v->host_header, "localhost");
3793 ngx_str_null(&v->port);
3794 v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
3795 }
3796
3797 v->uri = u->uri;
3798 }
3799
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.