Mercurial > hg > nginx-quic
comparison src/http/modules/proxy/ngx_http_event_proxy_handler.c @ 71:59229033ae93
nginx-0.0.1-2003-04-08-19:40:10 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 08 Apr 2003 15:40:10 +0000 |
parents | src/http/modules/ngx_http_event_proxy_handler.c@e320bf51c4e3 |
children | 66de3f065886 |
comparison
equal
deleted
inserted
replaced
70:e320bf51c4e3 | 71:59229033ae93 |
---|---|
1 | |
2 #include <ngx_config.h> | |
3 #include <ngx_core.h> | |
4 #include <ngx_string.h> | |
5 #include <ngx_file.h> | |
6 #include <ngx_hunk.h> | |
7 #include <ngx_inet.h> | |
8 #include <ngx_conf_file.h> | |
9 #include <ngx_event_write.h> | |
10 | |
11 #include <ngx_http.h> | |
12 #include <ngx_http_config.h> | |
13 #include <ngx_http_core_module.h> | |
14 #include <ngx_http_output_filter.h> | |
15 #include <ngx_http_event_proxy_handler.h> | |
16 | |
17 | |
18 static int ngx_http_proxy_handler(ngx_http_request_t *r); | |
19 | |
20 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); | |
21 static int ngx_http_proxy_process_upstream(ngx_http_proxy_ctx_t *p, | |
22 ngx_event_t *ev); | |
23 static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p); | |
24 static int ngx_http_proxy_process_upstream_event(ngx_event_t *ev); | |
25 static int ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); | |
26 static int ngx_http_proxy_init_upstream(ngx_http_proxy_ctx_t *p); | |
27 static int ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p); | |
28 static int ngx_http_proxy_process_upstream_status_line(ngx_http_proxy_ctx_t *p); | |
29 | |
30 | |
31 static int ngx_http_proxy_read_response_body(ngx_event_t *ev); | |
32 static int ngx_http_proxy_write_to_client(ngx_event_t *ev); | |
33 | |
34 static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx); | |
35 | |
36 static int ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int error); | |
37 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len); | |
38 | |
39 static void *ngx_http_proxy_create_loc_conf(ngx_pool_t *pool); | |
40 | |
41 static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
42 char *conf); | |
43 | |
44 static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, | |
45 ngx_http_proxy_upstream_url_t *uu); | |
46 | |
47 | |
48 static ngx_command_t ngx_http_proxy_commands[] = { | |
49 | |
50 {ngx_string("proxy_pass"), | |
51 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
52 ngx_http_proxy_set_pass, | |
53 NGX_HTTP_LOC_CONF_OFFSET, | |
54 0}, | |
55 | |
56 {ngx_string("proxy_large_header"), | |
57 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
58 ngx_conf_set_flag_slot, | |
59 NGX_HTTP_LOC_CONF_OFFSET, | |
60 offsetof(ngx_http_proxy_loc_conf_t, large_header)}, | |
61 | |
62 {ngx_null_string, 0, NULL, 0, 0} | |
63 }; | |
64 | |
65 | |
66 static ngx_http_module_t ngx_http_proxy_module_ctx = { | |
67 NGX_HTTP_MODULE, | |
68 | |
69 NULL, /* create server config */ | |
70 NULL, /* init server config */ | |
71 | |
72 ngx_http_proxy_create_loc_conf, /* create location config */ | |
73 NULL /* merge location config */ | |
74 }; | |
75 | |
76 | |
77 ngx_module_t ngx_http_proxy_module = { | |
78 0, /* module index */ | |
79 &ngx_http_proxy_module_ctx, /* module context */ | |
80 ngx_http_proxy_commands, /* module directives */ | |
81 NGX_HTTP_MODULE_TYPE, /* module type */ | |
82 NULL /* init module */ | |
83 }; | |
84 | |
85 | |
86 static ngx_str_t http_methods[] = { | |
87 ngx_string("GET "), | |
88 ngx_string("HEAD "), | |
89 ngx_string("POST ") | |
90 }; | |
91 | |
92 | |
93 static char http_version[] = " HTTP/1.0" CRLF; | |
94 static char host_header[] = "Host: "; | |
95 static char conn_close_header[] = "Connection: close" CRLF; | |
96 | |
97 | |
98 /* AF_INET only */ | |
99 | |
100 | |
101 static int ngx_http_proxy_handler(ngx_http_request_t *r) | |
102 { | |
103 int rc; | |
104 struct sockaddr_in addr; | |
105 ngx_chain_t *chain; | |
106 ngx_http_proxy_ctx_t *p; | |
107 ngx_http_log_ctx_t *hcx; | |
108 ngx_http_proxy_log_ctx_t *lcx; | |
109 ngx_http_proxy_loc_conf_t *lcf; | |
110 | |
111 p = (ngx_http_proxy_ctx_t *) | |
112 ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); | |
113 | |
114 if (p == NULL) { | |
115 ngx_http_create_ctx(r, p, ngx_http_proxy_module_ctx, | |
116 sizeof(ngx_http_proxy_ctx_t), | |
117 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
118 } | |
119 | |
120 if (p->upstream_url == NULL) { | |
121 lcf = (ngx_http_proxy_loc_conf_t *) | |
122 ngx_http_get_module_loc_conf(r, ngx_http_proxy_module_ctx); | |
123 | |
124 p->lcf = lcf; | |
125 p->request = r; | |
126 p->upstream_url = lcf->upstream_url; | |
127 p->upstreams = lcf->upstreams; | |
128 p->tries = lcf->upstreams->number; | |
129 } | |
130 | |
131 ngx_test_null(p->log, ngx_palloc(r->pool, sizeof(ngx_log_t)), | |
132 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
133 ngx_memcpy(p->log, r->connection->log, sizeof(ngx_log_t)); | |
134 ngx_test_null(lcx, ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)), | |
135 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
136 | |
137 p->log->data = lcx; | |
138 hcx = r->connection->log->data; | |
139 lcx->client = hcx->client; | |
140 lcx->url = hcx->url; | |
141 | |
142 p->method = r->method; | |
143 | |
144 /* TODO: read a client's body */ | |
145 | |
146 chain = ngx_http_proxy_create_request(p); | |
147 if (chain == NULL) { | |
148 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
149 } | |
150 | |
151 /* TODO: duplicate the hunks and chain if there is backend farm */ | |
152 p->out = chain; | |
153 | |
154 p->last_error = NGX_HTTP_BAD_GATEWAY; | |
155 ngx_http_proxy_process_upstream(p, NULL); | |
156 | |
157 /* On an error ngx_http_proxy_process_upstream() calls | |
158 ngx_http_proxy_finalize_request() so we return NGX_DONE to avoid | |
159 the additional NGX_HTTP_INTERNAL_SERVER_ERROR error | |
160 that would be generated by ngx_http_process_request() */ | |
161 | |
162 return NGX_DONE; | |
163 } | |
164 | |
165 | |
166 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) | |
167 { | |
168 int i; | |
169 size_t len; | |
170 ngx_hunk_t *hunk; | |
171 ngx_chain_t *chain; | |
172 ngx_table_elt_t *header; | |
173 ngx_http_request_t *r; | |
174 | |
175 r = p->request; | |
176 | |
177 len = http_methods[p->method - 1].len | |
178 + p->upstream_url->uri.len | |
179 + (r->uri.len - p->upstream_url->location->len) | |
180 + r->args.len + 1 /* 1 is for "?" */ | |
181 + sizeof(http_version) - 1 | |
182 + sizeof(host_header) - 1 + p->upstream_url->host.len + 2 | |
183 + sizeof(conn_close_header) - 1 | |
184 + 2; /* 2 is for "\r\n" at the header end */ | |
185 | |
186 header = (ngx_table_elt_t *) r->headers_in.headers->elts; | |
187 for (i = 0; i < r->headers_in.headers->nelts; i++) { | |
188 | |
189 if (&header[i] == r->headers_in.host) { | |
190 continue; | |
191 } | |
192 | |
193 if (&header[i] == r->headers_in.connection) { | |
194 continue; | |
195 } | |
196 | |
197 /* 2 is for ": " and 2 is for "\r\n" */ | |
198 len += header[i].key.len + 2 + header[i].value.len + 2; | |
199 } | |
200 | |
201 /* STUB */ len++; | |
202 | |
203 ngx_test_null(hunk, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL); | |
204 ngx_add_hunk_to_chain(chain, hunk, r->pool, NULL); | |
205 | |
206 /* the request line */ | |
207 | |
208 ngx_memcpy(hunk->last, http_methods[p->method - 1].data, | |
209 http_methods[p->method - 1].len); | |
210 hunk->last += http_methods[p->method - 1].len; | |
211 | |
212 ngx_memcpy(hunk->last, p->upstream_url->uri.data, p->upstream_url->uri.len); | |
213 hunk->last += p->upstream_url->uri.len; | |
214 | |
215 ngx_memcpy(hunk->last, r->uri.data + p->upstream_url->location->len, | |
216 r->uri.len - p->upstream_url->location->len); | |
217 hunk->last += r->uri.len - p->upstream_url->location->len; | |
218 | |
219 if (r->args.len > 0) { | |
220 *(hunk->last++) = '?'; | |
221 ngx_memcpy(hunk->last, r->args.data, r->args.len); | |
222 hunk->last += r->args.len; | |
223 } | |
224 | |
225 ngx_memcpy(hunk->last, http_version, sizeof(http_version) - 1); | |
226 hunk->last += sizeof(http_version) - 1; | |
227 | |
228 /* the "Host" header */ | |
229 | |
230 ngx_memcpy(hunk->last, host_header, sizeof(host_header) - 1); | |
231 hunk->last += sizeof(host_header) - 1; | |
232 | |
233 ngx_memcpy(hunk->last, p->upstream_url->host.data, | |
234 p->upstream_url->host.len); | |
235 hunk->last += p->upstream_url->host.len; | |
236 | |
237 *(hunk->last++) = CR; *(hunk->last++) = LF; | |
238 | |
239 /* the "Connection: close" header */ | |
240 | |
241 ngx_memcpy(hunk->last, conn_close_header, sizeof(conn_close_header) - 1); | |
242 hunk->last += sizeof(conn_close_header) - 1; | |
243 | |
244 for (i = 0; i < r->headers_in.headers->nelts; i++) { | |
245 | |
246 if (&header[i] == r->headers_in.host) { | |
247 continue; | |
248 } | |
249 | |
250 if (&header[i] == r->headers_in.connection) { | |
251 continue; | |
252 } | |
253 | |
254 ngx_memcpy(hunk->last, header[i].key.data, header[i].key.len); | |
255 hunk->last += header[i].key.len; | |
256 | |
257 *(hunk->last++) = ':'; *(hunk->last++) = ' '; | |
258 | |
259 ngx_memcpy(hunk->last, header[i].value.data, header[i].value.len); | |
260 hunk->last += header[i].value.len; | |
261 | |
262 *(hunk->last++) = CR; *(hunk->last++) = LF; | |
263 | |
264 ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _ | |
265 header[i].key.data _ header[i].value.data); | |
266 } | |
267 | |
268 /* add "\r\n" at the header end */ | |
269 *(hunk->last++) = CR; *(hunk->last++) = LF; | |
270 | |
271 /* STUB */ *(hunk->last++) = '\0'; | |
272 ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ hunk->pos); | |
273 | |
274 return chain; | |
275 } | |
276 | |
277 | |
278 static int ngx_http_proxy_process_upstream(ngx_http_proxy_ctx_t *p, | |
279 ngx_event_t *ev) | |
280 { | |
281 int rc; | |
282 time_t now; | |
283 ngx_connection_t *c; | |
284 ngx_http_proxy_upstream_t *u; | |
285 | |
286 for ( ;; ) { | |
287 | |
288 if (ev == NULL) { | |
289 /* STUB: look up cached connection */ | |
290 c = NULL; | |
291 | |
292 if (c) { | |
293 p->cached_connection = 1; | |
294 p->connection = c; | |
295 c->write->event_handler = ngx_http_proxy_process_upstream_event; | |
296 rc = ngx_http_proxy_send_request(p); | |
297 | |
298 } else { | |
299 p->cached_connection = 0; | |
300 p->connection = NULL; | |
301 rc = ngx_http_proxy_connect(p); | |
302 } | |
303 | |
304 if (p->connection) { | |
305 ev = p->connection->write; | |
306 } | |
307 | |
308 } else { | |
309 | |
310 if (ev->timedout) { | |
311 rc = NGX_HTTP_GATEWAY_TIME_OUT; | |
312 | |
313 } else if (ev->write) { | |
314 | |
315 rc = p->state_write_upstream_handler(p); | |
316 | |
317 } else { /* ev->read */ | |
318 | |
319 rc = p->state_read_upstream_handler(p); | |
320 } | |
321 } | |
322 | |
323 if (rc == NGX_DONE || rc == NGX_AGAIN) { | |
324 return rc; | |
325 } | |
326 | |
327 if (rc == NGX_ERROR) { | |
328 return ngx_http_proxy_finalize_request(p, | |
329 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
330 return NGX_DONE; | |
331 } | |
332 | |
333 if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT | |
334 || (rc == NGX_OK | |
335 && p->status == NGX_HTTP_INTERNAL_SERVER_ERROR | |
336 && p->lcf->retry_500_error)) | |
337 { | |
338 if (ev) { | |
339 ngx_event_close_connection(ev); | |
340 ev = NULL; | |
341 } | |
342 | |
343 if (!p->cached_connection) { | |
344 if (p->upstreams->number > 1) { | |
345 now = ngx_time(); | |
346 u = &p->upstreams->u[p->cur_upstream]; | |
347 | |
348 /* Here is the race condition when the upstreams are shared | |
349 between threads or processes but it's not serious */ | |
350 | |
351 u->fails++; | |
352 u->accessed = now; | |
353 | |
354 /* */ | |
355 } | |
356 | |
357 p->tries--; | |
358 p->last_error = rc; | |
359 } | |
360 | |
361 if (p->tries == 0) { | |
362 ngx_http_proxy_finalize_request(p, p->last_error); | |
363 return NGX_ERROR; | |
364 } | |
365 } | |
366 | |
367 if (rc == NGX_OK) { | |
368 ngx_http_proxy_finalize_request(p, p->status); | |
369 return NGX_DONE; | |
370 } | |
371 | |
372 if (rc > NGX_OK) { | |
373 ngx_http_proxy_finalize_request(p, rc); | |
374 } | |
375 | |
376 return NGX_DONE; | |
377 } | |
378 } | |
379 | |
380 | |
381 static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) | |
382 { | |
383 int rc, event; | |
384 struct sockaddr_in *addr; | |
385 ngx_err_t err; | |
386 ngx_socket_t s; | |
387 ngx_event_t *rev, *wev; | |
388 ngx_connection_t *c; | |
389 ngx_http_proxy_log_ctx_t *lcx; | |
390 ngx_http_proxy_upstream_t *u; | |
391 | |
392 if (p->upstreams->number > 1) { | |
393 if (p->tries == p->upstreams->number) { | |
394 | |
395 /* Here is the race condition | |
396 when the upstreams are shared between threads or processes | |
397 but it should not be serious */ | |
398 | |
399 p->cur_upstream = p->upstreams->current++; | |
400 | |
401 if (p->upstreams->current >= p->upstreams->number) { | |
402 p->upstreams->current = 0; | |
403 } | |
404 | |
405 /* */ | |
406 | |
407 #if (NGX_MULTITHREADED || NGX_MULTIPROCESSED) | |
408 /* eliminate the sequences of the race condition */ | |
409 if (p->cur_upstream >= p->upstreams->number) { | |
410 p->cur_upstream = 0; | |
411 } | |
412 #endif | |
413 } | |
414 | |
415 if (p->upstreams->max_fails > 0) { | |
416 | |
417 for ( ;; ) { | |
418 u = &p->upstreams->u[p->cur_upstream]; | |
419 | |
420 /* Here is the race condition | |
421 when the upstreams are shared between threads or processes | |
422 but it should not be serious */ | |
423 | |
424 if (u->fails > p->upstreams->max_fails | |
425 || u->accessed < p->upstreams->fail_timeout) | |
426 { | |
427 break; | |
428 } | |
429 | |
430 /* */ | |
431 | |
432 p->cur_upstream++; | |
433 | |
434 if (p->cur_upstream >= p->upstreams->number) { | |
435 p->cur_upstream = 0; | |
436 } | |
437 | |
438 p->tries--; | |
439 | |
440 if (p->tries == 0) { | |
441 return p->last_error; | |
442 } | |
443 } | |
444 } | |
445 } | |
446 | |
447 lcx = p->log->data; | |
448 lcx->action = "connecting to an upstream"; | |
449 lcx->upstream = p->upstreams->u[p->cur_upstream].addr_port_name.data; | |
450 p->log->handler = ngx_http_proxy_log_error; | |
451 | |
452 s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0); | |
453 | |
454 if (s == -1) { | |
455 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
456 ngx_socket_n " failed"); | |
457 return NGX_ERROR; | |
458 } | |
459 | |
460 if (p->lcf->rcvbuf) { | |
461 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, | |
462 (const void *) &p->lcf->rcvbuf, sizeof(int)) == -1) { | |
463 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
464 "setsockopt(SO_RCVBUF) failed"); | |
465 | |
466 if (ngx_close_socket(s) == -1) { | |
467 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
468 ngx_close_socket_n " failed"); | |
469 } | |
470 | |
471 return NGX_ERROR; | |
472 } | |
473 } | |
474 | |
475 if (ngx_nonblocking(s) == -1) { | |
476 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
477 ngx_nonblocking_n " failed"); | |
478 | |
479 if (ngx_close_socket(s) == -1) { | |
480 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
481 ngx_close_socket_n " failed"); | |
482 } | |
483 | |
484 return NGX_ERROR; | |
485 } | |
486 | |
487 c = &ngx_connections[s]; | |
488 rev = &ngx_read_events[s]; | |
489 wev = &ngx_write_events[s]; | |
490 | |
491 ngx_memzero(c, sizeof(ngx_connection_t)); | |
492 ngx_memzero(rev, sizeof(ngx_event_t)); | |
493 ngx_memzero(wev, sizeof(ngx_event_t)); | |
494 | |
495 rev->index = wev->index = NGX_INVALID_INDEX; | |
496 rev->data = wev->data = c; | |
497 c->read = rev; | |
498 c->write = wev; | |
499 rev->first = wev->first = 1; | |
500 rev->log = wev->log = c->log = p->log; | |
501 c->fd = s; | |
502 wev->close_handler = rev->close_handler = ngx_event_close_connection; | |
503 | |
504 #if !(USE_KQUEUE) | |
505 | |
506 #if (HAVE_EDGE_EVENT) /* epoll */ | |
507 | |
508 if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { | |
509 if (ngx_edge_add_event(wev) != NGX_OK) { | |
510 return NGX_ERROR; | |
511 } | |
512 } | |
513 | |
514 #endif | |
515 | |
516 #endif | |
517 | |
518 ngx_test_null(c->pool, ngx_create_pool(p->lcf->conn_pool_size, p->log), | |
519 NGX_ERROR); | |
520 | |
521 ngx_test_null(p->sockaddr, | |
522 ngx_pcalloc(c->pool, sizeof(struct sockaddr_in)), | |
523 NGX_ERROR); | |
524 | |
525 addr = (struct sockaddr_in *) p->sockaddr; | |
526 | |
527 addr->sin_family = AF_INET; | |
528 addr->sin_addr.s_addr = p->upstreams->u[p->cur_upstream].addr; | |
529 addr->sin_port = htons(p->upstreams->u[p->cur_upstream].port); | |
530 | |
531 rc = connect(s, p->sockaddr, sizeof(struct sockaddr_in)); | |
532 | |
533 if (rc == -1) { | |
534 err = ngx_socket_errno; | |
535 if (err != NGX_EINPROGRESS) { | |
536 ngx_log_error(NGX_LOG_CRIT, p->log, err, "connect() failed"); | |
537 | |
538 if (ngx_close_socket(s) == -1) { | |
539 ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno, | |
540 ngx_close_socket_n " failed"); | |
541 } | |
542 | |
543 ngx_destroy_pool(c->pool); | |
544 | |
545 return NGX_HTTP_BAD_GATEWAY; | |
546 } | |
547 } | |
548 | |
549 c->data = p->request; | |
550 p->connection = c; | |
551 | |
552 ngx_test_null(c->pool, ngx_create_pool(p->lcf->conn_pool_size, p->log), | |
553 NGX_ERROR); | |
554 | |
555 #if (USE_KQUEUE) | |
556 | |
557 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { | |
558 return NGX_ERROR; | |
559 } | |
560 | |
561 #else | |
562 | |
563 if ((ngx_event_flags & NGX_HAVE_EDGE_EVENT) == 0) { /* not epoll */ | |
564 | |
565 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { /* kqueue */ | |
566 event = NGX_CLEAR_EVENT; | |
567 | |
568 } else { /* select, poll, /dev/poll */ | |
569 event = NGX_LEVEL_EVENT; | |
570 } | |
571 | |
572 /* TODO: aio, iocp */ | |
573 | |
574 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { | |
575 return NGX_ERROR; | |
576 } | |
577 } | |
578 | |
579 #endif /* USE_KQUEUE */ | |
580 | |
581 wev->event_handler = rev->event_handler = | |
582 ngx_http_proxy_process_upstream_event; | |
583 | |
584 p->state_write_upstream_handler = ngx_http_proxy_send_request; | |
585 p->state_read_upstream_handler = ngx_http_proxy_init_upstream; | |
586 | |
587 /* The connection has been established */ | |
588 if (rc == 0) { | |
589 wev->write = 1; | |
590 wev->ready = 1; | |
591 | |
592 return ngx_http_proxy_send_request(p); | |
593 } | |
594 | |
595 /* The connection is in a progress */ | |
596 | |
597 wev->timer_set = 1; | |
598 ngx_add_timer(wev, p->lcf->connect_timeout); | |
599 | |
600 #if (USE_KQUEUE) | |
601 | |
602 if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { | |
603 return NGX_ERROR; | |
604 } | |
605 | |
606 #else | |
607 | |
608 /* TODO: aio, iocp */ | |
609 | |
610 if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { | |
611 return NGX_DONE; | |
612 } | |
613 | |
614 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { | |
615 return NGX_ERROR; | |
616 } | |
617 | |
618 #endif /* USE_KQUEUE */ | |
619 | |
620 return NGX_DONE; | |
621 } | |
622 | |
623 | |
624 static int ngx_http_proxy_process_upstream_event(ngx_event_t *ev) | |
625 { | |
626 ngx_connection_t *c; | |
627 ngx_http_request_t *r; | |
628 ngx_http_proxy_ctx_t *p; | |
629 | |
630 c = (ngx_connection_t *) ev->data; | |
631 r = (ngx_http_request_t *) c->data; | |
632 p = (ngx_http_proxy_ctx_t *) | |
633 ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); | |
634 | |
635 return ngx_http_proxy_process_upstream(p, ev); | |
636 } | |
637 | |
638 | |
639 static int ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p) | |
640 { | |
641 ngx_chain_t *chain; | |
642 ngx_event_t *wev; | |
643 | |
644 chain = ngx_write_chain(p->connection, p->out, 0); | |
645 if (chain == (ngx_chain_t *) -1) { | |
646 return NGX_ERROR; | |
647 } | |
648 | |
649 p->out = chain; | |
650 | |
651 wev = p->connection->write; | |
652 | |
653 ngx_del_timer(wev); | |
654 | |
655 if (chain) { | |
656 ngx_add_timer(wev, p->lcf->send_timeout); | |
657 wev->timer_set = 1; | |
658 | |
659 } else { | |
660 wev->timer_set = 0; | |
661 } | |
662 | |
663 return NGX_DONE; | |
664 } | |
665 | |
666 | |
667 static int ngx_http_proxy_init_upstream(ngx_http_proxy_ctx_t *p) | |
668 { | |
669 int n; | |
670 ngx_hunk_t **ph; | |
671 ngx_http_request_t *r; | |
672 | |
673 r = p->request; | |
674 | |
675 ngx_test_null(p->header_in, | |
676 ngx_create_temp_hunk(r->pool, p->lcf->header_size, 0, 0), | |
677 NGX_ERROR); | |
678 | |
679 p->header_in->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; | |
680 | |
681 ngx_test_null(p->headers_in, | |
682 ngx_palloc(r->pool, sizeof(ngx_http_proxy_headers_in_t)), | |
683 NGX_ERROR); | |
684 | |
685 p->hunks_number = p->lcf->max_block_size / p->lcf->block_size; | |
686 if (p->hunks_number * p->lcf->block_size < p->lcf->max_block_size) { | |
687 p->hunks_number++; | |
688 } | |
689 | |
690 ngx_init_array(p->hunks, r->pool, p->hunks_number, sizeof(ngx_hunk_t *), | |
691 NGX_ERROR); | |
692 | |
693 ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); | |
694 *ph = p->header_in; | |
695 | |
696 p->state_handler = ngx_http_proxy_process_upstream_status_line; | |
697 | |
698 return ngx_http_proxy_read_upstream_header(p); | |
699 } | |
700 | |
701 | |
702 static int ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p) | |
703 { | |
704 int n, rc; | |
705 ngx_event_t *rev; | |
706 | |
707 rev = p->connection->read; | |
708 | |
709 do { | |
710 n = ngx_event_recv(p->connection, p->header_in->last, | |
711 p->header_in->end - p->header_in->last); | |
712 | |
713 if (n == NGX_AGAIN) { | |
714 if (rev->timer_set) { | |
715 ngx_del_timer(rev); | |
716 } else { | |
717 rev->timer_set = 1; | |
718 } | |
719 | |
720 ngx_add_timer(rev, p->lcf->read_timeout); | |
721 return NGX_AGAIN; | |
722 } | |
723 | |
724 if (n == NGX_ERROR) { | |
725 return NGX_HTTP_BAD_GATEWAY; | |
726 } | |
727 | |
728 ngx_log_debug(p->log, "http proxy read %d" _ n); | |
729 | |
730 if (n == 0) { | |
731 ngx_log_error(NGX_LOG_INFO, p->log, 0, | |
732 "upstream closed prematurely connection"); | |
733 return NGX_HTTP_BAD_GATEWAY; | |
734 } | |
735 | |
736 p->header_in->last += n; | |
737 | |
738 /* the state handlers are called in the following order: | |
739 ngx_http_proxy_process_upstream_status_line(r) | |
740 ngx_http_proxy_process_upstream_headers(r) */ | |
741 | |
742 do { | |
743 rc = p->state_handler(p); | |
744 } while (rc == NGX_AGAIN && p->header_in->end < p->header_in->last); | |
745 | |
746 } while (rc == NGX_AGAIN | |
747 && (rev->ready || ngx_event_flags & NGX_HAVE_AIO_EVENT)); | |
748 | |
749 if (rc > NGX_OK) { | |
750 return rc; | |
751 } | |
752 | |
753 if (rc == NGX_OK) { | |
754 /* STUB */ return NGX_ERROR; | |
755 } | |
756 | |
757 /* STUB */ return NGX_ERROR; | |
758 } | |
759 | |
760 | |
761 static int ngx_http_proxy_process_upstream_status_line(ngx_http_proxy_ctx_t *p) | |
762 { | |
763 int rc; | |
764 | |
765 #if 0 | |
766 *p->header_in->last = '\0'; | |
767 ngx_log_debug(p->log, "PROXY:\n'%s'" _ p->header_in->pos); | |
768 #endif | |
769 | |
770 rc = ngx_read_http_proxy_status_line(p); | |
771 | |
772 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { | |
773 p->status = 200; | |
774 p->status_line.len = 0; | |
775 p->full_status_line.len = 0; | |
776 } | |
777 | |
778 if (rc == NGX_OK) { | |
779 p->status_line.len = p->status_end - p->status_start; | |
780 p->full_status_line.len = p->status_end - p->header_in->start; | |
781 | |
782 if (p->lcf->large_header) { | |
783 ngx_test_null(p->full_status_line.data, | |
784 ngx_palloc(p->request->pool, | |
785 p->full_status_line.len + 1), | |
786 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
787 | |
788 ngx_cpystrn(p->full_status_line.data, p->header_in->start, | |
789 p->full_status_line.len + 1); | |
790 | |
791 if (p->header_in->pos == p->header_in->end) { | |
792 p->header_in->pos = p->header_in->last = p->header_in->start; | |
793 } | |
794 | |
795 } else { | |
796 p->status_line.data = p->status_start; | |
797 p->full_status_line.data = p->header_in->start; | |
798 *p->status_end = '\0'; | |
799 } | |
800 | |
801 ngx_log_debug(p->log, "upstream status: %d, '%s'" _ | |
802 p->status _ p->full_status_line.data); | |
803 | |
804 p->state_handler = NULL; | |
805 } | |
806 | |
807 if (p->header_in->last == p->header_in->end) { | |
808 rc = NGX_HTTP_PARSE_TOO_LONG_STATUS_LINE; | |
809 | |
810 } else if (rc == NGX_AGAIN) { | |
811 return NGX_AGAIN; | |
812 } | |
813 | |
814 /* STUB */ return NGX_ERROR; | |
815 } | |
816 | |
817 | |
818 | |
819 | |
820 | |
821 | |
822 | |
823 | |
824 | |
825 | |
826 #if 0 | |
827 static int ngx_http_proxy_process_response_header(ngx_http_request_t *r, | |
828 ngx_http_proxy_ctx_t *p) | |
829 { | |
830 return NGX_OK; | |
831 } | |
832 #endif | |
833 | |
834 | |
835 static int ngx_http_proxy_read_response_body(ngx_event_t *ev) | |
836 { | |
837 int n; | |
838 char *buf; | |
839 size_t left, size; | |
840 ngx_hunk_t *h, **ph; | |
841 ngx_connection_t *c; | |
842 ngx_http_request_t *r; | |
843 ngx_http_proxy_ctx_t *p; | |
844 | |
845 if (ev->timedout) { | |
846 return NGX_ERROR; | |
847 } | |
848 | |
849 c = (ngx_connection_t *) ev->data; | |
850 r = (ngx_http_request_t *) c->data; | |
851 p = (ngx_http_proxy_ctx_t *) | |
852 ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); | |
853 | |
854 if (p->hunks.nelts > 0) { | |
855 h = ((ngx_hunk_t **) p->hunks.elts)[p->hunks.nelts - 1]; | |
856 left = h->end - h->last; | |
857 | |
858 } else { | |
859 h = NULL; | |
860 left = 0; | |
861 } | |
862 | |
863 do { | |
864 | |
865 #if (USE_KQUEUE) | |
866 | |
867 /* do not allocate new block if there is EOF */ | |
868 if (ev->eof && ev->available == 0) { | |
869 left = 1; | |
870 } | |
871 | |
872 #elif (HAVE_KQUEUE) | |
873 | |
874 if (ngx_event_type == NGX_HAVE_KQUEUE_EVENT) { | |
875 /* do not allocate new block if there is EOF */ | |
876 if (ev->eof && ev->available == 0) { | |
877 left = 1; | |
878 } | |
879 } | |
880 | |
881 #endif | |
882 | |
883 if (left == 0) { | |
884 ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); | |
885 ngx_test_null(h, | |
886 ngx_create_temp_hunk(r->pool, | |
887 /* STUB */ 4096 /**/, 0, 0), | |
888 NGX_ERROR); | |
889 | |
890 h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; | |
891 *ph = h; | |
892 } | |
893 | |
894 if (h != NULL) { | |
895 buf = h->last; | |
896 size = h->end - h->last; | |
897 | |
898 } else { | |
899 buf = (char *) &buf; | |
900 size = 0; | |
901 } | |
902 | |
903 n = ngx_event_recv(c, buf, size); | |
904 | |
905 ngx_log_debug(c->log, "READ:%d" _ n); | |
906 | |
907 if (n == NGX_AGAIN) { | |
908 return NGX_DONE; | |
909 } | |
910 | |
911 if (n == NGX_ERROR) { | |
912 return NGX_ERROR; | |
913 } | |
914 | |
915 h->last += n; | |
916 left = h->end - h->last; | |
917 | |
918 /* STUB */ | |
919 *h->last = '\0'; | |
920 ngx_log_debug(c->log, "PROXY:\n'%s'" _ h->pos); | |
921 /**/ | |
922 | |
923 } while (n > 0 && left == 0); | |
924 | |
925 if (n == 0) { | |
926 ngx_log_debug(c->log, "CLOSE proxy"); | |
927 #if 0 | |
928 ngx_del_event(ev, NGX_READ_EVENT, NGX_CLOSE_EVENT); | |
929 #endif | |
930 ngx_event_close_connection(ev); | |
931 | |
932 p->hunk_n = 0; | |
933 c->write->event_handler = ngx_http_proxy_write_to_client; | |
934 return ngx_http_proxy_write_to_client(c->write); | |
935 } | |
936 | |
937 /* STUB */ return NGX_DONE; | |
938 } | |
939 | |
940 | |
941 static int ngx_http_proxy_write_to_client(ngx_event_t *ev) | |
942 { | |
943 int rc; | |
944 ngx_hunk_t *h; | |
945 ngx_connection_t *c; | |
946 ngx_http_request_t *r; | |
947 ngx_http_proxy_ctx_t *p; | |
948 | |
949 c = (ngx_connection_t *) ev->data; | |
950 r = (ngx_http_request_t *) c->data; | |
951 p = (ngx_http_proxy_ctx_t *) | |
952 ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); | |
953 | |
954 do { | |
955 h = ((ngx_hunk_t **) p->hunks.elts)[p->hunk_n]; | |
956 | |
957 rc = ngx_http_output_filter(r, h); | |
958 if (rc != NGX_OK) { | |
959 return rc; | |
960 } | |
961 | |
962 if (p->hunk_n >= p->hunks.nelts) { | |
963 break; | |
964 } | |
965 | |
966 p->hunk_n++; | |
967 | |
968 } while (rc == NGX_OK); | |
969 | |
970 return NGX_OK; | |
971 } | |
972 | |
973 | |
974 static int ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int error) | |
975 { | |
976 return ngx_http_finalize_request(p->request, error); | |
977 } | |
978 | |
979 | |
980 static int ngx_http_proxy_error(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p, | |
981 int error) | |
982 { | |
983 ngx_event_close_connection(p->connection->read); | |
984 | |
985 return ngx_http_error(r, error); | |
986 } | |
987 | |
988 | |
989 static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len) | |
990 { | |
991 ngx_http_proxy_log_ctx_t *lcx = (ngx_http_proxy_log_ctx_t *) data; | |
992 | |
993 return ngx_snprintf(buf, len, | |
994 " while %s, upstream: %s, client: %s, URL: %s", | |
995 lcx->action, lcx->upstream, lcx->client, lcx->url); | |
996 } | |
997 | |
998 | |
999 | |
1000 static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx) | |
1001 { | |
1002 char ch; | |
1003 char *p; | |
1004 enum { | |
1005 sw_start = 0, | |
1006 sw_first_major_digit, | |
1007 sw_major_digit, | |
1008 sw_first_minor_digit, | |
1009 sw_minor_digit, | |
1010 sw_status, | |
1011 sw_space_after_status, | |
1012 sw_status_text, | |
1013 sw_almost_done, | |
1014 sw_done | |
1015 } state; | |
1016 | |
1017 state = ctx->state; | |
1018 p = ctx->header_in->pos; | |
1019 | |
1020 while (p < ctx->header_in->last && state < sw_done) { | |
1021 ch = *p++; | |
1022 | |
1023 switch (state) { | |
1024 | |
1025 /* "HTTP/" */ | |
1026 case sw_start: | |
1027 if (p + 3 >= ctx->header_in->last) { | |
1028 return NGX_AGAIN; | |
1029 } | |
1030 | |
1031 if (ch != 'H' || *p != 'T' || *(p + 1) != 'T' || *(p + 2) != 'P' | |
1032 || *(p + 3) != '/') | |
1033 { | |
1034 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1035 } | |
1036 | |
1037 p += 4; | |
1038 state = sw_first_major_digit; | |
1039 break; | |
1040 | |
1041 /* first digit of major HTTP version */ | |
1042 case sw_first_major_digit: | |
1043 if (ch < '1' || ch > '9') { | |
1044 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1045 } | |
1046 | |
1047 state = sw_major_digit; | |
1048 break; | |
1049 | |
1050 /* major HTTP version or dot */ | |
1051 case sw_major_digit: | |
1052 if (ch == '.') { | |
1053 state = sw_first_minor_digit; | |
1054 break; | |
1055 } | |
1056 | |
1057 if (ch < '0' || ch > '9') { | |
1058 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1059 } | |
1060 | |
1061 break; | |
1062 | |
1063 /* first digit of minor HTTP version */ | |
1064 case sw_first_minor_digit: | |
1065 if (ch < '0' || ch > '9') { | |
1066 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1067 } | |
1068 | |
1069 state = sw_minor_digit; | |
1070 break; | |
1071 | |
1072 /* minor HTTP version or end of request line */ | |
1073 case sw_minor_digit: | |
1074 if (ch == ' ') { | |
1075 state = sw_status; | |
1076 break; | |
1077 } | |
1078 | |
1079 if (ch < '0' || ch > '9') { | |
1080 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1081 } | |
1082 | |
1083 break; | |
1084 | |
1085 /* HTTP status code */ | |
1086 case sw_status: | |
1087 if (ch < '0' || ch > '9') { | |
1088 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1089 } | |
1090 | |
1091 ctx->status = ctx->status * 10 + ch - '0'; | |
1092 | |
1093 if (++ctx->status_count == 3) { | |
1094 state = sw_space_after_status; | |
1095 ctx->status_start = p - 3; | |
1096 } | |
1097 | |
1098 break; | |
1099 | |
1100 /* space or end of line */ | |
1101 case sw_space_after_status: | |
1102 switch (ch) { | |
1103 case ' ': | |
1104 state = sw_status_text; | |
1105 break; | |
1106 case CR: | |
1107 state = sw_almost_done; | |
1108 break; | |
1109 case LF: | |
1110 state = sw_done; | |
1111 break; | |
1112 default: | |
1113 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1114 } | |
1115 break; | |
1116 | |
1117 /* any text until end of line */ | |
1118 case sw_status_text: | |
1119 switch (ch) { | |
1120 case CR: | |
1121 state = sw_almost_done; | |
1122 break; | |
1123 case LF: | |
1124 state = sw_done; | |
1125 break; | |
1126 } | |
1127 break; | |
1128 | |
1129 /* end of request line */ | |
1130 case sw_almost_done: | |
1131 ctx->status_end = p - 2; | |
1132 switch (ch) { | |
1133 case LF: | |
1134 state = sw_done; | |
1135 break; | |
1136 default: | |
1137 return NGX_HTTP_PROXY_PARSE_NO_HEADER; | |
1138 } | |
1139 break; | |
1140 } | |
1141 } | |
1142 | |
1143 ctx->header_in->pos = p; | |
1144 | |
1145 if (state == sw_done) { | |
1146 if (ctx->status_end == NULL) { | |
1147 ctx->status_end = p - 1; | |
1148 } | |
1149 | |
1150 ctx->state = sw_start; | |
1151 return NGX_OK; | |
1152 | |
1153 } else { | |
1154 ctx->state = state; | |
1155 return NGX_AGAIN; | |
1156 } | |
1157 } | |
1158 | |
1159 | |
1160 static void *ngx_http_proxy_create_loc_conf(ngx_pool_t *pool) | |
1161 { | |
1162 ngx_http_proxy_loc_conf_t *conf; | |
1163 | |
1164 ngx_test_null(conf, | |
1165 ngx_pcalloc(pool, sizeof(ngx_http_proxy_loc_conf_t)), | |
1166 NULL); | |
1167 | |
1168 /* STUB */ | |
1169 conf->conn_pool_size = 16384; | |
1170 conf->connect_timeout = 10000; | |
1171 conf->send_timeout = 10000; | |
1172 conf->read_timeout = 10000; | |
1173 conf->header_size = 1024; | |
1174 conf->block_size = 4096; | |
1175 conf->max_block_size = 32768; | |
1176 /**/ | |
1177 | |
1178 return conf; | |
1179 } | |
1180 | |
1181 | |
1182 static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, | |
1183 char *conf) | |
1184 { | |
1185 ngx_http_proxy_loc_conf_t *lcf = (ngx_http_proxy_loc_conf_t *) conf; | |
1186 | |
1187 int i, s, len; | |
1188 char *err, *host; | |
1189 struct hostent *h; | |
1190 u_int32_t addr; | |
1191 ngx_str_t *value; | |
1192 ngx_http_conf_ctx_t *ctx; | |
1193 ngx_http_core_loc_conf_t *core_lcf; | |
1194 | |
1195 value = (ngx_str_t *) cf->args->elts; | |
1196 | |
1197 if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) { | |
1198 return "invalid URL prefix"; | |
1199 } | |
1200 | |
1201 ngx_test_null(lcf->upstream_url, | |
1202 ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_url_t)), | |
1203 NGX_CONF_ERROR); | |
1204 | |
1205 value[1].data += 7; | |
1206 value[1].len -= 7; | |
1207 | |
1208 err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream_url); | |
1209 | |
1210 if (err) { | |
1211 return err; | |
1212 } | |
1213 | |
1214 if (lcf->upstream_url->port == 0) { | |
1215 lcf->upstream_url->port = 80; | |
1216 } | |
1217 | |
1218 ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream_url->host.len + 1), | |
1219 NGX_CONF_ERROR); | |
1220 ngx_cpystrn(host, lcf->upstream_url->host.data, | |
1221 lcf->upstream_url->host.len + 1); | |
1222 | |
1223 /* TODO: look up upstreams */ | |
1224 | |
1225 addr = inet_addr(host); | |
1226 if (addr == INADDR_NONE) { | |
1227 h = gethostbyname(host); | |
1228 | |
1229 if (h == NULL || h->h_addr_list[0] == NULL) { | |
1230 /* STUB: "host %s not found", host */ | |
1231 return "host not found"; | |
1232 } | |
1233 | |
1234 for (i = 0; h->h_addr_list[i] != NULL; i++) { | |
1235 /* void */ | |
1236 } | |
1237 | |
1238 /* MP: ngx_shared_palloc() */ | |
1239 | |
1240 ngx_test_null(lcf->upstreams, | |
1241 ngx_pcalloc(cf->pool, | |
1242 sizeof(ngx_http_proxy_upstreams_t) | |
1243 + sizeof(ngx_http_proxy_upstream_t) * (i - 1)), | |
1244 NGX_CONF_ERROR); | |
1245 | |
1246 lcf->upstreams->number = i; | |
1247 | |
1248 for (i = 0; h->h_addr_list[i] != NULL; i++) { | |
1249 lcf->upstreams->u[i].host.data = host; | |
1250 lcf->upstreams->u[i].host.len = lcf->upstream_url->host.len; | |
1251 lcf->upstreams->u[i].addr = *(u_int32_t *)(h->h_addr_list[i]); | |
1252 lcf->upstreams->u[i].port = lcf->upstream_url->port; | |
1253 | |
1254 len = INET_ADDRSTRLEN + lcf->upstream_url->port_name.len + 1; | |
1255 ngx_test_null(lcf->upstreams->u[i].addr_port_name.data, | |
1256 ngx_palloc(cf->pool, len), | |
1257 NGX_CONF_ERROR); | |
1258 | |
1259 s = ngx_inet_ntop(AF_INET, | |
1260 (char *) &lcf->upstreams->u[i].addr, | |
1261 lcf->upstreams->u[i].addr_port_name.data, | |
1262 len); | |
1263 | |
1264 lcf->upstreams->u[i].addr_port_name.data[s++] = ':'; | |
1265 | |
1266 ngx_cpystrn(lcf->upstreams->u[i].addr_port_name.data + s, | |
1267 lcf->upstream_url->port_name.data, | |
1268 lcf->upstream_url->port_name.len + 1); | |
1269 | |
1270 lcf->upstreams->u[i].addr_port_name.len = | |
1271 s + lcf->upstream_url->port_name.len + 1; | |
1272 } | |
1273 | |
1274 } else { | |
1275 | |
1276 /* MP: ngx_shared_palloc() */ | |
1277 | |
1278 ngx_test_null(lcf->upstreams, | |
1279 ngx_palloc(cf->pool, sizeof(ngx_http_proxy_upstreams_t)), | |
1280 NGX_CONF_ERROR); | |
1281 | |
1282 lcf->upstreams->number = 1; | |
1283 | |
1284 lcf->upstreams->u[0].host.data = host; | |
1285 lcf->upstreams->u[0].host.len = lcf->upstream_url->host.len; | |
1286 lcf->upstreams->u[0].addr = addr; | |
1287 lcf->upstreams->u[0].port = lcf->upstream_url->port; | |
1288 | |
1289 len = lcf->upstream_url->host.len | |
1290 + lcf->upstream_url->port_name.len + 1; | |
1291 | |
1292 ngx_test_null(lcf->upstreams->u[0].addr_port_name.data, | |
1293 ngx_palloc(cf->pool, len + 1), | |
1294 NGX_CONF_ERROR); | |
1295 | |
1296 ngx_memcpy(lcf->upstreams->u[0].addr_port_name.data, | |
1297 lcf->upstream_url->host.data, | |
1298 lcf->upstream_url->host.len); | |
1299 | |
1300 s = lcf->upstream_url->host.len; | |
1301 | |
1302 lcf->upstreams->u[0].addr_port_name.data[s++] = ':'; | |
1303 | |
1304 ngx_cpystrn(lcf->upstreams->u[0].addr_port_name.data + s, | |
1305 lcf->upstream_url->port_name.data, | |
1306 lcf->upstream_url->port_name.len + 1); | |
1307 | |
1308 lcf->upstreams->u[0].addr_port_name.len = len; | |
1309 } | |
1310 | |
1311 ctx = cf->ctx; | |
1312 core_lcf = ctx->loc_conf[ngx_http_core_module_ctx.index]; | |
1313 core_lcf->handler = ngx_http_proxy_handler; | |
1314 lcf->upstream_url->location = &core_lcf->name; | |
1315 | |
1316 return NULL; | |
1317 } | |
1318 | |
1319 | |
1320 static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, | |
1321 ngx_http_proxy_upstream_url_t *uu) | |
1322 { | |
1323 size_t i; | |
1324 | |
1325 if (url->data[0] == ':' || url->data[0] == '/') { | |
1326 return "invalid upstream URL"; | |
1327 } | |
1328 | |
1329 uu->host.data = url->data; | |
1330 uu->host_header.data = url->data; | |
1331 | |
1332 for (i = 1; i < url->len; i++) { | |
1333 if (url->data[i] == ':') { | |
1334 uu->port_name.data = &url->data[i] + 1; | |
1335 uu->host.len = i; | |
1336 } | |
1337 | |
1338 if (url->data[i] == '/') { | |
1339 uu->uri.data = &url->data[i]; | |
1340 uu->uri.len = url->len - i; | |
1341 uu->host_header.len = i; | |
1342 | |
1343 if (uu->host.len == 0) { | |
1344 uu->host.len = i; | |
1345 } | |
1346 | |
1347 if (uu->port_name.data == NULL) { | |
1348 return NULL; | |
1349 } | |
1350 | |
1351 uu->port_name.len = &url->data[i] - uu->port_name.data; | |
1352 | |
1353 if (uu->port_name.len > 0) { | |
1354 uu->port = ngx_atoi(uu->port_name.data, uu->port_name.len); | |
1355 if (uu->port > 0) { | |
1356 return NULL; | |
1357 } | |
1358 } | |
1359 | |
1360 return "invalid port in upstream URL"; | |
1361 } | |
1362 } | |
1363 | |
1364 if (uu->host.len == 0) { | |
1365 uu->host.len = i; | |
1366 } | |
1367 | |
1368 uu->host_header.len = i; | |
1369 | |
1370 uu->uri.data = "/"; | |
1371 uu->uri.len = 1; | |
1372 | |
1373 if (uu->port_name.data == NULL) { | |
1374 return NULL; | |
1375 } | |
1376 | |
1377 uu->port_name.len = &url->data[i] - uu->port_name.data; | |
1378 | |
1379 if (uu->port_name.len > 0) { | |
1380 uu->port = ngx_atoi(uu->port_name.data, uu->port_name.len); | |
1381 if (uu->port > 0) { | |
1382 return NULL; | |
1383 } | |
1384 } | |
1385 | |
1386 return "invalid port in upstream URL"; | |
1387 } |