comparison src/http/ngx_http_upstream.c @ 28:7ca9bdc82b3f NGINX_0_1_14

nginx 0.1.14 *) Feature: the autoconfiguration directives: --http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and --http-fastcgi-temp-path=PATH *) Change: the directory name for the temporary files with the client request body is specified by directive client_body_temp_path, by default it is <prefix>/client_body_temp. *) Feature: the ngx_http_fastcgi_module and the directives: fastcgi_pass, fastcgi_root, fastcgi_index, fastcgi_params, fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout, fastcgi_send_lowat, fastcgi_header_buffer_size, fastcgi_buffers, fastcgi_busy_buffers_size, fastcgi_temp_path, fastcgi_max_temp_file_size, fastcgi_temp_file_write_size, fastcgi_next_upstream, and fastcgi_x_powered_by. *) Bugfix: the "[alert] zero size buf" error; bug appeared in 0.1.3. *) Change: the URI must be specified after the host name in the proxy_pass directive. *) Change: the %3F symbol in the URI was considered as the argument string start. *) Feature: the unix domain sockets support in the ngx_http_proxy_module. *) Feature: the ssl_engine and ssl_ciphers directives. Thanks to Sergey Skvortsov for SSL-accelerator.
author Igor Sysoev <http://sysoev.ru>
date Tue, 18 Jan 2005 00:00:00 +0300
parents
children e1ada20fc595
comparison
equal deleted inserted replaced
27:66901c2556fd 28:7ca9bdc82b3f
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10 #include <ngx_event_connect.h>
11
12
13 static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev);
14 static void ngx_http_upstream_connect(ngx_http_request_t *r,
15 ngx_http_upstream_t *u);
16 static void ngx_http_upstream_reinit(ngx_http_request_t *r,
17 ngx_http_upstream_t *u);
18 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
19 ngx_http_upstream_t *u);
20 static void ngx_http_upstream_send_request_handler(ngx_event_t *wev);
21 static void ngx_http_upstream_process_header(ngx_event_t *rev);
22 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
23 ngx_http_upstream_t *u);
24 static void ngx_http_upstream_process_body(ngx_event_t *ev);
25 static void ngx_http_upstream_dummy_handler(ngx_event_t *wev);
26 static void ngx_http_upstream_next(ngx_http_request_t *r,
27 ngx_http_upstream_t *u,
28 ngx_uint_t ft_type);
29 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
30 ngx_http_upstream_t *u,
31 ngx_int_t rc);
32
33 static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r,
34 uintptr_t data);
35 static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf,
36 ngx_http_log_op_t *op);
37
38
39 static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf);
40
41
42 ngx_http_module_t ngx_http_upstream_module_ctx = {
43 ngx_http_upstream_add_log_formats, /* pre conf */
44
45 NULL, /* create main configuration */
46 NULL, /* init main configuration */
47
48 NULL, /* create server configuration */
49 NULL, /* merge server configuration */
50
51 NULL, /* create location configuration */
52 NULL /* merge location configuration */
53 };
54
55
56 ngx_module_t ngx_http_upstream_module = {
57 NGX_MODULE,
58 &ngx_http_upstream_module_ctx, /* module context */
59 NULL, /* module directives */
60 NGX_HTTP_MODULE, /* module type */
61 NULL, /* init module */
62 NULL /* init process */
63 };
64
65
66 static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = {
67 { ngx_string("upstream_status"), 0, NULL,
68 ngx_http_upstream_log_status_getlen,
69 ngx_http_upstream_log_status },
70 { ngx_null_string, 0, NULL, NULL, NULL }
71 };
72
73
74 char *ngx_http_upstream_header_errors[] = {
75 "upstream sent invalid header",
76 "upstream sent too long header line"
77 };
78
79
80 void ngx_http_upstream_init(ngx_http_request_t *r)
81 {
82 ngx_connection_t *c;
83 ngx_http_upstream_t *u;
84
85 c = r->connection;
86
87 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
88 "http init upstream, client timer: %d", c->read->timer_set);
89
90 if (c->read->timer_set) {
91 ngx_del_timer(c->read);
92 }
93
94 c->read->event_handler = ngx_http_upstream_check_broken_connection;
95
96 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
97
98 c->write->event_handler = ngx_http_upstream_check_broken_connection;
99
100 if (!c->write->active) {
101 if (ngx_add_event(c->write, NGX_WRITE_EVENT,
102 NGX_CLEAR_EVENT) == NGX_ERROR)
103 {
104 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
105 return;
106 }
107 }
108 }
109
110 u = r->upstream;
111
112 u->method = r->method;
113
114 if (u->create_request(r) == NGX_ERROR) {
115 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
116 return;
117 }
118
119 u->peer.log = r->connection->log;
120 u->saved_ctx = r->connection->log->data;
121 u->saved_handler = r->connection->log->handler;
122 r->connection->log->data = u->log_ctx;
123 r->connection->log->handler = u->log_handler;
124
125 u->output.sendfile = r->connection->sendfile;
126 u->output.pool = r->pool;
127 u->output.bufs.num = 1;
128 u->output.output_filter = ngx_chain_writer;
129 u->output.filter_ctx = &u->writer;
130
131 u->writer.pool = r->pool;
132
133 if (ngx_array_init(&u->states, r->pool, u->peer.peers->number,
134 sizeof(ngx_http_upstream_state_t)) == NGX_ERROR)
135 {
136 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
137 return;
138 }
139
140 if (!(u->state = ngx_push_array(&u->states))) {
141 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
142 return;
143 }
144
145 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
146
147 ngx_http_upstream_connect(r, u);
148 }
149
150
151 static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev)
152 {
153 int n;
154 char buf[1];
155 ngx_err_t err;
156 ngx_connection_t *c;
157 ngx_http_request_t *r;
158 ngx_http_upstream_t *u;
159
160 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
161 "http upstream check client, write event:%d", ev->write);
162
163 #if (NGX_HAVE_KQUEUE)
164
165 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
166
167 if (!ev->pending_eof) {
168 return;
169 }
170
171 ev->eof = 1;
172
173 if (ev->kq_errno) {
174 ev->error = 1;
175 }
176
177 c = ev->data;
178 r = c->data;
179 u = r->upstream;
180
181 if (!u->cachable && u->peer.connection) {
182 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
183 "kevent() reported that client closed "
184 "prematurely connection, "
185 "so upstream connection is closed too");
186 ngx_http_upstream_finalize_request(r, u,
187 NGX_HTTP_CLIENT_CLOSED_REQUEST);
188 return;
189 }
190
191 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
192 "kevent() reported that client closed "
193 "prematurely connection");
194
195 if (u->peer.connection == NULL) {
196 ngx_http_upstream_finalize_request(r, u,
197 NGX_HTTP_CLIENT_CLOSED_REQUEST);
198 return;
199 }
200
201 return;
202 }
203
204 #endif
205
206 c = ev->data;
207
208 n = recv(c->fd, buf, 1, MSG_PEEK);
209
210 err = ngx_socket_errno;
211
212 /*
213 * we do not need to disable the write event because
214 * that event has NGX_USE_CLEAR_EVENT type
215 */
216
217 if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
218 return;
219 }
220
221 r = c->data;
222 u = r->upstream;
223
224 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
225 if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
226 ngx_http_upstream_finalize_request(r, u,
227 NGX_HTTP_INTERNAL_SERVER_ERROR);
228 return;
229 }
230 }
231
232 if (n > 0) {
233 return;
234 }
235
236 ev->eof = 1;
237
238 if (n == -1) {
239 if (err == NGX_EAGAIN) {
240 return;
241 }
242
243 ev->error = 1;
244
245 } else {
246 /* n == 0 */
247 err = 0;
248 }
249
250 if (!u->cachable && u->peer.connection) {
251 ngx_log_error(NGX_LOG_INFO, ev->log, err,
252 "client closed prematurely connection, "
253 "so upstream connection is closed too");
254 ngx_http_upstream_finalize_request(r, u,
255 NGX_HTTP_CLIENT_CLOSED_REQUEST);
256 return;
257 }
258
259 ngx_log_error(NGX_LOG_INFO, ev->log, err,
260 "client closed prematurely connection");
261
262 if (u->peer.connection == NULL) {
263 ngx_http_upstream_finalize_request(r, u,
264 NGX_HTTP_CLIENT_CLOSED_REQUEST);
265 return;
266 }
267 }
268
269
270 static void ngx_http_upstream_connect(ngx_http_request_t *r,
271 ngx_http_upstream_t *u)
272 {
273 ngx_int_t rc;
274 ngx_connection_t *c;
275 ngx_http_log_ctx_t *ctx;
276
277 ctx = r->connection->log->data;
278 ctx->action = "connecting to upstream";
279
280 r->connection->single_connection = 0;
281
282 rc = ngx_event_connect_peer(&u->peer);
283
284 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
285 "http upstream connect: %i", rc);
286
287 if (rc == NGX_ERROR) {
288 ngx_http_upstream_finalize_request(r, u,
289 NGX_HTTP_INTERNAL_SERVER_ERROR);
290 return;
291 }
292
293 u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name;
294
295 if (rc == NGX_CONNECT_ERROR) {
296 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
297 return;
298 }
299
300 c = u->peer.connection;
301
302 c->data = r;
303 c->write->event_handler = ngx_http_upstream_send_request_handler;
304 c->read->event_handler = ngx_http_upstream_process_header;
305
306 c->sendfile = r->connection->sendfile;
307
308 c->pool = r->pool;
309 c->read->log = c->write->log = c->log = r->connection->log;
310
311 /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
312
313 u->writer.out = NULL;
314 u->writer.last = &u->writer.out;
315 u->writer.connection = c;
316 u->writer.limit = 0;
317
318 if (u->request_sent) {
319 ngx_http_upstream_reinit(r, u);
320 }
321
322 if (r->request_body->buf) {
323 if (r->request_body->temp_file) {
324
325 if (!(u->output.free = ngx_alloc_chain_link(r->pool))) {
326 ngx_http_upstream_finalize_request(r, u,
327 NGX_HTTP_INTERNAL_SERVER_ERROR);
328 return;
329 }
330
331 u->output.free->buf = r->request_body->buf;
332 u->output.free->next = NULL;
333 u->output.allocated = 1;
334
335 r->request_body->buf->pos = r->request_body->buf->start;
336 r->request_body->buf->last = r->request_body->buf->start;
337 r->request_body->buf->tag = u->output.tag;
338
339 } else {
340 r->request_body->buf->pos = r->request_body->buf->start;
341 }
342 }
343
344 u->request_sent = 0;
345
346 if (rc == NGX_AGAIN) {
347 ngx_add_timer(c->write, u->conf->connect_timeout);
348 return;
349 }
350
351 /* rc == NGX_OK */
352
353 ngx_http_upstream_send_request(r, u);
354 }
355
356
357 static void ngx_http_upstream_reinit(ngx_http_request_t *r,
358 ngx_http_upstream_t *u)
359 {
360 ngx_chain_t *cl;
361
362 if (u->reinit_request(r) == NGX_ERROR) {
363 ngx_http_upstream_finalize_request(r, u,
364 NGX_HTTP_INTERNAL_SERVER_ERROR);
365 return;
366 }
367
368 /* reinit the request chain */
369
370 for (cl = r->request_body->bufs; cl; cl = cl->next) {
371 cl->buf->pos = cl->buf->start;
372 cl->buf->file_pos = 0;
373 }
374
375 /* reinit the ngx_output_chain() context */
376
377 u->output.buf = NULL;
378 u->output.in = NULL;
379 u->output.free = NULL;
380 u->output.busy = NULL;
381
382 /* reinit u->header_in buffer */
383
384 #if 0
385 if (u->cache) {
386 u->header_in.pos = u->header_in.start + u->cache->ctx.header_size;
387 u->header_in.last = u->header_in.pos;
388
389 } else {
390 u->header_in.pos = u->header_in.start;
391 u->header_in.last = u->header_in.start;
392 }
393 #else
394 u->header_in.pos = u->header_in.start;
395 u->header_in.last = u->header_in.start;
396 #endif
397
398 /* add one more state */
399
400 if (!(u->state = ngx_push_array(&u->states))) {
401 ngx_http_upstream_finalize_request(r, u,
402 NGX_HTTP_INTERNAL_SERVER_ERROR);
403 return;
404 }
405
406 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
407
408 u->status = 0;
409 u->status_count = 0;
410 }
411
412
413 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
414 ngx_http_upstream_t *u)
415 {
416 int rc;
417 ngx_connection_t *c;
418 ngx_http_log_ctx_t *ctx;
419
420 c = u->peer.connection;
421
422 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
423 "http upstream send request");
424
425 #if (NGX_HAVE_KQUEUE)
426
427 if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT)
428 && !u->request_sent
429 && c->write->pending_eof)
430 {
431 ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno,
432 "connect() failed");
433
434 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
435 return;
436 }
437
438 #endif
439
440 ctx = c->log->data;
441 ctx->action = "sending request to upstream";
442
443 rc = ngx_output_chain(&u->output,
444 u->request_sent ? NULL : r->request_body->bufs);
445
446 u->request_sent = 1;
447
448 if (rc == NGX_ERROR) {
449 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
450 return;
451 }
452
453 if (c->write->timer_set) {
454 ngx_del_timer(c->write);
455 }
456
457 if (rc == NGX_AGAIN) {
458 ngx_add_timer(c->write, u->conf->send_timeout);
459
460 if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR)
461 {
462 ngx_http_upstream_finalize_request(r, u,
463 NGX_HTTP_INTERNAL_SERVER_ERROR);
464 return;
465 }
466
467 return;
468 }
469
470 /* rc == NGX_OK */
471
472 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
473 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
474 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
475 ngx_tcp_push_n " failed");
476 ngx_http_upstream_finalize_request(r, u,
477 NGX_HTTP_INTERNAL_SERVER_ERROR);
478 return;
479 }
480
481 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
482 return;
483 }
484
485 ngx_add_timer(c->read, u->conf->read_timeout);
486
487 #if 1
488 if (c->read->ready) {
489
490 /* post aio operation */
491
492 /*
493 * TODO comment
494 * although we can post aio operation just in the end
495 * of ngx_http_upstream_connect() CHECK IT !!!
496 * it's better to do here because we postpone header buffer allocation
497 */
498
499 ngx_http_upstream_process_header(c->read);
500 return;
501 }
502 #endif
503
504 c->write->event_handler = ngx_http_upstream_dummy_handler;
505
506 if (ngx_handle_level_write_event(c->write) == NGX_ERROR) {
507 ngx_http_upstream_finalize_request(r, u,
508 NGX_HTTP_INTERNAL_SERVER_ERROR);
509 return;
510 }
511 }
512
513
514 static void ngx_http_upstream_send_request_handler(ngx_event_t *wev)
515 {
516 ngx_connection_t *c;
517 ngx_http_request_t *r;
518 ngx_http_log_ctx_t *ctx;
519 ngx_http_upstream_t *u;
520
521 c = wev->data;
522 r = c->data;
523 u = r->upstream;
524
525 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
526 "http upstream send request handler");
527
528 if (wev->timedout) {
529 ctx = c->log->data;
530 ctx->action = "sending request to upstream";
531 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
532 return;
533 }
534
535 if (r->connection->write->eof && (!u->cachable || !u->request_sent)) {
536 ngx_http_upstream_finalize_request(r, u,
537 NGX_HTTP_INTERNAL_SERVER_ERROR);
538 return;
539 }
540
541 ngx_http_upstream_send_request(r, u);
542 }
543
544
545 static void ngx_http_upstream_process_header(ngx_event_t *rev)
546 {
547 ssize_t n;
548 ngx_int_t rc;
549 ngx_connection_t *c;
550 ngx_http_request_t *r;
551 ngx_http_log_ctx_t *ctx;
552 ngx_http_upstream_t *u;
553
554 c = rev->data;
555 r = c->data;
556 u = r->upstream;
557
558 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
559 "http upstream process handler");
560
561 ctx = c->log->data;
562 ctx->action = "reading response header from upstream";
563
564 if (rev->timedout) {
565 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
566 return;
567 }
568
569 if (u->header_in.start == NULL) {
570 u->header_in.start = ngx_palloc(r->pool, u->conf->header_buffer_size);
571 if (u->header_in.start == NULL) {
572 ngx_http_upstream_finalize_request(r, u,
573 NGX_HTTP_INTERNAL_SERVER_ERROR);
574 return;
575 }
576
577 u->header_in.pos = u->header_in.start;
578 u->header_in.last = u->header_in.start;
579 u->header_in.end = u->header_in.last + u->conf->header_buffer_size;
580 u->header_in.temporary = 1;
581
582 u->header_in.tag = u->output.tag;
583
584 #if 0
585 if (u->cache) {
586 u->header_in.pos += u->cache->ctx.header_size;
587 u->header_in.last = u->header_in.pos;
588 }
589 #endif
590 }
591
592 n = ngx_recv(u->peer.connection, u->header_in.last,
593 u->header_in.end - u->header_in.last);
594
595 if (n == NGX_AGAIN) {
596 #if 0
597 ngx_add_timer(rev, u->read_timeout);
598 #endif
599
600 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
601 ngx_http_upstream_finalize_request(r, u,
602 NGX_HTTP_INTERNAL_SERVER_ERROR);
603 return;
604 }
605
606 return;
607 }
608
609 if (n == 0) {
610 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
611 "upstream prematurely closed connection");
612 }
613
614 if (n == NGX_ERROR || n == 0) {
615 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
616 return;
617 }
618
619 if (n == NGX_HTTP_INTERNAL_SERVER_ERROR) {
620 ngx_http_upstream_finalize_request(r, u,
621 NGX_HTTP_INTERNAL_SERVER_ERROR);
622 return;
623 }
624
625 u->header_in.last += n;
626
627 #if 0
628 u->valid_header_in = 0;
629
630 u->peer.cached = 0;
631 #endif
632
633 rc = u->process_header(r);
634
635 if (rc == NGX_AGAIN) {
636 #if 0
637 ngx_add_timer(rev, u->read_timeout);
638 #endif
639
640 if (u->header_in.last == u->header_in.end) {
641 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
642 "upstream sent too big header");
643
644 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
645 return;
646 }
647
648 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
649 ngx_http_upstream_finalize_request(r, u,
650 NGX_HTTP_INTERNAL_SERVER_ERROR);
651 return;
652 }
653
654 return;
655 }
656
657 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
658 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
659 return;
660 }
661
662 if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
663 ngx_http_upstream_finalize_request(r, u,
664 NGX_HTTP_INTERNAL_SERVER_ERROR);
665 return;
666 }
667
668 /* rc == NGX_OK */
669
670 ngx_http_upstream_send_response(r, u);
671 }
672
673
674 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
675 ngx_http_upstream_t *u)
676 {
677 ngx_event_pipe_t *p;
678 ngx_http_core_loc_conf_t *clcf;
679
680
681 if (u->send_header(r) == NGX_HTTP_INTERNAL_SERVER_ERROR) {
682 ngx_http_upstream_finalize_request(r, u,
683 NGX_HTTP_INTERNAL_SERVER_ERROR);
684 return;
685 }
686
687 u->header_sent = 1;
688
689 /* TODO: preallocate event_pipe bufs, look "Content-Length" */
690
691 #if 0
692
693 if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
694 if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
695 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
696 ngx_close_file_n " \"%s\" failed",
697 u->cache->ctx.file.name.data);
698 }
699 }
700
701 if (u->cachable) {
702 header = (ngx_http_cache_header_t *) u->header_in->start;
703
704 header->expires = u->cache->ctx.expires;
705 header->last_modified = u->cache->ctx.last_modified;
706 header->date = u->cache->ctx.date;
707 header->length = r->headers_out.content_length_n;
708 u->cache->ctx.length = r->headers_out.content_length_n;
709
710 header->key_len = u->cache->ctx.key0.len;
711 ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len);
712 header->key[header->key_len] = LF;
713 }
714
715 #endif
716
717 p = &u->pipe;
718
719 p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
720 p->output_ctx = r;
721 p->tag = u->output.tag;
722 p->bufs = u->conf->bufs;
723 p->busy_size = u->conf->busy_buffers_size;
724 p->upstream = u->peer.connection;
725 p->downstream = r->connection;
726 p->pool = r->pool;
727 p->log = r->connection->log;
728
729 p->cachable = u->cachable;
730
731 if (!(p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) {
732 ngx_http_upstream_finalize_request(r, u, 0);
733 return;
734 }
735
736 p->temp_file->file.fd = NGX_INVALID_FILE;
737 p->temp_file->file.log = r->connection->log;
738 p->temp_file->path = u->conf->temp_path;
739 p->temp_file->pool = r->pool;
740
741 if (u->cachable) {
742 p->temp_file->persistent = 1;
743 } else {
744 p->temp_file->warn = "an upstream response is buffered "
745 "to a temporary file";
746 }
747
748 p->max_temp_file_size = u->conf->max_temp_file_size;
749 p->temp_file_write_size = u->conf->temp_file_write_size;
750
751 if (!(p->preread_bufs = ngx_alloc_chain_link(r->pool))) {
752 ngx_http_upstream_finalize_request(r, u, 0);
753 return;
754 }
755 p->preread_bufs->buf = &u->header_in;
756 p->preread_bufs->next = NULL;
757 u->header_in.recycled = 1;
758
759 p->preread_size = u->header_in.last - u->header_in.pos;
760
761 if (u->cachable) {
762 p->buf_to_file = ngx_calloc_buf(r->pool);
763 if (p->buf_to_file == NULL) {
764 ngx_http_upstream_finalize_request(r, u, 0);
765 return;
766 }
767 p->buf_to_file->pos = u->header_in.start;
768 p->buf_to_file->last = u->header_in.pos;
769 p->buf_to_file->temporary = 1;
770 }
771
772 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
773 /* the posted aio operation may currupt a shadow buffer */
774 p->single_buf = 1;
775 }
776
777 /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
778 p->free_bufs = 1;
779
780 /*
781 * event_pipe would do u->header_in.last += p->preread_size
782 * as though these bytes were read
783 */
784 u->header_in.last = u->header_in.pos;
785
786 if (u->conf->cyclic_temp_file) {
787
788 /*
789 * we need to disable the use of sendfile() if we use cyclic temp file
790 * because the writing a new data may interfere with sendfile()
791 * that uses the same kernel file pages (at least on FreeBSD)
792 */
793
794 p->cyclic_temp_file = 1;
795 r->connection->sendfile = 0;
796
797 } else {
798 p->cyclic_temp_file = 0;
799 }
800
801 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
802
803 p->read_timeout = u->conf->read_timeout;
804 p->send_timeout = clcf->send_timeout;
805 p->send_lowat = clcf->send_lowat;
806
807 u->peer.connection->read->event_handler = ngx_http_upstream_process_body;
808 r->connection->write->event_handler = ngx_http_upstream_process_body;
809
810 ngx_http_upstream_process_body(u->peer.connection->read);
811 }
812
813
814 static void ngx_http_upstream_process_body(ngx_event_t *ev)
815 {
816 ngx_connection_t *c;
817 ngx_http_request_t *r;
818 ngx_http_log_ctx_t *ctx;
819 ngx_http_upstream_t *u;
820 ngx_event_pipe_t *p;
821
822 c = ev->data;
823 r = c->data;
824 u = r->upstream;
825
826 ctx = ev->log->data;
827
828 if (ev->write) {
829 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
830 "http proxy process downstream");
831 ctx->action = "sending to client";
832
833 } else {
834 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
835 "http proxy process upstream");
836 ctx->action = "reading upstream body";
837 }
838
839 p = &u->pipe;
840
841 if (ev->timedout) {
842 if (ev->write) {
843 p->downstream_error = 1;
844 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
845 "client timed out");
846
847 } else {
848 p->upstream_error = 1;
849 ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT,
850 "upstream timed out");
851 }
852
853 } else {
854 if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
855 ngx_http_upstream_finalize_request(r, u, 0);
856 return;
857 }
858 }
859
860 if (u->peer.connection) {
861
862 #if (NGX_HTTP_FILE_CACHE)
863
864 if (p->upstream_done && u->cachable) {
865 if (ngx_http_cache_update(r) == NGX_ERROR) {
866 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
867 ngx_http_upstream_finalize_request(r, u, 0);
868 return;
869 }
870
871 } else if (p->upstream_eof && u->cachable) {
872
873 /* TODO: check length & update cache */
874
875 if (ngx_http_cache_update(r) == NGX_ERROR) {
876 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
877 ngx_http_upstream_finalize_request(r, u, 0);
878 return;
879 }
880 }
881
882 #endif
883
884 if (p->upstream_done || p->upstream_eof || p->upstream_error) {
885 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0,
886 "http proxy upstream exit: %p", p->out);
887 #if 0
888 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
889 #endif
890 ngx_http_upstream_finalize_request(r, u, 0);
891 return;
892 }
893 }
894
895 if (p->downstream_error) {
896 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0,
897 "http proxy downstream error");
898
899 if (!u->cachable && u->peer.connection) {
900 ngx_http_upstream_finalize_request(r, u, 0);
901 }
902 }
903 }
904
905
906 static void ngx_http_upstream_dummy_handler(ngx_event_t *wev)
907 {
908 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
909 "http upstream dummy handler");
910 }
911
912
913 static void ngx_http_upstream_next(ngx_http_request_t *r,
914 ngx_http_upstream_t *u,
915 ngx_uint_t ft_type)
916 {
917 ngx_uint_t status;
918
919 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
920 "http next upstream, %xD", ft_type);
921
922 #if 0
923 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
924 #endif
925
926 if (ft_type != NGX_HTTP_UPSTREAM_FT_HTTP_404) {
927 ngx_event_connect_peer_failed(&u->peer);
928 }
929
930 if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
931 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
932 "upstream timed out");
933 }
934
935 if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
936 status = 0;
937
938 } else {
939 switch(ft_type) {
940
941 case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
942 status = NGX_HTTP_GATEWAY_TIME_OUT;
943 break;
944
945 case NGX_HTTP_UPSTREAM_FT_HTTP_500:
946 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
947 break;
948
949 case NGX_HTTP_UPSTREAM_FT_HTTP_404:
950 status = NGX_HTTP_NOT_FOUND;
951 break;
952
953 /*
954 * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
955 * never reach here
956 */
957
958 default:
959 status = NGX_HTTP_BAD_GATEWAY;
960 }
961 }
962
963 if (r->connection->write->eof) {
964 ngx_http_upstream_finalize_request(r, u,
965 NGX_HTTP_CLIENT_CLOSED_REQUEST);
966 return;
967 }
968
969 if (status) {
970 u->state->status = status;
971
972 if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type))
973 {
974
975 #if (NGX_HTTP_CACHE)
976
977 if (u->stale && (u->conf->use_stale & ft_type)) {
978 ngx_http_upstream_finalize_request(r, u,
979 ngx_http_proxy_send_cached_response(r));
980 return;
981 }
982
983 #endif
984
985 ngx_http_upstream_finalize_request(r, u, status);
986 return;
987 }
988 }
989
990 if (u->peer.connection) {
991 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
992 "close http upstream connection: %d",
993 u->peer.connection->fd);
994
995 ngx_close_connection(u->peer.connection);
996 }
997
998 #if 0
999 if (u->conf->busy_lock && !u->busy_locked) {
1000 ngx_http_upstream_busy_lock(p);
1001 return;
1002 }
1003 #endif
1004
1005 ngx_http_upstream_connect(r, u);
1006 }
1007
1008
1009 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
1010 ngx_http_upstream_t *u,
1011 ngx_int_t rc)
1012 {
1013 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1014 "finalize http upstream request");
1015
1016 u->finalize_request(r, rc);
1017
1018 if (u->peer.connection) {
1019 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1020 "close http upstream connection: %d",
1021 u->peer.connection->fd);
1022
1023 ngx_close_connection(u->peer.connection);
1024 }
1025
1026 if (u->header_sent
1027 && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
1028 {
1029 rc = 0;
1030 }
1031
1032 if (u->saved_ctx) {
1033 r->connection->log->data = u->saved_ctx;
1034 r->connection->log->handler = u->saved_handler;
1035 }
1036
1037 if (u->pipe.temp_file->file.fd) {
1038 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1039 "http upstream temp fd: %d",
1040 u->pipe.temp_file->file.fd);
1041 }
1042
1043 #if 0
1044 if (u->cache) {
1045 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1046 "http proxy cache fd: %d",
1047 u->cache->ctx.file.fd);
1048 }
1049 #endif
1050
1051 if (u->pipe.temp_file->file.fd) {
1052 r->file.fd = u->pipe.temp_file->file.fd;
1053
1054 #if 0
1055 } else if (u->cache) {
1056 r->file.fd = u->cache->ctx.file.fd;
1057 #endif
1058 }
1059
1060 if (rc == 0 && r->main == NULL) {
1061 rc = ngx_http_send_last(r);
1062 }
1063
1064 ngx_http_finalize_request(r, rc);
1065 }
1066
1067
1068 static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r,
1069 uintptr_t data)
1070 {
1071 if (r->upstream) {
1072 return r->upstream->states.nelts * (3 + 2);
1073 }
1074
1075 return 1;
1076 }
1077
1078
1079 static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf,
1080 ngx_http_log_op_t *op)
1081 {
1082 ngx_uint_t i;
1083 ngx_http_upstream_t *u;
1084 ngx_http_upstream_state_t *state;
1085
1086 u = r->upstream;
1087
1088 if (u == NULL) {
1089 *buf = '-';
1090 return buf + 1;
1091 }
1092
1093 i = 0;
1094 state = u->states.elts;
1095
1096 for ( ;; ) {
1097 if (state[i].status == 0) {
1098 *buf++ = '-';
1099
1100 } else {
1101 buf = ngx_sprintf(buf, "%ui", state[i].status);
1102 }
1103
1104 if (++i == u->states.nelts) {
1105 return buf;
1106 }
1107
1108 *buf++ = ',';
1109 *buf++ = ' ';
1110 }
1111 }
1112
1113
1114 u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len)
1115 {
1116 ngx_http_log_ctx_t *ctx = data;
1117
1118 u_char *p;
1119 ngx_int_t escape;
1120 ngx_str_t uri;
1121 ngx_http_request_t *r;
1122 ngx_http_upstream_t *u;
1123 ngx_peer_connection_t *peer;
1124
1125 r = ctx->request;
1126 u = r->upstream;
1127 peer = &u->peer;
1128
1129 p = ngx_snprintf(buf, len,
1130 " while %s, client: %V, URL: %V, upstream: %V%V%s%V",
1131 ctx->action,
1132 &r->connection->addr_text,
1133 &r->unparsed_uri,
1134 &u->schema,
1135 &peer->peers->peer[peer->cur_peer].name,
1136 peer->peers->peer[peer->cur_peer].uri_separator,
1137 &u->uri);
1138 len -= p - buf;
1139 buf = p;
1140
1141 if (r->quoted_uri) {
1142 escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location->len,
1143 r->uri.len - u->location->len,
1144 NGX_ESCAPE_URI);
1145 } else {
1146 escape = 0;
1147 }
1148
1149 if (escape) {
1150 if (len >= r->uri.len - u->location->len + escape) {
1151
1152 ngx_escape_uri(buf, r->uri.data + u->location->len,
1153 r->uri.len - u->location->len, NGX_ESCAPE_URI);
1154
1155 buf += r->uri.len - u->location->len + escape;
1156
1157 if (r->args.len == 0) {
1158 return buf;
1159 }
1160
1161 len -= r->uri.len - u->location->len + escape;
1162
1163 return ngx_snprintf(buf, len, "?%V", &r->args);
1164 }
1165
1166 p = ngx_palloc(r->pool, r->uri.len - u->location->len + escape);
1167 if (p == NULL) {
1168 return buf;
1169 }
1170
1171 ngx_escape_uri(p, r->uri.data + u->location->len,
1172 r->uri.len - u->location->len, NGX_ESCAPE_URI);
1173
1174 uri.len = r->uri.len - u->location->len + escape;
1175 uri.data = p;
1176
1177 } else {
1178 uri.len = r->uri.len - u->location->len;
1179 uri.data = r->uri.data + u->location->len;
1180
1181 }
1182
1183 return ngx_snprintf(buf, len, "%V%s%V",
1184 &uri, r->args.len ? "?" : "", &r->args);
1185 }
1186
1187
1188 static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf)
1189 {
1190 ngx_http_log_op_name_t *op;
1191
1192 for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ }
1193 op->run = NULL;
1194
1195 for (op = ngx_http_log_fmt_ops; op->run; op++) {
1196 if (op->name.len == 0) {
1197 op = (ngx_http_log_op_name_t *) op->run;
1198 }
1199 }
1200
1201 op->run = (ngx_http_log_op_run_pt) ngx_http_upstream_log_fmt_ops;
1202
1203 return NGX_OK;
1204 }