comparison src/http/modules/proxy/ngx_http_proxy_upstream.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children cc9f381affaa
comparison
equal deleted inserted replaced
-1:000000000000 0:f0b350454894
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10 #include <ngx_event_connect.h>
11 #include <ngx_event_pipe.h>
12 #include <ngx_http.h>
13 #include <ngx_http_proxy_handler.h>
14
15
16 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
17 static void ngx_http_proxy_init_upstream(void *data);
18 static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p);
19 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p);
20 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
21 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
22 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev);
23 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev);
24 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
25 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
26 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
27 static void ngx_http_proxy_process_body(ngx_event_t *ev);
28 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
29
30
31 static ngx_str_t http_methods[] = {
32 ngx_string("GET "),
33 ngx_string("HEAD "),
34 ngx_string("POST ")
35 };
36
37
38 static char *upstream_header_errors[] = {
39 "upstream sent invalid header",
40 "upstream sent too long header line"
41 };
42
43
44 static char http_version[] = " HTTP/1.0" CRLF;
45 static char host_header[] = "Host: ";
46 static char x_real_ip_header[] = "X-Real-IP: ";
47 static char x_forwarded_for_header[] = "X-Forwarded-For: ";
48 static char connection_close_header[] = "Connection: close" CRLF;
49
50
51 int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p)
52 {
53 int rc;
54 ngx_temp_file_t *tf;
55 ngx_http_request_t *r;
56 ngx_http_request_body_t *rb;
57 ngx_http_proxy_upstream_t *u;
58
59 r = p->request;
60
61 if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t)))) {
62 return NGX_HTTP_INTERNAL_SERVER_ERROR;
63 }
64
65 p->upstream = u;
66
67 u->peer.log_error = NGX_ERROR_ERR;
68 u->peer.peers = p->lcf->peers;
69 u->peer.tries = p->lcf->peers->number;
70 #if (NGX_THREADS)
71 u->peer.lock = &r->connection->lock;
72 #endif
73
74 u->method = r->method;
75
76 if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) {
77 return NGX_HTTP_INTERNAL_SERVER_ERROR;
78 }
79 r->request_body = rb;
80
81 if (r->headers_in.content_length_n <= 0) {
82 ngx_http_proxy_init_upstream(p);
83 return NGX_DONE;
84 }
85
86 if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
87 return NGX_HTTP_INTERNAL_SERVER_ERROR;
88 }
89
90 tf->file.fd = NGX_INVALID_FILE;
91 tf->file.log = r->connection->log;
92 tf->path = p->lcf->temp_path;
93 tf->pool = r->pool;
94 tf->warn = "a client request body is buffered to a temporary file";
95 /* tf->persistent = 0; */
96
97 rb->handler = ngx_http_proxy_init_upstream;
98 rb->data = p;
99 /* rb->bufs = NULL; */
100 /* rb->buf = NULL; */
101 /* rb->rest = 0; */
102
103 rb->temp_file = tf;
104
105 rc = ngx_http_read_client_request_body(r);
106
107 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
108 return rc;
109 }
110
111 return NGX_DONE;
112 }
113
114
115 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p)
116 {
117 size_t len;
118 ngx_uint_t i;
119 ngx_buf_t *b;
120 ngx_chain_t *chain;
121 ngx_list_part_t *part;
122 ngx_table_elt_t *header;
123 ngx_http_request_t *r;
124 ngx_http_proxy_upstream_conf_t *uc;
125
126 r = p->request;
127 uc = p->lcf->upstream;
128
129 if (p->upstream->method) {
130 len = http_methods[p->upstream->method - 1].len;
131
132 } else {
133 len = r->method_name.len;
134 }
135
136 len += uc->uri.len
137 + r->uri.len - uc->location->len
138 + 1 + r->args.len /* 1 is for "?" */
139 + sizeof(http_version) - 1
140 + sizeof(connection_close_header) - 1
141 + 2; /* 2 is for "\r\n" at the header end */
142
143
144 if (p->lcf->preserve_host && r->headers_in.host) {
145 len += sizeof(host_header) - 1
146 + r->headers_in.host_name_len
147 + 1 /* 1 is for ":" */
148 + uc->port_text.len
149 + 2; /* 2 is for "\r\n" */
150 } else { /* 2 is for "\r\n" */
151 len += sizeof(host_header) - 1 + uc->host_header.len + 2;
152 }
153
154
155 if (p->lcf->set_x_real_ip) { /* 2 is for "\r\n" */
156 len += sizeof(x_real_ip_header) - 1 + INET_ADDRSTRLEN - 1 + 2;
157 }
158
159
160 if (p->lcf->add_x_forwarded_for) {
161 if (r->headers_in.x_forwarded_for) {
162 len += sizeof(x_forwarded_for_header) - 1
163 + r->headers_in.x_forwarded_for->value.len
164 + 2 /* 2 is ofr ", " */
165 + INET_ADDRSTRLEN - 1
166 + 2; /* 2 is for "\r\n" */
167 } else {
168 len += sizeof(x_forwarded_for_header) - 1 + INET_ADDRSTRLEN - 1 + 2;
169 /* 2 is for "\r\n" */
170 }
171 }
172
173
174 part = &r->headers_in.headers.part;
175 header = part->elts;
176
177 for (i = 0; /* void */; i++) {
178
179 if (i >= part->nelts) {
180 if (part->next == NULL) {
181 break;
182 }
183
184 part = part->next;
185 header = part->elts;
186 i = 0;
187 }
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 #if (NGX_DEBUG)
202 len++;
203 #endif
204
205 ngx_test_null(b, ngx_create_temp_buf(r->pool, len), NULL);
206 ngx_alloc_link_and_set_buf(chain, b, r->pool, NULL);
207
208
209 /* the request line */
210
211 if (p->upstream->method) {
212 b->last = ngx_cpymem(b->last,
213 http_methods[p->upstream->method - 1].data,
214 http_methods[p->upstream->method - 1].len);
215 } else {
216 b->last = ngx_cpymem(b->last, r->method_name.data, r->method_name.len);
217 }
218
219 b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len);
220
221 b->last = ngx_cpymem(b->last,
222 r->uri.data + uc->location->len,
223 r->uri.len - uc->location->len);
224
225 if (r->args.len > 0) {
226 *(b->last++) = '?';
227 b->last = ngx_cpymem(b->last, r->args.data, r->args.len);
228 }
229
230 b->last = ngx_cpymem(b->last, http_version, sizeof(http_version) - 1);
231
232
233 /* the "Connection: close" header */
234
235 b->last = ngx_cpymem(b->last, connection_close_header,
236 sizeof(connection_close_header) - 1);
237
238
239 /* the "Host" header */
240
241 b->last = ngx_cpymem(b->last, host_header, sizeof(host_header) - 1);
242
243 if (p->lcf->preserve_host && r->headers_in.host) {
244 b->last = ngx_cpymem(b->last, r->headers_in.host->value.data,
245 r->headers_in.host_name_len);
246
247 if (!uc->default_port) {
248 *(b->last++) = ':';
249 b->last = ngx_cpymem(b->last, uc->port_text.data,
250 uc->port_text.len);
251 }
252
253 } else {
254 b->last = ngx_cpymem(b->last, uc->host_header.data,
255 uc->host_header.len);
256 }
257 *(b->last++) = CR; *(b->last++) = LF;
258
259
260 /* the "X-Real-IP" header */
261
262 if (p->lcf->set_x_real_ip) {
263 b->last = ngx_cpymem(b->last, x_real_ip_header,
264 sizeof(x_real_ip_header) - 1);
265 b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
266 r->connection->addr_text.len);
267 *(b->last++) = CR; *(b->last++) = LF;
268 }
269
270
271 /* the "X-Forwarded-For" header */
272
273 if (p->lcf->add_x_forwarded_for) {
274 if (r->headers_in.x_forwarded_for) {
275 b->last = ngx_cpymem(b->last, x_forwarded_for_header,
276 sizeof(x_forwarded_for_header) - 1);
277
278 b->last = ngx_cpymem(b->last,
279 r->headers_in.x_forwarded_for->value.data,
280 r->headers_in.x_forwarded_for->value.len);
281
282 *(b->last++) = ','; *(b->last++) = ' ';
283
284 } else {
285 b->last = ngx_cpymem(b->last, x_forwarded_for_header,
286 sizeof(x_forwarded_for_header) - 1);
287 }
288
289 b->last = ngx_cpymem(b->last, r->connection->addr_text.data,
290 r->connection->addr_text.len);
291 *(b->last++) = CR; *(b->last++) = LF;
292 }
293
294
295 part = &r->headers_in.headers.part;
296 header = part->elts;
297
298 for (i = 0; /* void */; i++) {
299
300 if (i >= part->nelts) {
301 if (part->next == NULL) {
302 break;
303 }
304
305 part = part->next;
306 header = part->elts;
307 i = 0;
308 }
309
310 if (&header[i] == r->headers_in.host) {
311 continue;
312 }
313
314 if (&header[i] == r->headers_in.connection) {
315 continue;
316 }
317
318 if (&header[i] == r->headers_in.keep_alive) {
319 continue;
320 }
321
322 if (&header[i] == r->headers_in.x_forwarded_for
323 && p->lcf->add_x_forwarded_for)
324 {
325 continue;
326 }
327
328 b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len);
329
330 *(b->last++) = ':'; *(b->last++) = ' ';
331
332 b->last = ngx_cpymem(b->last, header[i].value.data,
333 header[i].value.len);
334
335 *(b->last++) = CR; *(b->last++) = LF;
336
337 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
338 "http proxy header: \"%s: %s\"",
339 header[i].key.data, header[i].value.data);
340 }
341
342 /* add "\r\n" at the header end */
343 *(b->last++) = CR; *(b->last++) = LF;
344
345 #if (NGX_DEBUG)
346 *(b->last) = '\0';
347 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
348 "http proxy header:\n\"%s\"", b->pos);
349 #endif
350
351 return chain;
352 }
353
354
355 static void ngx_http_proxy_init_upstream(void *data)
356 {
357 ngx_http_proxy_ctx_t *p = data;
358
359 ngx_chain_t *cl;
360 ngx_http_request_t *r;
361 ngx_output_chain_ctx_t *output;
362 ngx_chain_writer_ctx_t *writer;
363 ngx_http_proxy_log_ctx_t *ctx;
364
365 r = p->request;
366
367 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
368 "http proxy init upstream, client timer: %d",
369 r->connection->read->timer_set);
370
371 if (r->connection->read->timer_set) {
372 ngx_del_timer(r->connection->read);
373 }
374
375 r->connection->read->event_handler = ngx_http_proxy_check_broken_connection;
376
377 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
378
379 r->connection->write->event_handler =
380 ngx_http_proxy_check_broken_connection;
381
382 if (!r->connection->write->active) {
383 if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
384 NGX_CLEAR_EVENT) == NGX_ERROR)
385 {
386 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
387 return;
388 }
389 }
390 }
391
392
393 if (!(cl = ngx_http_proxy_create_request(p))) {
394 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
395 return;
396 }
397
398 if (r->request_body->bufs) {
399 cl->next = r->request_body->bufs;
400 }
401
402 r->request_body->bufs = cl;
403
404 if (!(ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)))) {
405 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
406 return;
407 }
408 ctx->connection = r->connection->number;
409 ctx->proxy = p;
410
411 p->upstream->peer.log = r->connection->log;
412 p->saved_ctx = r->connection->log->data;
413 p->saved_handler = r->connection->log->handler;
414 r->connection->log->data = ctx;
415 r->connection->log->handler = ngx_http_proxy_log_error;
416 p->action = "connecting to upstream";
417
418 if (!(output = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)))) {
419 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
420 return;
421 }
422
423 p->upstream->output_chain_ctx = output;
424
425 output->sendfile = r->sendfile;
426 output->pool = r->pool;
427 output->bufs.num = 1;
428 output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
429 output->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer;
430
431 if (!(writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) {
432 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
433 return;
434 }
435
436 output->filter_ctx = writer;
437 writer->pool = r->pool;
438
439 #if 0
440 if (p->lcf->busy_lock && p->busy_lock == NULL) {
441 #else
442 if (p->lcf->busy_lock && !p->busy_locked) {
443 #endif
444 ngx_http_proxy_upstream_busy_lock(p);
445 } else {
446 ngx_http_proxy_connect(p);
447 }
448 }
449
450
451 static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p)
452 {
453 ngx_chain_t *cl;
454 ngx_output_chain_ctx_t *output;
455
456 /* reinit the request chain */
457
458 for (cl = p->request->request_body->bufs; cl; cl = cl->next) {
459 cl->buf->pos = cl->buf->start;
460 cl->buf->file_pos = 0;
461 }
462
463 /* reinit the ngx_output_chain() context */
464
465 output = p->upstream->output_chain_ctx;
466
467 output->buf = NULL;
468 output->in = NULL;
469 output->free = NULL;
470 output->busy = NULL;
471
472 /* reinit r->header_in buffer */
473
474 if (p->header_in) {
475 if (p->cache) {
476 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
477 p->header_in->last = p->header_in->pos;
478
479 } else {
480 p->header_in->pos = p->header_in->start;
481 p->header_in->last = p->header_in->start;
482 }
483 }
484
485 /* add one more state */
486
487 if (!(p->state = ngx_push_array(&p->states))) {
488 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
489 return;
490 }
491
492 p->status = 0;
493 p->status_count = 0;
494 }
495
496
497 #if 0
498
499 void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
500 {
501 ngx_int_t rc;
502
503 rc = ngx_event_busy_lock(p->lcf->busy_lock, p->busy_lock);
504
505 if (rc == NGX_AGAIN) {
506 return;
507 }
508
509 if (rc == NGX_OK) {
510 ngx_http_proxy_connect(p);
511 return;
512 }
513
514 if (rc == NGX_ERROR) {
515 p->state->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
516 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
517 return;
518 }
519
520 /* rc == NGX_BUSY */
521
522 #if (NGX_HTTP_CACHE)
523
524 if (p->busy_lock->timer) {
525 ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
526 } else {
527 ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
528 }
529
530 if (p->stale && (p->lcf->use_stale & ft_type)) {
531 ngx_http_proxy_finalize_request(p,
532 ngx_http_proxy_send_cached_response(p));
533 return;
534 }
535
536 #endif
537
538 p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
539 ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
540 }
541
542 #endif
543
544
545 #if 1
546
547 void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
548 {
549 ngx_int_t rc;
550 #if (NGX_HTTP_CACHE)
551 ngx_int_t ft_type;
552 #endif
553
554 if (p->busy_lock.time == 0) {
555 p->busy_lock.event = p->request->connection->read;
556 p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
557 }
558
559 rc = ngx_http_busy_lock(p->lcf->busy_lock, &p->busy_lock);
560
561 if (rc == NGX_AGAIN) {
562 return;
563 }
564
565 if (rc == NGX_OK) {
566 ngx_http_proxy_connect(p);
567 return;
568 }
569
570 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
571
572 #if (NGX_HTTP_CACHE)
573
574 if (rc == NGX_DONE) {
575 ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
576
577 } else {
578 /* rc == NGX_ERROR */
579 ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
580 }
581
582 if (p->stale && (p->lcf->use_stale & ft_type)) {
583 ngx_http_proxy_finalize_request(p,
584 ngx_http_proxy_send_cached_response(p));
585 return;
586 }
587
588 #endif
589
590 p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
591 ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
592 }
593
594 #endif
595
596
597 static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
598 {
599 int rc;
600 ngx_connection_t *c;
601 ngx_http_request_t *r;
602 ngx_output_chain_ctx_t *output;
603 ngx_chain_writer_ctx_t *writer;
604
605 p->action = "connecting to upstream";
606
607 p->request->connection->single_connection = 0;
608
609 rc = ngx_event_connect_peer(&p->upstream->peer);
610
611 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
612 "http proxy connect: %d", rc);
613
614 if (rc == NGX_ERROR) {
615 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
616 return;
617 }
618
619 p->state->peer =
620 &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text;
621
622 if (rc == NGX_CONNECT_ERROR) {
623 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
624 return;
625 }
626
627 r = p->request;
628 c = p->upstream->peer.connection;
629
630 c->data = p;
631 c->write->event_handler = ngx_http_proxy_send_request_handler;
632 c->read->event_handler = ngx_http_proxy_process_upstream_status_line;
633
634 c->pool = r->pool;
635 c->read->log = c->write->log = c->log = r->connection->log;
636
637 /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
638
639 output = p->upstream->output_chain_ctx;
640 writer = output->filter_ctx;
641 writer->out = NULL;
642 writer->last = &writer->out;
643 writer->connection = c;
644 writer->limit = OFF_T_MAX_VALUE;
645
646 if (p->upstream->peer.tries > 1 && p->request_sent) {
647 ngx_http_proxy_reinit_upstream(p);
648 }
649
650 if (r->request_body->buf) {
651 if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) {
652
653 if (!(output->free = ngx_alloc_chain_link(r->pool))) {
654 ngx_http_proxy_finalize_request(p,
655 NGX_HTTP_INTERNAL_SERVER_ERROR);
656 return;
657 }
658
659 output->free->buf = r->request_body->buf;
660 output->free->next = NULL;
661 output->allocated = 1;
662
663 r->request_body->buf->pos = r->request_body->buf->start;
664 r->request_body->buf->last = r->request_body->buf->start;
665 r->request_body->buf->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
666
667 } else {
668 r->request_body->buf->pos = r->request_body->buf->start;
669 }
670 }
671
672 p->request_sent = 0;
673
674 if (rc == NGX_AGAIN) {
675 ngx_add_timer(c->write, p->lcf->connect_timeout);
676 return;
677 }
678
679 /* rc == NGX_OK */
680
681 #if 1 /* test only, see below about "post aio operation" */
682
683 if (c->read->ready) {
684 /* post aio operation */
685 ngx_http_proxy_process_upstream_status_line(c->read);
686 return;
687 }
688
689 #endif
690
691 ngx_http_proxy_send_request(p);
692 }
693
694
695 static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
696 {
697 int rc;
698 ngx_connection_t *c;
699
700 c = p->upstream->peer.connection;
701
702 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
703 "http proxy send request");
704
705 #if (HAVE_KQUEUE)
706
707 if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)
708 && !p->request_sent
709 && c->write->pending_eof)
710 {
711 ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
712 "connect() failed");
713
714 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
715 return;
716 }
717
718 #endif
719
720 p->action = "sending request to upstream";
721
722 rc = ngx_output_chain(p->upstream->output_chain_ctx,
723 p->request_sent ? NULL:
724 p->request->request_body->bufs);
725
726 if (rc == NGX_ERROR) {
727 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
728 return;
729 }
730
731 p->request_sent = 1;
732
733 if (c->write->timer_set) {
734 ngx_del_timer(c->write);
735 }
736
737 if (rc == NGX_AGAIN) {
738 ngx_add_timer(c->write, p->lcf->send_timeout);
739
740 c->write->available = /* STUB: lowat */ 0;
741 if (ngx_handle_write_event(c->write, NGX_LOWAT_EVENT) == NGX_ERROR) {
742 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
743 return;
744 }
745
746 return;
747 }
748
749 /* rc == NGX_OK */
750
751 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
752 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
753 ngx_log_error(NGX_LOG_CRIT, c->log,
754 ngx_socket_errno,
755 ngx_tcp_push_n " failed");
756 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
757 return;
758 }
759
760 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
761 return;
762 }
763
764 ngx_add_timer(c->read, p->lcf->read_timeout);
765
766 #if 0
767 if (c->read->ready) {
768
769 /* post aio operation */
770
771 /*
772 * although we can post aio operation just in the end
773 * of ngx_http_proxy_connect() CHECK IT !!!
774 * it's better to do here because we postpone header buffer allocation
775 */
776
777 ngx_http_proxy_process_upstream_status_line(c->read);
778 return;
779 }
780 #endif
781
782 c->write->event_handler = ngx_http_proxy_dummy_handler;
783
784 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
785 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
786 return;
787 }
788 }
789
790
791 static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
792 {
793 ngx_connection_t *c;
794 ngx_http_proxy_ctx_t *p;
795
796 c = wev->data;
797 p = c->data;
798
799 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
800 "http proxy send request handler");
801
802 if (wev->timedout) {
803 p->action = "sending request to upstream";
804 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
805 return;
806 }
807
808 if (p->request->connection->write->eof
809 && (!p->cachable || !p->request_sent))
810 {
811 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
812 return;
813 }
814
815 ngx_http_proxy_send_request(p);
816 }
817
818
819 static void ngx_http_proxy_dummy_handler(ngx_event_t *wev)
820 {
821 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http proxy dummy handler");
822 }
823
824
825 static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
826 {
827 int rc;
828 ssize_t n;
829 ngx_connection_t *c;
830 ngx_http_proxy_ctx_t *p;
831
832 c = rev->data;
833 p = c->data;
834 p->action = "reading upstream status line";
835
836 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
837 "http proxy process status line");
838
839 if (rev->timedout) {
840 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
841 return;
842 }
843
844 if (p->header_in == NULL) {
845 p->header_in = ngx_create_temp_buf(p->request->pool,
846 p->lcf->header_buffer_size);
847 if (p->header_in == NULL) {
848 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
849 return;
850 }
851 p->header_in->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
852
853 if (p->cache) {
854 p->header_in->pos += p->cache->ctx.header_size;
855 p->header_in->last = p->header_in->pos;
856 }
857 }
858
859 n = ngx_http_proxy_read_upstream_header(p);
860
861 if (n == NGX_AGAIN) {
862 return;
863 }
864
865 if (n == 0) {
866 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
867 "upstream prematurely closed connection");
868 }
869
870 if (n == NGX_ERROR || n == 0) {
871 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
872 return;
873 }
874
875 p->valid_header_in = 0;
876
877 p->upstream->peer.cached = 0;
878
879 rc = ngx_http_proxy_parse_status_line(p);
880
881 if (rc == NGX_AGAIN) {
882 if (p->header_in->pos == p->header_in->last) {
883 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
884 "upstream sent too long status line");
885 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
886 }
887 return;
888 }
889
890 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
891 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
892 "upstream sent no valid HTTP/1.0 header");
893
894 if (p->accel) {
895 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
896
897 } else {
898 p->request->http_version = NGX_HTTP_VERSION_9;
899 p->upstream->status = NGX_HTTP_OK;
900 ngx_http_proxy_send_response(p);
901 }
902
903 return;
904 }
905
906 /* rc == NGX_OK */
907
908 p->upstream->status = p->status;
909 p->state->status = p->status;
910
911 if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR) {
912
913 if (p->upstream->peer.tries > 1
914 && (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
915 {
916 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
917 return;
918 }
919
920 #if (NGX_HTTP_CACHE)
921
922 if (p->upstream->peer.tries == 0
923 && p->stale
924 && (p->lcf->use_stale & NGX_HTTP_PROXY_FT_HTTP_500))
925 {
926 ngx_http_proxy_finalize_request(p,
927 ngx_http_proxy_send_cached_response(p));
928
929 return;
930 }
931
932 #endif
933 }
934
935 if (p->status == NGX_HTTP_NOT_FOUND
936 && p->upstream->peer.tries > 1
937 && p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_404)
938 {
939 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_404);
940 return;
941 }
942
943 /* TODO: "proxy_error_page" */
944
945 p->upstream->status_line.len = p->status_end - p->status_start;
946 p->upstream->status_line.data = ngx_palloc(p->request->pool,
947 p->upstream->status_line.len + 1);
948 if (p->upstream->status_line.data == NULL) {
949 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
950 return;
951 }
952 ngx_cpystrn(p->upstream->status_line.data, p->status_start,
953 p->upstream->status_line.len + 1);
954
955 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
956 "http proxy status %d \"%s\"",
957 p->upstream->status, p->upstream->status_line.data);
958
959
960 /* init or reinit the p->upstream->headers_in.headers table */
961
962 if (p->upstream->headers_in.headers.part.elts) {
963 p->upstream->headers_in.headers.part.nelts = 0;
964 p->upstream->headers_in.headers.part.next = NULL;
965 p->upstream->headers_in.headers.last =
966 &p->upstream->headers_in.headers.part;
967
968 ngx_memzero(&p->upstream->headers_in.date,
969 sizeof(ngx_http_proxy_headers_in_t) - sizeof(ngx_list_t));
970
971 } else {
972 if (ngx_list_init(&p->upstream->headers_in.headers, p->request->pool,
973 20, sizeof(ngx_table_elt_t)) == NGX_ERROR)
974 {
975 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
976 return;
977 }
978 }
979
980
981 c->read->event_handler = ngx_http_proxy_process_upstream_headers;
982 ngx_http_proxy_process_upstream_headers(rev);
983 }
984
985
986 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
987 {
988 int i, rc;
989 ssize_t n;
990 ngx_table_elt_t *h;
991 ngx_connection_t *c;
992 ngx_http_request_t *r;
993 ngx_http_proxy_ctx_t *p;
994
995 c = rev->data;
996 p = c->data;
997 r = p->request;
998 p->action = "reading upstream headers";
999
1000 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1001 "http proxy process header line");
1002
1003 if (rev->timedout) {
1004 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
1005 return;
1006 }
1007
1008 rc = NGX_AGAIN;
1009
1010 for ( ;; ) {
1011 if (rc == NGX_AGAIN) {
1012 n = ngx_http_proxy_read_upstream_header(p);
1013
1014 if (n == 0) {
1015 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1016 "upstream prematurely closed connection");
1017 }
1018
1019 if (n == NGX_ERROR || n == 0) {
1020 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
1021 return;
1022 }
1023
1024 if (n == NGX_AGAIN) {
1025 return;
1026 }
1027 }
1028
1029 rc = ngx_http_parse_header_line(p->request, p->header_in);
1030
1031 if (rc == NGX_OK) {
1032
1033 /* a header line has been parsed successfully */
1034
1035 if (!(h = ngx_list_push(&p->upstream->headers_in.headers))) {
1036 ngx_http_proxy_finalize_request(p,
1037 NGX_HTTP_INTERNAL_SERVER_ERROR);
1038 return;
1039 }
1040
1041 h->key.len = r->header_name_end - r->header_name_start;
1042 h->value.len = r->header_end - r->header_start;
1043
1044 h->key.data = ngx_palloc(p->request->pool,
1045 h->key.len + 1 + h->value.len + 1);
1046 if (h->key.data == NULL) {
1047 ngx_http_proxy_finalize_request(p,
1048 NGX_HTTP_INTERNAL_SERVER_ERROR);
1049 return;
1050 }
1051
1052 h->value.data = h->key.data + h->key.len + 1;
1053 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
1054 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
1055
1056 for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
1057 if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
1058 continue;
1059 }
1060
1061 if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
1062 h->key.data) == 0)
1063 {
1064 *((ngx_table_elt_t **) ((char *) &p->upstream->headers_in
1065 + ngx_http_proxy_headers_in[i].offset)) = h;
1066 break;
1067 }
1068 }
1069
1070 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1071 "http proxy header: \"%s: %s\"",
1072 h->key.data, h->value.data);
1073
1074 continue;
1075
1076 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1077
1078 /* a whole header has been parsed successfully */
1079
1080 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1081 "http proxy header done");
1082
1083 /* TODO: hook to process the upstream header */
1084
1085 #if (NGX_HTTP_CACHE)
1086
1087 if (p->cachable) {
1088 p->cachable = ngx_http_proxy_is_cachable(p);
1089 }
1090
1091 #endif
1092
1093 ngx_http_proxy_send_response(p);
1094 return;
1095
1096 } else if (rc != NGX_AGAIN) {
1097
1098 /* there was error while a header line parsing */
1099
1100 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1101 upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
1102
1103 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
1104 return;
1105 }
1106
1107 /* rc == NGX_AGAIN: a header line parsing is still not complete */
1108
1109 if (p->header_in->last == p->header_in->end) {
1110 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1111 "upstream sent too big header");
1112
1113 ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER);
1114 return;
1115 }
1116 }
1117 }
1118
1119
1120 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
1121 {
1122 ssize_t n;
1123 ngx_event_t *rev;
1124
1125 rev = p->upstream->peer.connection->read;
1126
1127 n = p->header_in->last - p->header_in->pos;
1128
1129 if (n > 0) {
1130 return n;
1131 }
1132
1133 n = ngx_recv(p->upstream->peer.connection, p->header_in->last,
1134 p->header_in->end - p->header_in->last);
1135
1136 if (n == NGX_AGAIN) {
1137 #if 0
1138 ngx_add_timer(rev, p->lcf->read_timeout);
1139 #endif
1140
1141 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
1142 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1143 return NGX_ERROR;
1144 }
1145
1146 return NGX_AGAIN;
1147 }
1148
1149 if (n == 0) {
1150 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1151 "upstream closed prematurely connection");
1152 }
1153
1154 if (n == 0 || n == NGX_ERROR) {
1155 return NGX_ERROR;
1156 }
1157
1158 p->header_in->last += n;
1159
1160 return n;
1161 }
1162
1163
1164 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
1165 {
1166 int rc;
1167 ngx_event_pipe_t *ep;
1168 ngx_http_request_t *r;
1169 ngx_http_cache_header_t *header;
1170 ngx_http_core_loc_conf_t *clcf;
1171
1172 r = p->request;
1173
1174 r->headers_out.status = p->upstream->status;
1175
1176 #if 0
1177 r->headers_out.content_length_n = -1;
1178 r->headers_out.content_length = NULL;
1179 #endif
1180
1181 /* copy an upstream header to r->headers_out */
1182
1183 if (ngx_http_proxy_copy_header(p, &p->upstream->headers_in) == NGX_ERROR) {
1184 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
1185 return;
1186 }
1187
1188 /* TODO: preallocate event_pipe bufs, look "Content-Length" */
1189
1190 rc = ngx_http_send_header(r);
1191
1192 p->header_sent = 1;
1193
1194 if (p->cache && p->cache->ctx.file.fd != NGX_INVALID_FILE) {
1195 if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
1196 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
1197 ngx_close_file_n " \"%s\" failed",
1198 p->cache->ctx.file.name.data);
1199 }
1200 }
1201
1202 if (p->cachable) {
1203 header = (ngx_http_cache_header_t *) p->header_in->start;
1204
1205 header->expires = p->cache->ctx.expires;
1206 header->last_modified = p->cache->ctx.last_modified;
1207 header->date = p->cache->ctx.date;
1208 header->length = r->headers_out.content_length_n;
1209 p->cache->ctx.length = r->headers_out.content_length_n;
1210
1211 header->key_len = p->cache->ctx.key.len;
1212 ngx_memcpy(&header->key, p->cache->ctx.key.data, header->key_len);
1213 header->key[header->key_len] = LF;
1214 }
1215
1216 ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
1217 if (ep == NULL) {
1218 ngx_http_proxy_finalize_request(p, 0);
1219 return;
1220 }
1221
1222 p->upstream->event_pipe = ep;
1223
1224 ep->input_filter = ngx_event_pipe_copy_input_filter;
1225 ep->output_filter = (ngx_event_pipe_output_filter_pt)
1226 ngx_http_output_filter;
1227 ep->output_ctx = r;
1228 ep->tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
1229 ep->bufs = p->lcf->bufs;
1230 ep->busy_size = p->lcf->busy_buffers_size;
1231 ep->upstream = p->upstream->peer.connection;
1232 ep->downstream = r->connection;
1233 ep->pool = r->pool;
1234 ep->log = r->connection->log;
1235
1236 ep->cachable = p->cachable;
1237
1238 if (!(ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
1239 ngx_http_proxy_finalize_request(p, 0);
1240 return;
1241 }
1242
1243 ep->temp_file->file.fd = NGX_INVALID_FILE;
1244 ep->temp_file->file.log = r->connection->log;
1245 ep->temp_file->path = p->lcf->temp_path;
1246 ep->temp_file->pool = r->pool;
1247
1248 if (p->cachable) {
1249 ep->temp_file->persistent = 1;
1250 } else {
1251 ep->temp_file->warn = "an upstream response is buffered "
1252 "to a temporary file";
1253 }
1254
1255 ep->max_temp_file_size = p->lcf->max_temp_file_size;
1256 ep->temp_file_write_size = p->lcf->temp_file_write_size;
1257
1258 if (!(ep->preread_bufs = ngx_alloc_chain_link(r->pool))) {
1259 ngx_http_proxy_finalize_request(p, 0);
1260 return;
1261 }
1262 ep->preread_bufs->buf = p->header_in;
1263 ep->preread_bufs->next = NULL;
1264
1265 ep->preread_size = p->header_in->last - p->header_in->pos;
1266
1267 if (p->cachable) {
1268 ep->buf_to_file = ngx_calloc_buf(r->pool);
1269 if (ep->buf_to_file == NULL) {
1270 ngx_http_proxy_finalize_request(p, 0);
1271 return;
1272 }
1273 ep->buf_to_file->pos = p->header_in->start;
1274 ep->buf_to_file->last = p->header_in->pos;
1275 ep->buf_to_file->temporary = 1;
1276 }
1277
1278 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
1279 /* the posted aio operation can currupt a shadow buffer */
1280 ep->single_buf = 1;
1281 }
1282
1283 /* TODO: ep->free_bufs = 0 if use ngx_create_chain_of_bufs() */
1284 ep->free_bufs = 1;
1285
1286 /*
1287 * event_pipe would do p->header_in->last += ep->preread_size
1288 * as though these bytes were read.
1289 */
1290 p->header_in->last = p->header_in->pos;
1291
1292 if (p->lcf->cyclic_temp_file) {
1293
1294 /*
1295 * we need to disable the use of sendfile() if we use cyclic temp file
1296 * because the writing a new data can interfere with sendfile()
1297 * that uses the same kernel file pages (at least on FreeBSD)
1298 */
1299
1300 ep->cyclic_temp_file = 1;
1301 r->sendfile = 0;
1302
1303 } else {
1304 ep->cyclic_temp_file = 0;
1305 r->sendfile = 1;
1306 }
1307
1308 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1309
1310 ep->read_timeout = p->lcf->read_timeout;
1311 ep->send_timeout = clcf->send_timeout;
1312 ep->send_lowat = clcf->send_lowat;
1313
1314 p->upstream->peer.connection->read->event_handler =
1315 ngx_http_proxy_process_body;
1316 r->connection->write->event_handler = ngx_http_proxy_process_body;
1317
1318 ngx_http_proxy_process_body(p->upstream->peer.connection->read);
1319
1320 return;
1321 }
1322
1323
1324 static void ngx_http_proxy_process_body(ngx_event_t *ev)
1325 {
1326 ngx_connection_t *c;
1327 ngx_http_request_t *r;
1328 ngx_http_proxy_ctx_t *p;
1329 ngx_event_pipe_t *ep;
1330
1331 c = ev->data;
1332
1333 if (ev->write) {
1334 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1335 "http proxy process downstream");
1336 r = c->data;
1337 p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1338 p->action = "sending to client";
1339
1340 } else {
1341 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1342 "http proxy process upstream");
1343 p = c->data;
1344 r = p->request;
1345 p->action = "reading upstream body";
1346 }
1347
1348 ep = p->upstream->event_pipe;
1349
1350 if (ev->timedout) {
1351 if (ev->write) {
1352 ep->downstream_error = 1;
1353 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
1354 "client timed out");
1355
1356 } else {
1357 ep->upstream_error = 1;
1358 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
1359 "upstream timed out");
1360 }
1361
1362 } else {
1363 if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) {
1364 ngx_http_proxy_finalize_request(p, 0);
1365 return;
1366 }
1367 }
1368
1369 if (p->upstream->peer.connection) {
1370
1371 #if (NGX_HTTP_FILE_CACHE)
1372
1373 if (ep->upstream_done && p->cachable) {
1374 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1375 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
1376 ngx_http_proxy_finalize_request(p, 0);
1377 return;
1378 }
1379
1380 } else if (ep->upstream_eof && p->cachable) {
1381
1382 /* TODO: check length & update cache */
1383
1384 if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
1385 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
1386 ngx_http_proxy_finalize_request(p, 0);
1387 return;
1388 }
1389 }
1390
1391 #endif
1392
1393 if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
1394 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1395 "http proxy upstream exit: " PTR_FMT, ep->out);
1396 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
1397 ngx_http_proxy_finalize_request(p, 0);
1398 return;
1399 }
1400 }
1401
1402 if (ep->downstream_error) {
1403 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1404 "http proxy downstream error");
1405 if (!p->cachable && p->upstream->peer.connection) {
1406 ngx_http_proxy_finalize_request(p, 0);
1407 }
1408 }
1409 }
1410
1411
1412 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
1413 {
1414 int status;
1415
1416 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
1417 "http proxy next upstream: %d", ft_type);
1418
1419 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
1420
1421 if (ft_type != NGX_HTTP_PROXY_FT_HTTP_404) {
1422 ngx_event_connect_peer_failed(&p->upstream->peer);
1423 }
1424
1425 if (ft_type == NGX_HTTP_PROXY_FT_TIMEOUT) {
1426 ngx_log_error(NGX_LOG_ERR, p->request->connection->log, NGX_ETIMEDOUT,
1427 "upstream timed out");
1428 }
1429
1430 if (p->upstream->peer.cached && ft_type == NGX_HTTP_PROXY_FT_ERROR) {
1431 status = 0;
1432
1433 } else {
1434 switch(ft_type) {
1435 case NGX_HTTP_PROXY_FT_TIMEOUT:
1436 status = NGX_HTTP_GATEWAY_TIME_OUT;
1437 break;
1438
1439 case NGX_HTTP_PROXY_FT_HTTP_500:
1440 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
1441 break;
1442
1443 case NGX_HTTP_PROXY_FT_HTTP_404:
1444 status = NGX_HTTP_NOT_FOUND;
1445 break;
1446
1447 /*
1448 * NGX_HTTP_PROXY_FT_BUSY_LOCK and NGX_HTTP_PROXY_FT_MAX_WAITING
1449 * never reach here
1450 */
1451
1452 default:
1453 status = NGX_HTTP_BAD_GATEWAY;
1454 }
1455 }
1456
1457 if (p->upstream->peer.connection) {
1458 ngx_http_proxy_close_connection(p);
1459 }
1460
1461 if (p->request->connection->write->eof) {
1462 ngx_http_proxy_finalize_request(p, NGX_HTTP_CLIENT_CLOSED_REQUEST);
1463 return;
1464 }
1465
1466 if (status) {
1467 p->state->status = status;
1468
1469 if (p->upstream->peer.tries == 0 || !(p->lcf->next_upstream & ft_type))
1470 {
1471
1472 #if (NGX_HTTP_CACHE)
1473
1474 if (p->stale && (p->lcf->use_stale & ft_type)) {
1475 ngx_http_proxy_finalize_request(p,
1476 ngx_http_proxy_send_cached_response(p));
1477 return;
1478 }
1479
1480 #endif
1481
1482 ngx_http_proxy_finalize_request(p, status);
1483 return;
1484 }
1485 }
1486
1487 if (p->lcf->busy_lock && !p->busy_locked) {
1488 ngx_http_proxy_upstream_busy_lock(p);
1489 } else {
1490 ngx_http_proxy_connect(p);
1491 }
1492 }