Mercurial > hg > nginx
annotate src/http/modules/ngx_http_proxy_module.c @ 896:f247db60fc85
fix fastcgi and memcached upstreams
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Mon, 11 Dec 2006 08:59:30 +0000 |
parents | 4d68c486fcb0 |
children | a0310ac2814f |
rev | line source |
---|---|
507 | 1 |
577 | 2 /* |
507 | 3 * Copyright (C) Igor Sysoev |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
509 | 13 typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t; |
14 | |
15 typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r, | |
16 ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); | |
507 | 17 |
509 | 18 struct ngx_http_proxy_redirect_s { |
651 | 19 ngx_http_proxy_redirect_pt handler; |
20 ngx_str_t redirect; | |
507 | 21 |
509 | 22 union { |
651 | 23 ngx_str_t text; |
509 | 24 |
25 struct { | |
651 | 26 void *lengths; |
27 void *values; | |
509 | 28 } vars; |
507 | 29 |
651 | 30 void *regex; |
509 | 31 } replacement; |
32 }; | |
33 | |
34 | |
35 typedef struct { | |
651 | 36 ngx_http_upstream_conf_t upstream; |
37 | |
38 ngx_array_t *flushes; | |
39 ngx_array_t *body_set_len; | |
40 ngx_array_t *body_set; | |
41 ngx_array_t *headers_set_len; | |
42 ngx_array_t *headers_set; | |
43 ngx_hash_t headers_set_hash; | |
44 | |
45 ngx_array_t *headers_source; | |
46 ngx_array_t *headers_names; | |
47 | |
48 ngx_array_t *redirects; | |
49 | |
50 ngx_str_t body_source; | |
51 | |
52 ngx_str_t method; | |
53 ngx_str_t host_header; | |
54 ngx_str_t port_text; | |
55 | |
56 ngx_flag_t redirect; | |
507 | 57 } ngx_http_proxy_loc_conf_t; |
58 | |
59 | |
60 typedef struct { | |
651 | 61 ngx_uint_t status; |
62 ngx_uint_t status_count; | |
63 u_char *status_start; | |
64 u_char *status_end; | |
65 | |
66 size_t internal_body_length; | |
509 | 67 } ngx_http_proxy_ctx_t; |
507 | 68 |
69 | |
509 | 70 #define NGX_HTTP_PROXY_PARSE_NO_HEADER 20 |
507 | 71 |
72 | |
73 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); | |
74 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); | |
509 | 75 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); |
76 static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r, | |
77 ngx_http_proxy_ctx_t *p); | |
507 | 78 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); |
79 static void ngx_http_proxy_abort_request(ngx_http_request_t *r); | |
80 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, | |
81 ngx_int_t rc); | |
82 | |
573 | 83 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r, |
84 ngx_http_variable_value_t *v, uintptr_t data); | |
85 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r, | |
86 ngx_http_variable_value_t *v, uintptr_t data); | |
87 static ngx_int_t | |
509 | 88 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, |
573 | 89 ngx_http_variable_value_t *v, uintptr_t data); |
577 | 90 static ngx_int_t |
91 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, | |
92 ngx_http_variable_value_t *v, uintptr_t data); | |
509 | 93 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, |
94 ngx_table_elt_t *h, size_t prefix); | |
507 | 95 |
509 | 96 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); |
507 | 97 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); |
98 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, | |
99 void *parent, void *child); | |
100 | |
101 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
102 void *conf); | |
509 | 103 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, |
104 void *conf); | |
507 | 105 |
106 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); | |
107 | |
884 | 108 static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf, |
109 ngx_command_t *cmd, void *conf); | |
110 static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf, | |
111 ngx_command_t *cmd, void *conf); | |
112 | |
509 | 113 |
507 | 114 static ngx_conf_post_t ngx_http_proxy_lowat_post = |
509 | 115 { ngx_http_proxy_lowat_check }; |
116 | |
581 | 117 static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_header_buffer_size = { |
118 ngx_conf_deprecated, "proxy_header_buffer_size", "proxy_buffer_size" | |
119 }; | |
120 | |
657 | 121 static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_redirect_errors = { |
122 ngx_conf_deprecated, "proxy_redirect_errors", "proxy_intercept_errors" | |
123 }; | |
124 | |
507 | 125 |
126 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { | |
127 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, | |
128 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, | |
129 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, | |
130 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, | |
623 | 131 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, |
507 | 132 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, |
665 | 133 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, |
507 | 134 { ngx_null_string, 0 } |
135 }; | |
136 | |
137 | |
138 static ngx_command_t ngx_http_proxy_commands[] = { | |
139 | |
140 { ngx_string("proxy_pass"), | |
843
ebab9490204c
allow proxy_pass inside limit_except
Igor Sysoev <igor@sysoev.ru>
parents:
812
diff
changeset
|
141 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1, |
507 | 142 ngx_http_proxy_pass, |
143 NGX_HTTP_LOC_CONF_OFFSET, | |
144 0, | |
145 NULL }, | |
146 | |
509 | 147 { ngx_string("proxy_redirect"), |
148 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | |
149 ngx_http_proxy_redirect, | |
150 NGX_HTTP_LOC_CONF_OFFSET, | |
151 0, | |
152 NULL }, | |
153 | |
581 | 154 { ngx_string("proxy_buffering"), |
155 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
156 ngx_conf_set_flag_slot, | |
157 NGX_HTTP_LOC_CONF_OFFSET, | |
158 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering), | |
159 NULL }, | |
160 | |
629 | 161 { ngx_string("proxy_ignore_client_abort"), |
162 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
163 ngx_conf_set_flag_slot, | |
164 NGX_HTTP_LOC_CONF_OFFSET, | |
165 offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort), | |
166 NULL }, | |
167 | |
507 | 168 { ngx_string("proxy_connect_timeout"), |
169 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
170 ngx_conf_set_msec_slot, | |
171 NGX_HTTP_LOC_CONF_OFFSET, | |
172 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout), | |
173 NULL }, | |
174 | |
175 { ngx_string("proxy_send_timeout"), | |
176 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
177 ngx_conf_set_msec_slot, | |
178 NGX_HTTP_LOC_CONF_OFFSET, | |
179 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout), | |
180 NULL }, | |
181 | |
182 { ngx_string("proxy_send_lowat"), | |
183 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
184 ngx_conf_set_size_slot, | |
185 NGX_HTTP_LOC_CONF_OFFSET, | |
186 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), | |
187 &ngx_http_proxy_lowat_post }, | |
188 | |
657 | 189 { ngx_string("proxy_intercept_errors"), |
190 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
191 ngx_conf_set_flag_slot, | |
192 NGX_HTTP_LOC_CONF_OFFSET, | |
193 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), | |
194 NULL }, | |
195 | |
509 | 196 { ngx_string("proxy_redirect_errors"), |
197 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
198 ngx_conf_set_flag_slot, | |
199 NGX_HTTP_LOC_CONF_OFFSET, | |
657 | 200 offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), |
201 &ngx_conf_deprecated_proxy_redirect_errors }, | |
509 | 202 |
203 { ngx_string("proxy_set_header"), | |
204 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
649 | 205 ngx_conf_set_keyval_slot, |
507 | 206 NGX_HTTP_LOC_CONF_OFFSET, |
509 | 207 offsetof(ngx_http_proxy_loc_conf_t, headers_source), |
507 | 208 NULL }, |
209 | |
577 | 210 { ngx_string("proxy_set_body"), |
211 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
212 ngx_conf_set_str_slot, | |
213 NGX_HTTP_LOC_CONF_OFFSET, | |
214 offsetof(ngx_http_proxy_loc_conf_t, body_source), | |
215 NULL }, | |
216 | |
509 | 217 { ngx_string("proxy_method"), |
218 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
561 | 219 ngx_conf_set_str_slot, |
509 | 220 NGX_HTTP_LOC_CONF_OFFSET, |
561 | 221 offsetof(ngx_http_proxy_loc_conf_t, method), |
222 NULL }, | |
509 | 223 |
224 { ngx_string("proxy_pass_request_headers"), | |
507 | 225 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
226 ngx_conf_set_flag_slot, | |
227 NGX_HTTP_LOC_CONF_OFFSET, | |
509 | 228 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers), |
507 | 229 NULL }, |
230 | |
509 | 231 { ngx_string("proxy_pass_request_body"), |
507 | 232 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
233 ngx_conf_set_flag_slot, | |
234 NGX_HTTP_LOC_CONF_OFFSET, | |
509 | 235 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), |
507 | 236 NULL }, |
237 | |
581 | 238 { ngx_string("proxy_buffer_size"), |
239 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
240 ngx_conf_set_size_slot, | |
241 NGX_HTTP_LOC_CONF_OFFSET, | |
242 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), | |
243 NULL }, | |
244 | |
507 | 245 { ngx_string("proxy_header_buffer_size"), |
246 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
247 ngx_conf_set_size_slot, | |
248 NGX_HTTP_LOC_CONF_OFFSET, | |
581 | 249 offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size), |
250 &ngx_conf_deprecated_proxy_header_buffer_size }, | |
507 | 251 |
252 { ngx_string("proxy_read_timeout"), | |
253 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
254 ngx_conf_set_msec_slot, | |
255 NGX_HTTP_LOC_CONF_OFFSET, | |
256 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout), | |
257 NULL }, | |
258 | |
259 { ngx_string("proxy_buffers"), | |
260 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
261 ngx_conf_set_bufs_slot, | |
262 NGX_HTTP_LOC_CONF_OFFSET, | |
263 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs), | |
264 NULL }, | |
265 | |
266 { ngx_string("proxy_busy_buffers_size"), | |
267 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
268 ngx_conf_set_size_slot, | |
269 NGX_HTTP_LOC_CONF_OFFSET, | |
529 | 270 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf), |
507 | 271 NULL }, |
272 | |
273 { ngx_string("proxy_temp_path"), | |
274 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, | |
275 ngx_conf_set_path_slot, | |
276 NGX_HTTP_LOC_CONF_OFFSET, | |
277 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), | |
278 (void *) ngx_garbage_collector_temp_handler }, | |
279 | |
280 { ngx_string("proxy_max_temp_file_size"), | |
281 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
282 ngx_conf_set_size_slot, | |
283 NGX_HTTP_LOC_CONF_OFFSET, | |
529 | 284 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf), |
507 | 285 NULL }, |
286 | |
287 { ngx_string("proxy_temp_file_write_size"), | |
288 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
289 ngx_conf_set_size_slot, | |
290 NGX_HTTP_LOC_CONF_OFFSET, | |
529 | 291 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf), |
507 | 292 NULL }, |
293 | |
294 { ngx_string("proxy_next_upstream"), | |
547 | 295 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, |
507 | 296 ngx_conf_set_bitmask_slot, |
297 NGX_HTTP_LOC_CONF_OFFSET, | |
298 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), | |
299 &ngx_http_proxy_next_upstream_masks }, | |
300 | |
561 | 301 { ngx_string("proxy_upstream_max_fails"), |
302 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
884 | 303 ngx_http_proxy_upstream_max_fails_unsupported, |
304 0, | |
305 0, | |
561 | 306 NULL }, |
307 | |
308 { ngx_string("proxy_upstream_fail_timeout"), | |
309 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
884 | 310 ngx_http_proxy_upstream_fail_timeout_unsupported, |
311 0, | |
312 0, | |
561 | 313 NULL }, |
314 | |
649 | 315 { ngx_string("proxy_pass_header"), |
507 | 316 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
649 | 317 ngx_conf_set_str_array_slot, |
507 | 318 NGX_HTTP_LOC_CONF_OFFSET, |
649 | 319 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers), |
507 | 320 NULL }, |
321 | |
649 | 322 { ngx_string("proxy_hide_header"), |
507 | 323 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, |
649 | 324 ngx_conf_set_str_array_slot, |
507 | 325 NGX_HTTP_LOC_CONF_OFFSET, |
649 | 326 offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers), |
507 | 327 NULL }, |
328 | |
329 ngx_null_command | |
330 }; | |
331 | |
332 | |
667 | 333 static ngx_http_module_t ngx_http_proxy_module_ctx = { |
509 | 334 ngx_http_proxy_add_variables, /* preconfiguration */ |
335 NULL, /* postconfiguration */ | |
507 | 336 |
337 NULL, /* create main configuration */ | |
338 NULL, /* init main configuration */ | |
339 | |
340 NULL, /* create server configuration */ | |
341 NULL, /* merge server configuration */ | |
342 | |
343 ngx_http_proxy_create_loc_conf, /* create location configration */ | |
344 ngx_http_proxy_merge_loc_conf /* merge location configration */ | |
345 }; | |
346 | |
347 | |
348 ngx_module_t ngx_http_proxy_module = { | |
509 | 349 NGX_MODULE_V1, |
507 | 350 &ngx_http_proxy_module_ctx, /* module context */ |
351 ngx_http_proxy_commands, /* module directives */ | |
352 NGX_HTTP_MODULE, /* module type */ | |
541 | 353 NULL, /* init master */ |
509 | 354 NULL, /* init module */ |
541 | 355 NULL, /* init process */ |
356 NULL, /* init thread */ | |
357 NULL, /* exit thread */ | |
358 NULL, /* exit process */ | |
359 NULL, /* exit master */ | |
360 NGX_MODULE_V1_PADDING | |
507 | 361 }; |
362 | |
363 | |
364 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; | |
365 | |
509 | 366 |
649 | 367 static ngx_keyval_t ngx_http_proxy_headers[] = { |
368 { ngx_string("Host"), ngx_string("$proxy_host") }, | |
369 { ngx_string("Connection"), ngx_string("close") }, | |
370 { ngx_string("Keep-Alive"), ngx_string("") }, | |
371 { ngx_null_string, ngx_null_string } | |
372 }; | |
373 | |
374 | |
375 static ngx_str_t ngx_http_proxy_hide_headers[] = { | |
376 ngx_string("Date"), | |
377 ngx_string("Server"), | |
378 ngx_string("X-Pad"), | |
379 ngx_string("X-Accel-Expires"), | |
380 ngx_string("X-Accel-Redirect"), | |
381 ngx_string("X-Accel-Limit-Rate"), | |
382 ngx_string("X-Accel-Buffer"), | |
383 ngx_null_string | |
509 | 384 }; |
385 | |
386 | |
387 static ngx_http_variable_t ngx_http_proxy_vars[] = { | |
388 | |
637 | 389 { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, |
583 | 390 NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, |
509 | 391 |
637 | 392 { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0, |
583 | 393 NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, |
509 | 394 |
637 | 395 { ngx_string("proxy_add_x_forwarded_for"), NULL, |
583 | 396 ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, |
509 | 397 |
398 #if 0 | |
637 | 399 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, |
509 | 400 #endif |
401 | |
637 | 402 { ngx_string("proxy_internal_body_length"), NULL, |
583 | 403 ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, |
577 | 404 |
637 | 405 { ngx_null_string, NULL, NULL, 0, 0, 0 } |
509 | 406 }; |
507 | 407 |
408 | |
409 static ngx_int_t | |
410 ngx_http_proxy_handler(ngx_http_request_t *r) | |
577 | 411 { |
507 | 412 ngx_int_t rc; |
413 ngx_http_upstream_t *u; | |
414 ngx_http_proxy_loc_conf_t *plcf; | |
577 | 415 |
507 | 416 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); |
577 | 417 |
507 | 418 u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); |
419 if (u == NULL) { | |
420 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
421 } | |
577 | 422 |
507 | 423 u->peer.log = r->connection->log; |
424 u->peer.log_error = NGX_ERROR_ERR; | |
425 #if (NGX_THREADS) | |
426 u->peer.lock = &r->connection->lock; | |
427 #endif | |
428 | |
429 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; | |
430 | |
431 u->conf = &plcf->upstream; | |
432 | |
433 u->create_request = ngx_http_proxy_create_request; | |
434 u->reinit_request = ngx_http_proxy_reinit_request; | |
509 | 435 u->process_header = ngx_http_proxy_process_status_line; |
507 | 436 u->abort_request = ngx_http_proxy_abort_request; |
437 u->finalize_request = ngx_http_proxy_finalize_request; | |
438 | |
509 | 439 if (plcf->redirects) { |
440 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; | |
441 } | |
442 | |
649 | 443 u->buffering = plcf->upstream.buffering; |
444 | |
445 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); | |
446 if (u->pipe == NULL) { | |
447 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
581 | 448 } |
507 | 449 |
649 | 450 u->pipe->input_filter = ngx_event_pipe_copy_input_filter; |
451 | |
509 | 452 u->accel = 1; |
577 | 453 |
507 | 454 r->upstream = u; |
455 | |
456 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); | |
457 | |
458 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | |
459 return rc; | |
460 } | |
461 | |
462 return NGX_DONE; | |
463 } | |
464 | |
465 | |
466 static ngx_int_t | |
467 ngx_http_proxy_create_request(ngx_http_request_t *r) | |
468 { | |
577 | 469 size_t len, loc_len, body_len; |
509 | 470 uintptr_t escape; |
471 ngx_buf_t *b; | |
649 | 472 ngx_str_t method; |
473 ngx_uint_t i, unparsed_uri; | |
509 | 474 ngx_chain_t *cl, *body; |
475 ngx_list_part_t *part; | |
476 ngx_table_elt_t *header; | |
477 ngx_http_upstream_t *u; | |
577 | 478 ngx_http_proxy_ctx_t *p; |
509 | 479 ngx_http_script_code_pt code; |
480 ngx_http_script_engine_t e, le; | |
481 ngx_http_proxy_loc_conf_t *plcf; | |
482 ngx_http_script_len_code_pt lcode; | |
507 | 483 |
484 u = r->upstream; | |
485 | |
486 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
487 | |
577 | 488 p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); |
489 if (p == NULL) { | |
490 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
491 } | |
492 | |
493 ngx_http_set_ctx(r, p, ngx_http_proxy_module); | |
494 | |
507 | 495 len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; |
496 | |
561 | 497 if (u->method.len) { |
498 /* HEAD was changed to GET to cache response */ | |
499 method = u->method; | |
500 method.len++; | |
501 | |
502 } else if (plcf->method.len) { | |
503 method = plcf->method; | |
504 | |
507 | 505 } else { |
561 | 506 method = r->method_name; |
507 method.len++; | |
507 | 508 } |
509 | |
561 | 510 len += method.len + u->conf->uri.len; |
511 | |
507 | 512 escape = 0; |
509 | 513 |
627 | 514 loc_len = (r->valid_location && u->conf->uri.len) ? u->conf->location.len: |
515 0; | |
509 | 516 |
609 | 517 if (u->conf->uri.len == 0 && r->valid_unparsed_uri && r == r->main) { |
518 unparsed_uri = 1; | |
539 | 519 len += r->unparsed_uri.len; |
507 | 520 |
521 } else { | |
609 | 522 unparsed_uri = 0; |
507 | 523 if (r->quoted_uri) { |
509 | 524 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, |
525 r->uri.len - loc_len, NGX_ESCAPE_URI); | |
507 | 526 } |
527 | |
509 | 528 len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; |
507 | 529 } |
530 | |
573 | 531 ngx_http_script_flush_no_cachable_variables(r, plcf->flushes); |
532 | |
577 | 533 if (plcf->body_set_len) { |
534 le.ip = plcf->body_set_len->elts; | |
535 le.request = r; | |
536 le.flushed = 1; | |
537 body_len = 0; | |
538 | |
539 while (*(uintptr_t *) le.ip) { | |
540 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
541 body_len += lcode(&le); | |
542 } | |
543 | |
544 p->internal_body_length = body_len; | |
545 len += body_len; | |
546 } | |
547 | |
509 | 548 le.ip = plcf->headers_set_len->elts; |
549 le.request = r; | |
573 | 550 le.flushed = 1; |
507 | 551 |
509 | 552 while (*(uintptr_t *) le.ip) { |
553 while (*(uintptr_t *) le.ip) { | |
554 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
555 len += lcode(&le); | |
556 } | |
557 le.ip += sizeof(uintptr_t); | |
507 | 558 } |
559 | |
560 | |
509 | 561 if (plcf->upstream.pass_request_headers) { |
562 part = &r->headers_in.headers.part; | |
563 header = part->elts; | |
564 | |
565 for (i = 0; /* void */; i++) { | |
507 | 566 |
509 | 567 if (i >= part->nelts) { |
568 if (part->next == NULL) { | |
569 break; | |
570 } | |
571 | |
572 part = part->next; | |
573 header = part->elts; | |
577 | 574 i = 0; |
507 | 575 } |
576 | |
649 | 577 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash, |
578 header[i].lowcase_key, header[i].key.len)) | |
509 | 579 { |
580 continue; | |
581 } | |
582 | |
583 len += header[i].key.len + sizeof(": ") - 1 | |
584 + header[i].value.len + sizeof(CRLF) - 1; | |
507 | 585 } |
509 | 586 } |
507 | 587 |
588 | |
589 b = ngx_create_temp_buf(r->pool, len); | |
590 if (b == NULL) { | |
591 return NGX_ERROR; | |
592 } | |
593 | |
594 cl = ngx_alloc_chain_link(r->pool); | |
595 if (cl == NULL) { | |
596 return NGX_ERROR; | |
597 } | |
598 | |
599 cl->buf = b; | |
600 | |
601 | |
602 /* the request line */ | |
603 | |
573 | 604 b->last = ngx_copy(b->last, method.data, method.len); |
507 | 605 |
555 | 606 u->uri.data = b->last; |
607 | |
609 | 608 if (unparsed_uri) { |
573 | 609 b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len); |
610 | |
507 | 611 } else { |
555 | 612 if (r->valid_location) { |
573 | 613 b->last = ngx_copy(b->last, u->conf->uri.data, u->conf->uri.len); |
555 | 614 } |
551 | 615 |
507 | 616 if (escape) { |
509 | 617 ngx_escape_uri(b->last, r->uri.data + loc_len, |
618 r->uri.len - loc_len, NGX_ESCAPE_URI); | |
619 b->last += r->uri.len - loc_len + escape; | |
507 | 620 |
577 | 621 } else { |
573 | 622 b->last = ngx_copy(b->last, r->uri.data + loc_len, |
623 r->uri.len - loc_len); | |
507 | 624 } |
625 | |
626 if (r->args.len > 0) { | |
627 *b->last++ = '?'; | |
573 | 628 b->last = ngx_copy(b->last, r->args.data, r->args.len); |
507 | 629 } |
630 } | |
631 | |
555 | 632 u->uri.len = b->last - u->uri.data; |
633 | |
507 | 634 b->last = ngx_cpymem(b->last, ngx_http_proxy_version, |
635 sizeof(ngx_http_proxy_version) - 1); | |
636 | |
577 | 637 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); |
507 | 638 |
639 e.ip = plcf->headers_set->elts; | |
640 e.pos = b->last; | |
509 | 641 e.request = r; |
573 | 642 e.flushed = 1; |
507 | 643 |
509 | 644 le.ip = plcf->headers_set_len->elts; |
645 | |
646 while (*(uintptr_t *) le.ip) { | |
647 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
515 | 648 |
649 /* skip the header line name length */ | |
650 (void) lcode(&le); | |
509 | 651 |
652 if (*(ngx_http_script_len_code_pt *) le.ip) { | |
653 | |
654 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { | |
655 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
656 } | |
657 | |
658 e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0; | |
659 | |
660 } else { | |
661 e.skip = 0; | |
662 } | |
663 | |
664 le.ip += sizeof(uintptr_t); | |
665 | |
666 while (*(uintptr_t *) e.ip) { | |
667 code = *(ngx_http_script_code_pt *) e.ip; | |
668 code((ngx_http_script_engine_t *) &e); | |
577 | 669 } |
509 | 670 e.ip += sizeof(uintptr_t); |
507 | 671 } |
672 | |
673 b->last = e.pos; | |
674 | |
675 | |
509 | 676 if (plcf->upstream.pass_request_headers) { |
677 part = &r->headers_in.headers.part; | |
678 header = part->elts; | |
577 | 679 |
509 | 680 for (i = 0; /* void */; i++) { |
507 | 681 |
509 | 682 if (i >= part->nelts) { |
683 if (part->next == NULL) { | |
684 break; | |
685 } | |
686 | |
687 part = part->next; | |
688 header = part->elts; | |
577 | 689 i = 0; |
507 | 690 } |
691 | |
649 | 692 if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash, |
693 header[i].lowcase_key, header[i].key.len)) | |
509 | 694 { |
695 continue; | |
696 } | |
507 | 697 |
573 | 698 b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); |
507 | 699 |
509 | 700 *b->last++ = ':'; *b->last++ = ' '; |
507 | 701 |
573 | 702 b->last = ngx_copy(b->last, header[i].value.data, |
703 header[i].value.len); | |
507 | 704 |
509 | 705 *b->last++ = CR; *b->last++ = LF; |
507 | 706 |
509 | 707 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
708 "http proxy header: \"%V: %V\"", | |
709 &header[i].key, &header[i].value); | |
710 } | |
507 | 711 } |
712 | |
577 | 713 |
507 | 714 /* add "\r\n" at the header end */ |
715 *b->last++ = CR; *b->last++ = LF; | |
716 | |
577 | 717 if (plcf->body_set) { |
718 e.ip = plcf->body_set->elts; | |
719 e.pos = b->last; | |
720 | |
721 while (*(uintptr_t *) e.ip) { | |
722 code = *(ngx_http_script_code_pt *) e.ip; | |
723 code((ngx_http_script_engine_t *) &e); | |
724 } | |
579 | 725 |
726 b->last = e.pos; | |
577 | 727 } |
728 | |
507 | 729 #if (NGX_DEBUG) |
730 { | |
731 ngx_str_t s; | |
732 | |
733 s.len = b->last - b->pos; | |
734 s.data = b->pos; | |
735 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
736 "http proxy header:\n\"%V\"", &s); | |
737 } | |
738 #endif | |
739 | |
577 | 740 if (plcf->body_set == NULL && plcf->upstream.pass_request_body) { |
509 | 741 |
742 body = u->request_bufs; | |
743 u->request_bufs = cl; | |
744 | |
745 while (body) { | |
746 b = ngx_alloc_buf(r->pool); | |
747 if (b == NULL) { | |
748 return NGX_ERROR; | |
749 } | |
750 | |
751 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); | |
752 | |
753 cl->next = ngx_alloc_chain_link(r->pool); | |
754 if (cl->next == NULL) { | |
755 return NGX_ERROR; | |
756 } | |
757 | |
758 cl = cl->next; | |
759 cl->buf = b; | |
760 | |
761 body = body->next; | |
762 } | |
763 | |
611 | 764 b->flush = 1; |
765 | |
509 | 766 } else { |
767 u->request_bufs = cl; | |
768 } | |
769 | |
770 cl->next = NULL; | |
771 | |
507 | 772 return NGX_OK; |
773 } | |
774 | |
775 | |
776 static ngx_int_t | |
777 ngx_http_proxy_reinit_request(ngx_http_request_t *r) | |
778 { | |
509 | 779 ngx_http_proxy_ctx_t *p; |
780 | |
781 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
782 | |
783 if (p == NULL) { | |
784 return NGX_OK; | |
785 } | |
786 | |
787 p->status = 0; | |
788 p->status_count = 0; | |
789 p->status_start = NULL; | |
790 p->status_end = NULL; | |
791 | |
792 r->upstream->process_header = ngx_http_proxy_process_status_line; | |
793 | |
794 return NGX_OK; | |
795 } | |
796 | |
797 | |
798 static ngx_int_t | |
799 ngx_http_proxy_process_status_line(ngx_http_request_t *r) | |
800 { | |
801 ngx_int_t rc; | |
802 ngx_http_upstream_t *u; | |
803 ngx_http_proxy_ctx_t *p; | |
804 | |
805 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
806 | |
807 if (p == NULL) { | |
577 | 808 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
509 | 809 } |
810 | |
811 rc = ngx_http_proxy_parse_status_line(r, p); | |
812 | |
813 if (rc == NGX_AGAIN) { | |
814 return rc; | |
815 } | |
816 | |
817 u = r->upstream; | |
818 | |
819 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { | |
820 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
577 | 821 "upstream sent no valid HTTP/1.0 header"); |
509 | 822 |
619 | 823 #if 0 |
509 | 824 if (u->accel) { |
825 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
826 } | |
619 | 827 #endif |
509 | 828 |
829 r->http_version = NGX_HTTP_VERSION_9; | |
830 p->status = NGX_HTTP_OK; | |
577 | 831 |
509 | 832 return NGX_OK; |
833 } | |
834 | |
529 | 835 u->headers_in.status_n = p->status; |
509 | 836 u->state->status = p->status; |
837 | |
529 | 838 u->headers_in.status_line.len = p->status_end - p->status_start; |
839 u->headers_in.status_line.data = ngx_palloc(r->pool, | |
840 u->headers_in.status_line.len); | |
841 if (u->headers_in.status_line.data == NULL) { | |
509 | 842 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
843 } | |
573 | 844 |
529 | 845 ngx_memcpy(u->headers_in.status_line.data, p->status_start, |
846 u->headers_in.status_line.len); | |
509 | 847 |
848 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
849 "http proxy status %ui \"%V\"", | |
529 | 850 u->headers_in.status, &u->headers_in.status_line); |
509 | 851 |
852 u->process_header = ngx_http_proxy_process_header; | |
853 | |
854 return ngx_http_proxy_process_header(r); | |
855 } | |
856 | |
857 | |
858 static ngx_int_t | |
859 ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) | |
860 { | |
861 u_char ch; | |
862 u_char *pos; | |
863 ngx_http_upstream_t *u; | |
864 enum { | |
865 sw_start = 0, | |
866 sw_H, | |
867 sw_HT, | |
868 sw_HTT, | |
869 sw_HTTP, | |
870 sw_first_major_digit, | |
871 sw_major_digit, | |
872 sw_first_minor_digit, | |
873 sw_minor_digit, | |
874 sw_status, | |
875 sw_space_after_status, | |
876 sw_status_text, | |
877 sw_almost_done | |
577 | 878 } state; |
509 | 879 |
880 u = r->upstream; | |
881 | |
882 state = r->state; | |
883 | |
581 | 884 for (pos = u->buffer.pos; pos < u->buffer.last; pos++) { |
509 | 885 ch = *pos; |
886 | |
887 switch (state) { | |
888 | |
889 /* "HTTP/" */ | |
890 case sw_start: | |
891 switch (ch) { | |
577 | 892 case 'H': |
509 | 893 state = sw_H; |
894 break; | |
895 default: | |
896 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
897 } | |
898 break; | |
899 | |
577 | 900 case sw_H: |
509 | 901 switch (ch) { |
577 | 902 case 'T': |
509 | 903 state = sw_HT; |
904 break; | |
905 default: | |
906 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
907 } | |
908 break; | |
909 | |
910 case sw_HT: | |
911 switch (ch) { | |
577 | 912 case 'T': |
509 | 913 state = sw_HTT; |
914 break; | |
915 default: | |
916 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
917 } | |
918 break; | |
919 | |
920 case sw_HTT: | |
921 switch (ch) { | |
577 | 922 case 'P': |
509 | 923 state = sw_HTTP; |
924 break; | |
925 default: | |
926 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
927 } | |
928 break; | |
929 | |
930 case sw_HTTP: | |
931 switch (ch) { | |
577 | 932 case '/': |
509 | 933 state = sw_first_major_digit; |
934 break; | |
935 default: | |
936 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
937 } | |
938 break; | |
939 | |
940 /* the first digit of major HTTP version */ | |
941 case sw_first_major_digit: | |
942 if (ch < '1' || ch > '9') { | |
943 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
944 } | |
945 | |
946 state = sw_major_digit; | |
947 break; | |
948 | |
949 /* the major HTTP version or dot */ | |
950 case sw_major_digit: | |
951 if (ch == '.') { | |
952 state = sw_first_minor_digit; | |
953 break; | |
954 } | |
955 | |
956 if (ch < '0' || ch > '9') { | |
957 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
958 } | |
959 | |
960 break; | |
961 | |
962 /* the first digit of minor HTTP version */ | |
963 case sw_first_minor_digit: | |
964 if (ch < '0' || ch > '9') { | |
965 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
966 } | |
967 | |
968 state = sw_minor_digit; | |
969 break; | |
970 | |
971 /* the minor HTTP version or the end of the request line */ | |
972 case sw_minor_digit: | |
973 if (ch == ' ') { | |
974 state = sw_status; | |
975 break; | |
976 } | |
977 | |
978 if (ch < '0' || ch > '9') { | |
979 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
980 } | |
981 | |
982 break; | |
983 | |
984 /* HTTP status code */ | |
985 case sw_status: | |
619 | 986 if (ch == ' ') { |
987 break; | |
988 } | |
989 | |
509 | 990 if (ch < '0' || ch > '9') { |
991 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
992 } | |
993 | |
994 p->status = p->status * 10 + ch - '0'; | |
995 | |
996 if (++p->status_count == 3) { | |
997 state = sw_space_after_status; | |
998 p->status_start = pos - 2; | |
999 } | |
1000 | |
1001 break; | |
1002 | |
1003 /* space or end of line */ | |
1004 case sw_space_after_status: | |
1005 switch (ch) { | |
577 | 1006 case ' ': |
509 | 1007 state = sw_status_text; |
1008 break; | |
1009 case '.': /* IIS may send 403.1, 403.2, etc */ | |
1010 state = sw_status_text; | |
1011 break; | |
1012 case CR: | |
1013 state = sw_almost_done; | |
1014 break; | |
1015 case LF: | |
1016 goto done; | |
1017 default: | |
1018 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1019 } | |
1020 break; | |
1021 | |
1022 /* any text until end of line */ | |
1023 case sw_status_text: | |
1024 switch (ch) { | |
1025 case CR: | |
1026 state = sw_almost_done; | |
1027 | |
1028 break; | |
1029 case LF: | |
1030 goto done; | |
1031 } | |
1032 break; | |
1033 | |
527 | 1034 /* end of status line */ |
509 | 1035 case sw_almost_done: |
1036 p->status_end = pos - 1; | |
1037 switch (ch) { | |
1038 case LF: | |
1039 goto done; | |
1040 default: | |
1041 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1042 } | |
1043 } | |
1044 } | |
1045 | |
581 | 1046 u->buffer.pos = pos; |
509 | 1047 r->state = state; |
1048 | |
1049 return NGX_AGAIN; | |
1050 | |
1051 done: | |
1052 | |
581 | 1053 u->buffer.pos = pos + 1; |
509 | 1054 |
1055 if (p->status_end == NULL) { | |
1056 p->status_end = pos; | |
1057 } | |
1058 | |
1059 r->state = sw_start; | |
1060 | |
507 | 1061 return NGX_OK; |
1062 } | |
1063 | |
1064 | |
1065 static ngx_int_t | |
1066 ngx_http_proxy_process_header(ngx_http_request_t *r) | |
1067 { | |
509 | 1068 ngx_int_t rc; |
649 | 1069 ngx_uint_t i; |
509 | 1070 ngx_table_elt_t *h; |
1071 ngx_http_upstream_header_t *hh; | |
1072 ngx_http_upstream_main_conf_t *umcf; | |
1073 | |
1074 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); | |
1075 | |
1076 for ( ;; ) { | |
1077 | |
581 | 1078 rc = ngx_http_parse_header_line(r, &r->upstream->buffer); |
509 | 1079 |
1080 if (rc == NGX_OK) { | |
1081 | |
1082 /* a header line has been parsed successfully */ | |
507 | 1083 |
509 | 1084 h = ngx_list_push(&r->upstream->headers_in.headers); |
1085 if (h == NULL) { | |
1086 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1087 } | |
1088 | |
1089 h->hash = r->header_hash; | |
1090 | |
1091 h->key.len = r->header_name_end - r->header_name_start; | |
1092 h->value.len = r->header_end - r->header_start; | |
1093 | |
1094 h->key.data = ngx_palloc(r->pool, | |
649 | 1095 h->key.len + 1 + h->value.len + 1 + h->key.len); |
509 | 1096 if (h->key.data == NULL) { |
1097 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1098 } | |
1099 | |
1100 h->value.data = h->key.data + h->key.len + 1; | |
649 | 1101 h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; |
507 | 1102 |
509 | 1103 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); |
1104 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); | |
1105 | |
649 | 1106 if (h->key.len == r->lowcase_index) { |
1107 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); | |
1108 | |
1109 } else { | |
1110 for (i = 0; i < h->key.len; i++) { | |
1111 h->lowcase_key[i] = ngx_tolower(h->lowcase_key[i]); | |
509 | 1112 } |
1113 } | |
1114 | |
649 | 1115 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, |
1116 h->lowcase_key, h->key.len); | |
1117 | |
1118 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { | |
1119 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1120 } | |
1121 | |
509 | 1122 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1123 "http proxy header: \"%V: %V\"", | |
1124 &h->key, &h->value); | |
1125 | |
1126 continue; | |
1127 } | |
1128 | |
1129 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
1130 | |
1131 /* a whole header has been parsed successfully */ | |
1132 | |
1133 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1134 "http proxy header done"); | |
1135 | |
649 | 1136 /* |
1137 * if no "Server" and "Date" in header line, | |
1138 * then add the special empty headers | |
1139 */ | |
1140 | |
1141 if (r->upstream->headers_in.server == NULL) { | |
1142 h = ngx_list_push(&r->upstream->headers_in.headers); | |
1143 if (h == NULL) { | |
1144 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1145 } | |
1146 | |
1147 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( | |
1148 ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r'); | |
1149 | |
1150 h->key.len = sizeof("Server") - 1; | |
1151 h->key.data = (u_char *) "Server"; | |
1152 h->value.len = 0; | |
1153 h->value.data = NULL; | |
1154 h->lowcase_key = (u_char *) "server"; | |
1155 } | |
1156 | |
1157 if (r->upstream->headers_in.date == NULL) { | |
1158 h = ngx_list_push(&r->upstream->headers_in.headers); | |
1159 if (h == NULL) { | |
1160 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1161 } | |
1162 | |
1163 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); | |
1164 | |
1165 h->key.len = sizeof("Date") - 1; | |
1166 h->key.data = (u_char *) "Date"; | |
1167 h->value.len = 0; | |
1168 h->value.data = NULL; | |
1169 h->lowcase_key = (u_char *) "date"; | |
1170 } | |
1171 | |
509 | 1172 return NGX_OK; |
1173 } | |
1174 | |
521 | 1175 if (rc == NGX_AGAIN) { |
1176 return NGX_AGAIN; | |
1177 } | |
1178 | |
509 | 1179 /* there was error while a header line parsing */ |
1180 | |
1181 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
619 | 1182 "upstream sent invalid header"); |
509 | 1183 |
1184 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1185 } | |
507 | 1186 } |
1187 | |
1188 | |
1189 static void | |
1190 ngx_http_proxy_abort_request(ngx_http_request_t *r) | |
1191 { | |
1192 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1193 "abort http proxy request"); | |
577 | 1194 |
507 | 1195 return; |
1196 } | |
1197 | |
1198 | |
1199 static void | |
1200 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc) | |
577 | 1201 { |
507 | 1202 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1203 "finalize http proxy request"); | |
1204 | |
1205 return; | |
1206 } | |
1207 | |
1208 | |
573 | 1209 static ngx_int_t |
1210 ngx_http_proxy_host_variable(ngx_http_request_t *r, | |
1211 ngx_http_variable_value_t *v, uintptr_t data) | |
507 | 1212 { |
509 | 1213 ngx_http_proxy_loc_conf_t *plcf; |
507 | 1214 |
509 | 1215 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); |
507 | 1216 |
573 | 1217 v->len = plcf->host_header.len; |
577 | 1218 v->valid = 1; |
573 | 1219 v->no_cachable = 0; |
1220 v->not_found = 0; | |
1221 v->data = plcf->host_header.data; | |
507 | 1222 |
573 | 1223 return NGX_OK; |
507 | 1224 } |
1225 | |
1226 | |
573 | 1227 static ngx_int_t |
1228 ngx_http_proxy_port_variable(ngx_http_request_t *r, | |
1229 ngx_http_variable_value_t *v, uintptr_t data) | |
507 | 1230 { |
1231 ngx_http_proxy_loc_conf_t *plcf; | |
1232 | |
1233 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
1234 | |
573 | 1235 v->len = plcf->port_text.len; |
577 | 1236 v->valid = 1; |
573 | 1237 v->no_cachable = 0; |
1238 v->not_found = 0; | |
1239 v->data = plcf->port_text.data; | |
509 | 1240 |
573 | 1241 return NGX_OK; |
509 | 1242 } |
1243 | |
1244 | |
573 | 1245 static ngx_int_t |
509 | 1246 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, |
573 | 1247 ngx_http_variable_value_t *v, uintptr_t data) |
509 | 1248 { |
573 | 1249 u_char *p; |
509 | 1250 |
577 | 1251 v->valid = 1; |
573 | 1252 v->no_cachable = 0; |
1253 v->not_found = 0; | |
509 | 1254 |
1255 if (r->headers_in.x_forwarded_for == NULL) { | |
573 | 1256 v->len = r->connection->addr_text.len; |
1257 v->data = r->connection->addr_text.data; | |
1258 return NGX_OK; | |
509 | 1259 } |
1260 | |
573 | 1261 v->len = r->headers_in.x_forwarded_for->value.len |
1262 + sizeof(", ") - 1 + r->connection->addr_text.len; | |
509 | 1263 |
573 | 1264 p = ngx_palloc(r->pool, v->len); |
509 | 1265 if (p == NULL) { |
573 | 1266 return NGX_ERROR; |
509 | 1267 } |
1268 | |
573 | 1269 v->data = p; |
509 | 1270 |
573 | 1271 p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data, |
1272 r->headers_in.x_forwarded_for->value.len); | |
509 | 1273 |
1274 *p++ = ','; *p++ = ' '; | |
1275 | |
1276 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); | |
1277 | |
573 | 1278 return NGX_OK; |
509 | 1279 } |
1280 | |
1281 | |
1282 static ngx_int_t | |
577 | 1283 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r, |
1284 ngx_http_variable_value_t *v, uintptr_t data) | |
1285 { | |
1286 ngx_http_proxy_ctx_t *p; | |
1287 | |
1288 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
1289 | |
1290 if (p == NULL) { | |
1291 v->not_found = 1; | |
1292 return NGX_OK; | |
1293 } | |
1294 | |
1295 v->valid = 1; | |
1296 v->no_cachable = 0; | |
1297 v->not_found = 0; | |
1298 | |
1299 v->data = ngx_palloc(r->connection->pool, NGX_SIZE_T_LEN); | |
1300 | |
1301 if (v->data == NULL) { | |
1302 return NGX_ERROR; | |
1303 } | |
1304 | |
1305 v->len = ngx_sprintf(v->data, "%uz", p->internal_body_length) - v->data; | |
1306 | |
1307 return NGX_OK; | |
1308 } | |
1309 | |
1310 | |
1311 static ngx_int_t | |
509 | 1312 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, |
1313 size_t prefix) | |
1314 { | |
1315 ngx_int_t rc; | |
1316 ngx_uint_t i; | |
1317 ngx_http_proxy_loc_conf_t *plcf; | |
1318 ngx_http_proxy_redirect_t *pr; | |
1319 | |
1320 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
1321 | |
1322 pr = plcf->redirects->elts; | |
1323 | |
1324 if (pr == NULL) { | |
1325 return NGX_DECLINED; | |
1326 } | |
1327 | |
1328 for (i = 0; i < plcf->redirects->nelts; i++) { | |
605 | 1329 rc = pr[i].handler(r, h, prefix, &pr[i]); |
509 | 1330 |
1331 if (rc != NGX_DECLINED) { | |
1332 return rc; | |
1333 } | |
1334 } | |
1335 | |
1336 return NGX_DECLINED; | |
1337 } | |
1338 | |
1339 | |
1340 static ngx_int_t | |
1341 ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h, | |
1342 size_t prefix, ngx_http_proxy_redirect_t *pr) | |
1343 { | |
1344 size_t len; | |
1345 u_char *data, *p; | |
1346 | |
1347 if (pr->redirect.len > h->value.len - prefix | |
1348 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | |
1349 pr->redirect.len) != 0) | |
1350 { | |
1351 return NGX_DECLINED; | |
1352 } | |
1353 | |
1354 len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len; | |
507 | 1355 |
509 | 1356 data = ngx_palloc(r->pool, len); |
1357 if (data == NULL) { | |
1358 return NGX_ERROR; | |
1359 } | |
1360 | |
1361 p = data; | |
1362 | |
573 | 1363 p = ngx_copy(p, h->value.data, prefix); |
509 | 1364 |
653 | 1365 if (pr->replacement.text.len) { |
1366 p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); | |
1367 } | |
509 | 1368 |
1369 ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, | |
1370 h->value.len - pr->redirect.len - prefix); | |
1371 | |
1372 h->value.len = len; | |
1373 h->value.data = data; | |
1374 | |
1375 return NGX_OK; | |
1376 } | |
1377 | |
1378 | |
1379 static ngx_int_t | |
1380 ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h, | |
1381 size_t prefix, ngx_http_proxy_redirect_t *pr) | |
1382 { | |
1383 size_t len; | |
1384 u_char *data, *p; | |
1385 ngx_http_script_code_pt code; | |
1386 ngx_http_script_engine_t e; | |
1387 ngx_http_script_len_code_pt lcode; | |
1388 | |
1389 if (pr->redirect.len > h->value.len - prefix | |
1390 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | |
1391 pr->redirect.len) != 0) | |
1392 { | |
1393 return NGX_DECLINED; | |
1394 } | |
1395 | |
1396 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | |
1397 | |
1398 e.ip = pr->replacement.vars.lengths; | |
1399 e.request = r; | |
1400 | |
723
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1401 len = prefix + h->value.len - pr->redirect.len; |
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1402 |
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1403 while (*(uintptr_t *) e.ip) { |
509 | 1404 lcode = *(ngx_http_script_len_code_pt *) e.ip; |
723
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1405 len += lcode(&e); |
509 | 1406 } |
1407 | |
1408 data = ngx_palloc(r->pool, len); | |
1409 if (data == NULL) { | |
1410 return NGX_ERROR; | |
1411 } | |
1412 | |
1413 p = data; | |
1414 | |
573 | 1415 p = ngx_copy(p, h->value.data, prefix); |
509 | 1416 |
1417 e.ip = pr->replacement.vars.values; | |
1418 e.pos = p; | |
1419 | |
1420 while (*(uintptr_t *) e.ip) { | |
1421 code = *(ngx_http_script_code_pt *) e.ip; | |
1422 code(&e); | |
1423 } | |
1424 | |
723
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1425 ngx_memcpy(e.pos, h->value.data + prefix + pr->redirect.len, |
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1426 h->value.len - pr->redirect.len - prefix); |
ceb5ef29b119
fix proxy_redirect with variable
Igor Sysoev <igor@sysoev.ru>
parents:
673
diff
changeset
|
1427 |
509 | 1428 h->value.len = len; |
1429 h->value.data = data; | |
1430 | |
1431 return NGX_OK; | |
1432 } | |
1433 | |
1434 | |
1435 static ngx_int_t | |
1436 ngx_http_proxy_add_variables(ngx_conf_t *cf) | |
1437 { | |
1438 ngx_http_variable_t *var, *v; | |
1439 | |
1440 for (v = ngx_http_proxy_vars; v->name.len; v++) { | |
1441 var = ngx_http_add_variable(cf, &v->name, v->flags); | |
1442 if (var == NULL) { | |
1443 return NGX_ERROR; | |
1444 } | |
1445 | |
637 | 1446 var->get_handler = v->get_handler; |
509 | 1447 var->data = v->data; |
1448 } | |
1449 | |
1450 return NGX_OK; | |
507 | 1451 } |
1452 | |
1453 | |
1454 static void * | |
1455 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) | |
1456 { | |
1457 ngx_http_proxy_loc_conf_t *conf; | |
1458 | |
1459 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); | |
1460 if (conf == NULL) { | |
1461 return NGX_CONF_ERROR; | |
1462 } | |
1463 | |
1464 /* | |
1465 * set by ngx_pcalloc(): | |
1466 * | |
1467 * conf->upstream.bufs.num = 0; | |
1468 * conf->upstream.next_upstream = 0; | |
1469 * conf->upstream.temp_path = NULL; | |
649 | 1470 * conf->upstream.hide_headers_hash = { NULL, 0 }; |
1471 * conf->upstream.hide_headers = NULL; | |
1472 * conf->upstream.pass_headers = NULL; | |
509 | 1473 * conf->upstream.schema = { 0, NULL }; |
1474 * conf->upstream.uri = { 0, NULL }; | |
1475 * conf->upstream.location = NULL; | |
1476 * | |
561 | 1477 * conf->method = NULL; |
509 | 1478 * conf->headers_source = NULL; |
1479 * conf->headers_set_len = NULL; | |
1480 * conf->headers_set = NULL; | |
1481 * conf->headers_set_hash = NULL; | |
577 | 1482 * conf->body_set_len = NULL; |
1483 * conf->body_set = NULL; | |
1484 * conf->body_source = { 0, NULL }; | |
509 | 1485 * conf->rewrite_locations = NULL; |
507 | 1486 */ |
577 | 1487 |
581 | 1488 conf->upstream.buffering = NGX_CONF_UNSET; |
629 | 1489 conf->upstream.ignore_client_abort = NGX_CONF_UNSET; |
581 | 1490 |
507 | 1491 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; |
1492 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; | |
1493 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; | |
1494 | |
1495 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; | |
581 | 1496 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; |
529 | 1497 |
1498 conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; | |
577 | 1499 conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; |
529 | 1500 conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE; |
509 | 1501 |
1502 conf->upstream.pass_request_headers = NGX_CONF_UNSET; | |
1503 conf->upstream.pass_request_body = NGX_CONF_UNSET; | |
561 | 1504 |
657 | 1505 conf->upstream.intercept_errors = NGX_CONF_UNSET; |
507 | 1506 |
1507 /* "proxy_cyclic_temp_file" is disabled */ | |
1508 conf->upstream.cyclic_temp_file = 0; | |
1509 | |
509 | 1510 conf->redirect = NGX_CONF_UNSET; |
649 | 1511 conf->upstream.change_buffering = 1; |
507 | 1512 |
1513 return conf; | |
1514 } | |
1515 | |
1516 | |
1517 static char * | |
1518 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
1519 { | |
1520 ngx_http_proxy_loc_conf_t *prev = parent; | |
1521 ngx_http_proxy_loc_conf_t *conf = child; | |
1522 | |
509 | 1523 u_char *p; |
1524 size_t size; | |
1525 uintptr_t *code; | |
649 | 1526 ngx_str_t *header; |
1527 ngx_uint_t i, j; | |
1528 ngx_array_t hide_headers; | |
1529 ngx_keyval_t *src, *s, *h; | |
1530 ngx_hash_key_t *hk; | |
1531 ngx_hash_init_t hash; | |
509 | 1532 ngx_http_proxy_redirect_t *pr; |
1533 ngx_http_script_compile_t sc; | |
1534 ngx_http_script_copy_code_t *copy; | |
1535 | |
581 | 1536 ngx_conf_merge_value(conf->upstream.buffering, |
1537 prev->upstream.buffering, 1); | |
1538 | |
629 | 1539 ngx_conf_merge_value(conf->upstream.ignore_client_abort, |
1540 prev->upstream.ignore_client_abort, 0); | |
1541 | |
507 | 1542 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, |
1543 prev->upstream.connect_timeout, 60000); | |
1544 | |
1545 ngx_conf_merge_msec_value(conf->upstream.send_timeout, | |
1546 prev->upstream.send_timeout, 60000); | |
1547 | |
1548 ngx_conf_merge_msec_value(conf->upstream.read_timeout, | |
1549 prev->upstream.read_timeout, 60000); | |
1550 | |
1551 ngx_conf_merge_size_value(conf->upstream.send_lowat, | |
1552 prev->upstream.send_lowat, 0); | |
1553 | |
581 | 1554 ngx_conf_merge_size_value(conf->upstream.buffer_size, |
1555 prev->upstream.buffer_size, | |
507 | 1556 (size_t) ngx_pagesize); |
1557 | |
1558 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, | |
1559 8, ngx_pagesize); | |
1560 | |
1561 if (conf->upstream.bufs.num < 2) { | |
577 | 1562 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
507 | 1563 "there must be at least 2 \"proxy_buffers\""); |
1564 return NGX_CONF_ERROR; | |
1565 } | |
577 | 1566 |
507 | 1567 |
581 | 1568 size = conf->upstream.buffer_size; |
577 | 1569 if (size < conf->upstream.bufs.size) { |
507 | 1570 size = conf->upstream.bufs.size; |
1571 } | |
1572 | |
1573 | |
529 | 1574 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf, |
1575 prev->upstream.busy_buffers_size_conf, | |
507 | 1576 NGX_CONF_UNSET_SIZE); |
1577 | |
529 | 1578 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) { |
507 | 1579 conf->upstream.busy_buffers_size = 2 * size; |
529 | 1580 } else { |
1581 conf->upstream.busy_buffers_size = | |
1582 conf->upstream.busy_buffers_size_conf; | |
1583 } | |
577 | 1584 |
529 | 1585 if (conf->upstream.busy_buffers_size < size) { |
507 | 1586 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1587 "\"proxy_busy_buffers_size\" must be equal or bigger than " | |
1588 "maximum of the value of \"proxy_header_buffer_size\" and " | |
1589 "one of the \"proxy_buffers\""); | |
1590 | |
1591 return NGX_CONF_ERROR; | |
529 | 1592 } |
507 | 1593 |
529 | 1594 if (conf->upstream.busy_buffers_size |
1595 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) | |
507 | 1596 { |
1597 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1598 "\"proxy_busy_buffers_size\" must be less than " | |
1599 "the size of all \"proxy_buffers\" minus one buffer"); | |
1600 | |
1601 return NGX_CONF_ERROR; | |
1602 } | |
529 | 1603 |
507 | 1604 |
529 | 1605 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf, |
1606 prev->upstream.temp_file_write_size_conf, | |
507 | 1607 NGX_CONF_UNSET_SIZE); |
1608 | |
529 | 1609 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) { |
507 | 1610 conf->upstream.temp_file_write_size = 2 * size; |
529 | 1611 } else { |
1612 conf->upstream.temp_file_write_size = | |
1613 conf->upstream.temp_file_write_size_conf; | |
1614 } | |
577 | 1615 |
529 | 1616 if (conf->upstream.temp_file_write_size < size) { |
507 | 1617 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1618 "\"proxy_temp_file_write_size\" must be equal or bigger than " | |
1619 "maximum of the value of \"proxy_header_buffer_size\" and " | |
1620 "one of the \"proxy_buffers\""); | |
1621 | |
1622 return NGX_CONF_ERROR; | |
1623 } | |
1624 | |
529 | 1625 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf, |
1626 prev->upstream.max_temp_file_size_conf, | |
507 | 1627 NGX_CONF_UNSET_SIZE); |
1628 | |
529 | 1629 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) { |
507 | 1630 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; |
529 | 1631 } else { |
1632 conf->upstream.max_temp_file_size = | |
1633 conf->upstream.max_temp_file_size_conf; | |
1634 } | |
507 | 1635 |
529 | 1636 if (conf->upstream.max_temp_file_size != 0 |
1637 && conf->upstream.max_temp_file_size < size) | |
507 | 1638 { |
1639 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
561 | 1640 "\"proxy_max_temp_file_size\" must be equal to zero to disable " |
507 | 1641 "the temporary files usage or must be equal or bigger than " |
561 | 1642 "maximum of the value of \"proxy_header_buffer_size\" and " |
1643 "one of the \"proxy_buffers\""); | |
507 | 1644 |
1645 return NGX_CONF_ERROR; | |
1646 } | |
1647 | |
529 | 1648 |
507 | 1649 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, |
1650 prev->upstream.next_upstream, | |
1651 (NGX_CONF_BITMASK_SET | |
1652 |NGX_HTTP_UPSTREAM_FT_ERROR | |
1653 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); | |
1654 | |
665 | 1655 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { |
1656 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET | |
1657 |NGX_HTTP_UPSTREAM_FT_OFF; | |
1658 } | |
1659 | |
509 | 1660 ngx_conf_merge_path_value(conf->upstream.temp_path, |
1661 prev->upstream.temp_path, | |
1662 NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, | |
1663 ngx_garbage_collector_temp_handler, cf); | |
507 | 1664 |
561 | 1665 if (conf->method.len == 0) { |
1666 conf->method = prev->method; | |
1667 | |
1668 } else { | |
1669 conf->method.data[conf->method.len] = ' '; | |
1670 conf->method.len++; | |
509 | 1671 } |
1672 | |
1673 ngx_conf_merge_value(conf->upstream.pass_request_headers, | |
1674 prev->upstream.pass_request_headers, 1); | |
1675 ngx_conf_merge_value(conf->upstream.pass_request_body, | |
1676 prev->upstream.pass_request_body, 1); | |
1677 | |
657 | 1678 ngx_conf_merge_value(conf->upstream.intercept_errors, |
1679 prev->upstream.intercept_errors, 0); | |
509 | 1680 |
1681 ngx_conf_merge_value(conf->redirect, prev->redirect, 1); | |
1682 | |
1683 if (conf->redirect) { | |
507 | 1684 |
509 | 1685 if (conf->redirects == NULL) { |
1686 conf->redirects = prev->redirects; | |
1687 } | |
1688 | |
1689 if (conf->redirects == NULL && conf->upstream.url.data) { | |
1690 | |
1691 conf->redirects = ngx_array_create(cf->pool, 1, | |
1692 sizeof(ngx_http_proxy_redirect_t)); | |
1693 if (conf->redirects == NULL) { | |
1694 return NGX_CONF_ERROR; | |
1695 } | |
1696 | |
1697 pr = ngx_array_push(conf->redirects); | |
1698 if (pr == NULL) { | |
1699 return NGX_CONF_ERROR; | |
1700 } | |
1701 | |
1702 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
1703 pr->redirect = conf->upstream.url; | |
653 | 1704 |
1705 if (conf->upstream.uri.len) { | |
1706 pr->replacement.text = conf->upstream.location; | |
1707 | |
1708 } else { | |
1709 pr->replacement.text.len = 0; | |
1710 pr->replacement.text.data = NULL; | |
1711 } | |
509 | 1712 } |
1713 } | |
1714 | |
649 | 1715 if (conf->upstream.hide_headers == NULL |
1716 && conf->upstream.pass_headers == NULL) | |
1717 { | |
1718 conf->upstream.hide_headers = prev->upstream.hide_headers; | |
1719 conf->upstream.pass_headers = prev->upstream.pass_headers; | |
1720 conf->upstream.hide_headers_hash = prev->upstream.hide_headers_hash; | |
1721 | |
1722 if (conf->upstream.hide_headers_hash.buckets) { | |
1723 goto peers; | |
1724 } | |
1725 | |
1726 } else { | |
1727 if (conf->upstream.hide_headers == NULL) { | |
1728 conf->upstream.hide_headers = prev->upstream.hide_headers; | |
1729 } | |
1730 | |
1731 if (conf->upstream.pass_headers == NULL) { | |
1732 conf->upstream.pass_headers = prev->upstream.pass_headers; | |
1733 } | |
1734 } | |
1735 | |
1736 if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) | |
1737 != NGX_OK) | |
1738 { | |
1739 return NGX_CONF_ERROR; | |
1740 } | |
1741 | |
1742 for (header = ngx_http_proxy_hide_headers; header->len; header++) { | |
1743 hk = ngx_array_push(&hide_headers); | |
1744 if (hk == NULL) { | |
1745 return NGX_CONF_ERROR; | |
1746 } | |
1747 | |
1748 hk->key = *header; | |
1749 hk->key_hash = ngx_hash_key_lc(header->data, header->len); | |
1750 hk->value = (void *) 1; | |
1751 } | |
1752 | |
1753 if (conf->upstream.hide_headers) { | |
1754 | |
1755 header = conf->upstream.hide_headers->elts; | |
1756 | |
1757 for (i = 0; i < conf->upstream.hide_headers->nelts; i++) { | |
1758 | |
1759 hk = hide_headers.elts; | |
1760 | |
1761 for (j = 0; j < hide_headers.nelts; j++) { | |
1762 if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { | |
1763 goto exist; | |
1764 } | |
1765 } | |
1766 | |
1767 hk = ngx_array_push(&hide_headers); | |
1768 if (hk == NULL) { | |
1769 return NGX_CONF_ERROR; | |
1770 } | |
1771 | |
1772 hk->key = header[i]; | |
1773 hk->key_hash = ngx_hash_key_lc(header[i].data, header[i].len); | |
1774 hk->value = (void *) 1; | |
1775 | |
1776 exist: | |
1777 | |
1778 continue; | |
1779 } | |
1780 } | |
1781 | |
1782 if (conf->upstream.pass_headers) { | |
1783 | |
1784 hk = hide_headers.elts; | |
1785 header = conf->upstream.pass_headers->elts; | |
1786 | |
1787 for (i = 0; i < conf->upstream.pass_headers->nelts; i++) { | |
1788 for (j = 0; j < hide_headers.nelts; j++) { | |
1789 | |
1790 if (hk[j].key.data == NULL) { | |
1791 continue; | |
1792 } | |
1793 | |
1794 if (ngx_strcasecmp(header[i].data, hk[j].key.data) == 0) { | |
1795 hk[j].key.data = NULL; | |
1796 break; | |
1797 } | |
1798 } | |
1799 } | |
1800 } | |
1801 | |
1802 hash.hash = &conf->upstream.hide_headers_hash; | |
1803 hash.key = ngx_hash_key_lc; | |
1804 hash.max_size = 512; | |
751
bae59a740c40
align hash bucket size to cache line
Igor Sysoev <igor@sysoev.ru>
parents:
750
diff
changeset
|
1805 hash.bucket_size = ngx_align(64, ngx_cacheline_size); |
649 | 1806 hash.name = "proxy_hide_headers_hash"; |
1807 hash.pool = cf->pool; | |
1808 hash.temp_pool = NULL; | |
1809 | |
1810 if (ngx_hash_init(&hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) { | |
1811 return NGX_CONF_ERROR; | |
1812 } | |
1813 | |
1814 peers: | |
507 | 1815 |
884 | 1816 if (conf->upstream.upstream == NULL) { |
1817 conf->upstream.upstream = prev->upstream.upstream; | |
629 | 1818 |
1819 conf->host_header = prev->host_header; | |
1820 conf->port_text = prev->port_text; | |
1821 conf->upstream.schema = prev->upstream.schema; | |
507 | 1822 } |
1823 | |
577 | 1824 |
1825 if (conf->body_source.data == NULL) { | |
1826 conf->body_source = prev->body_source; | |
1827 conf->body_set_len = prev->body_set_len; | |
1828 conf->body_set = prev->body_set; | |
1829 } | |
1830 | |
579 | 1831 if (conf->body_source.data && conf->body_set_len == NULL) { |
577 | 1832 |
1833 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
1834 | |
1835 sc.cf = cf; | |
1836 sc.source = &conf->body_source; | |
1837 sc.flushes = &conf->flushes; | |
1838 sc.lengths = &conf->body_set_len; | |
1839 sc.values = &conf->body_set; | |
1840 sc.complete_lengths = 1; | |
1841 sc.complete_values = 1; | |
1842 | |
1843 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
1844 return NGX_CONF_ERROR; | |
1845 } | |
1846 | |
1847 if (conf->headers_source == NULL) { | |
1848 conf->headers_source = ngx_array_create(cf->pool, 4, | |
649 | 1849 sizeof(ngx_keyval_t)); |
577 | 1850 if (conf->headers_source == NULL) { |
1851 return NGX_CONF_ERROR; | |
1852 } | |
1853 } | |
1854 | |
1855 s = ngx_array_push(conf->headers_source); | |
1856 if (s == NULL) { | |
1857 return NGX_CONF_ERROR; | |
1858 } | |
1859 | |
1860 s->key.len = sizeof("Content-Length") - 1; | |
1861 s->key.data = (u_char *) "Content-Length"; | |
1862 s->value.len = sizeof("$proxy_internal_body_length") - 1; | |
1863 s->value.data = (u_char *) "$proxy_internal_body_length"; | |
1864 } | |
1865 | |
1866 | |
509 | 1867 if (conf->headers_source == NULL) { |
573 | 1868 conf->flushes = prev->flushes; |
507 | 1869 conf->headers_set_len = prev->headers_set_len; |
1870 conf->headers_set = prev->headers_set; | |
1871 conf->headers_set_hash = prev->headers_set_hash; | |
573 | 1872 conf->headers_source = prev->headers_source; |
507 | 1873 } |
1874 | |
649 | 1875 if (conf->headers_set_hash.buckets) { |
509 | 1876 return NGX_CONF_OK; |
1877 } | |
1878 | |
1879 | |
649 | 1880 conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t)); |
509 | 1881 if (conf->headers_names == NULL) { |
1882 return NGX_CONF_ERROR; | |
1883 } | |
1884 | |
1885 if (conf->headers_source == NULL) { | |
1886 conf->headers_source = ngx_array_create(cf->pool, 4, | |
649 | 1887 sizeof(ngx_keyval_t)); |
509 | 1888 if (conf->headers_source == NULL) { |
1889 return NGX_CONF_ERROR; | |
1890 } | |
1891 } | |
507 | 1892 |
509 | 1893 conf->headers_set_len = ngx_array_create(cf->pool, 64, 1); |
1894 if (conf->headers_set_len == NULL) { | |
1895 return NGX_CONF_ERROR; | |
1896 } | |
1897 | |
1898 conf->headers_set = ngx_array_create(cf->pool, 512, 1); | |
1899 if (conf->headers_set == NULL) { | |
1900 return NGX_CONF_ERROR; | |
1901 } | |
1902 | |
1903 | |
1904 src = conf->headers_source->elts; | |
1905 | |
1906 for (h = ngx_http_proxy_headers; h->key.len; h++) { | |
1907 | |
1908 for (i = 0; i < conf->headers_source->nelts; i++) { | |
1909 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { | |
1910 goto next; | |
507 | 1911 } |
1912 } | |
1913 | |
509 | 1914 s = ngx_array_push(conf->headers_source); |
1915 if (s == NULL) { | |
507 | 1916 return NGX_CONF_ERROR; |
1917 } | |
1918 | |
509 | 1919 *s = *h; |
507 | 1920 |
517 | 1921 src = conf->headers_source->elts; |
1922 | |
509 | 1923 next: |
507 | 1924 |
509 | 1925 continue; |
1926 } | |
507 | 1927 |
577 | 1928 |
1929 src = conf->headers_source->elts; | |
509 | 1930 for (i = 0; i < conf->headers_source->nelts; i++) { |
507 | 1931 |
649 | 1932 hk = ngx_array_push(conf->headers_names); |
1933 if (hk == NULL) { | |
507 | 1934 return NGX_CONF_ERROR; |
1935 } | |
1936 | |
649 | 1937 hk->key = src[i].key; |
1938 hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len); | |
1939 hk->value = (void *) 1; | |
509 | 1940 |
519 | 1941 if (src[i].value.len == 0) { |
1942 continue; | |
1943 } | |
1944 | |
509 | 1945 if (ngx_http_script_variables_count(&src[i].value) == 0) { |
1946 copy = ngx_array_push_n(conf->headers_set_len, | |
1947 sizeof(ngx_http_script_copy_code_t)); | |
1948 if (copy == NULL) { | |
1949 return NGX_CONF_ERROR; | |
1950 } | |
1951 | |
1952 copy->code = (ngx_http_script_code_pt) | |
1953 ngx_http_script_copy_len_code; | |
1954 copy->len = src[i].key.len + sizeof(": ") - 1 | |
1955 + src[i].value.len + sizeof(CRLF) - 1; | |
507 | 1956 |
1957 | |
509 | 1958 size = (sizeof(ngx_http_script_copy_code_t) |
1959 + src[i].key.len + sizeof(": ") - 1 | |
1960 + src[i].value.len + sizeof(CRLF) - 1 | |
1961 + sizeof(uintptr_t) - 1) | |
1962 & ~(sizeof(uintptr_t) - 1); | |
1963 | |
1964 copy = ngx_array_push_n(conf->headers_set, size); | |
1965 if (copy == NULL) { | |
1966 return NGX_CONF_ERROR; | |
1967 } | |
1968 | |
1969 copy->code = ngx_http_script_copy_code; | |
1970 copy->len = src[i].key.len + sizeof(": ") - 1 | |
1971 + src[i].value.len + sizeof(CRLF) - 1; | |
1972 | |
1973 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
1974 | |
1975 p = ngx_cpymem(p, src[i].key.data, src[i].key.len); | |
1976 *p++ = ':'; *p++ = ' '; | |
1977 p = ngx_cpymem(p, src[i].value.data, src[i].value.len); | |
1978 *p++ = CR; *p = LF; | |
1979 | |
1980 } else { | |
1981 copy = ngx_array_push_n(conf->headers_set_len, | |
1982 sizeof(ngx_http_script_copy_code_t)); | |
1983 if (copy == NULL) { | |
1984 return NGX_CONF_ERROR; | |
1985 } | |
1986 | |
1987 copy->code = (ngx_http_script_code_pt) | |
1988 ngx_http_script_copy_len_code; | |
1989 copy->len = src[i].key.len + sizeof(": ") - 1; | |
507 | 1990 |
1991 | |
509 | 1992 size = (sizeof(ngx_http_script_copy_code_t) |
1993 + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) | |
1994 & ~(sizeof(uintptr_t) - 1); | |
1995 | |
1996 copy = ngx_array_push_n(conf->headers_set, size); | |
1997 if (copy == NULL) { | |
1998 return NGX_CONF_ERROR; | |
1999 } | |
2000 | |
2001 copy->code = ngx_http_script_copy_code; | |
2002 copy->len = src[i].key.len + sizeof(": ") - 1; | |
2003 | |
2004 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
2005 p = ngx_cpymem(p, src[i].key.data, src[i].key.len); | |
2006 *p++ = ':'; *p = ' '; | |
2007 | |
2008 | |
2009 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
2010 | |
2011 sc.cf = cf; | |
2012 sc.source = &src[i].value; | |
573 | 2013 sc.flushes = &conf->flushes; |
509 | 2014 sc.lengths = &conf->headers_set_len; |
2015 sc.values = &conf->headers_set; | |
2016 | |
2017 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
2018 return NGX_CONF_ERROR; | |
2019 } | |
2020 | |
2021 | |
2022 copy = ngx_array_push_n(conf->headers_set_len, | |
2023 sizeof(ngx_http_script_copy_code_t)); | |
2024 if (copy == NULL) { | |
2025 return NGX_CONF_ERROR; | |
2026 } | |
2027 | |
2028 copy->code = (ngx_http_script_code_pt) | |
2029 ngx_http_script_copy_len_code; | |
2030 copy->len = sizeof(CRLF) - 1; | |
2031 | |
2032 | |
2033 size = (sizeof(ngx_http_script_copy_code_t) | |
2034 + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) | |
2035 & ~(sizeof(uintptr_t) - 1); | |
2036 | |
2037 copy = ngx_array_push_n(conf->headers_set, size); | |
2038 if (copy == NULL) { | |
2039 return NGX_CONF_ERROR; | |
2040 } | |
2041 | |
2042 copy->code = ngx_http_script_copy_code; | |
2043 copy->len = sizeof(CRLF) - 1; | |
2044 | |
2045 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
2046 *p++ = CR; *p = LF; | |
507 | 2047 } |
2048 | |
509 | 2049 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); |
2050 if (code == NULL) { | |
507 | 2051 return NGX_CONF_ERROR; |
2052 } | |
2053 | |
509 | 2054 *code = (uintptr_t) NULL; |
2055 | |
2056 code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t)); | |
2057 if (code == NULL) { | |
2058 return NGX_CONF_ERROR; | |
2059 } | |
2060 | |
2061 *code = (uintptr_t) NULL; | |
507 | 2062 } |
2063 | |
509 | 2064 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); |
2065 if (code == NULL) { | |
2066 return NGX_CONF_ERROR; | |
507 | 2067 } |
2068 | |
509 | 2069 *code = (uintptr_t) NULL; |
507 | 2070 |
2071 | |
649 | 2072 hash.hash = &conf->headers_set_hash; |
2073 hash.key = ngx_hash_key_lc; | |
2074 hash.max_size = 512; | |
2075 hash.bucket_size = ngx_cacheline_size; | |
2076 hash.name = "proxy_set_header_hash"; | |
2077 hash.pool = cf->pool; | |
2078 hash.temp_pool = NULL; | |
2079 | |
2080 if (ngx_hash_init(&hash, conf->headers_names->elts, | |
2081 conf->headers_names->nelts) | |
2082 != NGX_OK) | |
2083 { | |
2084 return NGX_CONF_ERROR; | |
2085 } | |
2086 | |
509 | 2087 return NGX_CONF_OK; |
507 | 2088 } |
2089 | |
2090 | |
2091 static char * | |
2092 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
2093 { | |
509 | 2094 ngx_http_proxy_loc_conf_t *plcf = conf; |
507 | 2095 |
577 | 2096 size_t add; |
593 | 2097 u_short port; |
507 | 2098 ngx_str_t *value, *url; |
651 | 2099 ngx_url_t u; |
507 | 2100 ngx_http_core_loc_conf_t *clcf; |
577 | 2101 #if (NGX_HTTP_SSL) |
2102 ngx_pool_cleanup_t *cln; | |
2103 #endif | |
507 | 2104 |
555 | 2105 if (plcf->upstream.schema.len) { |
2106 return "is duplicate"; | |
2107 } | |
2108 | |
507 | 2109 value = cf->args->elts; |
2110 | |
2111 url = &value[1]; | |
2112 | |
577 | 2113 if (ngx_strncasecmp(url->data, "http://", 7) == 0) { |
2114 add = 7; | |
591 | 2115 port = 80; |
577 | 2116 |
2117 } else if (ngx_strncasecmp(url->data, "https://", 8) == 0) { | |
2118 | |
2119 #if (NGX_HTTP_SSL) | |
2120 | |
2121 add = 8; | |
591 | 2122 port = 443; |
577 | 2123 |
2124 plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); | |
2125 if (plcf->upstream.ssl == NULL) { | |
2126 return NGX_CONF_ERROR; | |
2127 } | |
2128 | |
2129 plcf->upstream.ssl->log = cf->log; | |
2130 | |
2131 if (ngx_ssl_create(plcf->upstream.ssl, | |
2132 NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1) | |
2133 != NGX_OK) | |
2134 { | |
2135 return NGX_CONF_ERROR; | |
2136 } | |
2137 | |
2138 cln = ngx_pool_cleanup_add(cf->pool, 0); | |
2139 if (cln == NULL) { | |
2140 return NGX_CONF_ERROR; | |
2141 } | |
2142 | |
2143 cln->handler = ngx_ssl_cleanup_ctx; | |
2144 cln->data = plcf->upstream.ssl; | |
2145 | |
2146 #else | |
2147 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2148 "https protocol requires SSL support"); | |
2149 return NGX_CONF_ERROR; | |
2150 #endif | |
2151 | |
2152 } else { | |
507 | 2153 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); |
2154 return NGX_CONF_ERROR; | |
2155 } | |
2156 | |
651 | 2157 ngx_memzero(&u, sizeof(ngx_url_t)); |
2158 | |
2159 u.url.len = url->len - add; | |
2160 u.url.data = url->data + add; | |
2161 u.default_portn = port; | |
896
f247db60fc85
fix fastcgi and memcached upstreams
Igor Sysoev <igor@sysoev.ru>
parents:
884
diff
changeset
|
2162 u.upstream = 1; |
884 | 2163 u.no_resolve = 1; |
651 | 2164 u.uri_part = 1; |
884 | 2165 |
2166 plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); | |
2167 if (plcf->upstream.upstream == NULL) { | |
507 | 2168 return NGX_CONF_ERROR; |
2169 } | |
2170 | |
651 | 2171 plcf->host_header = u.host_header; |
2172 plcf->port_text = u.port; | |
2173 plcf->upstream.uri = u.uri; | |
2174 | |
591 | 2175 plcf->upstream.schema.len = add; |
2176 plcf->upstream.schema.data = url->data; | |
509 | 2177 |
507 | 2178 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); |
2179 | |
2180 clcf->handler = ngx_http_proxy_handler; | |
2181 | |
573 | 2182 plcf->upstream.location = clcf->name; |
555 | 2183 |
507 | 2184 #if (NGX_PCRE) |
555 | 2185 |
629 | 2186 if (clcf->regex || clcf->noname) { |
573 | 2187 if (plcf->upstream.uri.len) { |
2188 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2189 "\"proxy_pass\" may not have URI part in " | |
843
ebab9490204c
allow proxy_pass inside limit_except
Igor Sysoev <igor@sysoev.ru>
parents:
812
diff
changeset
|
2190 "location given by regular expression, " |
ebab9490204c
allow proxy_pass inside limit_except
Igor Sysoev <igor@sysoev.ru>
parents:
812
diff
changeset
|
2191 "or inside the \"if\" statement, " |
ebab9490204c
allow proxy_pass inside limit_except
Igor Sysoev <igor@sysoev.ru>
parents:
812
diff
changeset
|
2192 "or inside the \"limit_except\" block"); |
573 | 2193 return NGX_CONF_ERROR; |
2194 } | |
2195 | |
2196 plcf->upstream.location.len = 0; | |
555 | 2197 } |
2198 | |
507 | 2199 #endif |
2200 | |
509 | 2201 plcf->upstream.url = *url; |
2202 | |
507 | 2203 if (clcf->name.data[clcf->name.len - 1] == '/') { |
2204 clcf->auto_redirect = 1; | |
2205 } | |
2206 | |
2207 return NGX_CONF_OK; | |
2208 } | |
2209 | |
2210 | |
2211 static char * | |
509 | 2212 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
507 | 2213 { |
509 | 2214 ngx_http_proxy_loc_conf_t *plcf = conf; |
2215 | |
2216 ngx_str_t *value; | |
2217 ngx_array_t *vars_lengths, *vars_values; | |
2218 ngx_http_script_compile_t sc; | |
2219 ngx_http_proxy_redirect_t *pr; | |
2220 | |
2221 if (plcf->redirect == 0) { | |
2222 return NGX_CONF_OK; | |
2223 } | |
2224 | |
2225 value = cf->args->elts; | |
2226 | |
2227 if (ngx_strcmp(value[1].data, "off") == 0) { | |
2228 plcf->redirect = 0; | |
2229 plcf->redirects = NULL; | |
2230 return NGX_CONF_OK; | |
2231 } | |
2232 | |
2233 if (plcf->redirects == NULL) { | |
2234 plcf->redirects = ngx_array_create(cf->pool, 1, | |
2235 sizeof(ngx_http_proxy_redirect_t)); | |
2236 if (plcf->redirects == NULL) { | |
2237 return NGX_CONF_ERROR; | |
2238 } | |
2239 } | |
2240 | |
2241 pr = ngx_array_push(plcf->redirects); | |
2242 if (pr == NULL) { | |
2243 return NGX_CONF_ERROR; | |
2244 } | |
2245 | |
2246 if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { | |
2247 if (plcf->upstream.url.data == NULL) { | |
2248 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2249 "\"proxy_rewrite_location default\" must go " | |
2250 "after the \"proxy_pass\" directive"); | |
2251 return NGX_CONF_ERROR; | |
2252 } | |
2253 | |
2254 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
2255 pr->redirect = plcf->upstream.url; | |
653 | 2256 |
2257 if (plcf->upstream.uri.len) { | |
2258 pr->replacement.text = plcf->upstream.location; | |
2259 | |
2260 } else { | |
2261 pr->replacement.text.len = 0; | |
2262 pr->replacement.text.data = NULL; | |
2263 } | |
509 | 2264 |
2265 return NGX_CONF_OK; | |
2266 } | |
2267 | |
2268 if (ngx_http_script_variables_count(&value[2]) == 0) { | |
2269 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
2270 pr->redirect = value[1]; | |
2271 pr->replacement.text = value[2]; | |
2272 | |
2273 return NGX_CONF_OK; | |
2274 } | |
2275 | |
2276 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
2277 | |
2278 vars_lengths = NULL; | |
2279 vars_values = NULL; | |
2280 | |
2281 sc.cf = cf; | |
2282 sc.source = &value[2]; | |
2283 sc.lengths = &vars_lengths; | |
2284 sc.values = &vars_values; | |
2285 sc.complete_lengths = 1; | |
2286 sc.complete_values = 1; | |
2287 | |
2288 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
2289 return NGX_CONF_ERROR; | |
2290 } | |
2291 | |
2292 pr->handler = ngx_http_proxy_rewrite_redirect_vars; | |
2293 pr->redirect = value[1]; | |
2294 pr->replacement.vars.lengths = vars_lengths->elts; | |
2295 pr->replacement.vars.values = vars_values->elts; | |
2296 | |
507 | 2297 return NGX_CONF_OK; |
2298 } | |
2299 | |
2300 | |
2301 static char * | |
2302 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) | |
2303 { | |
2304 #if (NGX_FREEBSD) | |
2305 ssize_t *np = data; | |
2306 | |
673 | 2307 if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) { |
507 | 2308 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2309 "\"proxy_send_lowat\" must be less than %d " | |
2310 "(sysctl net.inet.tcp.sendspace)", | |
2311 ngx_freebsd_net_inet_tcp_sendspace); | |
2312 | |
2313 return NGX_CONF_ERROR; | |
2314 } | |
2315 | |
2316 #elif !(NGX_HAVE_SO_SNDLOWAT) | |
2317 ssize_t *np = data; | |
2318 | |
2319 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
2320 "\"proxy_send_lowat\" is not supported, ignored"); | |
2321 | |
2322 *np = 0; | |
2323 | |
2324 #endif | |
2325 | |
2326 return NGX_CONF_OK; | |
2327 } | |
884 | 2328 |
2329 | |
2330 static char * | |
2331 ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf, | |
2332 ngx_command_t *cmd, void *conf) | |
2333 { | |
2334 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2335 "\"proxy_upstream_max_fails\" is not supported, " | |
2336 "use the \"max_fails\" parameter of the \"server\" directive ", | |
2337 "inside the \"upstream\" block"); | |
2338 | |
2339 return NGX_CONF_ERROR; | |
2340 } | |
2341 | |
2342 | |
2343 static char * | |
2344 ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf, | |
2345 ngx_command_t *cmd, void *conf) | |
2346 { | |
2347 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2348 "\"proxy_upstream_fail_timeout\" is not supported, " | |
2349 "use the \"fail_timeout\" parameter of the \"server\" directive ", | |
2350 "inside the \"upstream\" block"); | |
2351 | |
2352 return NGX_CONF_ERROR; | |
2353 } |