blob: 5d646bb1cd66cd07f82ccf3ccb958387dd5ede27 [file] [log] [blame]
Igor Sysoev04410502003-08-01 14:56:33 +00001
2#include <ngx_config.h>
3#include <ngx_core.h>
Igor Sysoev04410502003-08-01 14:56:33 +00004#include <ngx_http.h>
5#include <ngx_http_proxy_handler.h>
6
7
Igor Sysoev2f657222004-06-16 15:32:11 +00008static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r);
Igor Sysoev6414b962003-10-24 16:10:38 +00009
Igor Sysoev10a543a2004-03-16 07:10:12 +000010static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
11 u_char *buf, uintptr_t data);
12static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
13 u_char *buf, uintptr_t data);
14static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
15 uintptr_t data);
Igor Sysoev78329332003-11-10 17:17:31 +000016
Igor Sysoev2f657222004-06-16 15:32:11 +000017static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf);
Igor Sysoevae5c59c2003-08-14 06:00:28 +000018static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
Igor Sysoevdc9dd432003-10-22 16:38:26 +000019static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
20 void *parent, void *child);
Igor Sysoevae5c59c2003-08-14 06:00:28 +000021
Igor Sysoevd404c972003-10-16 20:19:16 +000022static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
23 void *conf);
24static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
Igor Sysoeva1512b12003-11-03 17:33:31 +000025 ngx_http_proxy_upstream_conf_t *u);
Igor Sysoevd404c972003-10-16 20:19:16 +000026
Igor Sysoevae5c59c2003-08-14 06:00:28 +000027
Igor Sysoev68ee8f12003-10-30 08:51:06 +000028static ngx_conf_bitmask_t next_upstream_masks[] = {
29 { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
30 { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
Igor Sysoev65977492003-11-02 22:56:18 +000031 { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
Igor Sysoev68ee8f12003-10-30 08:51:06 +000032 { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
Igor Sysoev65977492003-11-02 22:56:18 +000033 { ngx_string("http_404"), NGX_HTTP_PROXY_FT_HTTP_404 },
34 { ngx_null_string, 0 }
35};
36
37
38static ngx_conf_bitmask_t use_stale_masks[] = {
39 { ngx_string("error"), NGX_HTTP_PROXY_FT_ERROR },
40 { ngx_string("timeout"), NGX_HTTP_PROXY_FT_TIMEOUT },
41 { ngx_string("invalid_header"), NGX_HTTP_PROXY_FT_INVALID_HEADER },
42 { ngx_string("http_500"), NGX_HTTP_PROXY_FT_HTTP_500 },
43 { ngx_string("busy_lock"), NGX_HTTP_PROXY_FT_BUSY_LOCK },
44 { ngx_string("max_waiting"), NGX_HTTP_PROXY_FT_MAX_WAITING },
Igor Sysoev68ee8f12003-10-30 08:51:06 +000045 { ngx_null_string, 0 }
46};
Igor Sysoevd404c972003-10-16 20:19:16 +000047
Igor Sysoevcf80a702003-11-03 22:20:44 +000048
49static ngx_conf_num_bounds_t ngx_http_proxy_lm_factor_bounds = {
50 ngx_conf_check_num_bounds, 0, 100
51};
52
53
Igor Sysoev68ee8f12003-10-30 08:51:06 +000054static ngx_command_t ngx_http_proxy_commands[] = {
Igor Sysoevd404c972003-10-16 20:19:16 +000055
Igor Sysoev68ee8f12003-10-30 08:51:06 +000056 { ngx_string("proxy_pass"),
57 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
58 ngx_http_proxy_set_pass,
59 NGX_HTTP_LOC_CONF_OFFSET,
60 0,
61 NULL },
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000062
Igor Sysoev68ee8f12003-10-30 08:51:06 +000063 { ngx_string("proxy_connect_timeout"),
64 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
65 ngx_conf_set_msec_slot,
66 NGX_HTTP_LOC_CONF_OFFSET,
67 offsetof(ngx_http_proxy_loc_conf_t, connect_timeout),
68 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +000069
Igor Sysoev68ee8f12003-10-30 08:51:06 +000070 { ngx_string("proxy_send_timeout"),
71 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
72 ngx_conf_set_msec_slot,
73 NGX_HTTP_LOC_CONF_OFFSET,
74 offsetof(ngx_http_proxy_loc_conf_t, send_timeout),
75 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +000076
Igor Sysoev3646a162004-03-14 20:46:25 +000077 { ngx_string("proxy_preserve_host"),
78 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
79 ngx_conf_set_flag_slot,
80 NGX_HTTP_LOC_CONF_OFFSET,
81 offsetof(ngx_http_proxy_loc_conf_t, preserve_host),
82 NULL },
83
Igor Sysoev67f88e92004-03-12 16:57:08 +000084 { ngx_string("proxy_set_x_real_ip"),
85 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
86 ngx_conf_set_flag_slot,
87 NGX_HTTP_LOC_CONF_OFFSET,
88 offsetof(ngx_http_proxy_loc_conf_t, set_x_real_ip),
89 NULL },
90
91 { ngx_string("proxy_add_x_forwarded_for"),
92 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
93 ngx_conf_set_flag_slot,
94 NGX_HTTP_LOC_CONF_OFFSET,
95 offsetof(ngx_http_proxy_loc_conf_t, add_x_forwarded_for),
96 NULL },
97
Igor Sysoev68ee8f12003-10-30 08:51:06 +000098 { ngx_string("proxy_header_buffer_size"),
99 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
100 ngx_conf_set_size_slot,
101 NGX_HTTP_LOC_CONF_OFFSET,
102 offsetof(ngx_http_proxy_loc_conf_t, header_buffer_size),
103 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000104
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000105 { ngx_string("proxy_read_timeout"),
106 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
107 ngx_conf_set_msec_slot,
108 NGX_HTTP_LOC_CONF_OFFSET,
109 offsetof(ngx_http_proxy_loc_conf_t, read_timeout),
110 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000111
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000112 { ngx_string("proxy_buffers"),
113 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
114 ngx_conf_set_bufs_slot,
115 NGX_HTTP_LOC_CONF_OFFSET,
116 offsetof(ngx_http_proxy_loc_conf_t, bufs),
117 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000118
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000119 { ngx_string("proxy_busy_buffers_size"),
120 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
121 ngx_conf_set_size_slot,
122 NGX_HTTP_LOC_CONF_OFFSET,
123 offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size),
124 NULL },
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000125
Igor Sysoev67f88e92004-03-12 16:57:08 +0000126#if (NGX_HTTP_FILE_CACHE)
127
Igor Sysoev65977492003-11-02 22:56:18 +0000128 { ngx_string("proxy_cache_path"),
129 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
130 ngx_conf_set_path_slot,
131 NGX_HTTP_LOC_CONF_OFFSET,
132 offsetof(ngx_http_proxy_loc_conf_t, cache_path),
Igor Sysoev1b138ed2003-11-18 21:34:08 +0000133 ngx_garbage_collector_http_cache_handler },
Igor Sysoev65977492003-11-02 22:56:18 +0000134
Igor Sysoev67f88e92004-03-12 16:57:08 +0000135#endif
136
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000137 { ngx_string("proxy_temp_path"),
138 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
139 ngx_conf_set_path_slot,
140 NGX_HTTP_LOC_CONF_OFFSET,
141 offsetof(ngx_http_proxy_loc_conf_t, temp_path),
Igor Sysoev10a543a2004-03-16 07:10:12 +0000142 (void *) ngx_garbage_collector_temp_handler },
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000143
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000144 { ngx_string("proxy_temp_file_write_size"),
145 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
146 ngx_conf_set_size_slot,
147 NGX_HTTP_LOC_CONF_OFFSET,
148 offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size),
149 NULL },
Igor Sysoevab0c4f52003-10-28 15:45:41 +0000150
Igor Sysoev65977492003-11-02 22:56:18 +0000151 { ngx_string("proxy_cache"),
152 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
153 ngx_conf_set_flag_slot,
154 NGX_HTTP_LOC_CONF_OFFSET,
155 offsetof(ngx_http_proxy_loc_conf_t, cache),
156 NULL },
157
Igor Sysoevcf80a702003-11-03 22:20:44 +0000158
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000159 { ngx_string("proxy_busy_lock"),
Igor Sysoev74e95c22003-11-09 20:03:38 +0000160 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000161 ngx_http_set_busy_lock_slot,
162 NGX_HTTP_LOC_CONF_OFFSET,
163 offsetof(ngx_http_proxy_loc_conf_t, busy_lock),
164 NULL },
165
166
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000167 { ngx_string("proxy_pass_server"),
168 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
169 ngx_conf_set_flag_slot,
170 NGX_HTTP_LOC_CONF_OFFSET,
171 offsetof(ngx_http_proxy_loc_conf_t, pass_server),
172 NULL },
173
Igor Sysoevcf80a702003-11-03 22:20:44 +0000174 { ngx_string("proxy_pass_x_accel_expires"),
175 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
176 ngx_conf_set_flag_slot,
177 NGX_HTTP_LOC_CONF_OFFSET,
178 offsetof(ngx_http_proxy_loc_conf_t, pass_x_accel_expires),
179 NULL },
180
181 { ngx_string("proxy_ignore_expires"),
182 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
183 ngx_conf_set_flag_slot,
184 NGX_HTTP_LOC_CONF_OFFSET,
185 offsetof(ngx_http_proxy_loc_conf_t, ignore_expires),
186 NULL },
187
188 { ngx_string("proxy_lm_factor"),
189 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
190 ngx_conf_set_num_slot,
191 NGX_HTTP_LOC_CONF_OFFSET,
192 offsetof(ngx_http_proxy_loc_conf_t, lm_factor),
193 &ngx_http_proxy_lm_factor_bounds },
194
195 { ngx_string("proxy_default_expires"),
196 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
197 ngx_conf_set_sec_slot,
198 NGX_HTTP_LOC_CONF_OFFSET,
199 offsetof(ngx_http_proxy_loc_conf_t, default_expires),
200 NULL },
201
202
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000203 { ngx_string("proxy_next_upstream"),
204 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
205 ngx_conf_set_bitmask_slot,
206 NGX_HTTP_LOC_CONF_OFFSET,
207 offsetof(ngx_http_proxy_loc_conf_t, next_upstream),
208 &next_upstream_masks },
209
Igor Sysoev65977492003-11-02 22:56:18 +0000210 { ngx_string("proxy_use_stale"),
211 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
212 ngx_conf_set_bitmask_slot,
213 NGX_HTTP_LOC_CONF_OFFSET,
214 offsetof(ngx_http_proxy_loc_conf_t, use_stale),
215 &use_stale_masks },
216
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000217 ngx_null_command
Igor Sysoev04410502003-08-01 14:56:33 +0000218};
219
220
221ngx_http_module_t ngx_http_proxy_module_ctx = {
Igor Sysoev78329332003-11-10 17:17:31 +0000222 ngx_http_proxy_pre_conf, /* pre conf */
223
Igor Sysoev04410502003-08-01 14:56:33 +0000224 NULL, /* create main configuration */
225 NULL, /* init main configuration */
226
227 NULL, /* create server configuration */
228 NULL, /* merge server configuration */
229
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000230 ngx_http_proxy_create_loc_conf, /* create location configration */
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000231 ngx_http_proxy_merge_loc_conf /* merge location configration */
Igor Sysoev04410502003-08-01 14:56:33 +0000232};
233
234
235ngx_module_t ngx_http_proxy_module = {
236 NGX_MODULE,
237 &ngx_http_proxy_module_ctx, /* module context */
238 ngx_http_proxy_commands, /* module directives */
239 NGX_HTTP_MODULE, /* module type */
Igor Sysoevd404c972003-10-16 20:19:16 +0000240 NULL, /* init module */
Igor Sysoev04410502003-08-01 14:56:33 +0000241 NULL /* init child */
242};
243
244
Igor Sysoev78329332003-11-10 17:17:31 +0000245
246static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = {
247 { ngx_string("proxy"), /* STUB */ 100,
248 ngx_http_proxy_log_proxy_state },
249 { ngx_string("proxy_cache_state"), sizeof("BYPASS") - 1,
250 ngx_http_proxy_log_cache_state },
251 { ngx_string("proxy_reason"), sizeof("BPS") - 1,
252 ngx_http_proxy_log_reason },
253 { ngx_null_string, 0, NULL }
254};
255
256
257
Igor Sysoev65977492003-11-02 22:56:18 +0000258ngx_http_header_t ngx_http_proxy_headers_in[] = {
Igor Sysoeve6779222003-10-03 15:50:53 +0000259 { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
260 { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
Igor Sysoeva1512b12003-11-03 17:33:31 +0000261
262 { ngx_string("Expires"), offsetof(ngx_http_proxy_headers_in_t, expires) },
263 { ngx_string("Cache-Control"),
264 offsetof(ngx_http_proxy_headers_in_t, cache_control) },
Igor Sysoevb3968b32004-04-14 17:44:28 +0000265 { ngx_string("ETag"), offsetof(ngx_http_proxy_headers_in_t, etag) },
Igor Sysoeva1512b12003-11-03 17:33:31 +0000266 { ngx_string("X-Accel-Expires"),
267 offsetof(ngx_http_proxy_headers_in_t, x_accel_expires) },
268
Igor Sysoeve6779222003-10-03 15:50:53 +0000269 { ngx_string("Connection"),
270 offsetof(ngx_http_proxy_headers_in_t, connection) },
271 { ngx_string("Content-Type"),
272 offsetof(ngx_http_proxy_headers_in_t, content_type) },
273 { ngx_string("Content-Length"),
274 offsetof(ngx_http_proxy_headers_in_t, content_length) },
275 { ngx_string("Last-Modified"),
276 offsetof(ngx_http_proxy_headers_in_t, last_modified) },
Igor Sysoev1b138ed2003-11-18 21:34:08 +0000277 { ngx_string("Location"),
278 offsetof(ngx_http_proxy_headers_in_t, location) },
Igor Sysoev931a4002003-10-07 15:30:05 +0000279 { ngx_string("Accept-Ranges"),
280 offsetof(ngx_http_proxy_headers_in_t, accept_ranges) },
Igor Sysoevab517d52004-05-18 15:29:08 +0000281 { ngx_string("X-Pad"), offsetof(ngx_http_proxy_headers_in_t, x_pad) },
Igor Sysoeve6779222003-10-03 15:50:53 +0000282
283 { ngx_null_string, 0 }
284};
285
286
Igor Sysoev74e95c22003-11-09 20:03:38 +0000287static ngx_str_t cache_states[] = {
288 ngx_string("PASS"),
289 ngx_string("BYPASS"),
290 ngx_string("AUTH"),
291 ngx_string("PGNC"),
292 ngx_string("MISS"),
293 ngx_string("EXPR"),
294 ngx_string("AGED"),
295 ngx_string("HIT")
296};
297
298
Igor Sysoev78329332003-11-10 17:17:31 +0000299static ngx_str_t cache_reasons[] = {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000300 ngx_string("BPS"),
301 ngx_string("XAE"),
302 ngx_string("CTL"),
303 ngx_string("EXP"),
304 ngx_string("MVD"),
305 ngx_string("LMF"),
306 ngx_string("PDE")
307};
308
309
Igor Sysoev2f657222004-06-16 15:32:11 +0000310static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r)
Igor Sysoev04410502003-08-01 14:56:33 +0000311{
Igor Sysoeva1512b12003-11-03 17:33:31 +0000312 ngx_http_proxy_ctx_t *p;
Igor Sysoev04410502003-08-01 14:56:33 +0000313
314 ngx_http_create_ctx(r, p, ngx_http_proxy_module,
315 sizeof(ngx_http_proxy_ctx_t),
316 NGX_HTTP_INTERNAL_SERVER_ERROR);
317
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000318 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
Igor Sysoev65977492003-11-02 22:56:18 +0000319 p->request = r;
320
321 /* TODO: we currently support reverse proxy only */
322 p->accel = 1;
323
Igor Sysoevcf80a702003-11-03 22:20:44 +0000324 ngx_init_array(p->states, r->pool, p->lcf->peers->number,
325 sizeof(ngx_http_proxy_state_t),
326 NGX_HTTP_INTERNAL_SERVER_ERROR);
327
328 if (!(p->state = ngx_push_array(&p->states))) {
329 return NGX_HTTP_INTERNAL_SERVER_ERROR;
330 }
331
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000332 ngx_memzero(p->state, sizeof(ngx_http_proxy_state_t));
333
Igor Sysoev67f88e92004-03-12 16:57:08 +0000334#if (NGX_HTTP_FILE_CACHE)
Igor Sysoevcf80a702003-11-03 22:20:44 +0000335
Igor Sysoeve8732b02003-11-05 17:03:41 +0000336 if (!p->lcf->cache
337 || (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD))
338 {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000339 p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS;
Igor Sysoevcf80a702003-11-03 22:20:44 +0000340
341 } else if (r->bypass_cache) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000342 p->state->cache_state = NGX_HTTP_PROXY_CACHE_BYPASS;
Igor Sysoevcf80a702003-11-03 22:20:44 +0000343
344 } else if (r->headers_in.authorization) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000345 p->state->cache_state = NGX_HTTP_PROXY_CACHE_AUTH;
Igor Sysoevcf80a702003-11-03 22:20:44 +0000346
347 } else if (r->no_cache) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000348 p->state->cache_state = NGX_HTTP_PROXY_CACHE_PGNC;
Igor Sysoevcf80a702003-11-03 22:20:44 +0000349 p->cachable = 1;
350
351 } else {
352 p->cachable = 1;
353 }
354
355
Igor Sysoev74e95c22003-11-09 20:03:38 +0000356 if (p->state->cache_state != 0) {
Igor Sysoev65977492003-11-02 22:56:18 +0000357 return ngx_http_proxy_request_upstream(p);
358 }
359
Igor Sysoev74e95c22003-11-09 20:03:38 +0000360 return ngx_http_proxy_get_cached_response(p);
Igor Sysoev67f88e92004-03-12 16:57:08 +0000361
362#else
363
364 p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS;
365
366 return ngx_http_proxy_request_upstream(p);
367
368#endif
Igor Sysoev74e95c22003-11-09 20:03:38 +0000369}
Igor Sysoev65977492003-11-02 22:56:18 +0000370
Igor Sysoev74e95c22003-11-09 20:03:38 +0000371
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000372void ngx_http_proxy_check_broken_connection(ngx_event_t *ev)
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000373{
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000374 int n;
375 char buf[1];
376 ngx_err_t err;
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000377 ngx_connection_t *c;
378 ngx_http_request_t *r;
379 ngx_http_proxy_ctx_t *p;
380
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000381 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
382 "http proxy check client, write event:%d", ev->write);
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000383
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000384#if (HAVE_KQUEUE)
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000385
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000386 if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000387
Igor Sysoev98c1cf12004-07-02 15:54:34 +0000388 if (!ev->pending_eof) {
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000389 return;
390 }
391
392 c = ev->data;
393 r = c->data;
394 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
395
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000396 ev->eof = 1;
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000397
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000398 if (ev->kq_errno) {
399 ev->error = 1;
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000400 }
401
402 if (!p->cachable && p->upstream->peer.connection) {
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000403 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
Igor Sysoev54498db2004-02-11 17:08:49 +0000404 "kevent() reported that client have closed "
405 "prematurely connection, "
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000406 "so upstream connection is closed too");
407 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
408 return;
409 }
410
Igor Sysoev6881bfb2004-03-30 06:27:36 +0000411 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
Igor Sysoev54498db2004-02-11 17:08:49 +0000412 "kevent() reported that client have closed "
413 "prematurely connection");
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000414
415 if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
416 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
417 }
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000418
419 return;
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000420 }
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000421
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000422#endif
423
424 c = ev->data;
425 r = c->data;
426 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000427
428 n = recv(c->fd, buf, 1, MSG_PEEK);
429
Igor Sysoev3d540612004-04-13 15:08:48 +0000430 err = ngx_socket_errno;
431
Igor Sysoev68df19d2004-04-15 15:34:36 +0000432 /*
433 * we do not need to disable the write event because
434 * that event has NGX_USE_CLEAR_EVENT type
435 */
436
Igor Sysoev3d540612004-04-13 15:08:48 +0000437 if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
Igor Sysoeva21e30b2004-04-13 05:27:03 +0000438 return;
439 }
440
Igor Sysoev68df19d2004-04-15 15:34:36 +0000441 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
442 if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
443 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000444 }
Igor Sysoev68df19d2004-04-15 15:34:36 +0000445 }
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000446
Igor Sysoev68df19d2004-04-15 15:34:36 +0000447 if (n > 0) {
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000448 return;
449 }
450
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000451 ev->eof = 1;
452
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000453 if (n == -1) {
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000454 if (err == NGX_EAGAIN) {
455 return;
456 }
457
458 ev->error = 1;
459
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000460 } else {
461 /* n == 0 */
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000462 err = 0;
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000463 }
464
465 if (!p->cachable && p->upstream->peer.connection) {
466 ngx_log_error(NGX_LOG_INFO, ev->log, err,
467 "client have closed prematurely connection, "
468 "so upstream connection is closed too");
469 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
470 return;
471 }
472
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000473 ngx_log_error(NGX_LOG_INFO, ev->log, err,
Igor Sysoevc972a3f2004-04-02 15:13:20 +0000474 "client have closed prematurely connection");
475
476 if (p->upstream == NULL || p->upstream->peer.connection == NULL) {
477 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
478 }
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000479}
480
481
Igor Sysoev74e95c22003-11-09 20:03:38 +0000482void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev)
483{
484 ngx_connection_t *c;
485 ngx_http_request_t *r;
486 ngx_http_proxy_ctx_t *p;
Igor Sysoev5f800782003-12-08 20:48:12 +0000487
Igor Sysoev54498db2004-02-11 17:08:49 +0000488 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http proxy busy lock");
Igor Sysoev74e95c22003-11-09 20:03:38 +0000489
490 c = rev->data;
491 r = c->data;
492 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
493 p->action = "waiting upstream in busy lock";
494
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000495 if (p->request->connection->write->eof) {
496 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
497 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
498 return;
499 }
500
Igor Sysoev74e95c22003-11-09 20:03:38 +0000501 if (rev->timedout) {
502 rev->timedout = 0;
503 p->busy_lock.time++;
504 p->state->bl_time = p->busy_lock.time;
Igor Sysoev67f88e92004-03-12 16:57:08 +0000505
506#if (NGX_HTTP_FILE_CACHE)
507
Igor Sysoev74e95c22003-11-09 20:03:38 +0000508 if (p->state->cache_state < NGX_HTTP_PROXY_CACHE_MISS) {
509 ngx_http_proxy_upstream_busy_lock(p);
510
511 } else {
512 ngx_http_proxy_cache_busy_lock(p);
513 }
Igor Sysoev67f88e92004-03-12 16:57:08 +0000514#else
515
516 ngx_http_proxy_upstream_busy_lock(p);
517
518#endif
Igor Sysoev74e95c22003-11-09 20:03:38 +0000519
520 return;
Igor Sysoeve8732b02003-11-05 17:03:41 +0000521 }
522
Igor Sysoev54498db2004-02-11 17:08:49 +0000523 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
524 "http proxy: client sent while busy lock");
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000525
Igor Sysoev74e95c22003-11-09 20:03:38 +0000526 /*
527 * TODO: kevent() notify about error, otherwise we need to
Igor Sysoev54498db2004-02-11 17:08:49 +0000528 * call ngx_peek(): recv(MSG_PEEK) to get errno. THINK about aio.
Igor Sysoev74e95c22003-11-09 20:03:38 +0000529 * if there's no error we need to disable event.
530 */
531
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000532#if 0
Igor Sysoev74e95c22003-11-09 20:03:38 +0000533#if (HAVE_KQUEUE)
534
535 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) && rev->kq_eof) {
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000536 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000537
538 ngx_del_timer(rev);
539
540 ngx_log_error(NGX_LOG_ERR, c->log, rev->kq_errno,
541 "client() closed connection");
542
543 if (ngx_del_event(rev, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) {
544 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
545 return;
546 }
547
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000548 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000549 return;
Igor Sysoev65977492003-11-02 22:56:18 +0000550 }
551
Igor Sysoev74e95c22003-11-09 20:03:38 +0000552#endif
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000553#endif
Igor Sysoev65977492003-11-02 22:56:18 +0000554
Igor Sysoevfe0f5cc2003-10-31 16:05:33 +0000555}
556
557
Igor Sysoeva1512b12003-11-03 17:33:31 +0000558void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
Igor Sysoev931a4002003-10-07 15:30:05 +0000559{
Igor Sysoev1ef22522003-11-20 17:36:43 +0000560 ngx_http_request_t *r;
561
562 r = p->request;
563
Igor Sysoev54498db2004-02-11 17:08:49 +0000564 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
565 "finalize http proxy request");
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000566
Igor Sysoev74e95c22003-11-09 20:03:38 +0000567 if (p->upstream && p->upstream->peer.connection) {
Igor Sysoeve8732b02003-11-05 17:03:41 +0000568 ngx_http_proxy_close_connection(p);
Igor Sysoev931a4002003-10-07 15:30:05 +0000569 }
570
Igor Sysoev9760a132003-10-21 07:47:21 +0000571 if (p->header_sent
572 && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
573 {
Igor Sysoev931a4002003-10-07 15:30:05 +0000574 rc = 0;
575 }
576
Igor Sysoev74e95c22003-11-09 20:03:38 +0000577 if (p->saved_ctx) {
Igor Sysoev1ef22522003-11-20 17:36:43 +0000578 r->connection->log->data = p->saved_ctx;
579 r->connection->log->handler = p->saved_handler;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000580 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000581
Igor Sysoev1ef22522003-11-20 17:36:43 +0000582 if (p->upstream && p->upstream->event_pipe) {
Igor Sysoev54498db2004-02-11 17:08:49 +0000583 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
584 "http proxy temp fd: %d",
585 p->upstream->event_pipe->temp_file->file.fd);
Igor Sysoev1ef22522003-11-20 17:36:43 +0000586 }
587
588 if (p->cache) {
Igor Sysoev54498db2004-02-11 17:08:49 +0000589 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
590 "http proxy cache fd: %d",
591 p->cache->ctx.file.fd);
Igor Sysoev1ef22522003-11-20 17:36:43 +0000592 }
593
594 if (p->upstream && p->upstream->event_pipe) {
595 r->file.fd = p->upstream->event_pipe->temp_file->file.fd;
596
597 } else if (p->cache) {
598 r->file.fd = p->cache->ctx.file.fd;
599 }
600
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000601 if (rc == 0 && r->main == NULL) {
602 rc = ngx_http_send_last(r);
603 }
604
Igor Sysoev1ef22522003-11-20 17:36:43 +0000605 ngx_http_finalize_request(r, rc);
Igor Sysoev931a4002003-10-07 15:30:05 +0000606}
607
608
Igor Sysoeve8732b02003-11-05 17:03:41 +0000609void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p)
Igor Sysoeve6779222003-10-03 15:50:53 +0000610{
Igor Sysoeve8732b02003-11-05 17:03:41 +0000611 ngx_connection_t *c;
612
613 c = p->upstream->peer.connection;
614 p->upstream->peer.connection = NULL;
615
616 if (p->lcf->busy_lock) {
Igor Sysoev74e95c22003-11-09 20:03:38 +0000617 p->lcf->busy_lock->busy--;
Igor Sysoeve8732b02003-11-05 17:03:41 +0000618 }
619
Igor Sysoev54498db2004-02-11 17:08:49 +0000620 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
621 "http proxy close connection: %d", c->fd);
Igor Sysoeve6779222003-10-03 15:50:53 +0000622
623 if (c->fd == -1) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000624#if 0
Igor Sysoeve6779222003-10-03 15:50:53 +0000625 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
Igor Sysoev931a4002003-10-07 15:30:05 +0000626#endif
Igor Sysoeve6779222003-10-03 15:50:53 +0000627 return;
628 }
629
630 if (c->read->timer_set) {
631 ngx_del_timer(c->read);
Igor Sysoeve6779222003-10-03 15:50:53 +0000632 }
633
634 if (c->write->timer_set) {
635 ngx_del_timer(c->write);
Igor Sysoeve6779222003-10-03 15:50:53 +0000636 }
637
Igor Sysoevfd3e3742003-10-08 04:34:07 +0000638 /* TODO: move connection to the connection pool */
639
Igor Sysoeve6779222003-10-03 15:50:53 +0000640 if (ngx_del_conn) {
Igor Sysoev22a7c502004-02-17 21:11:27 +0000641 ngx_del_conn(c, NGX_CLOSE_EVENT);
Igor Sysoeve6779222003-10-03 15:50:53 +0000642
643 } else {
Igor Sysoev98c1cf12004-07-02 15:54:34 +0000644 if (c->read->active || c->read->disabled) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000645 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
646 }
647
Igor Sysoev98c1cf12004-07-02 15:54:34 +0000648 if (c->write->active || c->read->disabled) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000649 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
650 }
651 }
652
653 if (ngx_close_socket(c->fd) == -1) {
654 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
655 ngx_close_socket_n " failed");
656 }
657
Igor Sysoev10a543a2004-03-16 07:10:12 +0000658 c->fd = (ngx_socket_t) -1;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000659}
660
Igor Sysoev04410502003-08-01 14:56:33 +0000661
Igor Sysoeva1512b12003-11-03 17:33:31 +0000662size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
Igor Sysoev04410502003-08-01 14:56:33 +0000663{
Igor Sysoev160d7742003-11-19 16:26:41 +0000664 ngx_http_proxy_log_ctx_t *ctx = data;
Igor Sysoev04410502003-08-01 14:56:33 +0000665
Igor Sysoeva1512b12003-11-03 17:33:31 +0000666 ngx_http_request_t *r;
667 ngx_peer_connection_t *peer;
668
Igor Sysoev160d7742003-11-19 16:26:41 +0000669 r = ctx->proxy->request;
670 peer = &ctx->proxy->upstream->peer;
Igor Sysoeva1512b12003-11-03 17:33:31 +0000671
Igor Sysoev04410502003-08-01 14:56:33 +0000672 return ngx_snprintf(buf, len,
Igor Sysoeva1512b12003-11-03 17:33:31 +0000673 " while %s, client: %s, URL: %s, upstream: %s%s%s%s%s",
Igor Sysoev160d7742003-11-19 16:26:41 +0000674 ctx->proxy->action,
Igor Sysoeva1512b12003-11-03 17:33:31 +0000675 r->connection->addr_text.data,
676 r->unparsed_uri.data,
677 peer->peers->peers[peer->cur_peer].addr_port_text.data,
Igor Sysoev160d7742003-11-19 16:26:41 +0000678 ctx->proxy->lcf->upstream->uri.data,
679 r->uri.data + ctx->proxy->lcf->upstream->location->len,
Igor Sysoeva1512b12003-11-03 17:33:31 +0000680 r->args.len ? "?" : "",
Igor Sysoev10a543a2004-03-16 07:10:12 +0000681 r->args.len ? r->args.data : (u_char *) "");
Igor Sysoev04410502003-08-01 14:56:33 +0000682}
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000683
684
Igor Sysoev10a543a2004-03-16 07:10:12 +0000685static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r,
686 u_char *buf, uintptr_t data)
Igor Sysoev78329332003-11-10 17:17:31 +0000687{
688 ngx_http_proxy_ctx_t *p;
689
Igor Sysoevd59a0472003-11-10 21:09:22 +0000690 p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
Igor Sysoev78329332003-11-10 17:17:31 +0000691
692 if (p == NULL) {
693 *buf = '-';
694 return buf + 1;
695 }
696
697 if (p->state->cache_state == 0) {
698 *buf++ = '-';
699
700 } else {
701 buf = ngx_cpymem(buf, cache_states[p->state->cache_state - 1].data,
702 cache_states[p->state->cache_state - 1].len);
703 }
704
705 *buf++ = '/';
706
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000707 if (p->state->expired == 0) {
708 *buf++ = '-';
709
710 } else {
Igor Sysoevc0247302004-06-27 18:01:57 +0000711 buf += ngx_snprintf((char *) buf, TIME_T_LEN,
Igor Sysoev10a543a2004-03-16 07:10:12 +0000712 TIME_T_FMT, p->state->expired);
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000713 }
Igor Sysoev78329332003-11-10 17:17:31 +0000714
715 *buf++ = '/';
716
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000717 if (p->state->bl_time == 0) {
718 *buf++ = '-';
719
720 } else {
Igor Sysoevc0247302004-06-27 18:01:57 +0000721 buf += ngx_snprintf((char *) buf, TIME_T_LEN,
Igor Sysoev10a543a2004-03-16 07:10:12 +0000722 TIME_T_FMT, p->state->bl_time);
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000723 }
Igor Sysoevd59a0472003-11-10 21:09:22 +0000724
725 *buf++ = '/';
726
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000727 *buf++ = '*';
Igor Sysoev78329332003-11-10 17:17:31 +0000728
729 *buf++ = ' ';
730
731 if (p->state->status == 0) {
732 *buf++ = '-';
733
734 } else {
Igor Sysoev2f657222004-06-16 15:32:11 +0000735 buf += ngx_snprintf((char *) buf, 4, "%" NGX_UINT_T_FMT,
736 p->state->status);
Igor Sysoev78329332003-11-10 17:17:31 +0000737 }
738
739 *buf++ = '/';
740
741 if (p->state->reason == 0) {
742 *buf++ = '-';
743
744 } else {
745 buf = ngx_cpymem(buf, cache_reasons[p->state->reason - 1].data,
746 cache_reasons[p->state->reason - 1].len);
747 }
748
749 *buf++ = '/';
750
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000751 if (p->state->reason < NGX_HTTP_PROXY_CACHE_XAE) {
Igor Sysoev78329332003-11-10 17:17:31 +0000752 *buf++ = '-';
753
754 } else {
Igor Sysoevc0247302004-06-27 18:01:57 +0000755 buf += ngx_snprintf((char *) buf, TIME_T_LEN,
Igor Sysoev10a543a2004-03-16 07:10:12 +0000756 TIME_T_FMT, p->state->expires);
Igor Sysoev78329332003-11-10 17:17:31 +0000757 }
758
Igor Sysoevd59a0472003-11-10 21:09:22 +0000759 *buf++ = ' ';
Igor Sysoeva8fa0a62003-11-25 20:44:56 +0000760 *buf++ = '*';
Igor Sysoevd59a0472003-11-10 21:09:22 +0000761
Igor Sysoev78329332003-11-10 17:17:31 +0000762 return buf;
763}
764
765
Igor Sysoev10a543a2004-03-16 07:10:12 +0000766static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r,
767 u_char *buf, uintptr_t data)
Igor Sysoev78329332003-11-10 17:17:31 +0000768{
769 ngx_http_proxy_ctx_t *p;
770
Igor Sysoevd59a0472003-11-10 21:09:22 +0000771 p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
Igor Sysoev78329332003-11-10 17:17:31 +0000772
773 if (p == NULL || p->state->cache_state == 0) {
774 *buf = '-';
775 return buf + 1;
776 }
777
778 return ngx_cpymem(buf, cache_states[p->state->cache_state - 1].data,
779 cache_states[p->state->cache_state - 1].len);
780}
781
782
Igor Sysoev10a543a2004-03-16 07:10:12 +0000783static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf,
784 uintptr_t data)
Igor Sysoev78329332003-11-10 17:17:31 +0000785{
786 ngx_http_proxy_ctx_t *p;
787
Igor Sysoevd59a0472003-11-10 21:09:22 +0000788 p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module);
Igor Sysoev78329332003-11-10 17:17:31 +0000789
790 if (p == NULL || p->state->reason == 0) {
791 *buf = '-';
792 return buf + 1;
793 }
794
795 return ngx_cpymem(buf, cache_reasons[p->state->reason - 1].data,
796 cache_reasons[p->state->reason - 1].len);
797}
798
799
Igor Sysoev2f657222004-06-16 15:32:11 +0000800static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf)
Igor Sysoev78329332003-11-10 17:17:31 +0000801{
802 ngx_http_log_op_name_t *op;
803
804 for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ }
805 op->op = NULL;
806
807 op = ngx_http_log_fmt_ops;
808
809 for (op = ngx_http_log_fmt_ops; op->op; op++) {
810 if (op->name.len == 0) {
811 op = (ngx_http_log_op_name_t *) op->op;
812 }
813 }
814
815 op->op = (ngx_http_log_op_pt) ngx_http_proxy_log_fmt_ops;
816
817 return NGX_OK;
818}
819
820
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000821static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
822{
823 ngx_http_proxy_loc_conf_t *conf;
824
825 ngx_test_null(conf,
826 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)),
827 NGX_CONF_ERROR);
828
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000829 /* set by ngx_pcalloc():
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000830
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000831 conf->bufs.num = 0;
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000832
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000833 conf->path = NULL;
Igor Sysoev931a4002003-10-07 15:30:05 +0000834
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000835 conf->next_upstream = 0;
Igor Sysoev65977492003-11-02 22:56:18 +0000836 conf->use_stale = 0;
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000837
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000838 conf->upstreams = NULL;
839 conf->peers = NULL;
Igor Sysoev9760a132003-10-21 07:47:21 +0000840
Igor Sysoev65977492003-11-02 22:56:18 +0000841 conf->cache_path = NULL;
842 conf->temp_path = NULL;
843
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000844 conf->busy_lock = NULL;
845
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000846 */
Igor Sysoev9760a132003-10-21 07:47:21 +0000847
Igor Sysoev10a543a2004-03-16 07:10:12 +0000848 conf->connect_timeout = NGX_CONF_UNSET_MSEC;
849 conf->send_timeout = NGX_CONF_UNSET_MSEC;
Igor Sysoev67f88e92004-03-12 16:57:08 +0000850
Igor Sysoev3646a162004-03-14 20:46:25 +0000851 conf->preserve_host = NGX_CONF_UNSET;
Igor Sysoev67f88e92004-03-12 16:57:08 +0000852 conf->set_x_real_ip = NGX_CONF_UNSET;
853 conf->add_x_forwarded_for = NGX_CONF_UNSET;
854
Igor Sysoev10a543a2004-03-16 07:10:12 +0000855 conf->header_buffer_size = NGX_CONF_UNSET_SIZE;
856 conf->read_timeout = NGX_CONF_UNSET_MSEC;
857 conf->busy_buffers_size = NGX_CONF_UNSET_SIZE;
Igor Sysoev9760a132003-10-21 07:47:21 +0000858
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000859 /*
860 * "proxy_max_temp_file_size" is hardcoded to 1G for reverse proxy,
861 * it should be configurable in the generic proxy
862 */
863 conf->max_temp_file_size = 1024 * 1024 * 1024;
Igor Sysoev9760a132003-10-21 07:47:21 +0000864
Igor Sysoev10a543a2004-03-16 07:10:12 +0000865 conf->temp_file_write_size = NGX_CONF_UNSET_SIZE;
Igor Sysoev931a4002003-10-07 15:30:05 +0000866
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000867 /* "proxy_cyclic_temp_file" is disabled */
868 conf->cyclic_temp_file = 0;
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000869
Igor Sysoev65977492003-11-02 22:56:18 +0000870 conf->cache = NGX_CONF_UNSET;
871
Igor Sysoevab0c4f52003-10-28 15:45:41 +0000872 conf->pass_server = NGX_CONF_UNSET;
Igor Sysoevcf80a702003-11-03 22:20:44 +0000873 conf->pass_x_accel_expires = NGX_CONF_UNSET;
874 conf->ignore_expires = NGX_CONF_UNSET;
875 conf->lm_factor = NGX_CONF_UNSET;
876 conf->default_expires = NGX_CONF_UNSET;
Igor Sysoevab0c4f52003-10-28 15:45:41 +0000877
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000878 return conf;
879}
Igor Sysoevd404c972003-10-16 20:19:16 +0000880
881
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000882static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
883 void *parent, void *child)
884{
885 ngx_http_proxy_loc_conf_t *prev = parent;
886 ngx_http_proxy_loc_conf_t *conf = child;
887
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000888 size_t size;
889
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000890 ngx_conf_merge_msec_value(conf->connect_timeout,
891 prev->connect_timeout, 60000);
892 ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 30000);
Igor Sysoev67f88e92004-03-12 16:57:08 +0000893
Igor Sysoev3646a162004-03-14 20:46:25 +0000894 ngx_conf_merge_value(conf->preserve_host, prev->preserve_host, 0);
Igor Sysoev67f88e92004-03-12 16:57:08 +0000895 ngx_conf_merge_value(conf->set_x_real_ip, prev->set_x_real_ip, 0);
896 ngx_conf_merge_value(conf->add_x_forwarded_for,
897 prev->add_x_forwarded_for, 0);
898
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000899 ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 30000);
900
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000901 ngx_conf_merge_size_value(conf->header_buffer_size,
902 prev->header_buffer_size, 4096);
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000903
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000904 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, 4096);
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000905
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000906 if (conf->bufs.num < 2) {
907 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
908 "there must be at least 2 \"proxy_buffers\"");
909 return NGX_CONF_ERROR;
910 }
911
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000912 size = conf->header_buffer_size;
913 if (size < conf->bufs.size) {
914 size = conf->bufs.size;
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000915 }
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000916
917
918 ngx_conf_merge_size_value(conf->busy_buffers_size,
919 prev->busy_buffers_size, NGX_CONF_UNSET_SIZE);
920
921 if (conf->busy_buffers_size == NGX_CONF_UNSET_SIZE) {
922 conf->busy_buffers_size = 2 * size;
923
924 } else if (conf->busy_buffers_size < size) {
925 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
926 "\"proxy_busy_buffers_size\" must be equal or bigger than "
927 "maximum of the value of \"proxy_header_buffer_size\" and "
928 "one of the \"proxy_buffers\"");
929
930 return NGX_CONF_ERROR;
Igor Sysoev9a864bd2004-04-04 20:32:09 +0000931
932 } else if (conf->busy_buffers_size > (conf->bufs.num - 1) * conf->bufs.size)
933 {
934 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
935 "\"proxy_busy_buffers_size\" must be less than "
936 "the size of all \"proxy_buffers\" minus one buffer");
937
938 return NGX_CONF_ERROR;
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000939 }
940
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000941
942 ngx_conf_merge_size_value(conf->temp_file_write_size,
Igor Sysoevdebb39e2004-04-02 05:14:40 +0000943 prev->temp_file_write_size, NGX_CONF_UNSET_SIZE);
944
945 if (conf->temp_file_write_size == NGX_CONF_UNSET_SIZE) {
946 conf->temp_file_write_size = 2 * size;
947
948 } else if (conf->temp_file_write_size < size) {
949 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
950 "\"proxy_temp_file_write_size\" must be equal or bigger than "
951 "maximum of the value of \"proxy_header_buffer_size\" and "
952 "one of the \"proxy_buffers\"");
953
954 return NGX_CONF_ERROR;
955 }
956
957
958 ngx_conf_merge_size_value(conf->max_temp_file_size,
959 prev->max_temp_file_size, NGX_CONF_UNSET_SIZE);
960
961 if (conf->max_temp_file_size == NGX_CONF_UNSET_SIZE) {
962 conf->max_temp_file_size = 2 * size;
963
964 } else if (conf->max_temp_file_size < size) {
965 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
966 "\"proxy_max_temp_file_size\" must be equal or bigger than "
967 "maximum of the value of \"proxy_header_buffer_size\" and "
968 "one of the \"proxy_buffers\"");
969
970 return NGX_CONF_ERROR;
971 }
972
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000973
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000974 ngx_conf_merge_bitmask_value(conf->next_upstream, prev->next_upstream,
Igor Sysoev65977492003-11-02 22:56:18 +0000975 (NGX_CONF_BITMASK_SET
976 |NGX_HTTP_PROXY_FT_ERROR
977 |NGX_HTTP_PROXY_FT_TIMEOUT));
978
979 ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale,
980 NGX_CONF_BITMASK_SET);
981
982 ngx_conf_merge_path_value(conf->cache_path, prev->cache_path,
983 "cache", 1, 2, 0, cf->pool);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000984
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000985 ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
986 "temp", 1, 2, 0, cf->pool);
987
Igor Sysoev65977492003-11-02 22:56:18 +0000988 ngx_conf_merge_value(conf->cache, prev->cache, 0);
989
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000990
991 /* conf->cache must be merged */
992
993 if (conf->busy_lock == NULL) {
994 conf->busy_lock = prev->busy_lock;
995 }
996
Igor Sysoev74e95c22003-11-09 20:03:38 +0000997 if (conf->busy_lock && conf->cache && conf->busy_lock->md5 == NULL) {
Igor Sysoev9cc1ace2003-11-04 22:12:39 +0000998
Igor Sysoev74e95c22003-11-09 20:03:38 +0000999 /* ngx_calloc_shared() */
1000 conf->busy_lock->md5_mask =
1001 ngx_pcalloc(cf->pool, (conf->busy_lock->max_busy + 7) / 8);
1002 if (conf->busy_lock->md5_mask == NULL) {
Igor Sysoeve8732b02003-11-05 17:03:41 +00001003 return NGX_CONF_ERROR;
1004 }
1005
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001006 /* 16 bytes are 128 bits of the md5 */
1007
1008 /* ngx_alloc_shared() */
Igor Sysoev74e95c22003-11-09 20:03:38 +00001009 conf->busy_lock->md5 = ngx_palloc(cf->pool,
1010 16 * conf->busy_lock->max_busy);
1011 if (conf->busy_lock->md5 == NULL) {
Igor Sysoev9cc1ace2003-11-04 22:12:39 +00001012 return NGX_CONF_ERROR;
1013 }
1014 }
1015
1016
Igor Sysoevab0c4f52003-10-28 15:45:41 +00001017 ngx_conf_merge_value(conf->pass_server, prev->pass_server, 0);
Igor Sysoevcf80a702003-11-03 22:20:44 +00001018 ngx_conf_merge_value(conf->pass_x_accel_expires,
1019 prev->pass_x_accel_expires, 0);
1020 ngx_conf_merge_value(conf->ignore_expires, prev->ignore_expires, 0);
1021 ngx_conf_merge_value(conf->lm_factor, prev->lm_factor, 0);
1022 ngx_conf_merge_sec_value(conf->default_expires, prev->default_expires, 0);
Igor Sysoevab0c4f52003-10-28 15:45:41 +00001023
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001024 return NULL;
1025}
1026
1027
1028
Igor Sysoevd404c972003-10-16 20:19:16 +00001029static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
1030 void *conf)
1031{
1032 ngx_http_proxy_loc_conf_t *lcf = conf;
1033
Igor Sysoev10a543a2004-03-16 07:10:12 +00001034 ngx_uint_t i, len;
1035 char *err;
1036 u_char *host;
Igor Sysoeva8fa0a62003-11-25 20:44:56 +00001037 in_addr_t addr;
Igor Sysoevd404c972003-10-16 20:19:16 +00001038 ngx_str_t *value;
1039 struct hostent *h;
Igor Sysoevd404c972003-10-16 20:19:16 +00001040 ngx_http_conf_ctx_t *ctx;
1041 ngx_http_core_loc_conf_t *clcf;
1042
1043
1044 value = cf->args->elts;
1045
1046 if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) {
1047 return "invalid URL prefix";
1048 }
1049
1050 ngx_test_null(lcf->upstream,
Igor Sysoeva1512b12003-11-03 17:33:31 +00001051 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_conf_t)),
Igor Sysoevd404c972003-10-16 20:19:16 +00001052 NGX_CONF_ERROR);
1053
Igor Sysoev65977492003-11-02 22:56:18 +00001054 lcf->upstream->url.len = value[1].len;
1055 if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) {
1056 return NGX_CONF_ERROR;
1057 }
1058 ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1);
1059
Igor Sysoevd404c972003-10-16 20:19:16 +00001060 value[1].data += 7;
1061 value[1].len -= 7;
1062
1063 err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream);
1064
1065 if (err) {
1066 return err;
1067 }
1068
1069 ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream->host.len + 1),
1070 NGX_CONF_ERROR);
1071 ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1);
1072
Igor Sysoeva8fa0a62003-11-25 20:44:56 +00001073 /* AF_INET only */
1074
Igor Sysoev10a543a2004-03-16 07:10:12 +00001075 addr = inet_addr((char *) host);
Igor Sysoevd404c972003-10-16 20:19:16 +00001076
1077 if (addr == INADDR_NONE) {
Igor Sysoev10a543a2004-03-16 07:10:12 +00001078 h = gethostbyname((char *) host);
Igor Sysoevd404c972003-10-16 20:19:16 +00001079
1080 if (h == NULL || h->h_addr_list[0] == NULL) {
1081 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host);
1082 return NGX_CONF_ERROR;
1083 }
1084
1085 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
1086
1087 /* MP: ngx_shared_palloc() */
1088
1089 ngx_test_null(lcf->peers,
1090 ngx_pcalloc(cf->pool,
1091 sizeof(ngx_peers_t)
1092 + sizeof(ngx_peer_t) * (i - 1)),
1093 NGX_CONF_ERROR);
1094
1095 lcf->peers->number = i;
1096
1097 for (i = 0; h->h_addr_list[i] != NULL; i++) {
1098 lcf->peers->peers[i].host.data = host;
1099 lcf->peers->peers[i].host.len = lcf->upstream->host.len;
Igor Sysoeva8fa0a62003-11-25 20:44:56 +00001100 lcf->peers->peers[i].addr = *(in_addr_t *)(h->h_addr_list[i]);
Igor Sysoevd404c972003-10-16 20:19:16 +00001101 lcf->peers->peers[i].port = lcf->upstream->port;
1102
1103 len = INET_ADDRSTRLEN + lcf->upstream->port_text.len + 1;
1104 ngx_test_null(lcf->peers->peers[i].addr_port_text.data,
1105 ngx_palloc(cf->pool, len),
1106 NGX_CONF_ERROR);
1107
1108 len = ngx_inet_ntop(AF_INET,
Igor Sysoev9c610952004-03-16 13:35:20 +00001109 &lcf->peers->peers[i].addr,
Igor Sysoevd404c972003-10-16 20:19:16 +00001110 lcf->peers->peers[i].addr_port_text.data,
1111 len);
1112
1113 lcf->peers->peers[i].addr_port_text.data[len++] = ':';
1114
1115 ngx_cpystrn(lcf->peers->peers[i].addr_port_text.data + len,
1116 lcf->upstream->port_text.data,
1117 lcf->upstream->port_text.len + 1);
1118
1119 lcf->peers->peers[i].addr_port_text.len =
1120 len + lcf->upstream->port_text.len + 1;
1121 }
1122
1123 } else {
1124
1125 /* MP: ngx_shared_palloc() */
1126
1127 ngx_test_null(lcf->peers, ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)),
1128 NGX_CONF_ERROR);
1129
1130 lcf->peers->number = 1;
1131
1132 lcf->peers->peers[0].host.data = host;
1133 lcf->peers->peers[0].host.len = lcf->upstream->host.len;
1134 lcf->peers->peers[0].addr = addr;
1135 lcf->peers->peers[0].port = lcf->upstream->port;
1136
1137 len = lcf->upstream->host.len + lcf->upstream->port_text.len + 1;
1138
1139 ngx_test_null(lcf->peers->peers[0].addr_port_text.data,
1140 ngx_palloc(cf->pool, len + 1),
1141 NGX_CONF_ERROR);
1142
1143 len = lcf->upstream->host.len;
1144
1145 ngx_memcpy(lcf->peers->peers[0].addr_port_text.data,
1146 lcf->upstream->host.data, len);
1147
1148 lcf->peers->peers[0].addr_port_text.data[len++] = ':';
1149
1150 ngx_cpystrn(lcf->peers->peers[0].addr_port_text.data + len,
1151 lcf->upstream->port_text.data,
1152 lcf->upstream->port_text.len + 1);
1153 }
1154
1155 ctx = cf->ctx;
1156 clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
1157 lcf->upstream->location = &clcf->name;
1158 clcf->handler = ngx_http_proxy_handler;
Igor Sysoev160d7742003-11-19 16:26:41 +00001159 if (clcf->name.data[clcf->name.len - 1] == '/') {
1160 clcf->auto_redirect = 1;
1161 }
Igor Sysoevd404c972003-10-16 20:19:16 +00001162
1163 return NULL;
1164}
1165
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001166
Igor Sysoevd404c972003-10-16 20:19:16 +00001167static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
Igor Sysoeva1512b12003-11-03 17:33:31 +00001168 ngx_http_proxy_upstream_conf_t *u)
Igor Sysoevd404c972003-10-16 20:19:16 +00001169{
1170 size_t i;
1171
1172 if (url->data[0] == ':' || url->data[0] == '/') {
1173 return "invalid upstream URL";
1174 }
1175
1176 u->host.data = url->data;
1177 u->host_header.data = url->data;
1178
1179 for (i = 1; i < url->len; i++) {
1180 if (url->data[i] == ':') {
1181 u->port_text.data = &url->data[i] + 1;
1182 u->host.len = i;
1183 }
1184
1185 if (url->data[i] == '/') {
1186 u->uri.data = &url->data[i];
1187 u->uri.len = url->len - i;
1188 u->host_header.len = i;
1189
1190 if (u->host.len == 0) {
1191 u->host.len = i;
1192 }
1193
1194 if (u->port_text.data == NULL) {
Igor Sysoev3646a162004-03-14 20:46:25 +00001195 u->default_port = 1;
Igor Sysoevd404c972003-10-16 20:19:16 +00001196 u->port = htons(80);
1197 u->port_text.len = 2;
Igor Sysoevda85f7f2004-03-16 21:26:01 +00001198 u->port_text.data = (u_char *) "80";
Igor Sysoevd404c972003-10-16 20:19:16 +00001199 return NULL;
1200 }
1201
1202 u->port_text.len = &url->data[i] - u->port_text.data;
1203
1204 if (u->port_text.len > 0) {
1205 u->port = ngx_atoi(u->port_text.data, u->port_text.len);
1206 if (u->port > 0) {
Igor Sysoev11688f82004-05-10 19:53:35 +00001207
1208 if (u->port == 80) {
1209 u->default_port = 1;
1210 }
1211
Igor Sysoevd404c972003-10-16 20:19:16 +00001212 u->port = htons((u_short) u->port);
1213 return NULL;
1214 }
1215 }
1216
1217 return "invalid port in upstream URL";
1218 }
1219 }
1220
1221 if (u->host.len == 0) {
1222 u->host.len = i;
1223 }
1224
1225 u->host_header.len = i;
1226
Igor Sysoevda85f7f2004-03-16 21:26:01 +00001227 u->uri.data = (u_char *) "/";
Igor Sysoevd404c972003-10-16 20:19:16 +00001228 u->uri.len = 1;
1229
1230 if (u->port_text.data == NULL) {
Igor Sysoev3646a162004-03-14 20:46:25 +00001231 u->default_port = 1;
Igor Sysoevd404c972003-10-16 20:19:16 +00001232 u->port = htons(80);
1233 u->port_text.len = 2;
Igor Sysoevda85f7f2004-03-16 21:26:01 +00001234 u->port_text.data = (u_char *) "80";
Igor Sysoevd404c972003-10-16 20:19:16 +00001235 return NULL;
1236 }
1237
1238 u->port_text.len = &url->data[i] - u->port_text.data;
1239
1240 if (u->port_text.len > 0) {
1241 u->port = ngx_atoi(u->port_text.data, u->port_text.len);
1242 if (u->port > 0) {
1243 u->port = htons((u_short) u->port);
1244 return NULL;
1245 }
1246 }
1247
1248 return "invalid port in upstream URL";
1249}