blob: b4a0d425d5474765ea180e08a6db5aca31082438 [file] [log] [blame]
Igor Sysoev04410502003-08-01 14:56:33 +00001
2#include <ngx_config.h>
3#include <ngx_core.h>
4#include <ngx_event.h>
Igor Sysoev419f9ac2003-10-21 16:49:56 +00005#include <ngx_event_connect.h>
6#include <ngx_event_pipe.h>
Igor Sysoev04410502003-08-01 14:56:33 +00007#include <ngx_http.h>
8#include <ngx_http_proxy_handler.h>
9
10
11
Igor Sysoeve6779222003-10-03 15:50:53 +000012static int ngx_http_proxy_handler(ngx_http_request_t *r);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000013static void ngx_http_proxy_init_request(void *data);
Igor Sysoeve6779222003-10-03 15:50:53 +000014static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
15static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
16static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
17static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
18static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
19static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
Igor Sysoev931a4002003-10-07 15:30:05 +000020static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
Igor Sysoev54276be2003-10-20 17:14:07 +000021static void ngx_http_proxy_process_body(ngx_event_t *ev);
Igor Sysoev931a4002003-10-07 15:30:05 +000022
Igor Sysoeve6779222003-10-03 15:50:53 +000023static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000024static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
Igor Sysoev931a4002003-10-07 15:30:05 +000025static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
Igor Sysoev87a01ea2003-10-02 05:39:37 +000026static void ngx_http_proxy_close_connection(ngx_connection_t *c);
Igor Sysoeve6779222003-10-03 15:50:53 +000027
Igor Sysoev6414b962003-10-24 16:10:38 +000028static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len);
29
Igor Sysoeve6779222003-10-03 15:50:53 +000030static int ngx_http_proxy_init(ngx_cycle_t *cycle);
Igor Sysoevae5c59c2003-08-14 06:00:28 +000031static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
Igor Sysoevdc9dd432003-10-22 16:38:26 +000032static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
33 void *parent, void *child);
Igor Sysoevae5c59c2003-08-14 06:00:28 +000034
Igor Sysoevd404c972003-10-16 20:19:16 +000035static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
36 void *conf);
37static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
38 ngx_http_proxy_upstream_t *u);
39
Igor Sysoevae5c59c2003-08-14 06:00:28 +000040
Igor Sysoev04410502003-08-01 14:56:33 +000041static ngx_command_t ngx_http_proxy_commands[] = {
Igor Sysoevd404c972003-10-16 20:19:16 +000042
43 {ngx_string("proxy_pass"),
44 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
45 ngx_http_proxy_set_pass,
46 NGX_HTTP_LOC_CONF_OFFSET,
47 0,
48 NULL},
49
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000050 {ngx_string("proxy_request_buffer_size"),
51 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
52 ngx_conf_set_size_slot,
53 NGX_HTTP_LOC_CONF_OFFSET,
54 offsetof(ngx_http_proxy_loc_conf_t, request_buffer_size),
55 NULL},
56
Igor Sysoevdc9dd432003-10-22 16:38:26 +000057 {ngx_string("proxy_connect_timeout"),
58 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
59 ngx_conf_set_msec_slot,
60 NGX_HTTP_LOC_CONF_OFFSET,
61 offsetof(ngx_http_proxy_loc_conf_t, connect_timeout),
62 NULL},
63
64 {ngx_string("proxy_send_timeout"),
65 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
66 ngx_conf_set_msec_slot,
67 NGX_HTTP_LOC_CONF_OFFSET,
68 offsetof(ngx_http_proxy_loc_conf_t, send_timeout),
69 NULL},
70
71 {ngx_string("proxy_header_buffer_size"),
72 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
73 ngx_conf_set_size_slot,
74 NGX_HTTP_LOC_CONF_OFFSET,
75 offsetof(ngx_http_proxy_loc_conf_t, header_buffer_size),
76 NULL},
77
78 {ngx_string("proxy_read_timeout"),
79 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
80 ngx_conf_set_msec_slot,
81 NGX_HTTP_LOC_CONF_OFFSET,
82 offsetof(ngx_http_proxy_loc_conf_t, read_timeout),
83 NULL},
84
85 {ngx_string("proxy_buffers"),
86 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
87 ngx_conf_set_bufs_slot,
88 NGX_HTTP_LOC_CONF_OFFSET,
89 offsetof(ngx_http_proxy_loc_conf_t, bufs),
90 NULL},
91
92 {ngx_string("proxy_busy_buffers_size"),
93 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
94 ngx_conf_set_size_slot,
95 NGX_HTTP_LOC_CONF_OFFSET,
96 offsetof(ngx_http_proxy_loc_conf_t, busy_buffers_size),
97 NULL},
98
99 {ngx_string("proxy_temp_path"),
100 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
101 ngx_conf_set_path_slot,
102 NGX_HTTP_LOC_CONF_OFFSET,
103 offsetof(ngx_http_proxy_loc_conf_t, temp_path),
104 NULL},
105
106 {ngx_string("proxy_temp_file_write_size"),
107 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
108 ngx_conf_set_size_slot,
109 NGX_HTTP_LOC_CONF_OFFSET,
110 offsetof(ngx_http_proxy_loc_conf_t, temp_file_write_size),
111 NULL},
112
Igor Sysoev04410502003-08-01 14:56:33 +0000113 ngx_null_command
114};
115
116
117ngx_http_module_t ngx_http_proxy_module_ctx = {
118 NULL, /* create main configuration */
119 NULL, /* init main configuration */
120
121 NULL, /* create server configuration */
122 NULL, /* merge server configuration */
123
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000124 ngx_http_proxy_create_loc_conf, /* create location configration */
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000125 ngx_http_proxy_merge_loc_conf /* merge location configration */
Igor Sysoev04410502003-08-01 14:56:33 +0000126};
127
128
129ngx_module_t ngx_http_proxy_module = {
130 NGX_MODULE,
131 &ngx_http_proxy_module_ctx, /* module context */
132 ngx_http_proxy_commands, /* module directives */
133 NGX_HTTP_MODULE, /* module type */
Igor Sysoevd404c972003-10-16 20:19:16 +0000134 NULL, /* init module */
Igor Sysoev04410502003-08-01 14:56:33 +0000135 NULL /* init child */
136};
137
138
Igor Sysoeve6779222003-10-03 15:50:53 +0000139static ngx_str_t http_methods[] = {
140 ngx_string("GET "),
141 ngx_string("HEAD "),
142 ngx_string("POST ")
143};
144
145
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000146static char *upstream_header_errors[] = {
Igor Sysoeve6779222003-10-03 15:50:53 +0000147 "upstream sent invalid header",
148 "upstream sent too long header line"
149};
Igor Sysoev04410502003-08-01 14:56:33 +0000150
Igor Sysoeve6779222003-10-03 15:50:53 +0000151
152static ngx_http_header_t headers_in[] = {
153 { ngx_string("Date"), offsetof(ngx_http_proxy_headers_in_t, date) },
154 { ngx_string("Server"), offsetof(ngx_http_proxy_headers_in_t, server) },
155 { ngx_string("Connection"),
156 offsetof(ngx_http_proxy_headers_in_t, connection) },
157 { ngx_string("Content-Type"),
158 offsetof(ngx_http_proxy_headers_in_t, content_type) },
159 { ngx_string("Content-Length"),
160 offsetof(ngx_http_proxy_headers_in_t, content_length) },
161 { ngx_string("Last-Modified"),
162 offsetof(ngx_http_proxy_headers_in_t, last_modified) },
Igor Sysoev931a4002003-10-07 15:30:05 +0000163 { ngx_string("Accept-Ranges"),
164 offsetof(ngx_http_proxy_headers_in_t, accept_ranges) },
Igor Sysoeve6779222003-10-03 15:50:53 +0000165
166 { ngx_null_string, 0 }
167};
168
169
170static char http_version[] = " HTTP/1.0" CRLF;
171static char host_header[] = "Host: ";
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000172static char connection_close_header[] = "Connection: close" CRLF;
Igor Sysoeve6779222003-10-03 15:50:53 +0000173
174
175
Igor Sysoeve6779222003-10-03 15:50:53 +0000176static int ngx_http_proxy_handler(ngx_http_request_t *r)
Igor Sysoev04410502003-08-01 14:56:33 +0000177{
Igor Sysoevd404c972003-10-16 20:19:16 +0000178 ngx_http_proxy_ctx_t *p;
Igor Sysoev04410502003-08-01 14:56:33 +0000179
180 ngx_http_create_ctx(r, p, ngx_http_proxy_module,
181 sizeof(ngx_http_proxy_ctx_t),
182 NGX_HTTP_INTERNAL_SERVER_ERROR);
183
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000184 p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000185 p->upstream.peers = p->lcf->peers;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000186 p->upstream.tries = p->lcf->peers->number;
Igor Sysoev04410502003-08-01 14:56:33 +0000187
Igor Sysoeve6779222003-10-03 15:50:53 +0000188 p->request = r;
189 p->method = r->method;
Igor Sysoevd404c972003-10-16 20:19:16 +0000190
Igor Sysoev6414b962003-10-24 16:10:38 +0000191 /* TODO: we currently support reverse proxy only */
192 p->accel = 1;
Igor Sysoev931a4002003-10-07 15:30:05 +0000193
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000194 if (r->headers_in.content_length_n > 0) {
195 ngx_test_null(r->temp_file,
196 ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)),
197 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000198
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000199 r->temp_file->file.fd = NGX_INVALID_FILE;
200 r->temp_file->file.log = r->connection->log;
201 r->temp_file->path = *p->lcf->temp_path;
202 r->temp_file->pool = r->pool;
203 r->temp_file->warn = "a client request body is buffered "
204 "to a temporary file";
205 /* STUB */ r->temp_file->persistent = 1;
206
207 r->request_body_handler = ngx_http_proxy_init_request;
208 r->data = p;
209
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000210 ngx_http_read_client_request_body(r, p->lcf->request_buffer_size);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000211
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000212 return NGX_DONE;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000213 }
214
215 ngx_http_proxy_init_request(p);
216
217 return NGX_DONE;
218}
219
220
221static void ngx_http_proxy_init_request(void *data)
222{
223 ngx_http_proxy_ctx_t *p = data;
224
225 ngx_chain_t *cl;
226 ngx_http_request_t *r;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000227 ngx_output_chain_ctx_t *out_ctx;
228 ngx_chain_write_ctx_t *write_ctx;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000229
230
231 r = p->request;
232
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000233ngx_log_debug(r->connection->log, "timer_set: %d" _
234 r->connection->read->timer_set);
235
236 if (r->connection->read->timer_set) {
237 ngx_del_timer(r->connection->read);
238 }
239
240 ngx_is_null(cl, ngx_http_proxy_create_request(p)) {
241 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
242 return;
243 }
244
245#if 0
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000246 cl = ngx_http_proxy_create_request(p);
247 if (cl == NULL) {
248 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
249 return;
250 }
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000251#endif
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000252
253 if (r->request_hunks) {
254 cl->next = r->request_hunks;
255 }
256
257 r->request_hunks = cl;
Igor Sysoeve6779222003-10-03 15:50:53 +0000258
Igor Sysoev04410502003-08-01 14:56:33 +0000259 p->upstream.log = r->connection->log;
Igor Sysoev6414b962003-10-24 16:10:38 +0000260 p->saved_ctx = r->connection->log->data;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000261 p->saved_handler = r->connection->log->handler;
262 r->connection->log->data = p;
Igor Sysoev6414b962003-10-24 16:10:38 +0000263 r->connection->log->handler = ngx_http_proxy_log_error;
264 p->action = "connecting to upstream";
Igor Sysoev04410502003-08-01 14:56:33 +0000265
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000266 out_ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
267 if (out_ctx == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000268 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
269 }
Igor Sysoev04410502003-08-01 14:56:33 +0000270
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000271 p->output_chain_ctx = out_ctx;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000272
273 if (r->request_body_hunk) {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000274 out_ctx->free = ngx_alloc_chain_link(r->pool);
275 if (out_ctx->free == NULL) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000276 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
277 }
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000278 out_ctx->free->hunk = r->request_body_hunk;
279 out_ctx->free->next = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000280 }
281
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000282 out_ctx->sendfile = r->sendfile;
283 out_ctx->pool = r->pool;
284 out_ctx->bufs.num = 1;
285 out_ctx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
286 out_ctx->output_filter = (ngx_output_chain_filter_pt) ngx_chain_write;
287
288 write_ctx = ngx_pcalloc(r->pool, sizeof(ngx_chain_write_ctx_t));
289 if (write_ctx == NULL) {
290 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
291 }
292
293 out_ctx->output_ctx = write_ctx;
294 write_ctx->pool = r->pool;
295 write_ctx->last = &write_ctx->out;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000296
297 ngx_http_proxy_send_request(p);
Igor Sysoev04410502003-08-01 14:56:33 +0000298}
299
300
Igor Sysoeve6779222003-10-03 15:50:53 +0000301static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000302{
Igor Sysoev6414b962003-10-24 16:10:38 +0000303 int i;
304 size_t len;
305 ngx_hunk_t *h;
306 ngx_chain_t *chain;
307 ngx_table_elt_t *header;
308 ngx_http_request_t *r;
309 ngx_http_proxy_upstream_t *u;
Igor Sysoeve6779222003-10-03 15:50:53 +0000310
311 r = p->request;
Igor Sysoev6414b962003-10-24 16:10:38 +0000312 u = p->lcf->upstream;
Igor Sysoeve6779222003-10-03 15:50:53 +0000313
314 len = http_methods[p->method - 1].len
Igor Sysoev6414b962003-10-24 16:10:38 +0000315 + u->uri.len
316 + r->uri.len - u->location->len
Igor Sysoeve6779222003-10-03 15:50:53 +0000317 + 1 + r->args.len /* 1 is for "?" */
318 + sizeof(http_version) - 1
Igor Sysoev6414b962003-10-24 16:10:38 +0000319 + sizeof(host_header) - 1 + u->host_header.len + 2
Igor Sysoeve6779222003-10-03 15:50:53 +0000320 /* 2 is for "\r\n" */
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000321 + sizeof(connection_close_header) - 1
Igor Sysoeve6779222003-10-03 15:50:53 +0000322 + 2; /* 2 is for "\r\n" at the header end */
323
324 header = (ngx_table_elt_t *) r->headers_in.headers->elts;
325 for (i = 0; i < r->headers_in.headers->nelts; i++) {
326
327 if (&header[i] == r->headers_in.host) {
328 continue;
329 }
330
331 if (&header[i] == r->headers_in.connection) {
332 continue;
333 }
334
335 /* 2 is for ": " and 2 is for "\r\n" */
336 len += header[i].key.len + 2 + header[i].value.len + 2;
337 }
338
339 /* STUB */ len++;
340
341 ngx_test_null(h, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL);
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000342 ngx_alloc_link_and_set_hunk(chain, h, r->pool, NULL);
Igor Sysoeve6779222003-10-03 15:50:53 +0000343
344
345 /* the request line */
346
347 h->last = ngx_cpymem(h->last, http_methods[p->method - 1].data,
348 http_methods[p->method - 1].len);
349
Igor Sysoev6414b962003-10-24 16:10:38 +0000350 h->last = ngx_cpymem(h->last, u->uri.data, u->uri.len);
Igor Sysoeve6779222003-10-03 15:50:53 +0000351
352 h->last = ngx_cpymem(h->last,
Igor Sysoev6414b962003-10-24 16:10:38 +0000353 r->uri.data + u->location->len,
354 r->uri.len - u->location->len);
Igor Sysoeve6779222003-10-03 15:50:53 +0000355
356 if (r->args.len > 0) {
357 *(h->last++) = '?';
358 h->last = ngx_cpymem(h->last, r->args.data, r->args.len);
359 }
360
361 h->last = ngx_cpymem(h->last, http_version, sizeof(http_version) - 1);
362
363
Igor Sysoev6414b962003-10-24 16:10:38 +0000364 /* "Host" header */
Igor Sysoeve6779222003-10-03 15:50:53 +0000365
366 h->last = ngx_cpymem(h->last, host_header, sizeof(host_header) - 1);
Igor Sysoev6414b962003-10-24 16:10:38 +0000367 h->last = ngx_cpymem(h->last, u->host_header.data, u->host_header.len);
Igor Sysoeve6779222003-10-03 15:50:53 +0000368 *(h->last++) = CR; *(h->last++) = LF;
369
370
Igor Sysoev6414b962003-10-24 16:10:38 +0000371 /* "Connection: close" header */
Igor Sysoeve6779222003-10-03 15:50:53 +0000372
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000373 h->last = ngx_cpymem(h->last, connection_close_header,
374 sizeof(connection_close_header) - 1);
Igor Sysoeve6779222003-10-03 15:50:53 +0000375
376
377 for (i = 0; i < r->headers_in.headers->nelts; i++) {
378
379 if (&header[i] == r->headers_in.host) {
380 continue;
381 }
382
383 if (&header[i] == r->headers_in.connection) {
384 continue;
385 }
386
Igor Sysoev54276be2003-10-20 17:14:07 +0000387 if (&header[i] == r->headers_in.keep_alive) {
388 continue;
389 }
Igor Sysoeve6779222003-10-03 15:50:53 +0000390
391 h->last = ngx_cpymem(h->last, header[i].key.data, header[i].key.len);
392
393 *(h->last++) = ':'; *(h->last++) = ' ';
394
395 h->last = ngx_cpymem(h->last, header[i].value.data,
396 header[i].value.len);
397
398 *(h->last++) = CR; *(h->last++) = LF;
399
400 ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _
401 header[i].key.data _ header[i].value.data);
402 }
403
404 /* add "\r\n" at the header end */
405 *(h->last++) = CR; *(h->last++) = LF;
406
Igor Sysoev6414b962003-10-24 16:10:38 +0000407 /* STUB */ *(h->last) = '\0';
Igor Sysoeve6779222003-10-03 15:50:53 +0000408 ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ h->pos);
409
410 return chain;
411}
412
413
414static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
415{
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000416 ngx_connection_t *c;
417 ngx_http_proxy_ctx_t *p;
Igor Sysoev04410502003-08-01 14:56:33 +0000418
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000419 c = wev->data;
420 p = c->data;
Igor Sysoev04410502003-08-01 14:56:33 +0000421
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000422 p->action = "sending request to upstream";
423
Igor Sysoev6414b962003-10-24 16:10:38 +0000424 if (wev->timedout) {
425 p->timedout = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000426 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
Igor Sysoev6414b962003-10-24 16:10:38 +0000427 return;
428 }
429
Igor Sysoeve6779222003-10-03 15:50:53 +0000430 ngx_http_proxy_send_request(p);
431
432 return;
433}
434
435
436static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
437{
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000438 int rc;
439 ngx_chain_t *cl;
440 ngx_connection_t *c;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000441 ngx_chain_write_ctx_t *ctx;
Igor Sysoeve6779222003-10-03 15:50:53 +0000442
443 c = p->upstream.connection;
444
Igor Sysoev04410502003-08-01 14:56:33 +0000445 for ( ;; ) {
Igor Sysoev6414b962003-10-24 16:10:38 +0000446
Igor Sysoeve6779222003-10-03 15:50:53 +0000447 if (c) {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000448 p->action = "sending request to upstream";
449 ctx = p->output_chain_ctx->output_ctx;
450 ctx->connection = c;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000451 rc = ngx_output_chain(p->output_chain_ctx,
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000452 !p->request_sent ? p->request->request_hunks:
453 NULL);
Igor Sysoev04410502003-08-01 14:56:33 +0000454
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000455 if (rc != NGX_ERROR) {
Igor Sysoev6414b962003-10-24 16:10:38 +0000456 p->request_sent = 1;
Igor Sysoeve6779222003-10-03 15:50:53 +0000457
458 if (c->write->timer_set) {
459 ngx_del_timer(c->write);
460 }
461
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000462 if (rc == NGX_AGAIN) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000463 ngx_add_timer(c->write, p->lcf->send_timeout);
Igor Sysoeve6779222003-10-03 15:50:53 +0000464
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000465 if (ngx_handle_write_event(c->write, /* STUB: lowat */ 0)
466 == NGX_ERROR)
467 {
468 ngx_http_proxy_finalize_request(p,
469 NGX_HTTP_INTERNAL_SERVER_ERROR);
470 return;
471 }
472
Igor Sysoeve6779222003-10-03 15:50:53 +0000473 } else {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000474
475 /* rc == NGX_OK */
476
477 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
478 ngx_http_proxy_finalize_request(p,
479 NGX_HTTP_INTERNAL_SERVER_ERROR);
480 return;
481 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000482
483 if (c->tcp_nopush) {
484 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
485 ngx_log_error(NGX_LOG_CRIT, c->log,
486 ngx_socket_errno,
487 ngx_tcp_push_n " failed");
488 ngx_http_proxy_finalize_request(p,
489 NGX_HTTP_INTERNAL_SERVER_ERROR);
490 return;
491 }
492 c->tcp_nopush = 0;
493 }
Igor Sysoeve6779222003-10-03 15:50:53 +0000494 }
495
496 return;
497 }
498
Igor Sysoev425a42c2003-10-27 16:16:17 +0000499 ngx_event_connect_peer_failed(&p->upstream);
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000500 ngx_http_proxy_close_connection(c);
Igor Sysoeve6779222003-10-03 15:50:53 +0000501 }
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000502
Igor Sysoeve6779222003-10-03 15:50:53 +0000503 for ( ;; ) {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000504 p->action = "connecting to upstream";
505
Igor Sysoeve6779222003-10-03 15:50:53 +0000506 rc = ngx_event_connect_peer(&p->upstream);
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000507
Igor Sysoeve6779222003-10-03 15:50:53 +0000508 if (rc == NGX_ERROR) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000509 ngx_http_proxy_finalize_request(p,
510 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000511 return;
512 }
513
514 if (rc == NGX_CONNECT_ERROR) {
515 ngx_event_connect_peer_failed(&p->upstream);
516
517 if (p->upstream.tries == 0) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000518 ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
Igor Sysoeve6779222003-10-03 15:50:53 +0000519 return;
520 }
521
522 continue;
523 }
524
525 p->upstream.connection->data = p;
526 p->upstream.connection->write->event_handler =
527 ngx_http_proxy_send_request_handler;
528 p->upstream.connection->read->event_handler =
529 ngx_http_proxy_process_upstream_status_line;
530
531 c = p->upstream.connection;
532 c->pool = p->request->pool;
533 c->read->log = c->write->log = c->log = p->request->connection->log;
534
Igor Sysoev6414b962003-10-24 16:10:38 +0000535 if (p->upstream.tries > 1 && p->request_sent) {
536
537 /* reinit the request chain */
538
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000539 for (cl = p->request->request_hunks; cl; cl = cl->next) {
Igor Sysoev6414b962003-10-24 16:10:38 +0000540 cl->hunk->pos = cl->hunk->start;
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000541 }
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000542 }
543
Igor Sysoev6414b962003-10-24 16:10:38 +0000544 p->request_sent = 0;
545 p->timedout = 0;
546
Igor Sysoeve6779222003-10-03 15:50:53 +0000547 if (rc == NGX_OK) {
548 break;
549 }
550
551 /* rc == NGX_AGAIN */
552
553 ngx_add_timer(c->write, p->lcf->connect_timeout);
Igor Sysoeve6779222003-10-03 15:50:53 +0000554
Igor Sysoevae5c59c2003-08-14 06:00:28 +0000555 return;
556 }
557 }
558}
Igor Sysoev04410502003-08-01 14:56:33 +0000559
Igor Sysoeve6779222003-10-03 15:50:53 +0000560
561static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000562{
Igor Sysoeve6779222003-10-03 15:50:53 +0000563 int rc;
564 ssize_t n;
565 ngx_connection_t *c;
566 ngx_http_proxy_ctx_t *p;
567
568 c = rev->data;
569 p = c->data;
570
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000571 p->action = "reading upstream status line";
572
Igor Sysoeve6779222003-10-03 15:50:53 +0000573 ngx_log_debug(rev->log, "http proxy process status line");
574
575 if (rev->timedout) {
Igor Sysoev6414b962003-10-24 16:10:38 +0000576 p->timedout = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000577 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
Igor Sysoeve6779222003-10-03 15:50:53 +0000578 return;
579 }
580
581 if (p->header_in == NULL) {
582 p->header_in = ngx_create_temp_hunk(p->request->pool,
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000583 p->lcf->header_buffer_size,
Igor Sysoeve6779222003-10-03 15:50:53 +0000584 0, 0);
585 if (p->header_in == NULL) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000586 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000587 return;
588 }
Igor Sysoev5bf3d252003-10-22 07:05:29 +0000589 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
Igor Sysoeve6779222003-10-03 15:50:53 +0000590 }
591
592 n = ngx_http_proxy_read_upstream_header(p);
593
Igor Sysoev1dd4ac82003-10-06 03:56:42 +0000594 if (n == NGX_ERROR) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000595 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
Igor Sysoev1dd4ac82003-10-06 03:56:42 +0000596 return;
597 }
598
599 if (n == NGX_AGAIN) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000600 return;
601 }
602
603 rc = ngx_http_proxy_parse_status_line(p);
604
605 if (rc == NGX_AGAIN) {
606 if (p->header_in->pos == p->header_in->last) {
607 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000608 "upstream sent too long status line");
609 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
Igor Sysoeve6779222003-10-03 15:50:53 +0000610 }
611
612 return;
613 }
614
615 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000616 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
617 "upstream sent no valid HTTP/1.0 header");
618
619 if (p->accel) {
620 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
621
622 } else {
623 p->request->http_version = NGX_HTTP_VERSION_9;
624 p->status = NGX_HTTP_OK;
625 ngx_http_proxy_send_response(p);
626 }
627
Igor Sysoeve6779222003-10-03 15:50:53 +0000628 return;
629 }
630
631 /* rc == NGX_OK */
632
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000633 if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR
634 && p->upstream.tries > 1
635 && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
636 {
637 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
638 return;
639 }
640
Igor Sysoeve6779222003-10-03 15:50:53 +0000641 p->status_line.len = p->status_end - p->status_start;
642 p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1);
643 if (p->status_line.data == NULL) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000644 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000645 return;
646 }
647 ngx_cpystrn(p->status_line.data, p->status_start, p->status_line.len + 1);
648
649 ngx_log_debug(rev->log, "http proxy status %d '%s'" _
650 p->status _ p->status_line.data);
651
Igor Sysoeve6779222003-10-03 15:50:53 +0000652 if (p->headers_in.headers) {
653 p->headers_in.headers->nelts = 0;
654 } else {
655 p->headers_in.headers = ngx_create_table(p->request->pool, 10);
656 }
657
658 c->read->event_handler = ngx_http_proxy_process_upstream_headers;
659 ngx_http_proxy_process_upstream_headers(rev);
660
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000661 return;
662}
663
Igor Sysoeve6779222003-10-03 15:50:53 +0000664
Igor Sysoeve6779222003-10-03 15:50:53 +0000665static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000666{
Igor Sysoeve6779222003-10-03 15:50:53 +0000667 int i, rc;
668 ssize_t n;
669 ngx_table_elt_t *h;
670 ngx_connection_t *c;
671 ngx_http_request_t *r;
672 ngx_http_proxy_ctx_t *p;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000673
Igor Sysoeve6779222003-10-03 15:50:53 +0000674 c = rev->data;
675 p = c->data;
676 r = p->request;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000677
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000678 p->action = "reading upstream headers";
679
Igor Sysoeve6779222003-10-03 15:50:53 +0000680 ngx_log_debug(rev->log, "http proxy process header line");
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000681
Igor Sysoeve6779222003-10-03 15:50:53 +0000682 if (rev->timedout) {
Igor Sysoev6414b962003-10-24 16:10:38 +0000683 p->timedout = 1;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000684 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
Igor Sysoeve6779222003-10-03 15:50:53 +0000685 return;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000686 }
687
Igor Sysoeve6779222003-10-03 15:50:53 +0000688 rc = NGX_AGAIN;
Igor Sysoev87a01ea2003-10-02 05:39:37 +0000689
Igor Sysoeve6779222003-10-03 15:50:53 +0000690 for ( ;; ) {
691 if (rc == NGX_AGAIN) {
692 n = ngx_http_proxy_read_upstream_header(p);
693
Igor Sysoev1dd4ac82003-10-06 03:56:42 +0000694 if (n == NGX_ERROR) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000695 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
Igor Sysoev1dd4ac82003-10-06 03:56:42 +0000696 return;
697 }
698
699 if (n == NGX_AGAIN) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000700 return;
701 }
702 }
703
704 rc = ngx_http_parse_header_line(p->request, p->header_in);
705
706 if (rc == NGX_OK) {
707
708 /* a header line has been parsed successfully */
709
710 h = ngx_push_table(p->headers_in.headers);
711 if (h == NULL) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000712 ngx_http_proxy_finalize_request(p,
713 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000714 return;
715 }
716
717 h->key.len = r->header_name_end - r->header_name_start;
718 h->value.len = r->header_end - r->header_start;
719
720 h->key.data = ngx_palloc(p->request->pool,
721 h->key.len + 1 + h->value.len + 1);
722 if (h->key.data == NULL) {
Igor Sysoev931a4002003-10-07 15:30:05 +0000723 ngx_http_proxy_finalize_request(p,
724 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeve6779222003-10-03 15:50:53 +0000725 return;
726 }
727
728 h->value.data = h->key.data + h->key.len + 1;
729 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
730 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
731
732 for (i = 0; headers_in[i].name.len != 0; i++) {
733 if (headers_in[i].name.len != h->key.len) {
734 continue;
735 }
736
737 if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) {
738 *((ngx_table_elt_t **)
739 ((char *) &p->headers_in + headers_in[i].offset)) = h;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000740 break;
Igor Sysoeve6779222003-10-03 15:50:53 +0000741 }
742 }
743
744 ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _
745 h->key.data _ h->value.data);
746
747 continue;
748
749 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
750
751 /* a whole header has been parsed successfully */
752
753 ngx_log_debug(c->log, "HTTP header done");
754
Igor Sysoev931a4002003-10-07 15:30:05 +0000755 ngx_http_proxy_send_response(p);
756
Igor Sysoeve6779222003-10-03 15:50:53 +0000757 return;
758
759 } else if (rc != NGX_AGAIN) {
760
761 /* there was error while a header line parsing */
762
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000763 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
764 upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
765
766 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
Igor Sysoeve6779222003-10-03 15:50:53 +0000767 return;
768 }
769
770 /* NGX_AGAIN: a header line parsing is still not complete */
771
772 if (p->header_in->last == p->header_in->end) {
773 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
774 "upstream sent too big header");
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000775
776 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
Igor Sysoeve6779222003-10-03 15:50:53 +0000777 return;
778 }
779 }
780}
781
782
783static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
784{
Igor Sysoeve6779222003-10-03 15:50:53 +0000785 ssize_t n;
786 ngx_event_t *rev;
787
788 rev = p->upstream.connection->read;
789
790 n = p->header_in->last - p->header_in->pos;
791
792 if (n > 0) {
Igor Sysoevd404c972003-10-16 20:19:16 +0000793#if 0
794 /* TODO THINK */
Igor Sysoeve6779222003-10-03 15:50:53 +0000795 rev->ready = 0;
Igor Sysoevd404c972003-10-16 20:19:16 +0000796#endif
Igor Sysoeve6779222003-10-03 15:50:53 +0000797 return n;
798 }
799
800 n = ngx_recv(p->upstream.connection, p->header_in->last,
801 p->header_in->end - p->header_in->last);
802
803 if (n == NGX_AGAIN) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000804 ngx_add_timer(rev, p->lcf->read_timeout);
805
Igor Sysoev0a280a32003-10-12 16:49:16 +0000806 if (ngx_handle_read_event(rev) == NGX_ERROR) {
807 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
808 return NGX_ERROR;
Igor Sysoeve6779222003-10-03 15:50:53 +0000809 }
810
811 return NGX_AGAIN;
812 }
813
814 if (n == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000815 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
Igor Sysoeve6779222003-10-03 15:50:53 +0000816 "upstream closed prematurely connection");
817 }
818
819 if (n == 0 || n == NGX_ERROR) {
Igor Sysoeve6779222003-10-03 15:50:53 +0000820 return NGX_ERROR;
821 }
822
823 p->header_in->last += n;
824
825 return n;
826}
827
828
Igor Sysoev931a4002003-10-07 15:30:05 +0000829static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
830{
831 int rc, i;
832 ngx_table_elt_t *ch, *ph;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000833 ngx_event_pipe_t *ep;
Igor Sysoev931a4002003-10-07 15:30:05 +0000834 ngx_http_request_t *r;
835
836 r = p->request;
837
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000838 r->headers_out.content_length_n = -1;
839 r->headers_out.content_length = NULL;
Igor Sysoev931a4002003-10-07 15:30:05 +0000840
841 /* copy an upstream header to r->headers_out */
842
843 ph = (ngx_table_elt_t *) p->headers_in.headers->elts;
844 for (i = 0; i < p->headers_in.headers->nelts; i++) {
845
846 if (&ph[i] == p->headers_in.connection) {
847 continue;
848 }
849
850 if (p->accel) {
851 if (&ph[i] == p->headers_in.date
852 || &ph[i] == p->headers_in.accept_ranges) {
853 continue;
854 }
855 }
856
Igor Sysoev931a4002003-10-07 15:30:05 +0000857 ch = ngx_push_table(r->headers_out.headers);
858 if (ch == NULL) {
859 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
860 return;
861 }
862
863 *ch = ph[i];
864
865 if (&ph[i] == p->headers_in.content_type) {
866 r->headers_out.content_type = ch;
867 r->headers_out.content_type->key.len = 0;
868 continue;
869 }
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000870
871 if (&ph[i] == p->headers_in.content_length) {
872 r->headers_out.content_length_n =
873 ngx_atoi(p->headers_in.content_length->value.data,
874 p->headers_in.content_length->value.len);
875 r->headers_out.content_length = ch;
876 continue;
877 }
Igor Sysoev931a4002003-10-07 15:30:05 +0000878 }
879
880 /* STUB */
881
882 if (p->headers_in.server) {
883 r->headers_out.server = p->headers_in.server;
884 }
885
886 if (!p->accel && p->headers_in.date) {
887 r->headers_out.date = p->headers_in.date;
888 }
889
890 /* */
891
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000892
893 /* TODO: preallocate event_pipe hunks, look "Content-Length" */
Igor Sysoev931a4002003-10-07 15:30:05 +0000894
895 r->headers_out.status = p->status;
896
897 rc = ngx_http_send_header(r);
898
899 p->header_sent = 1;
900
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000901 ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
Igor Sysoev931a4002003-10-07 15:30:05 +0000902 if (ep == NULL) {
903 ngx_http_proxy_finalize_request(p, 0);
904 return;
905 }
906
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000907 ep->input_filter = ngx_event_pipe_copy_input_filter;
908 ep->output_filter = (ngx_event_pipe_output_filter_pt)
Igor Sysoev931a4002003-10-07 15:30:05 +0000909 ngx_http_output_filter;
Igor Sysoevd404c972003-10-16 20:19:16 +0000910 ep->output_ctx = r;
Igor Sysoev5bf3d252003-10-22 07:05:29 +0000911 ep->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
Igor Sysoevd404c972003-10-16 20:19:16 +0000912 ep->bufs = p->lcf->bufs;
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000913 ep->busy_size = p->lcf->busy_buffers_size;
Igor Sysoev931a4002003-10-07 15:30:05 +0000914 ep->upstream = p->upstream.connection;
915 ep->downstream = r->connection;
916 ep->pool = r->pool;
917 ep->log = r->connection->log;
918 ep->temp_path = p->lcf->temp_path;
919
Igor Sysoev5bf3d252003-10-22 07:05:29 +0000920 ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
Igor Sysoev931a4002003-10-07 15:30:05 +0000921 if (ep->temp_file == NULL) {
922 ngx_http_proxy_finalize_request(p, 0);
923 return;
924 }
925
926 ep->temp_file->fd = NGX_INVALID_FILE;
927 ep->temp_file->log = r->connection->log;
928
929 ep->max_temp_file_size = p->lcf->max_temp_file_size;
930 ep->temp_file_write_size = p->lcf->temp_file_write_size;
931 ep->temp_file_warn = "an upstream response is buffered "
932 "to a temporary file";
933
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000934 ep->preread_hunks = ngx_alloc_chain_link(r->pool);
Igor Sysoev931a4002003-10-07 15:30:05 +0000935 if (ep->preread_hunks == NULL) {
936 ngx_http_proxy_finalize_request(p, 0);
937 return;
938 }
939 ep->preread_hunks->hunk = p->header_in;
940 ep->preread_hunks->next = NULL;
941
942 ep->preread_size = p->header_in->last - p->header_in->pos;
943
Igor Sysoev9760a132003-10-21 07:47:21 +0000944 /*
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000945 * event_pipe would do p->header_in->last += ep->preread_size
946 * as though these bytes were read.
Igor Sysoev9760a132003-10-21 07:47:21 +0000947 */
948 p->header_in->last = p->header_in->pos;
949
Igor Sysoev5bf3d252003-10-22 07:05:29 +0000950 /* STUB */ ep->cachable = 0;
951
952 if (p->lcf->cyclic_temp_file) {
953
954 /*
955 * we need to disable the use of sendfile() if we use cyclic temp file
Igor Sysoevdc9dd432003-10-22 16:38:26 +0000956 * because the writing a new data can interfere with sendfile()
957 * that uses the same kernel file pages (at least on FreeBSD)
Igor Sysoev5bf3d252003-10-22 07:05:29 +0000958 */
959
960 ep->cyclic_temp_file = 1;
961 r->sendfile = 0;
962
963 } else {
964 ep->cyclic_temp_file = 0;
965 r->sendfile = 1;
966 }
Igor Sysoev54276be2003-10-20 17:14:07 +0000967
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000968 p->event_pipe = ep;
Igor Sysoev931a4002003-10-07 15:30:05 +0000969
Igor Sysoev54276be2003-10-20 17:14:07 +0000970 p->upstream.connection->read->event_handler = ngx_http_proxy_process_body;
971 r->connection->write->event_handler = ngx_http_proxy_process_body;
Igor Sysoevd404c972003-10-16 20:19:16 +0000972
Igor Sysoev54276be2003-10-20 17:14:07 +0000973 ngx_http_proxy_process_body(p->upstream.connection->read);
Igor Sysoev931a4002003-10-07 15:30:05 +0000974
975 return;
976}
977
978
Igor Sysoev54276be2003-10-20 17:14:07 +0000979static void ngx_http_proxy_process_body(ngx_event_t *ev)
Igor Sysoevd404c972003-10-16 20:19:16 +0000980{
981 ngx_connection_t *c;
Igor Sysoev13829b72003-10-19 19:57:23 +0000982 ngx_http_request_t *r;
Igor Sysoevd404c972003-10-16 20:19:16 +0000983 ngx_http_proxy_ctx_t *p;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000984 ngx_event_pipe_t *ep;
Igor Sysoevd404c972003-10-16 20:19:16 +0000985
Igor Sysoev54276be2003-10-20 17:14:07 +0000986 c = ev->data;
987
988 if (ev->write) {
989 ngx_log_debug(ev->log, "http proxy process downstream");
990 r = c->data;
991 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000992 p->action = "sending to client";
Igor Sysoev54276be2003-10-20 17:14:07 +0000993
994 } else {
995 ngx_log_debug(ev->log, "http proxy process upstream");
996 p = c->data;
997 r = p->request;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000998 p->action = "reading upstream body";
Igor Sysoev54276be2003-10-20 17:14:07 +0000999 }
1000
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001001 ep = p->event_pipe;
Igor Sysoev54276be2003-10-20 17:14:07 +00001002
1003 if (ev->timedout) {
1004 if (ev->write) {
1005 ep->downstream_error = 1;
Igor Sysoev6414b962003-10-24 16:10:38 +00001006 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
1007 "client timed out");
Igor Sysoev54276be2003-10-20 17:14:07 +00001008
1009 } else {
1010 ep->upstream_error = 1;
Igor Sysoev6414b962003-10-24 16:10:38 +00001011 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
1012 "upstream timed out");
Igor Sysoev54276be2003-10-20 17:14:07 +00001013 }
1014
1015 } else {
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001016 if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) {
Igor Sysoev54276be2003-10-20 17:14:07 +00001017 ngx_http_proxy_finalize_request(p, 0);
1018 return;
1019 }
1020 }
1021
1022 if (p->upstream.connection) {
1023 if (ep->upstream_done) {
1024 /* TODO: update cache */
1025
1026 } else if (ep->upstream_eof) {
1027 /* TODO: check length & update cache */
1028 }
1029
1030 if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
Igor Sysoev9760a132003-10-21 07:47:21 +00001031 ngx_http_proxy_close_connection(p->upstream.connection);
Igor Sysoev54276be2003-10-20 17:14:07 +00001032 p->upstream.connection = NULL;
1033 }
1034 }
1035
1036 if (ep->downstream_done) {
1037 ngx_log_debug(ev->log, "http proxy downstream done");
1038 ngx_http_proxy_finalize_request(p, r->main ? 0 : ngx_http_send_last(r));
1039 return;
1040 }
1041
1042 if (ep->downstream_error) {
1043 if (!p->cachable && p->upstream.connection) {
Igor Sysoev9760a132003-10-21 07:47:21 +00001044 ngx_http_proxy_close_connection(p->upstream.connection);
Igor Sysoev54276be2003-10-20 17:14:07 +00001045 p->upstream.connection = NULL;
1046 }
Igor Sysoev13829b72003-10-19 19:57:23 +00001047
Igor Sysoev54276be2003-10-20 17:14:07 +00001048 if (p->upstream.connection == NULL) {
1049 ngx_http_close_connection(c);
1050 }
Igor Sysoevfd3e3742003-10-08 04:34:07 +00001051 }
1052
Igor Sysoev931a4002003-10-07 15:30:05 +00001053 return;
1054}
1055
1056
Igor Sysoeve6779222003-10-03 15:50:53 +00001057static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p)
1058{
1059 char ch;
1060 char *pos;
1061 enum {
1062 sw_start = 0,
1063 sw_H,
1064 sw_HT,
1065 sw_HTT,
1066 sw_HTTP,
1067 sw_first_major_digit,
1068 sw_major_digit,
1069 sw_first_minor_digit,
1070 sw_minor_digit,
1071 sw_status,
1072 sw_space_after_status,
1073 sw_status_text,
1074 sw_almost_done,
1075 sw_done
1076 } state;
1077
1078 state = p->state;
1079 pos = p->header_in->pos;
1080
1081 while (pos < p->header_in->last && state < sw_done) {
1082 ch = *pos++;
1083
1084 switch (state) {
1085
1086 /* "HTTP/" */
1087 case sw_start:
1088 switch (ch) {
1089 case 'H':
1090 state = sw_H;
1091 break;
1092 default:
1093 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1094 }
1095 break;
1096
1097 case sw_H:
1098 switch (ch) {
1099 case 'T':
1100 state = sw_HT;
1101 break;
1102 default:
1103 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1104 }
1105 break;
1106
1107 case sw_HT:
1108 switch (ch) {
1109 case 'T':
1110 state = sw_HTT;
1111 break;
1112 default:
1113 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1114 }
1115 break;
1116
1117 case sw_HTT:
1118 switch (ch) {
1119 case 'P':
1120 state = sw_HTTP;
1121 break;
1122 default:
1123 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1124 }
1125 break;
1126
1127 case sw_HTTP:
1128 switch (ch) {
1129 case '/':
1130 state = sw_first_major_digit;
1131 break;
1132 default:
1133 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1134 }
1135 break;
1136
1137 /* the first digit of major HTTP version */
1138 case sw_first_major_digit:
1139 if (ch < '1' || ch > '9') {
1140 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1141 }
1142
1143 state = sw_major_digit;
1144 break;
1145
1146 /* the major HTTP version or dot */
1147 case sw_major_digit:
1148 if (ch == '.') {
1149 state = sw_first_minor_digit;
1150 break;
1151 }
1152
1153 if (ch < '0' || ch > '9') {
1154 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1155 }
1156
1157 break;
1158
1159 /* the first digit of minor HTTP version */
1160 case sw_first_minor_digit:
1161 if (ch < '0' || ch > '9') {
1162 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1163 }
1164
1165 state = sw_minor_digit;
1166 break;
1167
1168 /* the minor HTTP version or the end of the request line */
1169 case sw_minor_digit:
1170 if (ch == ' ') {
1171 state = sw_status;
1172 break;
1173 }
1174
1175 if (ch < '0' || ch > '9') {
1176 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1177 }
1178
1179 break;
1180
1181 /* HTTP status code */
1182 case sw_status:
1183 if (ch < '0' || ch > '9') {
1184 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1185 }
1186
1187 p->status = p->status * 10 + ch - '0';
1188
1189 if (++p->status_count == 3) {
1190 state = sw_space_after_status;
1191 p->status_start = pos - 3;
1192 }
1193
1194 break;
1195
1196 /* space or end of line */
1197 case sw_space_after_status:
1198 switch (ch) {
1199 case ' ':
1200 state = sw_status_text;
1201 break;
1202 case CR:
1203 state = sw_almost_done;
1204 break;
1205 case LF:
1206 state = sw_done;
1207 break;
1208 default:
1209 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1210 }
1211 break;
1212
1213 /* any text until end of line */
1214 case sw_status_text:
1215 switch (ch) {
1216 case CR:
1217 state = sw_almost_done;
1218
1219 break;
1220 case LF:
1221 state = sw_done;
1222 break;
1223 }
1224 break;
1225
1226 /* end of request line */
1227 case sw_almost_done:
1228 p->status_end = pos - 2;
1229 switch (ch) {
1230 case LF:
1231 state = sw_done;
1232 break;
1233 default:
1234 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1235 }
1236 break;
1237 }
1238 }
1239
1240 p->header_in->pos = pos;
1241
1242 if (state == sw_done) {
1243 if (p->status_end == NULL) {
1244 p->status_end = pos - 1;
1245 }
1246
1247 p->state = sw_start;
1248 return NGX_OK;
1249 }
1250
1251 p->state = state;
1252 return NGX_AGAIN;
1253}
1254
Igor Sysoev931a4002003-10-07 15:30:05 +00001255
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001256static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001257{
Igor Sysoev6414b962003-10-24 16:10:38 +00001258 ngx_event_connect_peer_failed(&p->upstream);
1259
1260 if (p->timedout) {
1261 ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT,
1262 "upstream timed out");
1263 }
1264
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001265 if (p->upstream.connection) {
1266 ngx_http_proxy_close_connection(p->upstream.connection);
1267 p->upstream.connection = NULL;
Igor Sysoev931a4002003-10-07 15:30:05 +00001268 }
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001269
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001270 if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) {
Igor Sysoev6414b962003-10-24 16:10:38 +00001271 ngx_http_proxy_finalize_request(p,
1272 p->timedout ? NGX_HTTP_GATEWAY_TIME_OUT:
1273 NGX_HTTP_BAD_GATEWAY);
1274 return;
1275 }
1276
Igor Sysoev931a4002003-10-07 15:30:05 +00001277 if (!p->fatal_error) {
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001278 ngx_http_proxy_send_request(p);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001279 return;
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001280 }
1281
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001282ngx_log_debug(p->request->connection->log, "FATAL ERROR IN NEXT UPSTREAM");
1283
Igor Sysoev1dd4ac82003-10-06 03:56:42 +00001284 return;
1285}
1286
Igor Sysoev931a4002003-10-07 15:30:05 +00001287static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
1288{
Igor Sysoev2b0c76c2003-10-27 21:01:00 +00001289 ngx_log_debug(p->request->connection->log,
1290 "finalize http proxy request");
1291
Igor Sysoev931a4002003-10-07 15:30:05 +00001292 if (p->upstream.connection) {
1293 ngx_http_proxy_close_connection(p->upstream.connection);
1294 p->upstream.connection = NULL;
1295 }
1296
Igor Sysoev9760a132003-10-21 07:47:21 +00001297 if (p->header_sent
1298 && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
1299 {
Igor Sysoev931a4002003-10-07 15:30:05 +00001300 rc = 0;
1301 }
1302
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001303 p->request->connection->log->data = p->saved_ctx;
1304 p->request->connection->log->handler = p->saved_handler;
1305
Igor Sysoev931a4002003-10-07 15:30:05 +00001306 ngx_http_finalize_request(p->request, rc);
1307
1308 p->fatal_error = 1;
1309
1310 return;
1311}
1312
1313
Igor Sysoeve6779222003-10-03 15:50:53 +00001314
1315static void ngx_http_proxy_close_connection(ngx_connection_t *c)
1316{
1317 ngx_log_debug(c->log, "close connection: %d" _ c->fd);
1318
1319 if (c->fd == -1) {
Igor Sysoev931a4002003-10-07 15:30:05 +00001320#if 0
Igor Sysoeve6779222003-10-03 15:50:53 +00001321 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
Igor Sysoev931a4002003-10-07 15:30:05 +00001322#endif
Igor Sysoeve6779222003-10-03 15:50:53 +00001323 return;
1324 }
1325
1326 if (c->read->timer_set) {
1327 ngx_del_timer(c->read);
Igor Sysoeve6779222003-10-03 15:50:53 +00001328 }
1329
1330 if (c->write->timer_set) {
1331 ngx_del_timer(c->write);
Igor Sysoeve6779222003-10-03 15:50:53 +00001332 }
1333
Igor Sysoevfd3e3742003-10-08 04:34:07 +00001334 /* TODO: move connection to the connection pool */
1335
Igor Sysoeve6779222003-10-03 15:50:53 +00001336 if (ngx_del_conn) {
1337 ngx_del_conn(c);
1338
1339 } else {
1340 if (c->read->active) {
1341 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
1342 }
1343
1344 if (c->write->active) {
1345 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
1346 }
1347 }
1348
1349 if (ngx_close_socket(c->fd) == -1) {
1350 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
1351 ngx_close_socket_n " failed");
1352 }
1353
1354 c->fd = -1;
1355
1356 return;
Igor Sysoev87a01ea2003-10-02 05:39:37 +00001357}
1358
Igor Sysoev04410502003-08-01 14:56:33 +00001359
1360static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
1361{
1362 ngx_http_proxy_ctx_t *p = data;
1363
1364 return ngx_snprintf(buf, len,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001365 " while %s, client: %s, URL: %s, upstream: %s%s%s%s%s",
Igor Sysoev04410502003-08-01 14:56:33 +00001366 p->action,
Igor Sysoev04410502003-08-01 14:56:33 +00001367 p->request->connection->addr_text.data,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001368 p->request->unparsed_uri.data,
1369 p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data,
1370 p->lcf->upstream->uri.data,
1371 p->request->uri.data + p->lcf->upstream->location->len,
1372 p->request->args.len ? "?" : "",
1373 p->request->args.len ? p->request->args.data : "");
Igor Sysoev04410502003-08-01 14:56:33 +00001374}
Igor Sysoevae5c59c2003-08-14 06:00:28 +00001375
1376
1377static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
1378{
1379 ngx_http_proxy_loc_conf_t *conf;
1380
1381 ngx_test_null(conf,
1382 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)),
1383 NGX_CONF_ERROR);
1384
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001385 /* set by ngx_pcalloc():
Igor Sysoevae5c59c2003-08-14 06:00:28 +00001386
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001387 conf->bufs.num = 0;
Igor Sysoevae5c59c2003-08-14 06:00:28 +00001388
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001389 conf->path = NULL;
Igor Sysoev931a4002003-10-07 15:30:05 +00001390
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001391 conf->upstreams = NULL;
1392 conf->peers = NULL;
Igor Sysoev9760a132003-10-21 07:47:21 +00001393
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001394 */
Igor Sysoev9760a132003-10-21 07:47:21 +00001395
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001396 conf->request_buffer_size = NGX_CONF_UNSET;
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001397 conf->connect_timeout = NGX_CONF_UNSET;
1398 conf->send_timeout = NGX_CONF_UNSET;
1399 conf->header_buffer_size = NGX_CONF_UNSET;
1400 conf->read_timeout = NGX_CONF_UNSET;
1401 conf->busy_buffers_size = NGX_CONF_UNSET;
Igor Sysoev9760a132003-10-21 07:47:21 +00001402
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001403 /*
1404 * "proxy_max_temp_file_size" is hardcoded to 1G for reverse proxy,
1405 * it should be configurable in the generic proxy
1406 */
1407 conf->max_temp_file_size = 1024 * 1024 * 1024;
Igor Sysoev9760a132003-10-21 07:47:21 +00001408
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001409 conf->temp_file_write_size = NGX_CONF_UNSET;
Igor Sysoev931a4002003-10-07 15:30:05 +00001410
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001411 /* "proxy_cyclic_temp_file" is disabled */
1412 conf->cyclic_temp_file = 0;
Igor Sysoevae5c59c2003-08-14 06:00:28 +00001413
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001414 conf->next_upstream = NGX_CONF_UNSET;
1415
Igor Sysoevae5c59c2003-08-14 06:00:28 +00001416 return conf;
1417}
Igor Sysoevd404c972003-10-16 20:19:16 +00001418
1419
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001420static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
1421 void *parent, void *child)
1422{
1423 ngx_http_proxy_loc_conf_t *prev = parent;
1424 ngx_http_proxy_loc_conf_t *conf = child;
1425
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001426 ngx_conf_merge_size_value(conf->request_buffer_size,
1427 prev->request_buffer_size, 8192);
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001428 ngx_conf_merge_msec_value(conf->connect_timeout,
1429 prev->connect_timeout, 60000);
1430 ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 30000);
1431 ngx_conf_merge_size_value(conf->header_buffer_size,
1432 prev->header_buffer_size, 4096);
1433 ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 30000);
1434 ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 8, 4096);
1435 ngx_conf_merge_size_value(conf->busy_buffers_size,
1436 prev->busy_buffers_size, 8192);
1437
1438#if 0
1439 if (conf->max_temp_file_size > conf->bufs.size) {
1440 return "\"proxy_max_temp_file\" must be greater "
1441 "than one of the \"proxy_buffers\"";
1442 }
1443#endif
1444
1445 ngx_conf_merge_size_value(conf->temp_file_write_size,
1446 prev->temp_file_write_size, 16384);
1447
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001448 ngx_conf_merge_value(conf->next_upstream, prev->next_upstream,
1449 (NGX_HTTP_PROXY_FT_ERROR|NGX_HTTP_PROXY_FT_TIMEOUT));
1450
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001451 ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
1452 "temp", 1, 2, 0, cf->pool);
1453
1454 return NULL;
1455}
1456
1457
1458
Igor Sysoevd404c972003-10-16 20:19:16 +00001459static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
1460 void *conf)
1461{
1462 ngx_http_proxy_loc_conf_t *lcf = conf;
1463
1464 int i, len;
1465 char *err, *host;
1466 ngx_str_t *value;
1467 struct hostent *h;
1468 u_int32_t addr;
1469 ngx_http_conf_ctx_t *ctx;
1470 ngx_http_core_loc_conf_t *clcf;
1471
1472
1473 value = cf->args->elts;
1474
1475 if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) {
1476 return "invalid URL prefix";
1477 }
1478
1479 ngx_test_null(lcf->upstream,
1480 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_t)),
1481 NGX_CONF_ERROR);
1482
1483 value[1].data += 7;
1484 value[1].len -= 7;
1485
1486 err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream);
1487
1488 if (err) {
1489 return err;
1490 }
1491
1492 ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream->host.len + 1),
1493 NGX_CONF_ERROR);
1494 ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1);
1495
1496 addr = inet_addr(host);
1497
1498 if (addr == INADDR_NONE) {
1499 h = gethostbyname(host);
1500
1501 if (h == NULL || h->h_addr_list[0] == NULL) {
1502 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host);
1503 return NGX_CONF_ERROR;
1504 }
1505
1506 for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
1507
1508 /* MP: ngx_shared_palloc() */
1509
1510 ngx_test_null(lcf->peers,
1511 ngx_pcalloc(cf->pool,
1512 sizeof(ngx_peers_t)
1513 + sizeof(ngx_peer_t) * (i - 1)),
1514 NGX_CONF_ERROR);
1515
1516 lcf->peers->number = i;
1517
1518 for (i = 0; h->h_addr_list[i] != NULL; i++) {
1519 lcf->peers->peers[i].host.data = host;
1520 lcf->peers->peers[i].host.len = lcf->upstream->host.len;
1521 lcf->peers->peers[i].addr = *(u_int32_t *)(h->h_addr_list[i]);
1522 lcf->peers->peers[i].port = lcf->upstream->port;
1523
1524 len = INET_ADDRSTRLEN + lcf->upstream->port_text.len + 1;
1525 ngx_test_null(lcf->peers->peers[i].addr_port_text.data,
1526 ngx_palloc(cf->pool, len),
1527 NGX_CONF_ERROR);
1528
1529 len = ngx_inet_ntop(AF_INET,
1530 (char *) &lcf->peers->peers[i].addr,
1531 lcf->peers->peers[i].addr_port_text.data,
1532 len);
1533
1534 lcf->peers->peers[i].addr_port_text.data[len++] = ':';
1535
1536 ngx_cpystrn(lcf->peers->peers[i].addr_port_text.data + len,
1537 lcf->upstream->port_text.data,
1538 lcf->upstream->port_text.len + 1);
1539
1540 lcf->peers->peers[i].addr_port_text.len =
1541 len + lcf->upstream->port_text.len + 1;
1542 }
1543
1544 } else {
1545
1546 /* MP: ngx_shared_palloc() */
1547
1548 ngx_test_null(lcf->peers, ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)),
1549 NGX_CONF_ERROR);
1550
1551 lcf->peers->number = 1;
1552
1553 lcf->peers->peers[0].host.data = host;
1554 lcf->peers->peers[0].host.len = lcf->upstream->host.len;
1555 lcf->peers->peers[0].addr = addr;
1556 lcf->peers->peers[0].port = lcf->upstream->port;
1557
1558 len = lcf->upstream->host.len + lcf->upstream->port_text.len + 1;
1559
1560 ngx_test_null(lcf->peers->peers[0].addr_port_text.data,
1561 ngx_palloc(cf->pool, len + 1),
1562 NGX_CONF_ERROR);
1563
1564 len = lcf->upstream->host.len;
1565
1566 ngx_memcpy(lcf->peers->peers[0].addr_port_text.data,
1567 lcf->upstream->host.data, len);
1568
1569 lcf->peers->peers[0].addr_port_text.data[len++] = ':';
1570
1571 ngx_cpystrn(lcf->peers->peers[0].addr_port_text.data + len,
1572 lcf->upstream->port_text.data,
1573 lcf->upstream->port_text.len + 1);
1574 }
1575
1576 ctx = cf->ctx;
1577 clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
1578 lcf->upstream->location = &clcf->name;
1579 clcf->handler = ngx_http_proxy_handler;
1580
1581 return NULL;
1582}
1583
Igor Sysoevdc9dd432003-10-22 16:38:26 +00001584
Igor Sysoevd404c972003-10-16 20:19:16 +00001585static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
1586 ngx_http_proxy_upstream_t *u)
1587{
1588 size_t i;
1589
1590 if (url->data[0] == ':' || url->data[0] == '/') {
1591 return "invalid upstream URL";
1592 }
1593
1594 u->host.data = url->data;
1595 u->host_header.data = url->data;
1596
1597 for (i = 1; i < url->len; i++) {
1598 if (url->data[i] == ':') {
1599 u->port_text.data = &url->data[i] + 1;
1600 u->host.len = i;
1601 }
1602
1603 if (url->data[i] == '/') {
1604 u->uri.data = &url->data[i];
1605 u->uri.len = url->len - i;
1606 u->host_header.len = i;
1607
1608 if (u->host.len == 0) {
1609 u->host.len = i;
1610 }
1611
1612 if (u->port_text.data == NULL) {
1613 u->port = htons(80);
1614 u->port_text.len = 2;
1615 u->port_text.data = "80";
1616 return NULL;
1617 }
1618
1619 u->port_text.len = &url->data[i] - u->port_text.data;
1620
1621 if (u->port_text.len > 0) {
1622 u->port = ngx_atoi(u->port_text.data, u->port_text.len);
1623 if (u->port > 0) {
1624 u->port = htons((u_short) u->port);
1625 return NULL;
1626 }
1627 }
1628
1629 return "invalid port in upstream URL";
1630 }
1631 }
1632
1633 if (u->host.len == 0) {
1634 u->host.len = i;
1635 }
1636
1637 u->host_header.len = i;
1638
1639 u->uri.data = "/";
1640 u->uri.len = 1;
1641
1642 if (u->port_text.data == NULL) {
1643 u->port = htons(80);
1644 u->port_text.len = 2;
1645 u->port_text.data = "80";
1646 return NULL;
1647 }
1648
1649 u->port_text.len = &url->data[i] - u->port_text.data;
1650
1651 if (u->port_text.len > 0) {
1652 u->port = ngx_atoi(u->port_text.data, u->port_text.len);
1653 if (u->port > 0) {
1654 u->port = htons((u_short) u->port);
1655 return NULL;
1656 }
1657 }
1658
1659 return "invalid port in upstream URL";
1660}