Annotation of embedaddon/nginx/src/http/modules/ngx_http_proxy_module.c, revision 1.1.1.1
1.1 misho 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,
619: NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
620:
621: { ngx_null_string, NULL, NULL, 0, 0, 0 }
622: };
623:
624:
625: static ngx_path_init_t ngx_http_proxy_temp_path = {
626: ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
627: };
628:
629:
630: static ngx_int_t
631: ngx_http_proxy_handler(ngx_http_request_t *r)
632: {
633: ngx_int_t rc;
634: ngx_http_upstream_t *u;
635: ngx_http_proxy_ctx_t *ctx;
636: ngx_http_proxy_loc_conf_t *plcf;
637:
638: if (ngx_http_upstream_create(r) != NGX_OK) {
639: return NGX_HTTP_INTERNAL_SERVER_ERROR;
640: }
641:
642: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
643: if (ctx == NULL) {
644: return NGX_ERROR;
645: }
646:
647: ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
648:
649: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
650:
651: u = r->upstream;
652:
653: if (plcf->proxy_lengths == NULL) {
654: ctx->vars = plcf->vars;
655: u->schema = plcf->vars.schema;
656: #if (NGX_HTTP_SSL)
657: u->ssl = (plcf->upstream.ssl != NULL);
658: #endif
659:
660: } else {
661: if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
662: return NGX_HTTP_INTERNAL_SERVER_ERROR;
663: }
664: }
665:
666: u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
667:
668: u->conf = &plcf->upstream;
669:
670: #if (NGX_HTTP_CACHE)
671: u->create_key = ngx_http_proxy_create_key;
672: #endif
673: u->create_request = ngx_http_proxy_create_request;
674: u->reinit_request = ngx_http_proxy_reinit_request;
675: u->process_header = ngx_http_proxy_process_status_line;
676: u->abort_request = ngx_http_proxy_abort_request;
677: u->finalize_request = ngx_http_proxy_finalize_request;
678: r->state = 0;
679:
680: if (plcf->redirects) {
681: u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
682: }
683:
684: if (plcf->cookie_domains || plcf->cookie_paths) {
685: u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
686: }
687:
688: u->buffering = plcf->upstream.buffering;
689:
690: u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
691: if (u->pipe == NULL) {
692: return NGX_HTTP_INTERNAL_SERVER_ERROR;
693: }
694:
695: u->pipe->input_filter = ngx_http_proxy_copy_filter;
696: u->pipe->input_ctx = r;
697:
698: u->input_filter_init = ngx_http_proxy_input_filter_init;
699: u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
700: u->input_filter_ctx = r;
701:
702: u->accel = 1;
703:
704: rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
705:
706: if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
707: return rc;
708: }
709:
710: return NGX_DONE;
711: }
712:
713:
714: static ngx_int_t
715: ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
716: ngx_http_proxy_loc_conf_t *plcf)
717: {
718: u_char *p;
719: size_t add;
720: u_short port;
721: ngx_str_t proxy;
722: ngx_url_t url;
723: ngx_http_upstream_t *u;
724:
725: if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
726: plcf->proxy_values->elts)
727: == NULL)
728: {
729: return NGX_ERROR;
730: }
731:
732: if (proxy.len > 7
733: && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
734: {
735: add = 7;
736: port = 80;
737:
738: #if (NGX_HTTP_SSL)
739:
740: } else if (proxy.len > 8
741: && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
742: {
743: add = 8;
744: port = 443;
745: r->upstream->ssl = 1;
746:
747: #endif
748:
749: } else {
750: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
751: "invalid URL prefix in \"%V\"", &proxy);
752: return NGX_ERROR;
753: }
754:
755: u = r->upstream;
756:
757: u->schema.len = add;
758: u->schema.data = proxy.data;
759:
760: ngx_memzero(&url, sizeof(ngx_url_t));
761:
762: url.url.len = proxy.len - add;
763: url.url.data = proxy.data + add;
764: url.default_port = port;
765: url.uri_part = 1;
766: url.no_resolve = 1;
767:
768: if (ngx_parse_url(r->pool, &url) != NGX_OK) {
769: if (url.err) {
770: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
771: "%s in upstream \"%V\"", url.err, &url.url);
772: }
773:
774: return NGX_ERROR;
775: }
776:
777: if (url.uri.len) {
778: if (url.uri.data[0] == '?') {
779: p = ngx_pnalloc(r->pool, url.uri.len + 1);
780: if (p == NULL) {
781: return NGX_ERROR;
782: }
783:
784: *p++ = '/';
785: ngx_memcpy(p, url.uri.data, url.uri.len);
786:
787: url.uri.len++;
788: url.uri.data = p - 1;
789: }
790: }
791:
792: ctx->vars.key_start = u->schema;
793:
794: ngx_http_proxy_set_vars(&url, &ctx->vars);
795:
796: u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
797: if (u->resolved == NULL) {
798: return NGX_ERROR;
799: }
800:
801: if (url.addrs && url.addrs[0].sockaddr) {
802: u->resolved->sockaddr = url.addrs[0].sockaddr;
803: u->resolved->socklen = url.addrs[0].socklen;
804: u->resolved->naddrs = 1;
805: u->resolved->host = url.addrs[0].name;
806:
807: } else {
808: u->resolved->host = url.host;
809: u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
810: u->resolved->no_port = url.no_port;
811: }
812:
813: return NGX_OK;
814: }
815:
816:
817: #if (NGX_HTTP_CACHE)
818:
819: static ngx_int_t
820: ngx_http_proxy_create_key(ngx_http_request_t *r)
821: {
822: size_t len, loc_len;
823: u_char *p;
824: uintptr_t escape;
825: ngx_str_t *key;
826: ngx_http_upstream_t *u;
827: ngx_http_proxy_ctx_t *ctx;
828: ngx_http_proxy_loc_conf_t *plcf;
829:
830: u = r->upstream;
831:
832: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
833:
834: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
835:
836: key = ngx_array_push(&r->cache->keys);
837: if (key == NULL) {
838: return NGX_ERROR;
839: }
840:
841: if (plcf->cache_key.value.data) {
842:
843: if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
844: return NGX_ERROR;
845: }
846:
847: return NGX_OK;
848: }
849:
850: *key = ctx->vars.key_start;
851:
852: key = ngx_array_push(&r->cache->keys);
853: if (key == NULL) {
854: return NGX_ERROR;
855: }
856:
857: if (plcf->proxy_lengths && ctx->vars.uri.len) {
858:
859: *key = ctx->vars.uri;
860: u->uri = ctx->vars.uri;
861:
862: return NGX_OK;
863:
864: } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
865: {
866: *key = r->unparsed_uri;
867: u->uri = r->unparsed_uri;
868:
869: return NGX_OK;
870: }
871:
872: loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
873:
874: if (r->quoted_uri || r->internal) {
875: escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
876: r->uri.len - loc_len, NGX_ESCAPE_URI);
877: } else {
878: escape = 0;
879: }
880:
881: len = ctx->vars.uri.len + r->uri.len - loc_len + escape
882: + sizeof("?") - 1 + r->args.len;
883:
884: p = ngx_pnalloc(r->pool, len);
885: if (p == NULL) {
886: return NGX_ERROR;
887: }
888:
889: key->data = p;
890:
891: if (r->valid_location) {
892: p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
893: }
894:
895: if (escape) {
896: ngx_escape_uri(p, r->uri.data + loc_len,
897: r->uri.len - loc_len, NGX_ESCAPE_URI);
898: p += r->uri.len - loc_len + escape;
899:
900: } else {
901: p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
902: }
903:
904: if (r->args.len > 0) {
905: *p++ = '?';
906: p = ngx_copy(p, r->args.data, r->args.len);
907: }
908:
909: key->len = p - key->data;
910: u->uri = *key;
911:
912: return NGX_OK;
913: }
914:
915: #endif
916:
917:
918: static ngx_int_t
919: ngx_http_proxy_create_request(ngx_http_request_t *r)
920: {
921: size_t len, uri_len, loc_len, body_len;
922: uintptr_t escape;
923: ngx_buf_t *b;
924: ngx_str_t method;
925: ngx_uint_t i, unparsed_uri;
926: ngx_chain_t *cl, *body;
927: ngx_list_part_t *part;
928: ngx_table_elt_t *header;
929: ngx_http_upstream_t *u;
930: ngx_http_proxy_ctx_t *ctx;
931: ngx_http_script_code_pt code;
932: ngx_http_script_engine_t e, le;
933: ngx_http_proxy_loc_conf_t *plcf;
934: ngx_http_script_len_code_pt lcode;
935:
936: u = r->upstream;
937:
938: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
939:
940: if (u->method.len) {
941: /* HEAD was changed to GET to cache response */
942: method = u->method;
943: method.len++;
944:
945: } else if (plcf->method.len) {
946: method = plcf->method;
947:
948: } else {
949: method = r->method_name;
950: method.len++;
951: }
952:
953: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
954:
955: if (method.len == 5
956: && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
957: {
958: ctx->head = 1;
959: }
960:
961: len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
962:
963: escape = 0;
964: loc_len = 0;
965: unparsed_uri = 0;
966:
967: if (plcf->proxy_lengths && ctx->vars.uri.len) {
968: uri_len = ctx->vars.uri.len;
969:
970: } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
971: {
972: unparsed_uri = 1;
973: uri_len = r->unparsed_uri.len;
974:
975: } else {
976: loc_len = (r->valid_location && ctx->vars.uri.len) ?
977: plcf->location.len : 0;
978:
979: if (r->quoted_uri || r->space_in_uri || r->internal) {
980: escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
981: r->uri.len - loc_len, NGX_ESCAPE_URI);
982: }
983:
984: uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
985: + sizeof("?") - 1 + r->args.len;
986: }
987:
988: if (uri_len == 0) {
989: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
990: "zero length URI to proxy");
991: return NGX_ERROR;
992: }
993:
994: len += uri_len;
995:
996: ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
997:
998: if (plcf->body_set_len) {
999: le.ip = plcf->body_set_len->elts;
1000: le.request = r;
1001: le.flushed = 1;
1002: body_len = 0;
1003:
1004: while (*(uintptr_t *) le.ip) {
1005: lcode = *(ngx_http_script_len_code_pt *) le.ip;
1006: body_len += lcode(&le);
1007: }
1008:
1009: ctx->internal_body_length = body_len;
1010: len += body_len;
1011:
1012: } else {
1013: ctx->internal_body_length = r->headers_in.content_length_n;
1014: }
1015:
1016: le.ip = plcf->headers_set_len->elts;
1017: le.request = r;
1018: le.flushed = 1;
1019:
1020: while (*(uintptr_t *) le.ip) {
1021: while (*(uintptr_t *) le.ip) {
1022: lcode = *(ngx_http_script_len_code_pt *) le.ip;
1023: len += lcode(&le);
1024: }
1025: le.ip += sizeof(uintptr_t);
1026: }
1027:
1028:
1029: if (plcf->upstream.pass_request_headers) {
1030: part = &r->headers_in.headers.part;
1031: header = part->elts;
1032:
1033: for (i = 0; /* void */; i++) {
1034:
1035: if (i >= part->nelts) {
1036: if (part->next == NULL) {
1037: break;
1038: }
1039:
1040: part = part->next;
1041: header = part->elts;
1042: i = 0;
1043: }
1044:
1045: if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1046: header[i].lowcase_key, header[i].key.len))
1047: {
1048: continue;
1049: }
1050:
1051: len += header[i].key.len + sizeof(": ") - 1
1052: + header[i].value.len + sizeof(CRLF) - 1;
1053: }
1054: }
1055:
1056:
1057: b = ngx_create_temp_buf(r->pool, len);
1058: if (b == NULL) {
1059: return NGX_ERROR;
1060: }
1061:
1062: cl = ngx_alloc_chain_link(r->pool);
1063: if (cl == NULL) {
1064: return NGX_ERROR;
1065: }
1066:
1067: cl->buf = b;
1068:
1069:
1070: /* the request line */
1071:
1072: b->last = ngx_copy(b->last, method.data, method.len);
1073:
1074: u->uri.data = b->last;
1075:
1076: if (plcf->proxy_lengths && ctx->vars.uri.len) {
1077: b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1078:
1079: } else if (unparsed_uri) {
1080: b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1081:
1082: } else {
1083: if (r->valid_location) {
1084: b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1085: }
1086:
1087: if (escape) {
1088: ngx_escape_uri(b->last, r->uri.data + loc_len,
1089: r->uri.len - loc_len, NGX_ESCAPE_URI);
1090: b->last += r->uri.len - loc_len + escape;
1091:
1092: } else {
1093: b->last = ngx_copy(b->last, r->uri.data + loc_len,
1094: r->uri.len - loc_len);
1095: }
1096:
1097: if (r->args.len > 0) {
1098: *b->last++ = '?';
1099: b->last = ngx_copy(b->last, r->args.data, r->args.len);
1100: }
1101: }
1102:
1103: u->uri.len = b->last - u->uri.data;
1104:
1105: if (plcf->http_version == NGX_HTTP_VERSION_11) {
1106: b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1107: sizeof(ngx_http_proxy_version_11) - 1);
1108:
1109: } else {
1110: b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1111: sizeof(ngx_http_proxy_version) - 1);
1112: }
1113:
1114: ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1115:
1116: e.ip = plcf->headers_set->elts;
1117: e.pos = b->last;
1118: e.request = r;
1119: e.flushed = 1;
1120:
1121: le.ip = plcf->headers_set_len->elts;
1122:
1123: while (*(uintptr_t *) le.ip) {
1124: lcode = *(ngx_http_script_len_code_pt *) le.ip;
1125:
1126: /* skip the header line name length */
1127: (void) lcode(&le);
1128:
1129: if (*(ngx_http_script_len_code_pt *) le.ip) {
1130:
1131: for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1132: lcode = *(ngx_http_script_len_code_pt *) le.ip;
1133: }
1134:
1135: e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1136:
1137: } else {
1138: e.skip = 0;
1139: }
1140:
1141: le.ip += sizeof(uintptr_t);
1142:
1143: while (*(uintptr_t *) e.ip) {
1144: code = *(ngx_http_script_code_pt *) e.ip;
1145: code((ngx_http_script_engine_t *) &e);
1146: }
1147: e.ip += sizeof(uintptr_t);
1148: }
1149:
1150: b->last = e.pos;
1151:
1152:
1153: if (plcf->upstream.pass_request_headers) {
1154: part = &r->headers_in.headers.part;
1155: header = part->elts;
1156:
1157: for (i = 0; /* void */; i++) {
1158:
1159: if (i >= part->nelts) {
1160: if (part->next == NULL) {
1161: break;
1162: }
1163:
1164: part = part->next;
1165: header = part->elts;
1166: i = 0;
1167: }
1168:
1169: if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1170: header[i].lowcase_key, header[i].key.len))
1171: {
1172: continue;
1173: }
1174:
1175: b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1176:
1177: *b->last++ = ':'; *b->last++ = ' ';
1178:
1179: b->last = ngx_copy(b->last, header[i].value.data,
1180: header[i].value.len);
1181:
1182: *b->last++ = CR; *b->last++ = LF;
1183:
1184: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1185: "http proxy header: \"%V: %V\"",
1186: &header[i].key, &header[i].value);
1187: }
1188: }
1189:
1190:
1191: /* add "\r\n" at the header end */
1192: *b->last++ = CR; *b->last++ = LF;
1193:
1194: if (plcf->body_set) {
1195: e.ip = plcf->body_set->elts;
1196: e.pos = b->last;
1197:
1198: while (*(uintptr_t *) e.ip) {
1199: code = *(ngx_http_script_code_pt *) e.ip;
1200: code((ngx_http_script_engine_t *) &e);
1201: }
1202:
1203: b->last = e.pos;
1204: }
1205:
1206: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1207: "http proxy header:\n\"%*s\"",
1208: (size_t) (b->last - b->pos), b->pos);
1209:
1210: if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
1211:
1212: body = u->request_bufs;
1213: u->request_bufs = cl;
1214:
1215: while (body) {
1216: b = ngx_alloc_buf(r->pool);
1217: if (b == NULL) {
1218: return NGX_ERROR;
1219: }
1220:
1221: ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1222:
1223: cl->next = ngx_alloc_chain_link(r->pool);
1224: if (cl->next == NULL) {
1225: return NGX_ERROR;
1226: }
1227:
1228: cl = cl->next;
1229: cl->buf = b;
1230:
1231: body = body->next;
1232: }
1233:
1234: } else {
1235: u->request_bufs = cl;
1236: }
1237:
1238: b->flush = 1;
1239: cl->next = NULL;
1240:
1241: return NGX_OK;
1242: }
1243:
1244:
1245: static ngx_int_t
1246: ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1247: {
1248: ngx_http_proxy_ctx_t *ctx;
1249:
1250: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1251:
1252: if (ctx == NULL) {
1253: return NGX_OK;
1254: }
1255:
1256: ctx->status.code = 0;
1257: ctx->status.count = 0;
1258: ctx->status.start = NULL;
1259: ctx->status.end = NULL;
1260: ctx->chunked.state = 0;
1261:
1262: r->upstream->process_header = ngx_http_proxy_process_status_line;
1263: r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1264: r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1265: r->state = 0;
1266:
1267: return NGX_OK;
1268: }
1269:
1270:
1271: static ngx_int_t
1272: ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1273: {
1274: size_t len;
1275: ngx_int_t rc;
1276: ngx_http_upstream_t *u;
1277: ngx_http_proxy_ctx_t *ctx;
1278:
1279: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1280:
1281: if (ctx == NULL) {
1282: return NGX_ERROR;
1283: }
1284:
1285: u = r->upstream;
1286:
1287: rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1288:
1289: if (rc == NGX_AGAIN) {
1290: return rc;
1291: }
1292:
1293: if (rc == NGX_ERROR) {
1294:
1295: #if (NGX_HTTP_CACHE)
1296:
1297: if (r->cache) {
1298: r->http_version = NGX_HTTP_VERSION_9;
1299: return NGX_OK;
1300: }
1301:
1302: #endif
1303:
1304: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1305: "upstream sent no valid HTTP/1.0 header");
1306:
1307: #if 0
1308: if (u->accel) {
1309: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1310: }
1311: #endif
1312:
1313: r->http_version = NGX_HTTP_VERSION_9;
1314: u->state->status = NGX_HTTP_OK;
1315: u->headers_in.connection_close = 1;
1316:
1317: return NGX_OK;
1318: }
1319:
1320: if (u->state) {
1321: u->state->status = ctx->status.code;
1322: }
1323:
1324: u->headers_in.status_n = ctx->status.code;
1325:
1326: len = ctx->status.end - ctx->status.start;
1327: u->headers_in.status_line.len = len;
1328:
1329: u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1330: if (u->headers_in.status_line.data == NULL) {
1331: return NGX_ERROR;
1332: }
1333:
1334: ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1335:
1336: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1337: "http proxy status %ui \"%V\"",
1338: u->headers_in.status_n, &u->headers_in.status_line);
1339:
1340: if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1341: u->headers_in.connection_close = 1;
1342: }
1343:
1344: u->process_header = ngx_http_proxy_process_header;
1345:
1346: return ngx_http_proxy_process_header(r);
1347: }
1348:
1349:
1350: static ngx_int_t
1351: ngx_http_proxy_process_header(ngx_http_request_t *r)
1352: {
1353: ngx_int_t rc;
1354: ngx_table_elt_t *h;
1355: ngx_http_upstream_t *u;
1356: ngx_http_proxy_ctx_t *ctx;
1357: ngx_http_upstream_header_t *hh;
1358: ngx_http_upstream_main_conf_t *umcf;
1359:
1360: umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1361:
1362: for ( ;; ) {
1363:
1364: rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1365:
1366: if (rc == NGX_OK) {
1367:
1368: /* a header line has been parsed successfully */
1369:
1370: h = ngx_list_push(&r->upstream->headers_in.headers);
1371: if (h == NULL) {
1372: return NGX_ERROR;
1373: }
1374:
1375: h->hash = r->header_hash;
1376:
1377: h->key.len = r->header_name_end - r->header_name_start;
1378: h->value.len = r->header_end - r->header_start;
1379:
1380: h->key.data = ngx_pnalloc(r->pool,
1381: h->key.len + 1 + h->value.len + 1 + h->key.len);
1382: if (h->key.data == NULL) {
1383: return NGX_ERROR;
1384: }
1385:
1386: h->value.data = h->key.data + h->key.len + 1;
1387: h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1388:
1389: ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1390: h->key.data[h->key.len] = '\0';
1391: ngx_memcpy(h->value.data, r->header_start, h->value.len);
1392: h->value.data[h->value.len] = '\0';
1393:
1394: if (h->key.len == r->lowcase_index) {
1395: ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1396:
1397: } else {
1398: ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1399: }
1400:
1401: hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1402: h->lowcase_key, h->key.len);
1403:
1404: if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1405: return NGX_ERROR;
1406: }
1407:
1408: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1409: "http proxy header: \"%V: %V\"",
1410: &h->key, &h->value);
1411:
1412: continue;
1413: }
1414:
1415: if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1416:
1417: /* a whole header has been parsed successfully */
1418:
1419: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1420: "http proxy header done");
1421:
1422: /*
1423: * if no "Server" and "Date" in header line,
1424: * then add the special empty headers
1425: */
1426:
1427: if (r->upstream->headers_in.server == NULL) {
1428: h = ngx_list_push(&r->upstream->headers_in.headers);
1429: if (h == NULL) {
1430: return NGX_ERROR;
1431: }
1432:
1433: h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1434: ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1435:
1436: ngx_str_set(&h->key, "Server");
1437: ngx_str_null(&h->value);
1438: h->lowcase_key = (u_char *) "server";
1439: }
1440:
1441: if (r->upstream->headers_in.date == NULL) {
1442: h = ngx_list_push(&r->upstream->headers_in.headers);
1443: if (h == NULL) {
1444: return NGX_ERROR;
1445: }
1446:
1447: h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1448:
1449: ngx_str_set(&h->key, "Date");
1450: ngx_str_null(&h->value);
1451: h->lowcase_key = (u_char *) "date";
1452: }
1453:
1454: /* clear content length if response is chunked */
1455:
1456: u = r->upstream;
1457:
1458: if (u->headers_in.chunked) {
1459: u->headers_in.content_length_n = -1;
1460: }
1461:
1462: /*
1463: * set u->keepalive if response has no body; this allows to keep
1464: * connections alive in case of r->header_only or X-Accel-Redirect
1465: */
1466:
1467: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1468:
1469: if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1470: || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1471: || ctx->head
1472: || (!u->headers_in.chunked
1473: && u->headers_in.content_length_n == 0))
1474: {
1475: u->keepalive = !u->headers_in.connection_close;
1476: }
1477:
1478: if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1479: u->keepalive = 0;
1480:
1481: if (r->headers_in.upgrade) {
1482: u->upgrade = 1;
1483: }
1484: }
1485:
1486: return NGX_OK;
1487: }
1488:
1489: if (rc == NGX_AGAIN) {
1490: return NGX_AGAIN;
1491: }
1492:
1493: /* there was error while a header line parsing */
1494:
1495: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1496: "upstream sent invalid header");
1497:
1498: return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1499: }
1500: }
1501:
1502:
1503: static ngx_int_t
1504: ngx_http_proxy_input_filter_init(void *data)
1505: {
1506: ngx_http_request_t *r = data;
1507: ngx_http_upstream_t *u;
1508: ngx_http_proxy_ctx_t *ctx;
1509:
1510: u = r->upstream;
1511: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1512:
1513: if (ctx == NULL) {
1514: return NGX_ERROR;
1515: }
1516:
1517: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1518: "http proxy filter init s:%d h:%d c:%d l:%O",
1519: u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1520: u->headers_in.content_length_n);
1521:
1522: /* as per RFC2616, 4.4 Message Length */
1523:
1524: if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1525: || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1526: || ctx->head)
1527: {
1528: /* 1xx, 204, and 304 and replies to HEAD requests */
1529: /* no 1xx since we don't send Expect and Upgrade */
1530:
1531: u->pipe->length = 0;
1532: u->length = 0;
1533: u->keepalive = !u->headers_in.connection_close;
1534:
1535: } else if (u->headers_in.chunked) {
1536: /* chunked */
1537:
1538: u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1539: u->pipe->length = 3; /* "0" LF LF */
1540:
1541: u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1542: u->length = -1;
1543:
1544: } else if (u->headers_in.content_length_n == 0) {
1545: /* empty body: special case as filter won't be called */
1546:
1547: u->pipe->length = 0;
1548: u->length = 0;
1549: u->keepalive = !u->headers_in.connection_close;
1550:
1551: } else {
1552: /* content length or connection close */
1553:
1554: u->pipe->length = u->headers_in.content_length_n;
1555: u->length = u->headers_in.content_length_n;
1556: }
1557:
1558: return NGX_OK;
1559: }
1560:
1561:
1562: static ngx_int_t
1563: ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1564: {
1565: ngx_buf_t *b;
1566: ngx_chain_t *cl;
1567: ngx_http_request_t *r;
1568:
1569: if (buf->pos == buf->last) {
1570: return NGX_OK;
1571: }
1572:
1573: if (p->free) {
1574: cl = p->free;
1575: b = cl->buf;
1576: p->free = cl->next;
1577: ngx_free_chain(p->pool, cl);
1578:
1579: } else {
1580: b = ngx_alloc_buf(p->pool);
1581: if (b == NULL) {
1582: return NGX_ERROR;
1583: }
1584: }
1585:
1586: ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1587: b->shadow = buf;
1588: b->tag = p->tag;
1589: b->last_shadow = 1;
1590: b->recycled = 1;
1591: buf->shadow = b;
1592:
1593: cl = ngx_alloc_chain_link(p->pool);
1594: if (cl == NULL) {
1595: return NGX_ERROR;
1596: }
1597:
1598: cl->buf = b;
1599: cl->next = NULL;
1600:
1601: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1602:
1603: if (p->in) {
1604: *p->last_in = cl;
1605: } else {
1606: p->in = cl;
1607: }
1608: p->last_in = &cl->next;
1609:
1610: if (p->length == -1) {
1611: return NGX_OK;
1612: }
1613:
1614: p->length -= b->last - b->pos;
1615:
1616: if (p->length == 0) {
1617: r = p->input_ctx;
1618: p->upstream_done = 1;
1619: r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1620:
1621: } else if (p->length < 0) {
1622: r = p->input_ctx;
1623: p->upstream_done = 1;
1624:
1625: ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
1626: "upstream sent more data than specified in "
1627: "\"Content-Length\" header");
1628: }
1629:
1630: return NGX_OK;
1631: }
1632:
1633:
1634: static ngx_int_t
1635: ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1636: {
1637: ngx_int_t rc;
1638: ngx_buf_t *b, **prev;
1639: ngx_chain_t *cl;
1640: ngx_http_request_t *r;
1641: ngx_http_proxy_ctx_t *ctx;
1642:
1643: if (buf->pos == buf->last) {
1644: return NGX_OK;
1645: }
1646:
1647: r = p->input_ctx;
1648: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1649:
1650: if (ctx == NULL) {
1651: return NGX_ERROR;
1652: }
1653:
1654: b = NULL;
1655: prev = &buf->shadow;
1656:
1657: for ( ;; ) {
1658:
1659: rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1660:
1661: if (rc == NGX_OK) {
1662:
1663: /* a chunk has been parsed successfully */
1664:
1665: if (p->free) {
1666: cl = p->free;
1667: b = cl->buf;
1668: p->free = cl->next;
1669: ngx_free_chain(p->pool, cl);
1670:
1671: } else {
1672: b = ngx_alloc_buf(p->pool);
1673: if (b == NULL) {
1674: return NGX_ERROR;
1675: }
1676: }
1677:
1678: ngx_memzero(b, sizeof(ngx_buf_t));
1679:
1680: b->pos = buf->pos;
1681: b->start = buf->start;
1682: b->end = buf->end;
1683: b->tag = p->tag;
1684: b->temporary = 1;
1685: b->recycled = 1;
1686:
1687: *prev = b;
1688: prev = &b->shadow;
1689:
1690: cl = ngx_alloc_chain_link(p->pool);
1691: if (cl == NULL) {
1692: return NGX_ERROR;
1693: }
1694:
1695: cl->buf = b;
1696: cl->next = NULL;
1697:
1698: if (p->in) {
1699: *p->last_in = cl;
1700: } else {
1701: p->in = cl;
1702: }
1703: p->last_in = &cl->next;
1704:
1705: /* STUB */ b->num = buf->num;
1706:
1707: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1708: "input buf #%d %p", b->num, b->pos);
1709:
1710: if (buf->last - buf->pos >= ctx->chunked.size) {
1711:
1712: buf->pos += ctx->chunked.size;
1713: b->last = buf->pos;
1714: ctx->chunked.size = 0;
1715:
1716: continue;
1717: }
1718:
1719: ctx->chunked.size -= buf->last - buf->pos;
1720: buf->pos = buf->last;
1721: b->last = buf->last;
1722:
1723: continue;
1724: }
1725:
1726: if (rc == NGX_DONE) {
1727:
1728: /* a whole response has been parsed successfully */
1729:
1730: p->upstream_done = 1;
1731: r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1732:
1733: break;
1734: }
1735:
1736: if (rc == NGX_AGAIN) {
1737:
1738: /* set p->length, minimal amount of data we want to see */
1739:
1740: p->length = ctx->chunked.length;
1741:
1742: break;
1743: }
1744:
1745: /* invalid response */
1746:
1747: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1748: "upstream sent invalid chunked response");
1749:
1750: return NGX_ERROR;
1751: }
1752:
1753: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1754: "http proxy chunked state %d, length %d",
1755: ctx->chunked.state, p->length);
1756:
1757: if (b) {
1758: b->shadow = buf;
1759: b->last_shadow = 1;
1760:
1761: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1762: "input buf %p %z", b->pos, b->last - b->pos);
1763:
1764: return NGX_OK;
1765: }
1766:
1767: /* there is no data record in the buf, add it to free chain */
1768:
1769: if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1770: return NGX_ERROR;
1771: }
1772:
1773: return NGX_OK;
1774: }
1775:
1776:
1777: static ngx_int_t
1778: ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
1779: {
1780: ngx_http_request_t *r = data;
1781:
1782: ngx_buf_t *b;
1783: ngx_chain_t *cl, **ll;
1784: ngx_http_upstream_t *u;
1785:
1786: u = r->upstream;
1787:
1788: for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1789: ll = &cl->next;
1790: }
1791:
1792: cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1793: if (cl == NULL) {
1794: return NGX_ERROR;
1795: }
1796:
1797: *ll = cl;
1798:
1799: cl->buf->flush = 1;
1800: cl->buf->memory = 1;
1801:
1802: b = &u->buffer;
1803:
1804: cl->buf->pos = b->last;
1805: b->last += bytes;
1806: cl->buf->last = b->last;
1807: cl->buf->tag = u->output.tag;
1808:
1809: if (u->length == -1) {
1810: return NGX_OK;
1811: }
1812:
1813: u->length -= bytes;
1814:
1815: if (u->length == 0) {
1816: u->keepalive = !u->headers_in.connection_close;
1817: }
1818:
1819: return NGX_OK;
1820: }
1821:
1822:
1823: static ngx_int_t
1824: ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
1825: {
1826: ngx_http_request_t *r = data;
1827:
1828: ngx_int_t rc;
1829: ngx_buf_t *b, *buf;
1830: ngx_chain_t *cl, **ll;
1831: ngx_http_upstream_t *u;
1832: ngx_http_proxy_ctx_t *ctx;
1833:
1834: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1835:
1836: if (ctx == NULL) {
1837: return NGX_ERROR;
1838: }
1839:
1840: u = r->upstream;
1841: buf = &u->buffer;
1842:
1843: buf->pos = buf->last;
1844: buf->last += bytes;
1845:
1846: for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1847: ll = &cl->next;
1848: }
1849:
1850: for ( ;; ) {
1851:
1852: rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1853:
1854: if (rc == NGX_OK) {
1855:
1856: /* a chunk has been parsed successfully */
1857:
1858: cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1859: if (cl == NULL) {
1860: return NGX_ERROR;
1861: }
1862:
1863: *ll = cl;
1864: ll = &cl->next;
1865:
1866: b = cl->buf;
1867:
1868: b->flush = 1;
1869: b->memory = 1;
1870:
1871: b->pos = buf->pos;
1872: b->tag = u->output.tag;
1873:
1874: if (buf->last - buf->pos >= ctx->chunked.size) {
1875: buf->pos += ctx->chunked.size;
1876: b->last = buf->pos;
1877: ctx->chunked.size = 0;
1878:
1879: } else {
1880: ctx->chunked.size -= buf->last - buf->pos;
1881: buf->pos = buf->last;
1882: b->last = buf->last;
1883: }
1884:
1885: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1886: "http proxy out buf %p %z",
1887: b->pos, b->last - b->pos);
1888:
1889: continue;
1890: }
1891:
1892: if (rc == NGX_DONE) {
1893:
1894: /* a whole response has been parsed successfully */
1895:
1896: u->keepalive = !u->headers_in.connection_close;
1897: u->length = 0;
1898:
1899: break;
1900: }
1901:
1902: if (rc == NGX_AGAIN) {
1903: break;
1904: }
1905:
1906: /* invalid response */
1907:
1908: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1909: "upstream sent invalid chunked response");
1910:
1911: return NGX_ERROR;
1912: }
1913:
1914: /* provide continuous buffer for subrequests in memory */
1915:
1916: if (r->subrequest_in_memory) {
1917:
1918: cl = u->out_bufs;
1919:
1920: if (cl) {
1921: buf->pos = cl->buf->pos;
1922: }
1923:
1924: buf->last = buf->pos;
1925:
1926: for (cl = u->out_bufs; cl; cl = cl->next) {
1927: ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1928: "http proxy in memory %p-%p %uz",
1929: cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
1930:
1931: if (buf->last == cl->buf->pos) {
1932: buf->last = cl->buf->last;
1933: continue;
1934: }
1935:
1936: buf->last = ngx_movemem(buf->last, cl->buf->pos,
1937: cl->buf->last - cl->buf->pos);
1938:
1939: cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
1940: cl->buf->last = buf->last;
1941: }
1942: }
1943:
1944: return NGX_OK;
1945: }
1946:
1947:
1948: static void
1949: ngx_http_proxy_abort_request(ngx_http_request_t *r)
1950: {
1951: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1952: "abort http proxy request");
1953:
1954: return;
1955: }
1956:
1957:
1958: static void
1959: ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1960: {
1961: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1962: "finalize http proxy request");
1963:
1964: return;
1965: }
1966:
1967:
1968: static ngx_int_t
1969: ngx_http_proxy_host_variable(ngx_http_request_t *r,
1970: ngx_http_variable_value_t *v, uintptr_t data)
1971: {
1972: ngx_http_proxy_ctx_t *ctx;
1973:
1974: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1975:
1976: if (ctx == NULL) {
1977: v->not_found = 1;
1978: return NGX_OK;
1979: }
1980:
1981: v->len = ctx->vars.host_header.len;
1982: v->valid = 1;
1983: v->no_cacheable = 0;
1984: v->not_found = 0;
1985: v->data = ctx->vars.host_header.data;
1986:
1987: return NGX_OK;
1988: }
1989:
1990:
1991: static ngx_int_t
1992: ngx_http_proxy_port_variable(ngx_http_request_t *r,
1993: ngx_http_variable_value_t *v, uintptr_t data)
1994: {
1995: ngx_http_proxy_ctx_t *ctx;
1996:
1997: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1998:
1999: if (ctx == NULL) {
2000: v->not_found = 1;
2001: return NGX_OK;
2002: }
2003:
2004: v->len = ctx->vars.port.len;
2005: v->valid = 1;
2006: v->no_cacheable = 0;
2007: v->not_found = 0;
2008: v->data = ctx->vars.port.data;
2009:
2010: return NGX_OK;
2011: }
2012:
2013:
2014: static ngx_int_t
2015: ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2016: ngx_http_variable_value_t *v, uintptr_t data)
2017: {
2018: size_t len;
2019: u_char *p;
2020: ngx_uint_t i, n;
2021: ngx_table_elt_t **h;
2022:
2023: v->valid = 1;
2024: v->no_cacheable = 0;
2025: v->not_found = 0;
2026:
2027: n = r->headers_in.x_forwarded_for.nelts;
2028: h = r->headers_in.x_forwarded_for.elts;
2029:
2030: len = 0;
2031:
2032: for (i = 0; i < n; i++) {
2033: len += h[i]->value.len + sizeof(", ") - 1;
2034: }
2035:
2036: if (len == 0) {
2037: v->len = r->connection->addr_text.len;
2038: v->data = r->connection->addr_text.data;
2039: return NGX_OK;
2040: }
2041:
2042: len += r->connection->addr_text.len;
2043:
2044: p = ngx_pnalloc(r->pool, len);
2045: if (p == NULL) {
2046: return NGX_ERROR;
2047: }
2048:
2049: v->len = len;
2050: v->data = p;
2051:
2052: for (i = 0; i < n; i++) {
2053: p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2054: *p++ = ','; *p++ = ' ';
2055: }
2056:
2057: ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2058:
2059: return NGX_OK;
2060: }
2061:
2062:
2063: static ngx_int_t
2064: ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2065: ngx_http_variable_value_t *v, uintptr_t data)
2066: {
2067: ngx_http_proxy_ctx_t *ctx;
2068:
2069: ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2070:
2071: if (ctx == NULL || ctx->internal_body_length < 0) {
2072: v->not_found = 1;
2073: return NGX_OK;
2074: }
2075:
2076: v->valid = 1;
2077: v->no_cacheable = 0;
2078: v->not_found = 0;
2079:
2080: v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
2081:
2082: if (v->data == NULL) {
2083: return NGX_ERROR;
2084: }
2085:
2086: v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2087:
2088: return NGX_OK;
2089: }
2090:
2091:
2092: static ngx_int_t
2093: ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2094: size_t prefix)
2095: {
2096: size_t len;
2097: ngx_int_t rc;
2098: ngx_uint_t i;
2099: ngx_http_proxy_rewrite_t *pr;
2100: ngx_http_proxy_loc_conf_t *plcf;
2101:
2102: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2103:
2104: pr = plcf->redirects->elts;
2105:
2106: if (pr == NULL) {
2107: return NGX_DECLINED;
2108: }
2109:
2110: len = h->value.len - prefix;
2111:
2112: for (i = 0; i < plcf->redirects->nelts; i++) {
2113: rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2114:
2115: if (rc != NGX_DECLINED) {
2116: return rc;
2117: }
2118: }
2119:
2120: return NGX_DECLINED;
2121: }
2122:
2123:
2124: static ngx_int_t
2125: ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2126: {
2127: size_t prefix;
2128: u_char *p;
2129: ngx_int_t rc, rv;
2130: ngx_http_proxy_loc_conf_t *plcf;
2131:
2132: p = (u_char *) ngx_strchr(h->value.data, ';');
2133: if (p == NULL) {
2134: return NGX_DECLINED;
2135: }
2136:
2137: prefix = p + 1 - h->value.data;
2138:
2139: rv = NGX_DECLINED;
2140:
2141: plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2142:
2143: if (plcf->cookie_domains) {
2144: p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2145:
2146: if (p) {
2147: rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2148: plcf->cookie_domains);
2149: if (rc == NGX_ERROR) {
2150: return NGX_ERROR;
2151: }
2152:
2153: if (rc != NGX_DECLINED) {
2154: rv = rc;
2155: }
2156: }
2157: }
2158:
2159: if (plcf->cookie_paths) {
2160: p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2161:
2162: if (p) {
2163: rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2164: plcf->cookie_paths);
2165: if (rc == NGX_ERROR) {
2166: return NGX_ERROR;
2167: }
2168:
2169: if (rc != NGX_DECLINED) {
2170: rv = rc;
2171: }
2172: }
2173: }
2174:
2175: return rv;
2176: }
2177:
2178:
2179: static ngx_int_t
2180: ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2181: u_char *value, ngx_array_t *rewrites)
2182: {
2183: size_t len, prefix;
2184: u_char *p;
2185: ngx_int_t rc;
2186: ngx_uint_t i;
2187: ngx_http_proxy_rewrite_t *pr;
2188:
2189: prefix = value - h->value.data;
2190:
2191: p = (u_char *) ngx_strchr(value, ';');
2192:
2193: len = p ? (size_t) (p - value) : (h->value.len - prefix);
2194:
2195: pr = rewrites->elts;
2196:
2197: for (i = 0; i < rewrites->nelts; i++) {
2198: rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2199:
2200: if (rc != NGX_DECLINED) {
2201: return rc;
2202: }
2203: }
2204:
2205: return NGX_DECLINED;
2206: }
2207:
2208:
2209: static ngx_int_t
2210: ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2211: ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2212: {
2213: ngx_str_t pattern, replacement;
2214:
2215: if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2216: return NGX_ERROR;
2217: }
2218:
2219: if (pattern.len > len
2220: || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2221: pattern.len) != 0)
2222: {
2223: return NGX_DECLINED;
2224: }
2225:
2226: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2227: return NGX_ERROR;
2228: }
2229:
2230: return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2231: }
2232:
2233:
2234: #if (NGX_PCRE)
2235:
2236: static ngx_int_t
2237: ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2238: size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2239: {
2240: ngx_str_t pattern, replacement;
2241:
2242: pattern.len = len;
2243: pattern.data = h->value.data + prefix;
2244:
2245: if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2246: return NGX_DECLINED;
2247: }
2248:
2249: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2250: return NGX_ERROR;
2251: }
2252:
2253: if (prefix == 0 && h->value.len == len) {
2254: h->value = replacement;
2255: return NGX_OK;
2256: }
2257:
2258: return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2259: }
2260:
2261: #endif
2262:
2263:
2264: static ngx_int_t
2265: ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2266: ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2267: {
2268: u_char *p;
2269: ngx_str_t pattern, replacement;
2270:
2271: if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2272: return NGX_ERROR;
2273: }
2274:
2275: p = h->value.data + prefix;
2276:
2277: if (p[0] == '.') {
2278: p++;
2279: prefix++;
2280: len--;
2281: }
2282:
2283: if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2284: return NGX_DECLINED;
2285: }
2286:
2287: if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2288: return NGX_ERROR;
2289: }
2290:
2291: return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2292: }
2293:
2294:
2295: static ngx_int_t
2296: ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2297: size_t len, ngx_str_t *replacement)
2298: {
2299: u_char *p, *data;
2300: size_t new_len;
2301:
2302: new_len = replacement->len + h->value.len - len;
2303:
2304: if (replacement->len > len) {
2305:
2306: data = ngx_pnalloc(r->pool, new_len);
2307: if (data == NULL) {
2308: return NGX_ERROR;
2309: }
2310:
2311: p = ngx_copy(data, h->value.data, prefix);
2312: p = ngx_copy(p, replacement->data, replacement->len);
2313:
2314: ngx_memcpy(p, h->value.data + prefix + len,
2315: h->value.len - len - prefix);
2316:
2317: h->value.data = data;
2318:
2319: } else {
2320: p = ngx_copy(h->value.data + prefix, replacement->data,
2321: replacement->len);
2322:
2323: ngx_memmove(p, h->value.data + prefix + len,
2324: h->value.len - len - prefix);
2325: }
2326:
2327: h->value.len = new_len;
2328:
2329: return NGX_OK;
2330: }
2331:
2332:
2333: static ngx_int_t
2334: ngx_http_proxy_add_variables(ngx_conf_t *cf)
2335: {
2336: ngx_http_variable_t *var, *v;
2337:
2338: for (v = ngx_http_proxy_vars; v->name.len; v++) {
2339: var = ngx_http_add_variable(cf, &v->name, v->flags);
2340: if (var == NULL) {
2341: return NGX_ERROR;
2342: }
2343:
2344: var->get_handler = v->get_handler;
2345: var->data = v->data;
2346: }
2347:
2348: return NGX_OK;
2349: }
2350:
2351:
2352: static void *
2353: ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2354: {
2355: ngx_http_proxy_loc_conf_t *conf;
2356:
2357: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2358: if (conf == NULL) {
2359: return NULL;
2360: }
2361:
2362: /*
2363: * set by ngx_pcalloc():
2364: *
2365: * conf->upstream.bufs.num = 0;
2366: * conf->upstream.ignore_headers = 0;
2367: * conf->upstream.next_upstream = 0;
2368: * conf->upstream.cache_use_stale = 0;
2369: * conf->upstream.cache_methods = 0;
2370: * conf->upstream.temp_path = NULL;
2371: * conf->upstream.hide_headers_hash = { NULL, 0 };
2372: * conf->upstream.uri = { 0, NULL };
2373: * conf->upstream.location = NULL;
2374: * conf->upstream.store_lengths = NULL;
2375: * conf->upstream.store_values = NULL;
2376: *
2377: * conf->method = { 0, NULL };
2378: * conf->headers_source = NULL;
2379: * conf->headers_set_len = NULL;
2380: * conf->headers_set = NULL;
2381: * conf->headers_set_hash = NULL;
2382: * conf->body_set_len = NULL;
2383: * conf->body_set = NULL;
2384: * conf->body_source = { 0, NULL };
2385: * conf->redirects = NULL;
2386: */
2387:
2388: conf->upstream.store = NGX_CONF_UNSET;
2389: conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2390: conf->upstream.buffering = NGX_CONF_UNSET;
2391: conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2392:
2393: conf->upstream.local = NGX_CONF_UNSET_PTR;
2394:
2395: conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2396: conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2397: conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2398:
2399: conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2400: conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2401:
2402: conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2403: conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2404: conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2405:
2406: conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2407: conf->upstream.pass_request_body = NGX_CONF_UNSET;
2408:
2409: #if (NGX_HTTP_CACHE)
2410: conf->upstream.cache = NGX_CONF_UNSET_PTR;
2411: conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2412: conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2413: conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2414: conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2415: conf->upstream.cache_lock = NGX_CONF_UNSET;
2416: conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2417: #endif
2418:
2419: conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2420: conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2421:
2422: conf->upstream.intercept_errors = NGX_CONF_UNSET;
2423: #if (NGX_HTTP_SSL)
2424: conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2425: #endif
2426:
2427: /* "proxy_cyclic_temp_file" is disabled */
2428: conf->upstream.cyclic_temp_file = 0;
2429:
2430: conf->redirect = NGX_CONF_UNSET;
2431: conf->upstream.change_buffering = 1;
2432:
2433: conf->cookie_domains = NGX_CONF_UNSET_PTR;
2434: conf->cookie_paths = NGX_CONF_UNSET_PTR;
2435:
2436: conf->http_version = NGX_CONF_UNSET_UINT;
2437:
2438: conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2439: conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2440:
2441: ngx_str_set(&conf->upstream.module, "proxy");
2442:
2443: return conf;
2444: }
2445:
2446:
2447: static char *
2448: ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2449: {
2450: ngx_http_proxy_loc_conf_t *prev = parent;
2451: ngx_http_proxy_loc_conf_t *conf = child;
2452:
2453: u_char *p;
2454: size_t size;
2455: ngx_hash_init_t hash;
2456: ngx_http_core_loc_conf_t *clcf;
2457: ngx_http_proxy_rewrite_t *pr;
2458: ngx_http_script_compile_t sc;
2459:
2460: if (conf->upstream.store != 0) {
2461: ngx_conf_merge_value(conf->upstream.store,
2462: prev->upstream.store, 0);
2463:
2464: if (conf->upstream.store_lengths == NULL) {
2465: conf->upstream.store_lengths = prev->upstream.store_lengths;
2466: conf->upstream.store_values = prev->upstream.store_values;
2467: }
2468: }
2469:
2470: ngx_conf_merge_uint_value(conf->upstream.store_access,
2471: prev->upstream.store_access, 0600);
2472:
2473: ngx_conf_merge_value(conf->upstream.buffering,
2474: prev->upstream.buffering, 1);
2475:
2476: ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2477: prev->upstream.ignore_client_abort, 0);
2478:
2479: ngx_conf_merge_ptr_value(conf->upstream.local,
2480: prev->upstream.local, NULL);
2481:
2482: ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2483: prev->upstream.connect_timeout, 60000);
2484:
2485: ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2486: prev->upstream.send_timeout, 60000);
2487:
2488: ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2489: prev->upstream.read_timeout, 60000);
2490:
2491: ngx_conf_merge_size_value(conf->upstream.send_lowat,
2492: prev->upstream.send_lowat, 0);
2493:
2494: ngx_conf_merge_size_value(conf->upstream.buffer_size,
2495: prev->upstream.buffer_size,
2496: (size_t) ngx_pagesize);
2497:
2498: ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2499: 8, ngx_pagesize);
2500:
2501: if (conf->upstream.bufs.num < 2) {
2502: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2503: "there must be at least 2 \"proxy_buffers\"");
2504: return NGX_CONF_ERROR;
2505: }
2506:
2507:
2508: size = conf->upstream.buffer_size;
2509: if (size < conf->upstream.bufs.size) {
2510: size = conf->upstream.bufs.size;
2511: }
2512:
2513:
2514: ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2515: prev->upstream.busy_buffers_size_conf,
2516: NGX_CONF_UNSET_SIZE);
2517:
2518: if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2519: conf->upstream.busy_buffers_size = 2 * size;
2520: } else {
2521: conf->upstream.busy_buffers_size =
2522: conf->upstream.busy_buffers_size_conf;
2523: }
2524:
2525: if (conf->upstream.busy_buffers_size < size) {
2526: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2527: "\"proxy_busy_buffers_size\" must be equal to or greater than "
2528: "the maximum of the value of \"proxy_buffer_size\" and "
2529: "one of the \"proxy_buffers\"");
2530:
2531: return NGX_CONF_ERROR;
2532: }
2533:
2534: if (conf->upstream.busy_buffers_size
2535: > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2536: {
2537: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2538: "\"proxy_busy_buffers_size\" must be less than "
2539: "the size of all \"proxy_buffers\" minus one buffer");
2540:
2541: return NGX_CONF_ERROR;
2542: }
2543:
2544:
2545: ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2546: prev->upstream.temp_file_write_size_conf,
2547: NGX_CONF_UNSET_SIZE);
2548:
2549: if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2550: conf->upstream.temp_file_write_size = 2 * size;
2551: } else {
2552: conf->upstream.temp_file_write_size =
2553: conf->upstream.temp_file_write_size_conf;
2554: }
2555:
2556: if (conf->upstream.temp_file_write_size < size) {
2557: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2558: "\"proxy_temp_file_write_size\" must be equal to or greater "
2559: "than the maximum of the value of \"proxy_buffer_size\" and "
2560: "one of the \"proxy_buffers\"");
2561:
2562: return NGX_CONF_ERROR;
2563: }
2564:
2565: ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2566: prev->upstream.max_temp_file_size_conf,
2567: NGX_CONF_UNSET_SIZE);
2568:
2569: if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2570: conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2571: } else {
2572: conf->upstream.max_temp_file_size =
2573: conf->upstream.max_temp_file_size_conf;
2574: }
2575:
2576: if (conf->upstream.max_temp_file_size != 0
2577: && conf->upstream.max_temp_file_size < size)
2578: {
2579: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2580: "\"proxy_max_temp_file_size\" must be equal to zero to disable "
2581: "temporary files usage or must be equal to or greater than "
2582: "the maximum of the value of \"proxy_buffer_size\" and "
2583: "one of the \"proxy_buffers\"");
2584:
2585: return NGX_CONF_ERROR;
2586: }
2587:
2588:
2589: ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2590: prev->upstream.ignore_headers,
2591: NGX_CONF_BITMASK_SET);
2592:
2593:
2594: ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2595: prev->upstream.next_upstream,
2596: (NGX_CONF_BITMASK_SET
2597: |NGX_HTTP_UPSTREAM_FT_ERROR
2598: |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2599:
2600: if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2601: conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2602: |NGX_HTTP_UPSTREAM_FT_OFF;
2603: }
2604:
2605: if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2606: prev->upstream.temp_path,
2607: &ngx_http_proxy_temp_path)
2608: != NGX_OK)
2609: {
2610: return NGX_CONF_ERROR;
2611: }
2612:
2613:
2614: #if (NGX_HTTP_CACHE)
2615:
2616: ngx_conf_merge_ptr_value(conf->upstream.cache,
2617: prev->upstream.cache, NULL);
2618:
2619: if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2620: ngx_shm_zone_t *shm_zone;
2621:
2622: shm_zone = conf->upstream.cache;
2623:
2624: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2625: "\"proxy_cache\" zone \"%V\" is unknown",
2626: &shm_zone->shm.name);
2627:
2628: return NGX_CONF_ERROR;
2629: }
2630:
2631: ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2632: prev->upstream.cache_min_uses, 1);
2633:
2634: ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2635: prev->upstream.cache_use_stale,
2636: (NGX_CONF_BITMASK_SET
2637: |NGX_HTTP_UPSTREAM_FT_OFF));
2638:
2639: if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2640: conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2641: |NGX_HTTP_UPSTREAM_FT_OFF;
2642: }
2643:
2644: if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2645: conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2646: }
2647:
2648: if (conf->upstream.cache_methods == 0) {
2649: conf->upstream.cache_methods = prev->upstream.cache_methods;
2650: }
2651:
2652: conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2653:
2654: ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2655: prev->upstream.cache_bypass, NULL);
2656:
2657: ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2658: prev->upstream.no_cache, NULL);
2659:
2660: if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
2661: ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2662: "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
2663: "now it should be used together with \"proxy_cache_bypass\"");
2664: }
2665:
2666: ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2667: prev->upstream.cache_valid, NULL);
2668:
2669: if (conf->cache_key.value.data == NULL) {
2670: conf->cache_key = prev->cache_key;
2671: }
2672:
2673: ngx_conf_merge_value(conf->upstream.cache_lock,
2674: prev->upstream.cache_lock, 0);
2675:
2676: ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2677: prev->upstream.cache_lock_timeout, 5000);
2678:
2679: #endif
2680:
2681: ngx_conf_merge_str_value(conf->method, prev->method, "");
2682:
2683: if (conf->method.len
2684: && conf->method.data[conf->method.len - 1] != ' ')
2685: {
2686: conf->method.data[conf->method.len] = ' ';
2687: conf->method.len++;
2688: }
2689:
2690: ngx_conf_merge_value(conf->upstream.pass_request_headers,
2691: prev->upstream.pass_request_headers, 1);
2692: ngx_conf_merge_value(conf->upstream.pass_request_body,
2693: prev->upstream.pass_request_body, 1);
2694:
2695: ngx_conf_merge_value(conf->upstream.intercept_errors,
2696: prev->upstream.intercept_errors, 0);
2697:
2698: #if (NGX_HTTP_SSL)
2699: ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
2700: prev->upstream.ssl_session_reuse, 1);
2701: #endif
2702:
2703: ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
2704:
2705: if (conf->redirect) {
2706:
2707: if (conf->redirects == NULL) {
2708: conf->redirects = prev->redirects;
2709: }
2710:
2711: if (conf->redirects == NULL && conf->url.data) {
2712:
2713: conf->redirects = ngx_array_create(cf->pool, 1,
2714: sizeof(ngx_http_proxy_rewrite_t));
2715: if (conf->redirects == NULL) {
2716: return NGX_CONF_ERROR;
2717: }
2718:
2719: pr = ngx_array_push(conf->redirects);
2720: if (pr == NULL) {
2721: return NGX_CONF_ERROR;
2722: }
2723:
2724: ngx_memzero(&pr->pattern.complex,
2725: sizeof(ngx_http_complex_value_t));
2726:
2727: ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
2728:
2729: pr->handler = ngx_http_proxy_rewrite_complex_handler;
2730:
2731: if (conf->vars.uri.len) {
2732: pr->pattern.complex.value = conf->url;
2733: pr->replacement.value = conf->location;
2734:
2735: } else {
2736: pr->pattern.complex.value.len = conf->url.len
2737: + sizeof("/") - 1;
2738:
2739: p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
2740: if (p == NULL) {
2741: return NGX_CONF_ERROR;
2742: }
2743:
2744: pr->pattern.complex.value.data = p;
2745:
2746: p = ngx_cpymem(p, conf->url.data, conf->url.len);
2747: *p = '/';
2748:
2749: ngx_str_set(&pr->replacement.value, "/");
2750: }
2751: }
2752: }
2753:
2754: ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
2755:
2756: ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
2757:
2758: #if (NGX_HTTP_SSL)
2759: if (conf->upstream.ssl == NULL) {
2760: conf->upstream.ssl = prev->upstream.ssl;
2761: }
2762: #endif
2763:
2764: ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
2765: NGX_HTTP_VERSION_10);
2766:
2767: ngx_conf_merge_uint_value(conf->headers_hash_max_size,
2768: prev->headers_hash_max_size, 512);
2769:
2770: ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
2771: prev->headers_hash_bucket_size, 64);
2772:
2773: conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
2774: ngx_cacheline_size);
2775:
2776: hash.max_size = conf->headers_hash_max_size;
2777: hash.bucket_size = conf->headers_hash_bucket_size;
2778: hash.name = "proxy_headers_hash";
2779:
2780: if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
2781: &prev->upstream, ngx_http_proxy_hide_headers, &hash)
2782: != NGX_OK)
2783: {
2784: return NGX_CONF_ERROR;
2785: }
2786:
2787: if (conf->upstream.upstream == NULL) {
2788: conf->upstream.upstream = prev->upstream.upstream;
2789: conf->vars = prev->vars;
2790: }
2791:
2792: if (conf->proxy_lengths == NULL) {
2793: conf->proxy_lengths = prev->proxy_lengths;
2794: conf->proxy_values = prev->proxy_values;
2795: }
2796:
2797: if (conf->upstream.upstream || conf->proxy_lengths) {
2798: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2799: if (clcf->handler == NULL && clcf->lmt_excpt) {
2800: clcf->handler = ngx_http_proxy_handler;
2801: conf->location = prev->location;
2802: }
2803: }
2804:
2805: if (conf->body_source.data == NULL) {
2806: conf->body_source = prev->body_source;
2807: conf->body_set_len = prev->body_set_len;
2808: conf->body_set = prev->body_set;
2809: }
2810:
2811: if (conf->body_source.data && conf->body_set_len == NULL) {
2812:
2813: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2814:
2815: sc.cf = cf;
2816: sc.source = &conf->body_source;
2817: sc.flushes = &conf->flushes;
2818: sc.lengths = &conf->body_set_len;
2819: sc.values = &conf->body_set;
2820: sc.complete_lengths = 1;
2821: sc.complete_values = 1;
2822:
2823: if (ngx_http_script_compile(&sc) != NGX_OK) {
2824: return NGX_CONF_ERROR;
2825: }
2826: }
2827:
2828: if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
2829: return NGX_CONF_ERROR;
2830: }
2831:
2832: return NGX_CONF_OK;
2833: }
2834:
2835:
2836: static ngx_int_t
2837: ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
2838: ngx_http_proxy_loc_conf_t *prev)
2839: {
2840: u_char *p;
2841: size_t size;
2842: uintptr_t *code;
2843: ngx_uint_t i;
2844: ngx_array_t headers_names, headers_merged;
2845: ngx_keyval_t *src, *s, *h;
2846: ngx_hash_key_t *hk;
2847: ngx_hash_init_t hash;
2848: ngx_http_script_compile_t sc;
2849: ngx_http_script_copy_code_t *copy;
2850:
2851: if (conf->headers_source == NULL) {
2852: conf->flushes = prev->flushes;
2853: conf->headers_set_len = prev->headers_set_len;
2854: conf->headers_set = prev->headers_set;
2855: conf->headers_set_hash = prev->headers_set_hash;
2856: conf->headers_source = prev->headers_source;
2857: }
2858:
2859: if (conf->headers_set_hash.buckets
2860: #if (NGX_HTTP_CACHE)
2861: && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
2862: #endif
2863: )
2864: {
2865: return NGX_OK;
2866: }
2867:
2868:
2869: if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2870: != NGX_OK)
2871: {
2872: return NGX_ERROR;
2873: }
2874:
2875: if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
2876: != NGX_OK)
2877: {
2878: return NGX_ERROR;
2879: }
2880:
2881: if (conf->headers_source == NULL) {
2882: conf->headers_source = ngx_array_create(cf->pool, 4,
2883: sizeof(ngx_keyval_t));
2884: if (conf->headers_source == NULL) {
2885: return NGX_ERROR;
2886: }
2887: }
2888:
2889: conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
2890: if (conf->headers_set_len == NULL) {
2891: return NGX_ERROR;
2892: }
2893:
2894: conf->headers_set = ngx_array_create(cf->pool, 512, 1);
2895: if (conf->headers_set == NULL) {
2896: return NGX_ERROR;
2897: }
2898:
2899:
2900: #if (NGX_HTTP_CACHE)
2901:
2902: h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
2903: ngx_http_proxy_headers;
2904: #else
2905:
2906: h = ngx_http_proxy_headers;
2907:
2908: #endif
2909:
2910: src = conf->headers_source->elts;
2911: for (i = 0; i < conf->headers_source->nelts; i++) {
2912:
2913: s = ngx_array_push(&headers_merged);
2914: if (s == NULL) {
2915: return NGX_ERROR;
2916: }
2917:
2918: *s = src[i];
2919: }
2920:
2921: while (h->key.len) {
2922:
2923: src = headers_merged.elts;
2924: for (i = 0; i < headers_merged.nelts; i++) {
2925: if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2926: goto next;
2927: }
2928: }
2929:
2930: s = ngx_array_push(&headers_merged);
2931: if (s == NULL) {
2932: return NGX_ERROR;
2933: }
2934:
2935: *s = *h;
2936:
2937: next:
2938:
2939: h++;
2940: }
2941:
2942:
2943: src = headers_merged.elts;
2944: for (i = 0; i < headers_merged.nelts; i++) {
2945:
2946: hk = ngx_array_push(&headers_names);
2947: if (hk == NULL) {
2948: return NGX_ERROR;
2949: }
2950:
2951: hk->key = src[i].key;
2952: hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
2953: hk->value = (void *) 1;
2954:
2955: if (src[i].value.len == 0) {
2956: continue;
2957: }
2958:
2959: if (ngx_http_script_variables_count(&src[i].value) == 0) {
2960: copy = ngx_array_push_n(conf->headers_set_len,
2961: sizeof(ngx_http_script_copy_code_t));
2962: if (copy == NULL) {
2963: return NGX_ERROR;
2964: }
2965:
2966: copy->code = (ngx_http_script_code_pt)
2967: ngx_http_script_copy_len_code;
2968: copy->len = src[i].key.len + sizeof(": ") - 1
2969: + src[i].value.len + sizeof(CRLF) - 1;
2970:
2971:
2972: size = (sizeof(ngx_http_script_copy_code_t)
2973: + src[i].key.len + sizeof(": ") - 1
2974: + src[i].value.len + sizeof(CRLF) - 1
2975: + sizeof(uintptr_t) - 1)
2976: & ~(sizeof(uintptr_t) - 1);
2977:
2978: copy = ngx_array_push_n(conf->headers_set, size);
2979: if (copy == NULL) {
2980: return NGX_ERROR;
2981: }
2982:
2983: copy->code = ngx_http_script_copy_code;
2984: copy->len = src[i].key.len + sizeof(": ") - 1
2985: + src[i].value.len + sizeof(CRLF) - 1;
2986:
2987: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2988:
2989: p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2990: *p++ = ':'; *p++ = ' ';
2991: p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
2992: *p++ = CR; *p = LF;
2993:
2994: } else {
2995: copy = ngx_array_push_n(conf->headers_set_len,
2996: sizeof(ngx_http_script_copy_code_t));
2997: if (copy == NULL) {
2998: return NGX_ERROR;
2999: }
3000:
3001: copy->code = (ngx_http_script_code_pt)
3002: ngx_http_script_copy_len_code;
3003: copy->len = src[i].key.len + sizeof(": ") - 1;
3004:
3005:
3006: size = (sizeof(ngx_http_script_copy_code_t)
3007: + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
3008: & ~(sizeof(uintptr_t) - 1);
3009:
3010: copy = ngx_array_push_n(conf->headers_set, size);
3011: if (copy == NULL) {
3012: return NGX_ERROR;
3013: }
3014:
3015: copy->code = ngx_http_script_copy_code;
3016: copy->len = src[i].key.len + sizeof(": ") - 1;
3017:
3018: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3019: p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3020: *p++ = ':'; *p = ' ';
3021:
3022:
3023: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3024:
3025: sc.cf = cf;
3026: sc.source = &src[i].value;
3027: sc.flushes = &conf->flushes;
3028: sc.lengths = &conf->headers_set_len;
3029: sc.values = &conf->headers_set;
3030:
3031: if (ngx_http_script_compile(&sc) != NGX_OK) {
3032: return NGX_ERROR;
3033: }
3034:
3035:
3036: copy = ngx_array_push_n(conf->headers_set_len,
3037: sizeof(ngx_http_script_copy_code_t));
3038: if (copy == NULL) {
3039: return NGX_ERROR;
3040: }
3041:
3042: copy->code = (ngx_http_script_code_pt)
3043: ngx_http_script_copy_len_code;
3044: copy->len = sizeof(CRLF) - 1;
3045:
3046:
3047: size = (sizeof(ngx_http_script_copy_code_t)
3048: + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3049: & ~(sizeof(uintptr_t) - 1);
3050:
3051: copy = ngx_array_push_n(conf->headers_set, size);
3052: if (copy == NULL) {
3053: return NGX_ERROR;
3054: }
3055:
3056: copy->code = ngx_http_script_copy_code;
3057: copy->len = sizeof(CRLF) - 1;
3058:
3059: p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3060: *p++ = CR; *p = LF;
3061: }
3062:
3063: code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3064: if (code == NULL) {
3065: return NGX_ERROR;
3066: }
3067:
3068: *code = (uintptr_t) NULL;
3069:
3070: code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
3071: if (code == NULL) {
3072: return NGX_ERROR;
3073: }
3074:
3075: *code = (uintptr_t) NULL;
3076: }
3077:
3078: code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3079: if (code == NULL) {
3080: return NGX_ERROR;
3081: }
3082:
3083: *code = (uintptr_t) NULL;
3084:
3085:
3086: hash.hash = &conf->headers_set_hash;
3087: hash.key = ngx_hash_key_lc;
3088: hash.max_size = conf->headers_hash_max_size;
3089: hash.bucket_size = conf->headers_hash_bucket_size;
3090: hash.name = "proxy_headers_hash";
3091: hash.pool = cf->pool;
3092: hash.temp_pool = NULL;
3093:
3094: return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3095: }
3096:
3097:
3098: static char *
3099: ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3100: {
3101: ngx_http_proxy_loc_conf_t *plcf = conf;
3102:
3103: size_t add;
3104: u_short port;
3105: ngx_str_t *value, *url;
3106: ngx_url_t u;
3107: ngx_uint_t n;
3108: ngx_http_core_loc_conf_t *clcf;
3109: ngx_http_script_compile_t sc;
3110:
3111: if (plcf->upstream.upstream || plcf->proxy_lengths) {
3112: return "is duplicate";
3113: }
3114:
3115: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3116:
3117: clcf->handler = ngx_http_proxy_handler;
3118:
3119: if (clcf->name.data[clcf->name.len - 1] == '/') {
3120: clcf->auto_redirect = 1;
3121: }
3122:
3123: value = cf->args->elts;
3124:
3125: url = &value[1];
3126:
3127: n = ngx_http_script_variables_count(url);
3128:
3129: if (n) {
3130:
3131: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3132:
3133: sc.cf = cf;
3134: sc.source = url;
3135: sc.lengths = &plcf->proxy_lengths;
3136: sc.values = &plcf->proxy_values;
3137: sc.variables = n;
3138: sc.complete_lengths = 1;
3139: sc.complete_values = 1;
3140:
3141: if (ngx_http_script_compile(&sc) != NGX_OK) {
3142: return NGX_CONF_ERROR;
3143: }
3144:
3145: #if (NGX_HTTP_SSL)
3146: if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3147: return NGX_CONF_ERROR;
3148: }
3149: #endif
3150:
3151: return NGX_CONF_OK;
3152: }
3153:
3154: if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3155: add = 7;
3156: port = 80;
3157:
3158: } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3159:
3160: #if (NGX_HTTP_SSL)
3161: if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3162: return NGX_CONF_ERROR;
3163: }
3164:
3165: add = 8;
3166: port = 443;
3167: #else
3168: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3169: "https protocol requires SSL support");
3170: return NGX_CONF_ERROR;
3171: #endif
3172:
3173: } else {
3174: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3175: return NGX_CONF_ERROR;
3176: }
3177:
3178: ngx_memzero(&u, sizeof(ngx_url_t));
3179:
3180: u.url.len = url->len - add;
3181: u.url.data = url->data + add;
3182: u.default_port = port;
3183: u.uri_part = 1;
3184: u.no_resolve = 1;
3185:
3186: plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3187: if (plcf->upstream.upstream == NULL) {
3188: return NGX_CONF_ERROR;
3189: }
3190:
3191: plcf->vars.schema.len = add;
3192: plcf->vars.schema.data = url->data;
3193: plcf->vars.key_start = plcf->vars.schema;
3194:
3195: ngx_http_proxy_set_vars(&u, &plcf->vars);
3196:
3197: plcf->location = clcf->name;
3198:
3199: if (clcf->named
3200: #if (NGX_PCRE)
3201: || clcf->regex
3202: #endif
3203: || clcf->noname)
3204: {
3205: if (plcf->vars.uri.len) {
3206: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3207: "\"proxy_pass\" cannot have URI part in "
3208: "location given by regular expression, "
3209: "or inside named location, "
3210: "or inside \"if\" statement, "
3211: "or inside \"limit_except\" block");
3212: return NGX_CONF_ERROR;
3213: }
3214:
3215: plcf->location.len = 0;
3216: }
3217:
3218: plcf->url = *url;
3219:
3220: return NGX_CONF_OK;
3221: }
3222:
3223:
3224: static char *
3225: ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3226: {
3227: ngx_http_proxy_loc_conf_t *plcf = conf;
3228:
3229: u_char *p;
3230: ngx_str_t *value;
3231: ngx_http_proxy_rewrite_t *pr;
3232: ngx_http_compile_complex_value_t ccv;
3233:
3234: if (plcf->redirect == 0) {
3235: return NGX_CONF_OK;
3236: }
3237:
3238: plcf->redirect = 1;
3239:
3240: value = cf->args->elts;
3241:
3242: if (cf->args->nelts == 2) {
3243: if (ngx_strcmp(value[1].data, "off") == 0) {
3244: plcf->redirect = 0;
3245: plcf->redirects = NULL;
3246: return NGX_CONF_OK;
3247: }
3248:
3249: if (ngx_strcmp(value[1].data, "false") == 0) {
3250: ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3251: "invalid parameter \"false\", use \"off\" instead");
3252: plcf->redirect = 0;
3253: plcf->redirects = NULL;
3254: return NGX_CONF_OK;
3255: }
3256:
3257: if (ngx_strcmp(value[1].data, "default") != 0) {
3258: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3259: "invalid parameter \"%V\"", &value[1]);
3260: return NGX_CONF_ERROR;
3261: }
3262: }
3263:
3264: if (plcf->redirects == NULL) {
3265: plcf->redirects = ngx_array_create(cf->pool, 1,
3266: sizeof(ngx_http_proxy_rewrite_t));
3267: if (plcf->redirects == NULL) {
3268: return NGX_CONF_ERROR;
3269: }
3270: }
3271:
3272: pr = ngx_array_push(plcf->redirects);
3273: if (pr == NULL) {
3274: return NGX_CONF_ERROR;
3275: }
3276:
3277: if (ngx_strcmp(value[1].data, "default") == 0) {
3278: if (plcf->proxy_lengths) {
3279: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3280: "\"proxy_redirect default\" cannot be used "
3281: "with \"proxy_pass\" directive with variables");
3282: return NGX_CONF_ERROR;
3283: }
3284:
3285: if (plcf->url.data == NULL) {
3286: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3287: "\"proxy_redirect default\" should be placed "
3288: "after the \"proxy_pass\" directive");
3289: return NGX_CONF_ERROR;
3290: }
3291:
3292: pr->handler = ngx_http_proxy_rewrite_complex_handler;
3293:
3294: ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3295:
3296: ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3297:
3298: if (plcf->vars.uri.len) {
3299: pr->pattern.complex.value = plcf->url;
3300: pr->replacement.value = plcf->location;
3301:
3302: } else {
3303: pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3304:
3305: p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3306: if (p == NULL) {
3307: return NGX_CONF_ERROR;
3308: }
3309:
3310: pr->pattern.complex.value.data = p;
3311:
3312: p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3313: *p = '/';
3314:
3315: ngx_str_set(&pr->replacement.value, "/");
3316: }
3317:
3318: return NGX_CONF_OK;
3319: }
3320:
3321:
3322: if (value[1].data[0] == '~') {
3323: value[1].len--;
3324: value[1].data++;
3325:
3326: if (value[1].data[0] == '*') {
3327: value[1].len--;
3328: value[1].data++;
3329:
3330: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3331: return NGX_CONF_ERROR;
3332: }
3333:
3334: } else {
3335: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3336: return NGX_CONF_ERROR;
3337: }
3338: }
3339:
3340: } else {
3341:
3342: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3343:
3344: ccv.cf = cf;
3345: ccv.value = &value[1];
3346: ccv.complex_value = &pr->pattern.complex;
3347:
3348: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3349: return NGX_CONF_ERROR;
3350: }
3351:
3352: pr->handler = ngx_http_proxy_rewrite_complex_handler;
3353: }
3354:
3355:
3356: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3357:
3358: ccv.cf = cf;
3359: ccv.value = &value[2];
3360: ccv.complex_value = &pr->replacement;
3361:
3362: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3363: return NGX_CONF_ERROR;
3364: }
3365:
3366: return NGX_CONF_OK;
3367: }
3368:
3369:
3370: static char *
3371: ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3372: {
3373: ngx_http_proxy_loc_conf_t *plcf = conf;
3374:
3375: ngx_str_t *value;
3376: ngx_http_proxy_rewrite_t *pr;
3377: ngx_http_compile_complex_value_t ccv;
3378:
3379: if (plcf->cookie_domains == NULL) {
3380: return NGX_CONF_OK;
3381: }
3382:
3383: value = cf->args->elts;
3384:
3385: if (cf->args->nelts == 2) {
3386:
3387: if (ngx_strcmp(value[1].data, "off") == 0) {
3388: plcf->cookie_domains = NULL;
3389: return NGX_CONF_OK;
3390: }
3391:
3392: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3393: "invalid parameter \"%V\"", &value[1]);
3394: return NGX_CONF_ERROR;
3395: }
3396:
3397: if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3398: plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3399: sizeof(ngx_http_proxy_rewrite_t));
3400: if (plcf->cookie_domains == NULL) {
3401: return NGX_CONF_ERROR;
3402: }
3403: }
3404:
3405: pr = ngx_array_push(plcf->cookie_domains);
3406: if (pr == NULL) {
3407: return NGX_CONF_ERROR;
3408: }
3409:
3410: if (value[1].data[0] == '~') {
3411: value[1].len--;
3412: value[1].data++;
3413:
3414: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3415: return NGX_CONF_ERROR;
3416: }
3417:
3418: } else {
3419:
3420: if (value[1].data[0] == '.') {
3421: value[1].len--;
3422: value[1].data++;
3423: }
3424:
3425: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3426:
3427: ccv.cf = cf;
3428: ccv.value = &value[1];
3429: ccv.complex_value = &pr->pattern.complex;
3430:
3431: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3432: return NGX_CONF_ERROR;
3433: }
3434:
3435: pr->handler = ngx_http_proxy_rewrite_domain_handler;
3436:
3437: if (value[2].data[0] == '.') {
3438: value[2].len--;
3439: value[2].data++;
3440: }
3441: }
3442:
3443: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3444:
3445: ccv.cf = cf;
3446: ccv.value = &value[2];
3447: ccv.complex_value = &pr->replacement;
3448:
3449: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3450: return NGX_CONF_ERROR;
3451: }
3452:
3453: return NGX_CONF_OK;
3454: }
3455:
3456:
3457: static char *
3458: ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3459: {
3460: ngx_http_proxy_loc_conf_t *plcf = conf;
3461:
3462: ngx_str_t *value;
3463: ngx_http_proxy_rewrite_t *pr;
3464: ngx_http_compile_complex_value_t ccv;
3465:
3466: if (plcf->cookie_paths == NULL) {
3467: return NGX_CONF_OK;
3468: }
3469:
3470: value = cf->args->elts;
3471:
3472: if (cf->args->nelts == 2) {
3473:
3474: if (ngx_strcmp(value[1].data, "off") == 0) {
3475: plcf->cookie_paths = NULL;
3476: return NGX_CONF_OK;
3477: }
3478:
3479: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3480: "invalid parameter \"%V\"", &value[1]);
3481: return NGX_CONF_ERROR;
3482: }
3483:
3484: if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3485: plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3486: sizeof(ngx_http_proxy_rewrite_t));
3487: if (plcf->cookie_paths == NULL) {
3488: return NGX_CONF_ERROR;
3489: }
3490: }
3491:
3492: pr = ngx_array_push(plcf->cookie_paths);
3493: if (pr == NULL) {
3494: return NGX_CONF_ERROR;
3495: }
3496:
3497: if (value[1].data[0] == '~') {
3498: value[1].len--;
3499: value[1].data++;
3500:
3501: if (value[1].data[0] == '*') {
3502: value[1].len--;
3503: value[1].data++;
3504:
3505: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3506: return NGX_CONF_ERROR;
3507: }
3508:
3509: } else {
3510: if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3511: return NGX_CONF_ERROR;
3512: }
3513: }
3514:
3515: } else {
3516:
3517: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3518:
3519: ccv.cf = cf;
3520: ccv.value = &value[1];
3521: ccv.complex_value = &pr->pattern.complex;
3522:
3523: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3524: return NGX_CONF_ERROR;
3525: }
3526:
3527: pr->handler = ngx_http_proxy_rewrite_complex_handler;
3528: }
3529:
3530: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3531:
3532: ccv.cf = cf;
3533: ccv.value = &value[2];
3534: ccv.complex_value = &pr->replacement;
3535:
3536: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3537: return NGX_CONF_ERROR;
3538: }
3539:
3540: return NGX_CONF_OK;
3541: }
3542:
3543:
3544: static ngx_int_t
3545: ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
3546: ngx_str_t *regex, ngx_uint_t caseless)
3547: {
3548: #if (NGX_PCRE)
3549: u_char errstr[NGX_MAX_CONF_ERRSTR];
3550: ngx_regex_compile_t rc;
3551:
3552: ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3553:
3554: rc.pattern = *regex;
3555: rc.err.len = NGX_MAX_CONF_ERRSTR;
3556: rc.err.data = errstr;
3557:
3558: if (caseless) {
3559: rc.options = NGX_REGEX_CASELESS;
3560: }
3561:
3562: pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
3563: if (pr->pattern.regex == NULL) {
3564: return NGX_ERROR;
3565: }
3566:
3567: pr->handler = ngx_http_proxy_rewrite_regex_handler;
3568:
3569: return NGX_OK;
3570:
3571: #else
3572:
3573: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3574: "using regex \"%V\" requires PCRE library", regex);
3575: return NGX_ERROR;
3576:
3577: #endif
3578: }
3579:
3580:
3581: static char *
3582: ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3583: {
3584: ngx_http_proxy_loc_conf_t *plcf = conf;
3585:
3586: ngx_str_t *value;
3587: ngx_http_script_compile_t sc;
3588:
3589: if (plcf->upstream.store != NGX_CONF_UNSET
3590: || plcf->upstream.store_lengths)
3591: {
3592: return "is duplicate";
3593: }
3594:
3595: value = cf->args->elts;
3596:
3597: if (ngx_strcmp(value[1].data, "off") == 0) {
3598: plcf->upstream.store = 0;
3599: return NGX_CONF_OK;
3600: }
3601:
3602: #if (NGX_HTTP_CACHE)
3603:
3604: if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
3605: && plcf->upstream.cache != NULL)
3606: {
3607: return "is incompatible with \"proxy_cache\"";
3608: }
3609:
3610: #endif
3611:
3612: if (ngx_strcmp(value[1].data, "on") == 0) {
3613: plcf->upstream.store = 1;
3614: return NGX_CONF_OK;
3615: }
3616:
3617: /* include the terminating '\0' into script */
3618: value[1].len++;
3619:
3620: ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3621:
3622: sc.cf = cf;
3623: sc.source = &value[1];
3624: sc.lengths = &plcf->upstream.store_lengths;
3625: sc.values = &plcf->upstream.store_values;
3626: sc.variables = ngx_http_script_variables_count(&value[1]);
3627: sc.complete_lengths = 1;
3628: sc.complete_values = 1;
3629:
3630: if (ngx_http_script_compile(&sc) != NGX_OK) {
3631: return NGX_CONF_ERROR;
3632: }
3633:
3634: return NGX_CONF_OK;
3635: }
3636:
3637:
3638: #if (NGX_HTTP_CACHE)
3639:
3640: static char *
3641: ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3642: {
3643: ngx_http_proxy_loc_conf_t *plcf = conf;
3644:
3645: ngx_str_t *value;
3646:
3647: value = cf->args->elts;
3648:
3649: if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
3650: return "is duplicate";
3651: }
3652:
3653: if (ngx_strcmp(value[1].data, "off") == 0) {
3654: plcf->upstream.cache = NULL;
3655: return NGX_CONF_OK;
3656: }
3657:
3658: if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
3659: return "is incompatible with \"proxy_store\"";
3660: }
3661:
3662: plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
3663: &ngx_http_proxy_module);
3664: if (plcf->upstream.cache == NULL) {
3665: return NGX_CONF_ERROR;
3666: }
3667:
3668: return NGX_CONF_OK;
3669: }
3670:
3671:
3672: static char *
3673: ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3674: {
3675: ngx_http_proxy_loc_conf_t *plcf = conf;
3676:
3677: ngx_str_t *value;
3678: ngx_http_compile_complex_value_t ccv;
3679:
3680: value = cf->args->elts;
3681:
3682: if (plcf->cache_key.value.data) {
3683: return "is duplicate";
3684: }
3685:
3686: ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3687:
3688: ccv.cf = cf;
3689: ccv.value = &value[1];
3690: ccv.complex_value = &plcf->cache_key;
3691:
3692: if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3693: return NGX_CONF_ERROR;
3694: }
3695:
3696: return NGX_CONF_OK;
3697: }
3698:
3699: #endif
3700:
3701:
3702: static char *
3703: ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
3704: {
3705: #if (NGX_FREEBSD)
3706: ssize_t *np = data;
3707:
3708: if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3709: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3710: "\"proxy_send_lowat\" must be less than %d "
3711: "(sysctl net.inet.tcp.sendspace)",
3712: ngx_freebsd_net_inet_tcp_sendspace);
3713:
3714: return NGX_CONF_ERROR;
3715: }
3716:
3717: #elif !(NGX_HAVE_SO_SNDLOWAT)
3718: ssize_t *np = data;
3719:
3720: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3721: "\"proxy_send_lowat\" is not supported, ignored");
3722:
3723: *np = 0;
3724:
3725: #endif
3726:
3727: return NGX_CONF_OK;
3728: }
3729:
3730:
3731: #if (NGX_HTTP_SSL)
3732:
3733: static ngx_int_t
3734: ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
3735: {
3736: ngx_pool_cleanup_t *cln;
3737:
3738: plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
3739: if (plcf->upstream.ssl == NULL) {
3740: return NGX_ERROR;
3741: }
3742:
3743: plcf->upstream.ssl->log = cf->log;
3744:
3745: if (ngx_ssl_create(plcf->upstream.ssl,
3746: NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
3747: |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
3748: NULL)
3749: != NGX_OK)
3750: {
3751: return NGX_ERROR;
3752: }
3753:
3754: cln = ngx_pool_cleanup_add(cf->pool, 0);
3755: if (cln == NULL) {
3756: return NGX_ERROR;
3757: }
3758:
3759: cln->handler = ngx_ssl_cleanup_ctx;
3760: cln->data = plcf->upstream.ssl;
3761:
3762: return NGX_OK;
3763: }
3764:
3765: #endif
3766:
3767:
3768: static void
3769: ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
3770: {
3771: if (u->family != AF_UNIX) {
3772:
3773: if (u->no_port || u->port == u->default_port) {
3774:
3775: v->host_header = u->host;
3776:
3777: if (u->default_port == 80) {
3778: ngx_str_set(&v->port, "80");
3779:
3780: } else {
3781: ngx_str_set(&v->port, "443");
3782: }
3783:
3784: } else {
3785: v->host_header.len = u->host.len + 1 + u->port_text.len;
3786: v->host_header.data = u->host.data;
3787: v->port = u->port_text;
3788: }
3789:
3790: v->key_start.len += v->host_header.len;
3791:
3792: } else {
3793: ngx_str_set(&v->host_header, "localhost");
3794: ngx_str_null(&v->port);
3795: v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
3796: }
3797:
3798: v->uri = u->uri;
3799: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>