comparison src/http/modules/proxy/ngx_http_proxy_upstream.c @ 171:aff0e5d32af8

nginx-0.0.1-2003-11-03-20:33:31 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 03 Nov 2003 17:33:31 +0000
parents c42be4185301
children caa57ddf6d77
comparison
equal deleted inserted replaced
170:c42be4185301 171:aff0e5d32af8
6 #include <ngx_event_pipe.h> 6 #include <ngx_event_pipe.h>
7 #include <ngx_http.h> 7 #include <ngx_http.h>
8 #include <ngx_http_proxy_handler.h> 8 #include <ngx_http_proxy_handler.h>
9 9
10 10
11 void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p) 11 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
12 static void ngx_http_proxy_init_upstream(void *data);
13 static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p);
14 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p);
15 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
16 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
17 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev);
18 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
19 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
20 static void ngx_http_proxy_process_upstream_header(ngx_http_proxy_ctx_t *p);
21 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
22 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
23 static void ngx_http_proxy_process_body(ngx_event_t *ev);
24 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
25
26
27 static ngx_str_t http_methods[] = {
28 ngx_string("GET "),
29 ngx_string("HEAD "),
30 ngx_string("POST ")
31 };
32
33
34 static char *upstream_header_errors[] = {
35 "upstream sent invalid header",
36 "upstream sent too long header line"
37 };
38
39
40 static char http_version[] = " HTTP/1.0" CRLF;
41 static char host_header[] = "Host: ";
42 static char connection_close_header[] = "Connection: close" CRLF;
43
44
45 int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
46 {
47 int rc;
48 ngx_http_request_t *r;
49 ngx_http_proxy_upstream_t *u;
50
51 r = p->request;
52
53 if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t)))) {
54 return NGX_HTTP_INTERNAL_SERVER_ERROR;
55 }
56
57 p->upstream = u;
58
59 u->peer.peers = p->lcf->peers;
60 u->peer.tries = p->lcf->peers->number;
61
62 ngx_init_array(p->states, r->pool, u->peer.tries,
63 sizeof(ngx_http_proxy_state_t),
64 NGX_HTTP_INTERNAL_SERVER_ERROR);
65
66 u->method = r->method;
67
68 /* STUB */ p->cachable = p->lcf->cache;
69
70 if (r->headers_in.content_length_n > 0) {
71 if (!(r->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
72 return NGX_HTTP_INTERNAL_SERVER_ERROR;
73 }
74
75 r->temp_file->file.fd = NGX_INVALID_FILE;
76 r->temp_file->file.log = r->connection->log;
77 r->temp_file->path = p->lcf->temp_path;
78 r->temp_file->pool = r->pool;
79 r->temp_file->warn = "a client request body is buffered "
80 "to a temporary file";
81 /* r->temp_file->persistent = 0; */
82
83 r->request_body_handler = ngx_http_proxy_init_upstream;
84 r->data = p;
85
86 rc = ngx_http_read_client_request_body(r, p->lcf->request_buffer_size);
87
88 if (rc == NGX_AGAIN) {
89 return NGX_DONE;
90 }
91
92 if (rc == NGX_ERROR) {
93 return NGX_HTTP_INTERNAL_SERVER_ERROR;
94 }
95 }
96
97 ngx_http_proxy_init_upstream(p);
98
99 return NGX_DONE;
100 }
101
102
103 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
104 {
105 int i;
106 size_t len;
107 ngx_hunk_t *h;
108 ngx_chain_t *chain;
109 ngx_table_elt_t *header;
110 ngx_http_request_t *r;
111 ngx_http_proxy_upstream_conf_t *uc;
112
113 r = p->request;
114 uc = p->lcf->upstream;
115
116 len = http_methods[p->upstream->method - 1].len
117 + uc->uri.len
118 + r->uri.len - uc->location->len
119 + 1 + r->args.len /* 1 is for "?" */
120 + sizeof(http_version) - 1
121 + sizeof(host_header) - 1 + uc->host_header.len + 2
122 /* 2 is for "\r\n" */
123 + sizeof(connection_close_header) - 1
124 + 2; /* 2 is for "\r\n" at the header end */
125
126 header = (ngx_table_elt_t *) r->headers_in.headers->elts;
127 for (i = 0; i < r->headers_in.headers->nelts; i++) {
128
129 if (&header[i] == r->headers_in.host) {
130 continue;
131 }
132
133 if (&header[i] == r->headers_in.connection) {
134 continue;
135 }
136
137 /* 2 is for ": " and 2 is for "\r\n" */
138 len += header[i].key.len + 2 + header[i].value.len + 2;
139 }
140
141 /* STUB */ len++;
142
143 ngx_test_null(h, ngx_create_temp_hunk(r->pool, len), NULL);
144 ngx_alloc_link_and_set_hunk(chain, h, r->pool, NULL);
145
146
147 /* the request line */
148
149 h->last = ngx_cpymem(h->last, http_methods[p->upstream->method - 1].data,
150 http_methods[p->upstream->method - 1].len);
151
152 h->last = ngx_cpymem(h->last, uc->uri.data, uc->uri.len);
153
154 h->last = ngx_cpymem(h->last,
155 r->uri.data + uc->location->len,
156 r->uri.len - uc->location->len);
157
158 if (r->args.len > 0) {
159 *(h->last++) = '?';
160 h->last = ngx_cpymem(h->last, r->args.data, r->args.len);
161 }
162
163 h->last = ngx_cpymem(h->last, http_version, sizeof(http_version) - 1);
164
165
166 /* "Host" header */
167
168 h->last = ngx_cpymem(h->last, host_header, sizeof(host_header) - 1);
169 h->last = ngx_cpymem(h->last, uc->host_header.data, uc->host_header.len);
170 *(h->last++) = CR; *(h->last++) = LF;
171
172
173 /* "Connection: close" header */
174
175 h->last = ngx_cpymem(h->last, connection_close_header,
176 sizeof(connection_close_header) - 1);
177
178
179 for (i = 0; i < r->headers_in.headers->nelts; i++) {
180
181 if (&header[i] == r->headers_in.host) {
182 continue;
183 }
184
185 if (&header[i] == r->headers_in.connection) {
186 continue;
187 }
188
189 if (&header[i] == r->headers_in.keep_alive) {
190 continue;
191 }
192
193 h->last = ngx_cpymem(h->last, header[i].key.data, header[i].key.len);
194
195 *(h->last++) = ':'; *(h->last++) = ' ';
196
197 h->last = ngx_cpymem(h->last, header[i].value.data,
198 header[i].value.len);
199
200 *(h->last++) = CR; *(h->last++) = LF;
201
202 ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _
203 header[i].key.data _ header[i].value.data);
204 }
205
206 /* add "\r\n" at the header end */
207 *(h->last++) = CR; *(h->last++) = LF;
208
209 /* STUB */ *(h->last) = '\0';
210 ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ h->pos);
211
212 return chain;
213 }
214
215
216 static void ngx_http_proxy_init_upstream(void *data)
217 {
218 ngx_http_proxy_ctx_t *p = data;
219
220 ngx_chain_t *cl;
221 ngx_http_request_t *r;
222 ngx_output_chain_ctx_t *octx;
223 ngx_chain_writer_ctx_t *wctx;
224
225 r = p->request;
226
227 ngx_log_debug(r->connection->log, "timer_set: %d" _
228 r->connection->read->timer_set);
229
230 if (r->connection->read->timer_set) {
231 ngx_del_timer(r->connection->read);
232 }
233
234 if (!(cl = ngx_http_proxy_create_request(p))) {
235 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
236 return;
237 }
238
239 if (r->request_hunks) {
240 cl->next = r->request_hunks;
241 }
242
243 r->request_hunks = cl;
244
245 p->upstream->peer.log = r->connection->log;
246 p->saved_ctx = r->connection->log->data;
247 p->saved_handler = r->connection->log->handler;
248 r->connection->log->data = p;
249 r->connection->log->handler = ngx_http_proxy_log_error;
250 p->action = "connecting to upstream";
251
252 if (!(octx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)))) {
253 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
254 return;
255 }
256
257 p->upstream->output_chain_ctx = octx;
258
259 octx->sendfile = r->sendfile;
260 octx->pool = r->pool;
261 octx->bufs.num = 1;
262 octx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
263 octx->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer;
264
265 if (!(wctx = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) {
266 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
267 return;
268 }
269
270 octx->output_ctx = wctx;
271
272 wctx->pool = r->pool;
273
274 ngx_http_proxy_connect(p);
275 }
276
277
278 static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p)
12 { 279 {
13 ngx_chain_t *cl; 280 ngx_chain_t *cl;
14 ngx_output_chain_ctx_t *octx; 281 ngx_output_chain_ctx_t *octx;
15 282
16 octx = p->output_chain_ctx; 283 octx = p->upstream->output_chain_ctx;
17 284
18 /* reinit the request chain */ 285 /* reinit the request chain */
19 286
20 for (cl = p->request->request_hunks; cl; cl = cl->next) { 287 for (cl = p->request->request_hunks; cl; cl = cl->next) {
21 cl->hunk->pos = cl->hunk->start; 288 cl->hunk->pos = cl->hunk->start;
30 297
31 /* reinit r->header_in buffer */ 298 /* reinit r->header_in buffer */
32 299
33 if (p->header_in) { 300 if (p->header_in) {
34 if (p->cache) { 301 if (p->cache) {
35 p->header_in->pos = p->header_in->start + p->cache->ctx.header.size; 302 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
36 p->header_in->last = p->header_in->pos; 303 p->header_in->last = p->header_in->pos;
37 304
38 } else { 305 } else {
39 p->header_in->pos = p->header_in->start; 306 p->header_in->pos = p->header_in->start;
40 p->header_in->last = p->header_in->start; 307 p->header_in->last = p->header_in->start;
41 } 308 }
42 } 309 }
43 } 310 }
311
312
313 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
314 {
315 int rc;
316 ngx_chain_t *cl;
317 ngx_connection_t *c;
318 ngx_http_request_t *r;
319 ngx_output_chain_ctx_t *octx;
320
321 p->action = "connecting to upstream";
322
323 rc = ngx_event_connect_peer(&p->upstream->peer);
324
325 if (rc == NGX_ERROR) {
326 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
327 return;
328 }
329
330 if (rc == NGX_CONNECT_ERROR) {
331 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
332 return;
333 }
334
335 p->upstream->peer.connection->data = p;
336 p->upstream->peer.connection->write->event_handler =
337 ngx_http_proxy_send_request_handler;
338 p->upstream->peer.connection->read->event_handler =
339 ngx_http_proxy_process_upstream_status_line;
340
341 r = p->request;
342 c = p->upstream->peer.connection;
343 c->pool = r->pool;
344 c->read->log = c->write->log = c->log = r->connection->log;
345
346 octx = p->upstream->output_chain_ctx;
347
348 if (p->upstream->peer.tries > 1 && p->request_sent) {
349 ngx_http_proxy_reinit_upstream(p);
350 }
351
352 /* init or reinit ngx_output_chain() context */
353
354 if (r->request_body_hunk) {
355 if (!(octx->free = ngx_alloc_chain_link(r->pool))) {
356 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
357 return;
358 }
359
360 octx->free->hunk = r->request_body_hunk;
361 octx->free->next = NULL;
362 octx->hunks = 1;
363
364 r->request_body_hunk->pos = r->request_body_hunk->start;
365 r->request_body_hunk->last = r->request_body_hunk->start;
366 }
367
368 p->request_sent = 0;
369
370 if (rc == NGX_AGAIN) {
371 ngx_add_timer(c->write, p->lcf->connect_timeout);
372 return;
373 }
374
375 /* rc == NGX_OK */
376
377 #if 1 /* test only */
378
379 if (c->read->ready) {
380 /* post aio operation */
381 ngx_http_proxy_process_upstream_status_line(c->read);
382 return;
383 }
384 #endif
385
386 ngx_http_proxy_send_request(p);
387 }
388
389
390 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
391 {
392 int rc;
393 ngx_connection_t *c;
394 ngx_chain_writer_ctx_t *wctx;
395
396 c = p->upstream->peer.connection;
397
398 #if (HAVE_KQUEUE)
399
400 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)
401 && !p->request_sent
402 && c->write->kq_eof)
403 {
404 ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
405 "connect() failed");
406
407 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
408 return;
409 }
410
411 #endif
412
413 p->action = "sending request to upstream";
414
415 wctx = p->upstream->output_chain_ctx->output_ctx;
416 wctx->out = NULL;
417 wctx->last = &wctx->out;
418 wctx->connection = c;
419
420 rc = ngx_output_chain(p->upstream->output_chain_ctx,
421 p->request_sent ? NULL : p->request->request_hunks);
422
423 if (rc == NGX_ERROR) {
424 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
425 return;
426 }
427
428 p->request_sent = 1;
429
430 if (c->write->timer_set) {
431 ngx_del_timer(c->write);
432 }
433
434 if (rc == NGX_AGAIN) {
435 ngx_add_timer(c->write, p->lcf->send_timeout);
436
437 if (ngx_handle_write_event(c->write, /* STUB: lowat */ 0) == NGX_ERROR)
438 {
439 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
440 return;
441 }
442
443 return;
444 }
445
446 /* rc == NGX_OK */
447
448 if (c->tcp_nopush) {
449 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
450 ngx_log_error(NGX_LOG_CRIT, c->log,
451 ngx_socket_errno,
452 ngx_tcp_push_n " failed");
453 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
454 return;
455 }
456
457 c->tcp_nopush = 0;
458 return;
459 }
460
461 #if 0
462 if (c->read->ready) {
463
464 /* post aio operation */
465
466 /*
467 * although we can post aio operation just in the end
468 * of ngx_http_proxy_connect() CHECK IT !!!
469 * it's better to do here because we postpone header buffer allocation
470 */
471
472 ngx_http_proxy_process_upstream_status_line(c->read);
473 return;
474 }
475 #endif
476
477 p->upstream->peer.connection->write->event_handler =
478 ngx_http_proxy_dummy_handler;
479
480 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
481 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
482 return;
483 }
484 }
485
486
487 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
488 {
489 ngx_connection_t *c;
490 ngx_http_proxy_ctx_t *p;
491
492 c = wev->data;
493 p = c->data;
494
495 if (wev->timedout) {
496 p->action = "sending request to upstream";
497 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
498 return;
499 }
500
501 ngx_http_proxy_send_request(p);
502 }
503
504
505 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev)
506 {
507 ngx_log_debug(wev->log, "dummy handler");
508 }
509
510
511 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
512 {
513 int rc;
514 ssize_t n;
515 ngx_connection_t *c;
516 ngx_http_proxy_ctx_t *p;
517
518 c = rev->data;
519 p = c->data;
520 p->action = "reading upstream status line";
521
522 ngx_log_debug(rev->log, "http proxy process status line");
523
524 if (rev->timedout) {
525 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
526 return;
527 }
528
529 if (p->header_in == NULL) {
530 p->header_in = ngx_create_temp_hunk(p->request->pool,
531 p->lcf->header_buffer_size);
532 if (p->header_in == NULL) {
533 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
534 return;
535 }
536 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
537
538 if (p->cache) {
539 p->header_in->pos += p->cache->ctx.header_size;
540 p->header_in->last = p->header_in->pos;
541 }
542 }
543
544 n = ngx_http_proxy_read_upstream_header(p);
545
546 if (n == NGX_AGAIN) {
547 return;
548 }
549
550 if (n == 0) {
551 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
552 "upstream prematurely closed connection");
553 }
554
555 if (n == NGX_ERROR || n == 0) {
556 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
557 return;
558 }
559
560 p->upstream->peer.cached = 0;
561
562 rc = ngx_http_proxy_parse_status_line(p);
563
564 if (rc == NGX_AGAIN) {
565 if (p->header_in->pos == p->header_in->last) {
566 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
567 "upstream sent too long status line");
568 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
569 }
570 return;
571 }
572
573 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
574 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
575 "upstream sent no valid HTTP/1.0 header");
576
577 if (p->accel) {
578 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
579
580 } else {
581 p->request->http_version = NGX_HTTP_VERSION_9;
582 p->upstream->status = NGX_HTTP_OK;
583 ngx_http_proxy_send_response(p);
584 }
585
586 return;
587 }
588
589 /* rc == NGX_OK */
590
591 p->upstream->status = p->status;
592
593 if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR) {
594
595 if (p->upstream->peer.tries > 1
596 && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
597 {
598 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
599 return;
600 }
601
602 if (p->upstream->peer.tries == 0
603 && p->stale
604 && (p->lcf->use_stale & NGX_HTTP_PROXY_FT_HTTP_500))
605 {
606 ngx_http_proxy_finalize_request(p,
607 ngx_http_proxy_send_cached_response(p));
608
609 return;
610 }
611 }
612
613 p->upstream->status_line.len = p->status_end - p->status_start;
614 p->upstream->status_line.data = ngx_palloc(p->request->pool,
615 p->upstream->status_line.len + 1);
616 if (p->upstream->status_line.data == NULL) {
617 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
618 return;
619 }
620 ngx_cpystrn(p->upstream->status_line.data, p->status_start,
621 p->upstream->status_line.len + 1);
622
623 ngx_log_debug(rev->log, "http proxy status %d '%s'" _
624 p->upstream->status _ p->upstream->status_line.data);
625
626 if (p->upstream->headers_in.headers) {
627 p->upstream->headers_in.headers->nelts = 0;
628 } else {
629 p->upstream->headers_in.headers = ngx_create_table(p->request->pool,
630 20);
631 }
632
633 c->read->event_handler = ngx_http_proxy_process_upstream_headers;
634 ngx_http_proxy_process_upstream_headers(rev);
635 }
636
637
638 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
639 {
640 int i, rc;
641 ssize_t n;
642 ngx_table_elt_t *h;
643 ngx_connection_t *c;
644 ngx_http_request_t *r;
645 ngx_http_proxy_ctx_t *p;
646
647 c = rev->data;
648 p = c->data;
649 r = p->request;
650 p->action = "reading upstream headers";
651
652 ngx_log_debug(rev->log, "http proxy process header line");
653
654 if (rev->timedout) {
655 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
656 return;
657 }
658
659 rc = NGX_AGAIN;
660
661 for ( ;; ) {
662 if (rc == NGX_AGAIN) {
663 n = ngx_http_proxy_read_upstream_header(p);
664
665 if (n == 0) {
666 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
667 "upstream prematurely closed connection");
668 }
669
670 if (n == NGX_ERROR || n == 0) {
671 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
672 return;
673 }
674
675 if (n == NGX_AGAIN) {
676 return;
677 }
678 }
679
680 rc = ngx_http_parse_header_line(p->request, p->header_in);
681
682 if (rc == NGX_OK) {
683
684 /* a header line has been parsed successfully */
685
686 h = ngx_http_add_header(&p->upstream->headers_in,
687 ngx_http_proxy_headers_in);
688 if (h == NULL) {
689 ngx_http_proxy_finalize_request(p,
690 NGX_HTTP_INTERNAL_SERVER_ERROR);
691 return;
692 }
693
694 h->key.len = r->header_name_end - r->header_name_start;
695 h->value.len = r->header_end - r->header_start;
696
697 h->key.data = ngx_palloc(p->request->pool,
698 h->key.len + 1 + h->value.len + 1);
699 if (h->key.data == NULL) {
700 ngx_http_proxy_finalize_request(p,
701 NGX_HTTP_INTERNAL_SERVER_ERROR);
702 return;
703 }
704
705 h->value.data = h->key.data + h->key.len + 1;
706 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
707 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
708
709 for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
710 if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
711 continue;
712 }
713
714 if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
715 h->key.data) == 0)
716 {
717 *((ngx_table_elt_t **) ((char *) &p->upstream->headers_in
718 + ngx_http_proxy_headers_in[i].offset)) = h;
719 break;
720 }
721 }
722
723 ngx_log_debug(c->log, "HTTP proxy header: '%s: %s'" _
724 h->key.data _ h->value.data);
725
726 continue;
727
728 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
729
730 /* a whole header has been parsed successfully */
731
732 ngx_log_debug(c->log, "HTTP header done");
733
734 ngx_http_proxy_process_upstream_header(p);
735 ngx_http_proxy_send_response(p);
736 return;
737
738 } else if (rc != NGX_AGAIN) {
739
740 /* there was error while a header line parsing */
741
742 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
743 upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
744
745 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
746 return;
747 }
748
749 /* rc == NGX_AGAIN: a header line parsing is still not complete */
750
751 if (p->header_in->last == p->header_in->end) {
752 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
753 "upstream sent too big header");
754
755 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
756 return;
757 }
758 }
759 }
760
761
762 static void ngx_http_proxy_process_upstream_header(ngx_http_proxy_ctx_t *p)
763 {
764 time_t expires;
765
766 expires = ngx_http_parse_time(p->upstream->headers_in.expires->value.data,
767 p->upstream->headers_in.expires->value.len);
768
769 p->cache->ctx.header.expires = expires;
770 }
771
772
773 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
774 {
775 ssize_t n;
776 ngx_event_t *rev;
777
778 rev = p->upstream->peer.connection->read;
779
780 n = p->header_in->last - p->header_in->pos;
781
782 if (n > 0) {
783 return n;
784 }
785
786 n = ngx_recv(p->upstream->peer.connection, p->header_in->last,
787 p->header_in->end - p->header_in->last);
788
789 if (n == NGX_AGAIN) {
790 ngx_add_timer(rev, p->lcf->read_timeout);
791
792 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
793 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
794 return NGX_ERROR;
795 }
796
797 return NGX_AGAIN;
798 }
799
800 if (n == 0) {
801 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
802 "upstream closed prematurely connection");
803 }
804
805 if (n == 0 || n == NGX_ERROR) {
806 return NGX_ERROR;
807 }
808
809 p->header_in->last += n;
810
811 return n;
812 }
813
814
815 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
816 {
817 int rc, i;
818 ngx_table_elt_t *ho, *h;
819 ngx_event_pipe_t *ep;
820 ngx_http_request_t *r;
821 ngx_http_cache_file_t *header;
822 ngx_http_core_loc_conf_t *clcf;
823
824 r = p->request;
825
826 r->headers_out.status = p->upstream->status;
827
828 #if 0
829 r->headers_out.content_length_n = -1;
830 r->headers_out.content_length = NULL;
831 #endif
832
833 /* copy an upstream header to r->headers_out */
834
835 if (ngx_http_proxy_copy_header(p, &p->upstream->headers_in) == NGX_ERROR) {
836 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
837 return;
838 }
839
840 /* TODO: preallocate event_pipe hunks, look "Content-Length" */
841
842 rc = ngx_http_send_header(r);
843
844 p->header_sent = 1;
845
846 if (p->cache) {
847 header = (ngx_http_cache_file_t *) p->header_in->start;
848
849 /* STUB */
850 header->header.expires = 0;
851 header->header.last_modified = 0;
852
853 header->header.length = r->headers_out.content_length_n;
854 header->key_len = p->cache->ctx.key.len;
855 ngx_memcpy(&header->key, p->cache->ctx.key.data, header->key_len);
856 header->key[header->key_len] = LF;
857 }
858
859 ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
860 if (ep == NULL) {
861 ngx_http_proxy_finalize_request(p, 0);
862 return;
863 }
864
865 p->upstream->event_pipe = ep;
866
867 ep->input_filter = ngx_event_pipe_copy_input_filter;
868 ep->output_filter = (ngx_event_pipe_output_filter_pt)
869 ngx_http_output_filter;
870 ep->output_ctx = r;
871 ep->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
872 ep->bufs = p->lcf->bufs;
873 ep->busy_size = p->lcf->busy_buffers_size;
874 ep->upstream = p->upstream->peer.connection;
875 ep->downstream = r->connection;
876 ep->pool = r->pool;
877 ep->log = r->connection->log;
878
879 if (!(ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
880 ngx_http_proxy_finalize_request(p, 0);
881 return;
882 }
883
884 ep->temp_file->file.fd = NGX_INVALID_FILE;
885 ep->temp_file->file.log = r->connection->log;
886 ep->temp_file->path = p->lcf->temp_path;
887 ep->temp_file->pool = r->pool;
888 ep->temp_file->warn = "an upstream response is buffered "
889 "to a temporary file";
890
891 ep->max_temp_file_size = p->lcf->max_temp_file_size;
892 ep->temp_file_write_size = p->lcf->temp_file_write_size;
893
894 ep->preread_hunks = ngx_alloc_chain_link(r->pool);
895 if (ep->preread_hunks == NULL) {
896 ngx_http_proxy_finalize_request(p, 0);
897 return;
898 }
899 ep->preread_hunks->hunk = p->header_in;
900 ep->preread_hunks->next = NULL;
901 p->header_in->type |= NGX_HUNK_PREREAD;
902
903 ep->preread_size = p->header_in->last - p->header_in->pos;
904
905 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
906
907 /* the posted aio operation can currupt shadow buf */
908 ep->single_buf = 1;
909 }
910
911 /* TODO: ep->free_bufs = 0 if use ngx_create_chain_of_hunks() */
912 ep->free_bufs = 1;
913
914 /*
915 * event_pipe would do p->header_in->last += ep->preread_size
916 * as though these bytes were read.
917 */
918 p->header_in->last = p->header_in->pos;
919
920 ep->cachable = p->cachable;
921
922 if (p->lcf->cyclic_temp_file) {
923
924 /*
925 * we need to disable the use of sendfile() if we use cyclic temp file
926 * because the writing a new data can interfere with sendfile()
927 * that uses the same kernel file pages (at least on FreeBSD)
928 */
929
930 ep->cyclic_temp_file = 1;
931 r->sendfile = 0;
932
933 } else {
934 ep->cyclic_temp_file = 0;
935 r->sendfile = 1;
936 }
937
938 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
939
940 ep->read_timeout = p->lcf->read_timeout;
941 ep->send_timeout = clcf->send_timeout;
942 ep->send_lowat = clcf->send_lowat;
943
944 p->upstream->peer.connection->read->event_handler =
945 ngx_http_proxy_process_body;
946 r->connection->write->event_handler = ngx_http_proxy_process_body;
947
948 ngx_http_proxy_process_body(p->upstream->peer.connection->read);
949
950 return;
951 }
952
953
954 static void ngx_http_proxy_process_body(ngx_event_t *ev)
955 {
956 ngx_connection_t *c;
957 ngx_http_request_t *r;
958 ngx_http_proxy_ctx_t *p;
959 ngx_event_pipe_t *ep;
960
961 c = ev->data;
962
963 if (ev->write) {
964 ngx_log_debug(ev->log, "http proxy process downstream");
965 r = c->data;
966 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
967 p->action = "sending to client";
968
969 } else {
970 ngx_log_debug(ev->log, "http proxy process upstream");
971 p = c->data;
972 r = p->request;
973 p->action = "reading upstream body";
974 }
975
976 ep = p->upstream->event_pipe;
977
978 if (ev->timedout) {
979 if (ev->write) {
980 ep->downstream_error = 1;
981 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
982 "client timed out");
983
984 } else {
985 ep->upstream_error = 1;
986 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
987 "upstream timed out");
988 }
989
990 } else {
991 if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) {
992 ngx_http_proxy_finalize_request(p, 0);
993 return;
994 }
995 }
996
997 if (p->upstream->peer.connection) {
998 if (ep->upstream_done) {
999 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1000 ngx_http_proxy_finalize_request(p, 0);
1001 return;
1002 }
1003
1004 } else if (ep->upstream_eof) {
1005
1006 /* TODO: check length & update cache */
1007
1008 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1009 ngx_http_proxy_finalize_request(p, 0);
1010 return;
1011 }
1012 }
1013
1014 if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
1015 ngx_http_proxy_close_connection(p->upstream->peer.connection);
1016 p->upstream->peer.connection = NULL;
1017 }
1018 }
1019
1020 if (ep->downstream_done) {
1021 ngx_log_debug(ev->log, "http proxy downstream done");
1022 ngx_http_proxy_finalize_request(p, r->main ? 0 : ngx_http_send_last(r));
1023 return;
1024 }
1025
1026 if (ep->downstream_error) {
1027 if (!p->cachable && p->upstream->peer.connection) {
1028 ngx_http_proxy_close_connection(p->upstream->peer.connection);
1029 p->upstream->peer.connection = NULL;
1030 }
1031
1032 if (p->upstream->peer.connection == NULL) {
1033 ngx_http_close_connection(c);
1034 }
1035 }
1036
1037 return;
1038 }
1039
1040
1041 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
1042 {
1043 int status;
1044
1045 ngx_log_debug(p->request->connection->log, "next upstream: %d" _ ft_type);
1046
1047 if (ft_type != NGX_HTTP_PROXY_FT_HTTP_404) {
1048 ngx_event_connect_peer_failed(&p->upstream->peer);
1049 }
1050
1051 if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) {
1052 ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT,
1053 "upstream timed out");
1054 }
1055
1056 if (p->upstream->peer.cached && ft_type == NGX_HTTP_PROXY_FT_ERROR) {
1057 status = 0;
1058
1059 } else {
1060 switch(ft_type) {
1061 case NGX_HTTP_PROXY_FT_TIMEOUT:
1062 status = NGX_HTTP_GATEWAY_TIME_OUT;
1063 break;
1064
1065 case NGX_HTTP_PROXY_FT_HTTP_500:
1066 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1067 break;
1068
1069 case NGX_HTTP_PROXY_FT_HTTP_404:
1070 status = NGX_HTTP_NOT_FOUND;
1071 break;
1072
1073 /*
1074 * NGX_HTTP_PROXY_FT_BUSY_LOCK and NGX_HTTP_PROXY_FT_MAX_WAITING
1075 * never reach here
1076 */
1077
1078 default:
1079 status = NGX_HTTP_BAD_GATEWAY;
1080 }
1081 }
1082
1083 if (p->upstream->peer.connection) {
1084 ngx_http_proxy_close_connection(p->upstream->peer.connection);
1085 p->upstream->peer.connection = NULL;
1086 }
1087
1088 if (status) {
1089 if (ngx_http_proxy_log_state(p, status) == NGX_ERROR) {
1090 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1091 return;
1092 }
1093
1094 if (p->upstream->peer.tries == 0 || !(p->lcf->next_upstream & ft_type))
1095 {
1096 if (p->stale && (p->lcf->use_stale & ft_type)) {
1097 ngx_http_proxy_finalize_request(p,
1098 ngx_http_proxy_send_cached_response(p));
1099 return;
1100 }
1101
1102 ngx_http_proxy_finalize_request(p, status);
1103 return;
1104 }
1105 }
1106
1107 ngx_http_proxy_connect(p);
1108 }