Mercurial > hg > nginx-mail
comparison src/http/modules/ngx_http_proxy_module.c @ 58:b55cbf18157e NGINX_0_1_29
nginx 0.1.29
*) Feature: the ngx_http_ssi_module supports "include virtual" command.
*) Feature: the ngx_http_ssi_module supports the condition command like
'if expr="$NAME"' and "else" and "endif" commands. Only one nested
level is supported.
*) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and
DATE_GMT variables and "config timefmt" command.
*) Feature: the "ssi_ignore_recycled_buffers" directive.
*) Bugfix: the "echo" command did not show the default value for the
empty QUERY_STRING variable.
*) Change: the ngx_http_proxy_module was rewritten.
*) Feature: the "proxy_redirect", "proxy_pass_request_headers",
"proxy_pass_request_body", and "proxy_method" directives.
*) Feature: the "proxy_set_header" directive. The "proxy_x_var" was
canceled and must be replaced with the proxy_set_header directive.
*) Change: the "proxy_preserve_host" is canceled and must be replaced
with the "proxy_set_header Host $host" and the "proxy_redirect off"
directives, the "proxy_set_header Host $host:$proxy_port" directive
and the appropriate proxy_redirect directives.
*) Change: the "proxy_set_x_real_ip" is canceled and must be replaced
with the "proxy_set_header X-Real-IP $remote_addr" directive.
*) Change: the "proxy_add_x_forwarded_for" is canceled and must be
replaced with
the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"
directive.
*) Change: the "proxy_set_x_url" is canceled and must be replaced with
the "proxy_set_header X-URL http://$host:$server_port$request_uri"
directive.
*) Feature: the "fastcgi_param" directive.
*) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params"
directive are canceled and must be replaced with the fastcgi_param
directives.
*) Feature: the "index" directive can use the variables.
*) Feature: the "index" directive can be used at http and server levels.
*) Change: the last index only in the "index" directive can be absolute.
*) Feature: the "rewrite" directive can use the variables.
*) Feature: the "internal" directive.
*) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.
*) Change: nginx now passes the invalid lines in a client request
headers or a backend response header.
*) Bugfix: if the backend did not transfer response for a long time and
the "send_timeout" was less than "proxy_read_timeout", then nginx
returned the 408 response.
*) Bugfix: the segmentation fault was occurred if the backend sent an
invalid line in response header; bug appeared in 0.1.26.
*) Bugfix: the segmentation fault may occurred in FastCGI fault
tolerance configuration.
*) Bugfix: the "expires" directive did not remove the previous
"Expires" and "Cache-Control" headers.
*) Bugfix: nginx did not take into account trailing dot in "Host"
header line.
*) Bugfix: the ngx_http_auth_module did not work under Linux.
*) Bugfix: the rewrite directive worked incorrectly, if the arguments
were in a request.
*) Bugfix: nginx could not be built on MacOS X.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Thu, 12 May 2005 00:00:00 +0400 |
parents | |
children | 5db440287648 |
comparison
equal
deleted
inserted
replaced
57:5df375c55338 | 58:b55cbf18157e |
---|---|
1 | |
2 /* | |
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 | |
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); | |
17 | |
18 struct ngx_http_proxy_redirect_s { | |
19 ngx_http_proxy_redirect_pt handler; | |
20 ngx_str_t redirect; | |
21 | |
22 union { | |
23 ngx_str_t text; | |
24 | |
25 struct { | |
26 void *lengths; | |
27 void *values; | |
28 } vars; | |
29 | |
30 void *regex; | |
31 } replacement; | |
32 }; | |
33 | |
34 | |
35 typedef struct { | |
36 ngx_http_upstream_conf_t upstream; | |
37 | |
38 ngx_peers_t *peers; | |
39 | |
40 ngx_array_t *headers_set_len; | |
41 ngx_array_t *headers_set; | |
42 ngx_hash_t *headers_set_hash; | |
43 | |
44 ngx_array_t *headers_source; | |
45 ngx_array_t *headers_names; | |
46 | |
47 ngx_array_t *redirects; | |
48 | |
49 ngx_str_t host_header; | |
50 ngx_str_t port_text; | |
51 | |
52 ngx_flag_t redirect; | |
53 } ngx_http_proxy_loc_conf_t; | |
54 | |
55 | |
56 typedef struct { | |
57 ngx_uint_t status; | |
58 ngx_uint_t status_count; | |
59 u_char *status_start; | |
60 u_char *status_end; | |
61 } ngx_http_proxy_ctx_t; | |
62 | |
63 | |
64 #define NGX_HTTP_PROXY_PARSE_NO_HEADER 20 | |
65 | |
66 | |
67 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); | |
68 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); | |
69 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); | |
70 static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r, | |
71 ngx_http_proxy_ctx_t *p); | |
72 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r); | |
73 static void ngx_http_proxy_abort_request(ngx_http_request_t *r); | |
74 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r, | |
75 ngx_int_t rc); | |
76 | |
77 static ngx_http_variable_value_t * | |
78 ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data); | |
79 static ngx_http_variable_value_t * | |
80 ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data); | |
81 static ngx_http_variable_value_t * | |
82 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, | |
83 uintptr_t data); | |
84 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, | |
85 ngx_table_elt_t *h, size_t prefix); | |
86 | |
87 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); | |
88 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); | |
89 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, | |
90 void *parent, void *child); | |
91 | |
92 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
93 void *conf); | |
94 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, | |
95 void *conf); | |
96 | |
97 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); | |
98 | |
99 | |
100 static ngx_conf_post_t ngx_http_proxy_lowat_post = | |
101 { ngx_http_proxy_lowat_check }; | |
102 | |
103 static ngx_conf_enum_t ngx_http_proxy_set_methods[] = { | |
104 { ngx_string("get"), NGX_HTTP_GET }, | |
105 { ngx_null_string, 0 } | |
106 }; | |
107 | |
108 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { | |
109 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, | |
110 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, | |
111 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, | |
112 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, | |
113 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, | |
114 { ngx_null_string, 0 } | |
115 }; | |
116 | |
117 | |
118 static ngx_command_t ngx_http_proxy_commands[] = { | |
119 | |
120 { ngx_string("proxy_pass"), | |
121 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
122 ngx_http_proxy_pass, | |
123 NGX_HTTP_LOC_CONF_OFFSET, | |
124 0, | |
125 NULL }, | |
126 | |
127 { ngx_string("proxy_redirect"), | |
128 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | |
129 ngx_http_proxy_redirect, | |
130 NGX_HTTP_LOC_CONF_OFFSET, | |
131 0, | |
132 NULL }, | |
133 | |
134 { ngx_string("proxy_connect_timeout"), | |
135 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
136 ngx_conf_set_msec_slot, | |
137 NGX_HTTP_LOC_CONF_OFFSET, | |
138 offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout), | |
139 NULL }, | |
140 | |
141 { ngx_string("proxy_send_timeout"), | |
142 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
143 ngx_conf_set_msec_slot, | |
144 NGX_HTTP_LOC_CONF_OFFSET, | |
145 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout), | |
146 NULL }, | |
147 | |
148 { ngx_string("proxy_send_lowat"), | |
149 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
150 ngx_conf_set_size_slot, | |
151 NGX_HTTP_LOC_CONF_OFFSET, | |
152 offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), | |
153 &ngx_http_proxy_lowat_post }, | |
154 | |
155 { ngx_string("proxy_redirect_errors"), | |
156 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
157 ngx_conf_set_flag_slot, | |
158 NGX_HTTP_LOC_CONF_OFFSET, | |
159 offsetof(ngx_http_proxy_loc_conf_t, upstream.redirect_errors), | |
160 NULL }, | |
161 | |
162 { ngx_string("proxy_pass_unparsed_uri"), | |
163 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
164 ngx_conf_set_flag_slot, | |
165 NGX_HTTP_LOC_CONF_OFFSET, | |
166 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri), | |
167 NULL }, | |
168 | |
169 { ngx_string("proxy_set_header"), | |
170 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
171 ngx_conf_set_table_elt_slot, | |
172 NGX_HTTP_LOC_CONF_OFFSET, | |
173 offsetof(ngx_http_proxy_loc_conf_t, headers_source), | |
174 NULL }, | |
175 | |
176 { ngx_string("proxy_method"), | |
177 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
178 ngx_conf_set_enum_slot, | |
179 NGX_HTTP_LOC_CONF_OFFSET, | |
180 offsetof(ngx_http_proxy_loc_conf_t, upstream.method), | |
181 ngx_http_proxy_set_methods }, | |
182 | |
183 { ngx_string("proxy_pass_request_headers"), | |
184 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
185 ngx_conf_set_flag_slot, | |
186 NGX_HTTP_LOC_CONF_OFFSET, | |
187 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers), | |
188 NULL }, | |
189 | |
190 { ngx_string("proxy_pass_request_body"), | |
191 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
192 ngx_conf_set_flag_slot, | |
193 NGX_HTTP_LOC_CONF_OFFSET, | |
194 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body), | |
195 NULL }, | |
196 | |
197 { ngx_string("proxy_header_buffer_size"), | |
198 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
199 ngx_conf_set_size_slot, | |
200 NGX_HTTP_LOC_CONF_OFFSET, | |
201 offsetof(ngx_http_proxy_loc_conf_t, upstream.header_buffer_size), | |
202 NULL }, | |
203 | |
204 { ngx_string("proxy_read_timeout"), | |
205 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
206 ngx_conf_set_msec_slot, | |
207 NGX_HTTP_LOC_CONF_OFFSET, | |
208 offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout), | |
209 NULL }, | |
210 | |
211 { ngx_string("proxy_buffers"), | |
212 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, | |
213 ngx_conf_set_bufs_slot, | |
214 NGX_HTTP_LOC_CONF_OFFSET, | |
215 offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs), | |
216 NULL }, | |
217 | |
218 { ngx_string("proxy_busy_buffers_size"), | |
219 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
220 ngx_conf_set_size_slot, | |
221 NGX_HTTP_LOC_CONF_OFFSET, | |
222 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size), | |
223 NULL }, | |
224 | |
225 { ngx_string("proxy_temp_path"), | |
226 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, | |
227 ngx_conf_set_path_slot, | |
228 NGX_HTTP_LOC_CONF_OFFSET, | |
229 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), | |
230 (void *) ngx_garbage_collector_temp_handler }, | |
231 | |
232 { ngx_string("proxy_max_temp_file_size"), | |
233 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
234 ngx_conf_set_size_slot, | |
235 NGX_HTTP_LOC_CONF_OFFSET, | |
236 offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size), | |
237 NULL }, | |
238 | |
239 { ngx_string("proxy_temp_file_write_size"), | |
240 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
241 ngx_conf_set_size_slot, | |
242 NGX_HTTP_LOC_CONF_OFFSET, | |
243 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size), | |
244 NULL }, | |
245 | |
246 { ngx_string("proxy_next_upstream"), | |
247 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, | |
248 ngx_conf_set_bitmask_slot, | |
249 NGX_HTTP_LOC_CONF_OFFSET, | |
250 offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream), | |
251 &ngx_http_proxy_next_upstream_masks }, | |
252 | |
253 { ngx_string("proxy_pass_x_powered_by"), | |
254 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
255 ngx_conf_set_flag_slot, | |
256 NGX_HTTP_LOC_CONF_OFFSET, | |
257 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_powered_by), | |
258 NULL }, | |
259 | |
260 { ngx_string("proxy_pass_server"), | |
261 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
262 ngx_conf_set_flag_slot, | |
263 NGX_HTTP_LOC_CONF_OFFSET, | |
264 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_server), | |
265 NULL }, | |
266 | |
267 { ngx_string("proxy_pass_x_accel_expires"), | |
268 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
269 ngx_conf_set_flag_slot, | |
270 NGX_HTTP_LOC_CONF_OFFSET, | |
271 offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_x_accel_expires), | |
272 NULL }, | |
273 | |
274 ngx_null_command | |
275 }; | |
276 | |
277 | |
278 ngx_http_module_t ngx_http_proxy_module_ctx = { | |
279 ngx_http_proxy_add_variables, /* preconfiguration */ | |
280 NULL, /* postconfiguration */ | |
281 | |
282 NULL, /* create main configuration */ | |
283 NULL, /* init main configuration */ | |
284 | |
285 NULL, /* create server configuration */ | |
286 NULL, /* merge server configuration */ | |
287 | |
288 ngx_http_proxy_create_loc_conf, /* create location configration */ | |
289 ngx_http_proxy_merge_loc_conf /* merge location configration */ | |
290 }; | |
291 | |
292 | |
293 ngx_module_t ngx_http_proxy_module = { | |
294 NGX_MODULE_V1, | |
295 &ngx_http_proxy_module_ctx, /* module context */ | |
296 ngx_http_proxy_commands, /* module directives */ | |
297 NGX_HTTP_MODULE, /* module type */ | |
298 NULL, /* init module */ | |
299 NULL /* init process */ | |
300 }; | |
301 | |
302 | |
303 static ngx_str_t ngx_http_proxy_methods[] = { | |
304 ngx_string("GET "), | |
305 ngx_string("HEAD "), | |
306 ngx_string("POST ") | |
307 }; | |
308 | |
309 | |
310 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF; | |
311 | |
312 | |
313 static ngx_table_elt_t ngx_http_proxy_headers[] = { | |
314 { 0, ngx_string("Host"), ngx_string("$proxy_host"), }, | |
315 { 0, ngx_string("Connection"), ngx_string("close"), }, | |
316 { 0, ngx_null_string, ngx_null_string } | |
317 }; | |
318 | |
319 | |
320 static ngx_http_variable_t ngx_http_proxy_vars[] = { | |
321 | |
322 { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0, | |
323 NGX_HTTP_VAR_CHANGABLE }, | |
324 | |
325 { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0, | |
326 NGX_HTTP_VAR_CHANGABLE }, | |
327 | |
328 { ngx_string("proxy_add_x_forwarded_for"), | |
329 ngx_http_proxy_add_x_forwarded_for_variable, 0, 0 }, | |
330 | |
331 #if 0 | |
332 { ngx_string("proxy_add_via"), NULL, 0, 0 }, | |
333 #endif | |
334 | |
335 { ngx_null_string, NULL, 0, 0 } | |
336 }; | |
337 | |
338 | |
339 #if (NGX_PCRE) | |
340 static ngx_str_t ngx_http_proxy_uri = ngx_string("/"); | |
341 #endif | |
342 | |
343 | |
344 static ngx_int_t | |
345 ngx_http_proxy_handler(ngx_http_request_t *r) | |
346 { | |
347 ngx_int_t rc; | |
348 ngx_http_upstream_t *u; | |
349 ngx_http_proxy_loc_conf_t *plcf; | |
350 | |
351 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
352 | |
353 u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); | |
354 if (u == NULL) { | |
355 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
356 } | |
357 | |
358 u->peer.log = r->connection->log; | |
359 u->peer.log_error = NGX_ERROR_ERR; | |
360 u->peer.peers = plcf->peers; | |
361 u->peer.tries = plcf->peers->number; | |
362 #if (NGX_THREADS) | |
363 u->peer.lock = &r->connection->lock; | |
364 #endif | |
365 | |
366 u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; | |
367 | |
368 u->conf = &plcf->upstream; | |
369 | |
370 u->create_request = ngx_http_proxy_create_request; | |
371 u->reinit_request = ngx_http_proxy_reinit_request; | |
372 u->process_header = ngx_http_proxy_process_status_line; | |
373 u->abort_request = ngx_http_proxy_abort_request; | |
374 u->finalize_request = ngx_http_proxy_finalize_request; | |
375 | |
376 if (plcf->redirects) { | |
377 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; | |
378 } | |
379 | |
380 u->pipe.input_filter = ngx_event_pipe_copy_input_filter; | |
381 | |
382 u->accel = 1; | |
383 | |
384 r->upstream = u; | |
385 | |
386 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); | |
387 | |
388 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | |
389 return rc; | |
390 } | |
391 | |
392 return NGX_DONE; | |
393 } | |
394 | |
395 | |
396 static ngx_int_t | |
397 ngx_http_proxy_create_request(ngx_http_request_t *r) | |
398 { | |
399 size_t len, loc_len; | |
400 ngx_uint_t i, key; | |
401 uintptr_t escape; | |
402 ngx_buf_t *b; | |
403 ngx_str_t *hh; | |
404 ngx_chain_t *cl, *body; | |
405 ngx_list_part_t *part; | |
406 ngx_table_elt_t *header; | |
407 ngx_http_upstream_t *u; | |
408 ngx_http_script_code_pt code; | |
409 ngx_http_script_engine_t e, le; | |
410 ngx_http_proxy_loc_conf_t *plcf; | |
411 ngx_http_script_len_code_pt lcode; | |
412 | |
413 u = r->upstream; | |
414 | |
415 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
416 | |
417 len = sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1; | |
418 | |
419 if (u->method) { | |
420 len += ngx_http_proxy_methods[u->method - 1].len + u->conf->uri.len; | |
421 } else { | |
422 len += r->method_name.len + 1 + u->conf->uri.len; | |
423 } | |
424 | |
425 escape = 0; | |
426 | |
427 loc_len = r->valid_location ? u->conf->location->len : 1; | |
428 | |
429 if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { | |
430 len += r->unparsed_uri.len - 1; | |
431 | |
432 } else { | |
433 if (r->quoted_uri) { | |
434 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, | |
435 r->uri.len - loc_len, NGX_ESCAPE_URI); | |
436 } | |
437 | |
438 len += r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len; | |
439 } | |
440 | |
441 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | |
442 | |
443 le.ip = plcf->headers_set_len->elts; | |
444 le.request = r; | |
445 | |
446 while (*(uintptr_t *) le.ip) { | |
447 while (*(uintptr_t *) le.ip) { | |
448 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
449 len += lcode(&le); | |
450 } | |
451 le.ip += sizeof(uintptr_t); | |
452 } | |
453 | |
454 | |
455 hh = (ngx_str_t *) plcf->headers_set_hash->buckets; | |
456 | |
457 if (plcf->upstream.pass_request_headers) { | |
458 part = &r->headers_in.headers.part; | |
459 header = part->elts; | |
460 | |
461 for (i = 0; /* void */; i++) { | |
462 | |
463 if (i >= part->nelts) { | |
464 if (part->next == NULL) { | |
465 break; | |
466 } | |
467 | |
468 part = part->next; | |
469 header = part->elts; | |
470 i = 0; | |
471 } | |
472 | |
473 key = header[i].hash % plcf->headers_set_hash->hash_size; | |
474 | |
475 if (hh[key].len == header[i].key.len | |
476 && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) | |
477 { | |
478 continue; | |
479 } | |
480 | |
481 len += header[i].key.len + sizeof(": ") - 1 | |
482 + header[i].value.len + sizeof(CRLF) - 1; | |
483 } | |
484 } | |
485 | |
486 | |
487 b = ngx_create_temp_buf(r->pool, len); | |
488 if (b == NULL) { | |
489 return NGX_ERROR; | |
490 } | |
491 | |
492 cl = ngx_alloc_chain_link(r->pool); | |
493 if (cl == NULL) { | |
494 return NGX_ERROR; | |
495 } | |
496 | |
497 cl->buf = b; | |
498 | |
499 | |
500 /* the request line */ | |
501 | |
502 if (u->method) { | |
503 b->last = ngx_cpymem(b->last, | |
504 ngx_http_proxy_methods[u->method - 1].data, | |
505 ngx_http_proxy_methods[u->method - 1].len); | |
506 } else { | |
507 b->last = ngx_cpymem(b->last, r->method_name.data, | |
508 r->method_name.len + 1); | |
509 } | |
510 | |
511 b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len); | |
512 | |
513 if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { | |
514 b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1, | |
515 r->unparsed_uri.len - 1); | |
516 } else { | |
517 if (escape) { | |
518 ngx_escape_uri(b->last, r->uri.data + loc_len, | |
519 r->uri.len - loc_len, NGX_ESCAPE_URI); | |
520 b->last += r->uri.len - loc_len + escape; | |
521 | |
522 } else { | |
523 b->last = ngx_cpymem(b->last, r->uri.data + loc_len, | |
524 r->uri.len - loc_len); | |
525 } | |
526 | |
527 if (r->args.len > 0) { | |
528 *b->last++ = '?'; | |
529 b->last = ngx_cpymem(b->last, r->args.data, r->args.len); | |
530 } | |
531 } | |
532 | |
533 b->last = ngx_cpymem(b->last, ngx_http_proxy_version, | |
534 sizeof(ngx_http_proxy_version) - 1); | |
535 | |
536 | |
537 e.ip = plcf->headers_set->elts; | |
538 e.pos = b->last; | |
539 e.request = r; | |
540 | |
541 le.ip = plcf->headers_set_len->elts; | |
542 | |
543 while (*(uintptr_t *) le.ip) { | |
544 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
545 lcode(&le); | |
546 | |
547 if (*(ngx_http_script_len_code_pt *) le.ip) { | |
548 | |
549 for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { | |
550 lcode = *(ngx_http_script_len_code_pt *) le.ip; | |
551 } | |
552 | |
553 e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0; | |
554 | |
555 } else { | |
556 e.skip = 0; | |
557 } | |
558 | |
559 le.ip += sizeof(uintptr_t); | |
560 | |
561 while (*(uintptr_t *) e.ip) { | |
562 code = *(ngx_http_script_code_pt *) e.ip; | |
563 code((ngx_http_script_engine_t *) &e); | |
564 } | |
565 e.ip += sizeof(uintptr_t); | |
566 } | |
567 | |
568 b->last = e.pos; | |
569 | |
570 | |
571 if (plcf->upstream.pass_request_headers) { | |
572 part = &r->headers_in.headers.part; | |
573 header = part->elts; | |
574 | |
575 for (i = 0; /* void */; i++) { | |
576 | |
577 if (i >= part->nelts) { | |
578 if (part->next == NULL) { | |
579 break; | |
580 } | |
581 | |
582 part = part->next; | |
583 header = part->elts; | |
584 i = 0; | |
585 } | |
586 | |
587 key = header[i].hash % plcf->headers_set_hash->hash_size; | |
588 | |
589 if (hh[key].len == header[i].key.len | |
590 && ngx_strcasecmp(hh[key].data, header[i].key.data) == 0) | |
591 { | |
592 continue; | |
593 } | |
594 | |
595 b->last = ngx_cpymem(b->last, header[i].key.data, | |
596 header[i].key.len); | |
597 | |
598 *b->last++ = ':'; *b->last++ = ' '; | |
599 | |
600 b->last = ngx_cpymem(b->last, header[i].value.data, | |
601 header[i].value.len); | |
602 | |
603 *b->last++ = CR; *b->last++ = LF; | |
604 | |
605 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
606 "http proxy header: \"%V: %V\"", | |
607 &header[i].key, &header[i].value); | |
608 } | |
609 } | |
610 | |
611 /* add "\r\n" at the header end */ | |
612 *b->last++ = CR; *b->last++ = LF; | |
613 | |
614 #if (NGX_DEBUG) | |
615 { | |
616 ngx_str_t s; | |
617 | |
618 s.len = b->last - b->pos; | |
619 s.data = b->pos; | |
620 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
621 "http proxy header:\n\"%V\"", &s); | |
622 } | |
623 #endif | |
624 | |
625 if (plcf->upstream.pass_request_body) { | |
626 | |
627 body = u->request_bufs; | |
628 u->request_bufs = cl; | |
629 | |
630 while (body) { | |
631 b = ngx_alloc_buf(r->pool); | |
632 if (b == NULL) { | |
633 return NGX_ERROR; | |
634 } | |
635 | |
636 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); | |
637 | |
638 cl->next = ngx_alloc_chain_link(r->pool); | |
639 if (cl->next == NULL) { | |
640 return NGX_ERROR; | |
641 } | |
642 | |
643 cl = cl->next; | |
644 cl->buf = b; | |
645 | |
646 body = body->next; | |
647 } | |
648 | |
649 } else { | |
650 u->request_bufs = cl; | |
651 } | |
652 | |
653 cl->next = NULL; | |
654 | |
655 return NGX_OK; | |
656 } | |
657 | |
658 | |
659 static ngx_int_t | |
660 ngx_http_proxy_reinit_request(ngx_http_request_t *r) | |
661 { | |
662 ngx_http_proxy_ctx_t *p; | |
663 | |
664 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
665 | |
666 if (p == NULL) { | |
667 return NGX_OK; | |
668 } | |
669 | |
670 p->status = 0; | |
671 p->status_count = 0; | |
672 p->status_start = NULL; | |
673 p->status_end = NULL; | |
674 | |
675 r->upstream->process_header = ngx_http_proxy_process_status_line; | |
676 | |
677 return NGX_OK; | |
678 } | |
679 | |
680 | |
681 static ngx_int_t | |
682 ngx_http_proxy_process_status_line(ngx_http_request_t *r) | |
683 { | |
684 ngx_int_t rc; | |
685 ngx_http_upstream_t *u; | |
686 ngx_http_proxy_ctx_t *p; | |
687 | |
688 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); | |
689 | |
690 if (p == NULL) { | |
691 p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); | |
692 if (p == NULL) { | |
693 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
694 } | |
695 | |
696 ngx_http_set_ctx(r, p, ngx_http_proxy_module); | |
697 } | |
698 | |
699 rc = ngx_http_proxy_parse_status_line(r, p); | |
700 | |
701 if (rc == NGX_AGAIN) { | |
702 return rc; | |
703 } | |
704 | |
705 u = r->upstream; | |
706 | |
707 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { | |
708 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
709 "upstream sent no valid HTTP/1.0 header"); | |
710 | |
711 if (u->accel) { | |
712 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
713 } | |
714 | |
715 r->http_version = NGX_HTTP_VERSION_9; | |
716 p->status = NGX_HTTP_OK; | |
717 | |
718 return NGX_OK; | |
719 } | |
720 | |
721 r->headers_out.status = p->status; | |
722 u->state->status = p->status; | |
723 | |
724 r->headers_out.status_line.len = p->status_end - p->status_start; | |
725 r->headers_out.status_line.data = ngx_palloc(r->pool, | |
726 r->headers_out.status_line.len); | |
727 if (r->headers_out.status_line.data == NULL) { | |
728 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
729 } | |
730 ngx_memcpy(r->headers_out.status_line.data, p->status_start, | |
731 r->headers_out.status_line.len); | |
732 | |
733 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
734 "http proxy status %ui \"%V\"", | |
735 r->headers_out.status, &r->headers_out.status_line); | |
736 | |
737 u->process_header = ngx_http_proxy_process_header; | |
738 | |
739 return ngx_http_proxy_process_header(r); | |
740 } | |
741 | |
742 | |
743 static ngx_int_t | |
744 ngx_http_proxy_parse_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) | |
745 { | |
746 u_char ch; | |
747 u_char *pos; | |
748 ngx_http_upstream_t *u; | |
749 enum { | |
750 sw_start = 0, | |
751 sw_H, | |
752 sw_HT, | |
753 sw_HTT, | |
754 sw_HTTP, | |
755 sw_first_major_digit, | |
756 sw_major_digit, | |
757 sw_first_minor_digit, | |
758 sw_minor_digit, | |
759 sw_status, | |
760 sw_space_after_status, | |
761 sw_status_text, | |
762 sw_almost_done | |
763 } state; | |
764 | |
765 u = r->upstream; | |
766 | |
767 state = r->state; | |
768 | |
769 for (pos = u->header_in.pos; pos < u->header_in.last; pos++) { | |
770 ch = *pos; | |
771 | |
772 switch (state) { | |
773 | |
774 /* "HTTP/" */ | |
775 case sw_start: | |
776 switch (ch) { | |
777 case 'H': | |
778 state = sw_H; | |
779 break; | |
780 default: | |
781 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
782 } | |
783 break; | |
784 | |
785 case sw_H: | |
786 switch (ch) { | |
787 case 'T': | |
788 state = sw_HT; | |
789 break; | |
790 default: | |
791 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
792 } | |
793 break; | |
794 | |
795 case sw_HT: | |
796 switch (ch) { | |
797 case 'T': | |
798 state = sw_HTT; | |
799 break; | |
800 default: | |
801 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
802 } | |
803 break; | |
804 | |
805 case sw_HTT: | |
806 switch (ch) { | |
807 case 'P': | |
808 state = sw_HTTP; | |
809 break; | |
810 default: | |
811 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
812 } | |
813 break; | |
814 | |
815 case sw_HTTP: | |
816 switch (ch) { | |
817 case '/': | |
818 state = sw_first_major_digit; | |
819 break; | |
820 default: | |
821 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
822 } | |
823 break; | |
824 | |
825 /* the first digit of major HTTP version */ | |
826 case sw_first_major_digit: | |
827 if (ch < '1' || ch > '9') { | |
828 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
829 } | |
830 | |
831 state = sw_major_digit; | |
832 break; | |
833 | |
834 /* the major HTTP version or dot */ | |
835 case sw_major_digit: | |
836 if (ch == '.') { | |
837 state = sw_first_minor_digit; | |
838 break; | |
839 } | |
840 | |
841 if (ch < '0' || ch > '9') { | |
842 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
843 } | |
844 | |
845 break; | |
846 | |
847 /* the first digit of minor HTTP version */ | |
848 case sw_first_minor_digit: | |
849 if (ch < '0' || ch > '9') { | |
850 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
851 } | |
852 | |
853 state = sw_minor_digit; | |
854 break; | |
855 | |
856 /* the minor HTTP version or the end of the request line */ | |
857 case sw_minor_digit: | |
858 if (ch == ' ') { | |
859 state = sw_status; | |
860 break; | |
861 } | |
862 | |
863 if (ch < '0' || ch > '9') { | |
864 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
865 } | |
866 | |
867 break; | |
868 | |
869 /* HTTP status code */ | |
870 case sw_status: | |
871 if (ch < '0' || ch > '9') { | |
872 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
873 } | |
874 | |
875 p->status = p->status * 10 + ch - '0'; | |
876 | |
877 if (++p->status_count == 3) { | |
878 state = sw_space_after_status; | |
879 p->status_start = pos - 2; | |
880 } | |
881 | |
882 break; | |
883 | |
884 /* space or end of line */ | |
885 case sw_space_after_status: | |
886 switch (ch) { | |
887 case ' ': | |
888 state = sw_status_text; | |
889 break; | |
890 case '.': /* IIS may send 403.1, 403.2, etc */ | |
891 state = sw_status_text; | |
892 break; | |
893 case CR: | |
894 state = sw_almost_done; | |
895 break; | |
896 case LF: | |
897 goto done; | |
898 default: | |
899 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
900 } | |
901 break; | |
902 | |
903 /* any text until end of line */ | |
904 case sw_status_text: | |
905 switch (ch) { | |
906 case CR: | |
907 state = sw_almost_done; | |
908 | |
909 break; | |
910 case LF: | |
911 goto done; | |
912 } | |
913 break; | |
914 | |
915 /* end of request line */ | |
916 case sw_almost_done: | |
917 p->status_end = pos - 1; | |
918 switch (ch) { | |
919 case LF: | |
920 goto done; | |
921 default: | |
922 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
923 } | |
924 } | |
925 } | |
926 | |
927 u->header_in.pos = pos + 1; | |
928 r->state = state; | |
929 | |
930 return NGX_AGAIN; | |
931 | |
932 done: | |
933 | |
934 u->header_in.pos = pos + 1; | |
935 | |
936 if (p->status_end == NULL) { | |
937 p->status_end = pos; | |
938 } | |
939 | |
940 r->state = sw_start; | |
941 | |
942 return NGX_OK; | |
943 } | |
944 | |
945 | |
946 static ngx_int_t | |
947 ngx_http_proxy_process_header(ngx_http_request_t *r) | |
948 { | |
949 ngx_int_t rc; | |
950 ngx_uint_t key; | |
951 ngx_table_elt_t *h; | |
952 ngx_http_upstream_header_t *hh; | |
953 ngx_http_upstream_main_conf_t *umcf; | |
954 | |
955 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); | |
956 hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets; | |
957 | |
958 for ( ;; ) { | |
959 | |
960 rc = ngx_http_parse_header_line(r, &r->upstream->header_in); | |
961 | |
962 if (rc == NGX_OK) { | |
963 | |
964 /* a header line has been parsed successfully */ | |
965 | |
966 h = ngx_list_push(&r->upstream->headers_in.headers); | |
967 if (h == NULL) { | |
968 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
969 } | |
970 | |
971 h->hash = r->header_hash; | |
972 | |
973 h->key.len = r->header_name_end - r->header_name_start; | |
974 h->value.len = r->header_end - r->header_start; | |
975 | |
976 h->key.data = ngx_palloc(r->pool, | |
977 h->key.len + 1 + h->value.len + 1); | |
978 if (h->key.data == NULL) { | |
979 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
980 } | |
981 | |
982 h->value.data = h->key.data + h->key.len + 1; | |
983 | |
984 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); | |
985 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); | |
986 | |
987 key = h->hash % umcf->headers_in_hash.hash_size; | |
988 | |
989 if (hh[key].name.len == h->key.len | |
990 && ngx_strcasecmp(hh[key].name.data, h->key.data) == 0) | |
991 { | |
992 if (hh[key].handler(r, h, hh[key].offset) != NGX_OK) { | |
993 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
994 } | |
995 } | |
996 | |
997 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
998 "http proxy header: \"%V: %V\"", | |
999 &h->key, &h->value); | |
1000 | |
1001 continue; | |
1002 } | |
1003 | |
1004 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
1005 | |
1006 /* a whole header has been parsed successfully */ | |
1007 | |
1008 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1009 "http proxy header done"); | |
1010 | |
1011 return NGX_OK; | |
1012 } | |
1013 | |
1014 /* there was error while a header line parsing */ | |
1015 | |
1016 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1017 ngx_http_upstream_header_errors[rc | |
1018 - NGX_HTTP_PARSE_HEADER_ERROR]); | |
1019 | |
1020 return NGX_HTTP_UPSTREAM_INVALID_HEADER; | |
1021 } | |
1022 } | |
1023 | |
1024 | |
1025 static void | |
1026 ngx_http_proxy_abort_request(ngx_http_request_t *r) | |
1027 { | |
1028 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1029 "abort http proxy request"); | |
1030 | |
1031 return; | |
1032 } | |
1033 | |
1034 | |
1035 static void | |
1036 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc) | |
1037 { | |
1038 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1039 "finalize http proxy request"); | |
1040 | |
1041 return; | |
1042 } | |
1043 | |
1044 | |
1045 static ngx_http_variable_value_t * | |
1046 ngx_http_proxy_host_variable(ngx_http_request_t *r, uintptr_t data) | |
1047 { | |
1048 ngx_http_variable_value_t *vv; | |
1049 ngx_http_proxy_loc_conf_t *plcf; | |
1050 | |
1051 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); | |
1052 if (vv == NULL) { | |
1053 return NULL; | |
1054 } | |
1055 | |
1056 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
1057 | |
1058 vv->value = 0; | |
1059 vv->text = plcf->host_header; | |
1060 | |
1061 return vv; | |
1062 } | |
1063 | |
1064 | |
1065 static ngx_http_variable_value_t * | |
1066 ngx_http_proxy_port_variable(ngx_http_request_t *r, uintptr_t data) | |
1067 { | |
1068 ngx_http_variable_value_t *vv; | |
1069 ngx_http_proxy_loc_conf_t *plcf; | |
1070 | |
1071 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); | |
1072 if (vv == NULL) { | |
1073 return NULL; | |
1074 } | |
1075 | |
1076 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
1077 | |
1078 vv->value = 0; | |
1079 vv->text = plcf->port_text; | |
1080 | |
1081 return vv; | |
1082 } | |
1083 | |
1084 | |
1085 static ngx_http_variable_value_t * | |
1086 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r, | |
1087 uintptr_t data) | |
1088 { | |
1089 u_char *p; | |
1090 ngx_http_variable_value_t *vv; | |
1091 | |
1092 vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); | |
1093 if (vv == NULL) { | |
1094 return NULL; | |
1095 } | |
1096 | |
1097 vv->value = 0; | |
1098 | |
1099 if (r->headers_in.x_forwarded_for == NULL) { | |
1100 vv->text = r->connection->addr_text; | |
1101 return vv; | |
1102 } | |
1103 | |
1104 vv->text.len = r->headers_in.x_forwarded_for->value.len | |
1105 + sizeof(", ") - 1 + r->connection->addr_text.len; | |
1106 | |
1107 p = ngx_palloc(r->pool, vv->text.len); | |
1108 if (p == NULL) { | |
1109 return NULL; | |
1110 } | |
1111 | |
1112 vv->text.data = p; | |
1113 | |
1114 p = ngx_cpymem(p, r->headers_in.x_forwarded_for->value.data, | |
1115 r->headers_in.x_forwarded_for->value.len); | |
1116 | |
1117 *p++ = ','; *p++ = ' '; | |
1118 | |
1119 ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); | |
1120 | |
1121 return vv; | |
1122 } | |
1123 | |
1124 | |
1125 static ngx_int_t | |
1126 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, | |
1127 size_t prefix) | |
1128 { | |
1129 ngx_int_t rc; | |
1130 ngx_uint_t i; | |
1131 ngx_http_proxy_loc_conf_t *plcf; | |
1132 ngx_http_proxy_redirect_t *pr; | |
1133 | |
1134 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | |
1135 | |
1136 pr = plcf->redirects->elts; | |
1137 | |
1138 if (pr == NULL) { | |
1139 return NGX_DECLINED; | |
1140 } | |
1141 | |
1142 for (i = 0; i < plcf->redirects->nelts; i++) { | |
1143 rc = pr->handler(r, h, prefix, pr); | |
1144 | |
1145 if (rc != NGX_DECLINED) { | |
1146 return rc; | |
1147 } | |
1148 } | |
1149 | |
1150 return NGX_DECLINED; | |
1151 } | |
1152 | |
1153 | |
1154 static ngx_int_t | |
1155 ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h, | |
1156 size_t prefix, ngx_http_proxy_redirect_t *pr) | |
1157 { | |
1158 size_t len; | |
1159 u_char *data, *p; | |
1160 | |
1161 if (pr->redirect.len > h->value.len - prefix | |
1162 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | |
1163 pr->redirect.len) != 0) | |
1164 { | |
1165 return NGX_DECLINED; | |
1166 } | |
1167 | |
1168 len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len; | |
1169 | |
1170 data = ngx_palloc(r->pool, len); | |
1171 if (data == NULL) { | |
1172 return NGX_ERROR; | |
1173 } | |
1174 | |
1175 p = data; | |
1176 | |
1177 if (prefix) { | |
1178 p = ngx_cpymem(p, h->value.data, prefix); | |
1179 } | |
1180 | |
1181 p = ngx_cpymem(p, pr->replacement.text.data, pr->replacement.text.len); | |
1182 | |
1183 ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, | |
1184 h->value.len - pr->redirect.len - prefix); | |
1185 | |
1186 h->value.len = len; | |
1187 h->value.data = data; | |
1188 | |
1189 return NGX_OK; | |
1190 } | |
1191 | |
1192 | |
1193 static ngx_int_t | |
1194 ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h, | |
1195 size_t prefix, ngx_http_proxy_redirect_t *pr) | |
1196 { | |
1197 size_t len; | |
1198 u_char *data, *p; | |
1199 ngx_http_script_code_pt code; | |
1200 ngx_http_script_engine_t e; | |
1201 ngx_http_script_len_code_pt lcode; | |
1202 | |
1203 if (pr->redirect.len > h->value.len - prefix | |
1204 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | |
1205 pr->redirect.len) != 0) | |
1206 { | |
1207 return NGX_DECLINED; | |
1208 } | |
1209 | |
1210 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | |
1211 | |
1212 e.ip = pr->replacement.vars.lengths; | |
1213 e.request = r; | |
1214 | |
1215 for (len = prefix; *(uintptr_t *) e.ip; len += lcode(&e)) { | |
1216 lcode = *(ngx_http_script_len_code_pt *) e.ip; | |
1217 } | |
1218 | |
1219 data = ngx_palloc(r->pool, len); | |
1220 if (data == NULL) { | |
1221 return NGX_ERROR; | |
1222 } | |
1223 | |
1224 p = data; | |
1225 | |
1226 if (prefix) { | |
1227 p = ngx_cpymem(p, h->value.data, prefix); | |
1228 } | |
1229 | |
1230 e.ip = pr->replacement.vars.values; | |
1231 e.pos = p; | |
1232 | |
1233 while (*(uintptr_t *) e.ip) { | |
1234 code = *(ngx_http_script_code_pt *) e.ip; | |
1235 code(&e); | |
1236 } | |
1237 | |
1238 h->value.len = len; | |
1239 h->value.data = data; | |
1240 | |
1241 return NGX_OK; | |
1242 } | |
1243 | |
1244 | |
1245 static ngx_int_t | |
1246 ngx_http_proxy_add_variables(ngx_conf_t *cf) | |
1247 { | |
1248 ngx_http_variable_t *var, *v; | |
1249 | |
1250 for (v = ngx_http_proxy_vars; v->name.len; v++) { | |
1251 var = ngx_http_add_variable(cf, &v->name, v->flags); | |
1252 if (var == NULL) { | |
1253 return NGX_ERROR; | |
1254 } | |
1255 | |
1256 var->handler = v->handler; | |
1257 var->data = v->data; | |
1258 } | |
1259 | |
1260 return NGX_OK; | |
1261 } | |
1262 | |
1263 | |
1264 static void * | |
1265 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) | |
1266 { | |
1267 ngx_http_proxy_loc_conf_t *conf; | |
1268 | |
1269 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); | |
1270 if (conf == NULL) { | |
1271 return NGX_CONF_ERROR; | |
1272 } | |
1273 | |
1274 /* | |
1275 * set by ngx_pcalloc(): | |
1276 * | |
1277 * conf->upstream.bufs.num = 0; | |
1278 * conf->upstream.path = NULL; | |
1279 * conf->upstream.next_upstream = 0; | |
1280 * conf->upstream.temp_path = NULL; | |
1281 * conf->upstream.schema = { 0, NULL }; | |
1282 * conf->upstream.uri = { 0, NULL }; | |
1283 * conf->upstream.location = NULL; | |
1284 * | |
1285 * conf->headers_source = NULL; | |
1286 * conf->headers_set_len = NULL; | |
1287 * conf->headers_set = NULL; | |
1288 * conf->headers_set_hash = NULL; | |
1289 * conf->rewrite_locations = NULL; | |
1290 */ | |
1291 | |
1292 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; | |
1293 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; | |
1294 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; | |
1295 | |
1296 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; | |
1297 conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; | |
1298 conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; | |
1299 conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; | |
1300 conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; | |
1301 | |
1302 conf->upstream.pass_unparsed_uri = NGX_CONF_UNSET; | |
1303 conf->upstream.method = NGX_CONF_UNSET_UINT; | |
1304 conf->upstream.pass_request_headers = NGX_CONF_UNSET; | |
1305 conf->upstream.pass_request_body = NGX_CONF_UNSET; | |
1306 | |
1307 conf->upstream.redirect_errors = NGX_CONF_UNSET; | |
1308 | |
1309 /* "proxy_cyclic_temp_file" is disabled */ | |
1310 conf->upstream.cyclic_temp_file = 0; | |
1311 | |
1312 conf->upstream.pass_x_powered_by = NGX_CONF_UNSET; | |
1313 conf->upstream.pass_server = NGX_CONF_UNSET; | |
1314 conf->upstream.pass_date = 0; | |
1315 conf->upstream.pass_x_accel_expires = NGX_CONF_UNSET; | |
1316 | |
1317 conf->redirect = NGX_CONF_UNSET; | |
1318 | |
1319 return conf; | |
1320 } | |
1321 | |
1322 | |
1323 static char * | |
1324 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
1325 { | |
1326 ngx_http_proxy_loc_conf_t *prev = parent; | |
1327 ngx_http_proxy_loc_conf_t *conf = child; | |
1328 | |
1329 u_char *p; | |
1330 size_t size; | |
1331 uintptr_t *code; | |
1332 ngx_str_t *name; | |
1333 ngx_uint_t i; | |
1334 ngx_table_elt_t *src, *s, *h; | |
1335 ngx_http_proxy_redirect_t *pr; | |
1336 ngx_http_script_compile_t sc; | |
1337 ngx_http_script_copy_code_t *copy; | |
1338 | |
1339 ngx_conf_merge_msec_value(conf->upstream.connect_timeout, | |
1340 prev->upstream.connect_timeout, 60000); | |
1341 | |
1342 ngx_conf_merge_msec_value(conf->upstream.send_timeout, | |
1343 prev->upstream.send_timeout, 60000); | |
1344 | |
1345 ngx_conf_merge_msec_value(conf->upstream.read_timeout, | |
1346 prev->upstream.read_timeout, 60000); | |
1347 | |
1348 ngx_conf_merge_size_value(conf->upstream.send_lowat, | |
1349 prev->upstream.send_lowat, 0); | |
1350 | |
1351 ngx_conf_merge_size_value(conf->upstream.header_buffer_size, | |
1352 prev->upstream.header_buffer_size, | |
1353 (size_t) ngx_pagesize); | |
1354 | |
1355 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, | |
1356 8, ngx_pagesize); | |
1357 | |
1358 if (conf->upstream.bufs.num < 2) { | |
1359 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1360 "there must be at least 2 \"proxy_buffers\""); | |
1361 return NGX_CONF_ERROR; | |
1362 } | |
1363 | |
1364 | |
1365 size = conf->upstream.header_buffer_size; | |
1366 if (size < conf->upstream.bufs.size) { | |
1367 size = conf->upstream.bufs.size; | |
1368 } | |
1369 | |
1370 | |
1371 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, | |
1372 prev->upstream.busy_buffers_size, | |
1373 NGX_CONF_UNSET_SIZE); | |
1374 | |
1375 if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { | |
1376 conf->upstream.busy_buffers_size = 2 * size; | |
1377 | |
1378 } else if (conf->upstream.busy_buffers_size < size) { | |
1379 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1380 "\"proxy_busy_buffers_size\" must be equal or bigger than " | |
1381 "maximum of the value of \"proxy_header_buffer_size\" and " | |
1382 "one of the \"proxy_buffers\""); | |
1383 | |
1384 return NGX_CONF_ERROR; | |
1385 | |
1386 } else if (conf->upstream.busy_buffers_size | |
1387 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) | |
1388 { | |
1389 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1390 "\"proxy_busy_buffers_size\" must be less than " | |
1391 "the size of all \"proxy_buffers\" minus one buffer"); | |
1392 | |
1393 return NGX_CONF_ERROR; | |
1394 } | |
1395 | |
1396 | |
1397 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, | |
1398 prev->upstream.temp_file_write_size, | |
1399 NGX_CONF_UNSET_SIZE); | |
1400 | |
1401 if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { | |
1402 conf->upstream.temp_file_write_size = 2 * size; | |
1403 | |
1404 } else if (conf->upstream.temp_file_write_size < size) { | |
1405 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1406 "\"proxy_temp_file_write_size\" must be equal or bigger than " | |
1407 "maximum of the value of \"proxy_header_buffer_size\" and " | |
1408 "one of the \"proxy_buffers\""); | |
1409 | |
1410 return NGX_CONF_ERROR; | |
1411 } | |
1412 | |
1413 | |
1414 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, | |
1415 prev->upstream.max_temp_file_size, | |
1416 NGX_CONF_UNSET_SIZE); | |
1417 | |
1418 if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { | |
1419 | |
1420 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; | |
1421 | |
1422 } else if (conf->upstream.max_temp_file_size != 0 | |
1423 && conf->upstream.max_temp_file_size < size) | |
1424 { | |
1425 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1426 "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " | |
1427 "the temporary files usage or must be equal or bigger than " | |
1428 "maximum of the value of \"fastcgi_header_buffer_size\" and " | |
1429 "one of the \"fastcgi_buffers\""); | |
1430 | |
1431 return NGX_CONF_ERROR; | |
1432 } | |
1433 | |
1434 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, | |
1435 prev->upstream.next_upstream, | |
1436 (NGX_CONF_BITMASK_SET | |
1437 |NGX_HTTP_UPSTREAM_FT_ERROR | |
1438 |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); | |
1439 | |
1440 ngx_conf_merge_path_value(conf->upstream.temp_path, | |
1441 prev->upstream.temp_path, | |
1442 NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, | |
1443 ngx_garbage_collector_temp_handler, cf); | |
1444 | |
1445 ngx_conf_merge_msec_value(conf->upstream.pass_unparsed_uri, | |
1446 prev->upstream.pass_unparsed_uri, 0); | |
1447 | |
1448 if (conf->upstream.pass_unparsed_uri && conf->upstream.location->len > 1) { | |
1449 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
1450 "\"proxy_pass_unparsed_uri\" can be set for " | |
1451 "location \"/\" or given by regular expression."); | |
1452 return NGX_CONF_ERROR; | |
1453 } | |
1454 | |
1455 if (conf->upstream.method == NGX_CONF_UNSET_UINT) { | |
1456 conf->upstream.method = prev->upstream.method; | |
1457 } | |
1458 | |
1459 ngx_conf_merge_value(conf->upstream.pass_request_headers, | |
1460 prev->upstream.pass_request_headers, 1); | |
1461 ngx_conf_merge_value(conf->upstream.pass_request_body, | |
1462 prev->upstream.pass_request_body, 1); | |
1463 | |
1464 ngx_conf_merge_msec_value(conf->upstream.redirect_errors, | |
1465 prev->upstream.redirect_errors, 0); | |
1466 | |
1467 ngx_conf_merge_msec_value(conf->upstream.pass_x_powered_by, | |
1468 prev->upstream.pass_x_powered_by, 1); | |
1469 ngx_conf_merge_msec_value(conf->upstream.pass_server, | |
1470 prev->upstream.pass_server, 0); | |
1471 ngx_conf_merge_msec_value(conf->upstream.pass_x_accel_expires, | |
1472 prev->upstream.pass_x_accel_expires, 0); | |
1473 | |
1474 | |
1475 ngx_conf_merge_value(conf->redirect, prev->redirect, 1); | |
1476 | |
1477 if (conf->redirect) { | |
1478 | |
1479 if (conf->redirects == NULL) { | |
1480 conf->redirects = prev->redirects; | |
1481 } | |
1482 | |
1483 if (conf->redirects == NULL && conf->upstream.url.data) { | |
1484 | |
1485 conf->redirects = ngx_array_create(cf->pool, 1, | |
1486 sizeof(ngx_http_proxy_redirect_t)); | |
1487 if (conf->redirects == NULL) { | |
1488 return NGX_CONF_ERROR; | |
1489 } | |
1490 | |
1491 pr = ngx_array_push(conf->redirects); | |
1492 if (pr == NULL) { | |
1493 return NGX_CONF_ERROR; | |
1494 } | |
1495 | |
1496 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
1497 pr->redirect = conf->upstream.url; | |
1498 pr->replacement.text = *conf->upstream.location; | |
1499 } | |
1500 } | |
1501 | |
1502 | |
1503 if (conf->peers == NULL) { | |
1504 conf->peers = prev->peers; | |
1505 conf->upstream = prev->upstream; | |
1506 } | |
1507 | |
1508 if (conf->headers_source == NULL) { | |
1509 conf->headers_source = prev->headers_source; | |
1510 conf->headers_set_len = prev->headers_set_len; | |
1511 conf->headers_set = prev->headers_set; | |
1512 conf->headers_set_hash = prev->headers_set_hash; | |
1513 } | |
1514 | |
1515 if (conf->headers_set_hash) { | |
1516 return NGX_CONF_OK; | |
1517 } | |
1518 | |
1519 | |
1520 conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); | |
1521 if (conf->headers_names == NULL) { | |
1522 return NGX_CONF_ERROR; | |
1523 } | |
1524 | |
1525 if (conf->headers_source == NULL) { | |
1526 conf->headers_source = ngx_array_create(cf->pool, 4, | |
1527 sizeof(ngx_table_elt_t)); | |
1528 if (conf->headers_source == NULL) { | |
1529 return NGX_CONF_ERROR; | |
1530 } | |
1531 } | |
1532 | |
1533 conf->headers_set_len = ngx_array_create(cf->pool, 64, 1); | |
1534 if (conf->headers_set_len == NULL) { | |
1535 return NGX_CONF_ERROR; | |
1536 } | |
1537 | |
1538 conf->headers_set = ngx_array_create(cf->pool, 512, 1); | |
1539 if (conf->headers_set == NULL) { | |
1540 return NGX_CONF_ERROR; | |
1541 } | |
1542 | |
1543 | |
1544 src = conf->headers_source->elts; | |
1545 | |
1546 for (h = ngx_http_proxy_headers; h->key.len; h++) { | |
1547 | |
1548 for (i = 0; i < conf->headers_source->nelts; i++) { | |
1549 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { | |
1550 goto next; | |
1551 } | |
1552 } | |
1553 | |
1554 s = ngx_array_push(conf->headers_source); | |
1555 if (s == NULL) { | |
1556 return NGX_CONF_ERROR; | |
1557 } | |
1558 | |
1559 *s = *h; | |
1560 | |
1561 next: | |
1562 | |
1563 continue; | |
1564 } | |
1565 | |
1566 for (i = 0; i < conf->headers_source->nelts; i++) { | |
1567 | |
1568 name = ngx_array_push(conf->headers_names); | |
1569 if (name == NULL) { | |
1570 return NGX_CONF_ERROR; | |
1571 } | |
1572 | |
1573 *name = src[i].key; | |
1574 | |
1575 if (ngx_http_script_variables_count(&src[i].value) == 0) { | |
1576 copy = ngx_array_push_n(conf->headers_set_len, | |
1577 sizeof(ngx_http_script_copy_code_t)); | |
1578 if (copy == NULL) { | |
1579 return NGX_CONF_ERROR; | |
1580 } | |
1581 | |
1582 copy->code = (ngx_http_script_code_pt) | |
1583 ngx_http_script_copy_len_code; | |
1584 copy->len = src[i].key.len + sizeof(": ") - 1 | |
1585 + src[i].value.len + sizeof(CRLF) - 1; | |
1586 | |
1587 | |
1588 size = (sizeof(ngx_http_script_copy_code_t) | |
1589 + src[i].key.len + sizeof(": ") - 1 | |
1590 + src[i].value.len + sizeof(CRLF) - 1 | |
1591 + sizeof(uintptr_t) - 1) | |
1592 & ~(sizeof(uintptr_t) - 1); | |
1593 | |
1594 copy = ngx_array_push_n(conf->headers_set, size); | |
1595 if (copy == NULL) { | |
1596 return NGX_CONF_ERROR; | |
1597 } | |
1598 | |
1599 copy->code = ngx_http_script_copy_code; | |
1600 copy->len = src[i].key.len + sizeof(": ") - 1 | |
1601 + src[i].value.len + sizeof(CRLF) - 1; | |
1602 | |
1603 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
1604 | |
1605 p = ngx_cpymem(p, src[i].key.data, src[i].key.len); | |
1606 *p++ = ':'; *p++ = ' '; | |
1607 p = ngx_cpymem(p, src[i].value.data, src[i].value.len); | |
1608 *p++ = CR; *p = LF; | |
1609 | |
1610 } else { | |
1611 copy = ngx_array_push_n(conf->headers_set_len, | |
1612 sizeof(ngx_http_script_copy_code_t)); | |
1613 if (copy == NULL) { | |
1614 return NGX_CONF_ERROR; | |
1615 } | |
1616 | |
1617 copy->code = (ngx_http_script_code_pt) | |
1618 ngx_http_script_copy_len_code; | |
1619 copy->len = src[i].key.len + sizeof(": ") - 1; | |
1620 | |
1621 | |
1622 size = (sizeof(ngx_http_script_copy_code_t) | |
1623 + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) | |
1624 & ~(sizeof(uintptr_t) - 1); | |
1625 | |
1626 copy = ngx_array_push_n(conf->headers_set, size); | |
1627 if (copy == NULL) { | |
1628 return NGX_CONF_ERROR; | |
1629 } | |
1630 | |
1631 copy->code = ngx_http_script_copy_code; | |
1632 copy->len = src[i].key.len + sizeof(": ") - 1; | |
1633 | |
1634 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
1635 p = ngx_cpymem(p, src[i].key.data, src[i].key.len); | |
1636 *p++ = ':'; *p = ' '; | |
1637 | |
1638 | |
1639 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
1640 | |
1641 sc.cf = cf; | |
1642 sc.source = &src[i].value; | |
1643 sc.lengths = &conf->headers_set_len; | |
1644 sc.values = &conf->headers_set; | |
1645 | |
1646 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
1647 return NGX_CONF_ERROR; | |
1648 } | |
1649 | |
1650 | |
1651 copy = ngx_array_push_n(conf->headers_set_len, | |
1652 sizeof(ngx_http_script_copy_code_t)); | |
1653 if (copy == NULL) { | |
1654 return NGX_CONF_ERROR; | |
1655 } | |
1656 | |
1657 copy->code = (ngx_http_script_code_pt) | |
1658 ngx_http_script_copy_len_code; | |
1659 copy->len = sizeof(CRLF) - 1; | |
1660 | |
1661 | |
1662 size = (sizeof(ngx_http_script_copy_code_t) | |
1663 + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) | |
1664 & ~(sizeof(uintptr_t) - 1); | |
1665 | |
1666 copy = ngx_array_push_n(conf->headers_set, size); | |
1667 if (copy == NULL) { | |
1668 return NGX_CONF_ERROR; | |
1669 } | |
1670 | |
1671 copy->code = ngx_http_script_copy_code; | |
1672 copy->len = sizeof(CRLF) - 1; | |
1673 | |
1674 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); | |
1675 *p++ = CR; *p = LF; | |
1676 } | |
1677 | |
1678 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); | |
1679 if (code == NULL) { | |
1680 return NGX_CONF_ERROR; | |
1681 } | |
1682 | |
1683 *code = (uintptr_t) NULL; | |
1684 | |
1685 code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t)); | |
1686 if (code == NULL) { | |
1687 return NGX_CONF_ERROR; | |
1688 } | |
1689 | |
1690 *code = (uintptr_t) NULL; | |
1691 } | |
1692 | |
1693 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); | |
1694 if (code == NULL) { | |
1695 return NGX_CONF_ERROR; | |
1696 } | |
1697 | |
1698 *code = (uintptr_t) NULL; | |
1699 | |
1700 | |
1701 conf->headers_set_hash = ngx_pcalloc(cf->pool, sizeof(ngx_hash_t)); | |
1702 if (conf->headers_set_hash == NULL) { | |
1703 return NGX_CONF_ERROR; | |
1704 } | |
1705 | |
1706 conf->headers_set_hash->max_size = 100; | |
1707 conf->headers_set_hash->bucket_limit = 1; | |
1708 conf->headers_set_hash->bucket_size = sizeof(ngx_str_t); | |
1709 conf->headers_set_hash->name = "proxy_headers"; | |
1710 | |
1711 if (ngx_hash_init(conf->headers_set_hash, cf->pool, | |
1712 conf->headers_names->elts, conf->headers_names->nelts) != NGX_OK) | |
1713 { | |
1714 return NGX_CONF_ERROR; | |
1715 } | |
1716 | |
1717 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, | |
1718 "proxy_headers hash size: %ui, " | |
1719 "max buckets per entry: %ui", | |
1720 conf->headers_set_hash->hash_size, | |
1721 conf->headers_set_hash->min_buckets); | |
1722 | |
1723 return NGX_CONF_OK; | |
1724 } | |
1725 | |
1726 | |
1727 static char * | |
1728 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
1729 { | |
1730 ngx_http_proxy_loc_conf_t *plcf = conf; | |
1731 | |
1732 ngx_uint_t i; | |
1733 ngx_str_t *value, *url; | |
1734 ngx_inet_upstream_t inet_upstream; | |
1735 ngx_http_core_loc_conf_t *clcf; | |
1736 #if (NGX_HAVE_UNIX_DOMAIN) | |
1737 ngx_unix_domain_upstream_t unix_upstream; | |
1738 #endif | |
1739 | |
1740 value = cf->args->elts; | |
1741 | |
1742 url = &value[1]; | |
1743 | |
1744 if (ngx_strncasecmp(url->data, "http://", 7) != 0) { | |
1745 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); | |
1746 return NGX_CONF_ERROR; | |
1747 } | |
1748 | |
1749 if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { | |
1750 | |
1751 #if (NGX_HAVE_UNIX_DOMAIN) | |
1752 | |
1753 ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); | |
1754 | |
1755 unix_upstream.name = *url; | |
1756 unix_upstream.url.len = url->len - 7; | |
1757 unix_upstream.url.data = url->data + 7; | |
1758 unix_upstream.uri_part = 1; | |
1759 | |
1760 plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); | |
1761 if (plcf->peers == NULL) { | |
1762 return NGX_CONF_ERROR; | |
1763 } | |
1764 | |
1765 plcf->peers->peer[0].uri_separator = ":"; | |
1766 | |
1767 plcf->host_header.len = sizeof("localhost") - 1; | |
1768 plcf->host_header.data = (u_char *) "localhost"; | |
1769 plcf->upstream.uri = unix_upstream.uri; | |
1770 | |
1771 #else | |
1772 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1773 "the unix domain sockets are not supported " | |
1774 "on this platform"); | |
1775 return NGX_CONF_ERROR; | |
1776 | |
1777 #endif | |
1778 | |
1779 } else { | |
1780 ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); | |
1781 | |
1782 inet_upstream.name = *url; | |
1783 inet_upstream.url.len = url->len - 7; | |
1784 inet_upstream.url.data = url->data + 7; | |
1785 inet_upstream.default_port_value = 80; | |
1786 inet_upstream.uri_part = 1; | |
1787 | |
1788 plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); | |
1789 if (plcf->peers == NULL) { | |
1790 return NGX_CONF_ERROR; | |
1791 } | |
1792 | |
1793 for (i = 0; i < plcf->peers->number; i++) { | |
1794 plcf->peers->peer[i].uri_separator = ":"; | |
1795 } | |
1796 | |
1797 plcf->host_header = inet_upstream.host_header; | |
1798 plcf->port_text = inet_upstream.port_text; | |
1799 plcf->upstream.uri = inet_upstream.uri; | |
1800 } | |
1801 | |
1802 plcf->upstream.schema.len = sizeof("http://") - 1; | |
1803 plcf->upstream.schema.data = (u_char *) "http://"; | |
1804 | |
1805 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); | |
1806 | |
1807 clcf->handler = ngx_http_proxy_handler; | |
1808 | |
1809 #if (NGX_PCRE) | |
1810 plcf->upstream.location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; | |
1811 #else | |
1812 plcf->upstream.location = &clcf->name; | |
1813 #endif | |
1814 | |
1815 plcf->upstream.url = *url; | |
1816 | |
1817 if (clcf->name.data[clcf->name.len - 1] == '/') { | |
1818 clcf->auto_redirect = 1; | |
1819 } | |
1820 | |
1821 return NGX_CONF_OK; | |
1822 } | |
1823 | |
1824 | |
1825 static char * | |
1826 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
1827 { | |
1828 ngx_http_proxy_loc_conf_t *plcf = conf; | |
1829 | |
1830 ngx_str_t *value; | |
1831 ngx_array_t *vars_lengths, *vars_values; | |
1832 ngx_http_script_compile_t sc; | |
1833 ngx_http_proxy_redirect_t *pr; | |
1834 | |
1835 if (plcf->redirect == 0) { | |
1836 return NGX_CONF_OK; | |
1837 } | |
1838 | |
1839 value = cf->args->elts; | |
1840 | |
1841 if (ngx_strcmp(value[1].data, "off") == 0) { | |
1842 plcf->redirect = 0; | |
1843 plcf->redirects = NULL; | |
1844 return NGX_CONF_OK; | |
1845 } | |
1846 | |
1847 if (plcf->redirects == NULL) { | |
1848 plcf->redirects = ngx_array_create(cf->pool, 1, | |
1849 sizeof(ngx_http_proxy_redirect_t)); | |
1850 if (plcf->redirects == NULL) { | |
1851 return NGX_CONF_ERROR; | |
1852 } | |
1853 } | |
1854 | |
1855 pr = ngx_array_push(plcf->redirects); | |
1856 if (pr == NULL) { | |
1857 return NGX_CONF_ERROR; | |
1858 } | |
1859 | |
1860 if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { | |
1861 if (plcf->upstream.url.data == NULL) { | |
1862 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1863 "\"proxy_rewrite_location default\" must go " | |
1864 "after the \"proxy_pass\" directive"); | |
1865 return NGX_CONF_ERROR; | |
1866 } | |
1867 | |
1868 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
1869 pr->redirect = plcf->upstream.url; | |
1870 pr->replacement.text = *plcf->upstream.location; | |
1871 | |
1872 return NGX_CONF_OK; | |
1873 } | |
1874 | |
1875 if (ngx_http_script_variables_count(&value[2]) == 0) { | |
1876 pr->handler = ngx_http_proxy_rewrite_redirect_text; | |
1877 pr->redirect = value[1]; | |
1878 pr->replacement.text = value[2]; | |
1879 | |
1880 return NGX_CONF_OK; | |
1881 } | |
1882 | |
1883 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | |
1884 | |
1885 vars_lengths = NULL; | |
1886 vars_values = NULL; | |
1887 | |
1888 sc.cf = cf; | |
1889 sc.source = &value[2]; | |
1890 sc.lengths = &vars_lengths; | |
1891 sc.values = &vars_values; | |
1892 sc.complete_lengths = 1; | |
1893 sc.complete_values = 1; | |
1894 | |
1895 if (ngx_http_script_compile(&sc) != NGX_OK) { | |
1896 return NGX_CONF_ERROR; | |
1897 } | |
1898 | |
1899 pr->handler = ngx_http_proxy_rewrite_redirect_vars; | |
1900 pr->redirect = value[1]; | |
1901 pr->replacement.vars.lengths = vars_lengths->elts; | |
1902 pr->replacement.vars.values = vars_values->elts; | |
1903 | |
1904 return NGX_CONF_OK; | |
1905 } | |
1906 | |
1907 | |
1908 static char * | |
1909 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) | |
1910 { | |
1911 #if (NGX_FREEBSD) | |
1912 ssize_t *np = data; | |
1913 | |
1914 if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { | |
1915 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1916 "\"proxy_send_lowat\" must be less than %d " | |
1917 "(sysctl net.inet.tcp.sendspace)", | |
1918 ngx_freebsd_net_inet_tcp_sendspace); | |
1919 | |
1920 return NGX_CONF_ERROR; | |
1921 } | |
1922 | |
1923 #elif !(NGX_HAVE_SO_SNDLOWAT) | |
1924 ssize_t *np = data; | |
1925 | |
1926 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
1927 "\"proxy_send_lowat\" is not supported, ignored"); | |
1928 | |
1929 *np = 0; | |
1930 | |
1931 #endif | |
1932 | |
1933 return NGX_CONF_OK; | |
1934 } |