nginx 0.7.8
[nginx-catap.git] / src / http / ngx_http_upstream.c
blob191219b7381a4714410b273296edd070618c4c18
2 /*
3 * Copyright (C) Igor Sysoev
4 */
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
12 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
13 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
14 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
15 static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
16 ngx_event_t *ev);
17 static void ngx_http_upstream_connect(ngx_http_request_t *r,
18 ngx_http_upstream_t *u);
19 static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
20 ngx_http_upstream_t *u);
21 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
22 ngx_http_upstream_t *u);
23 static void ngx_http_upstream_send_request_handler(ngx_event_t *wev);
24 static void ngx_http_upstream_process_header(ngx_event_t *rev);
25 static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
26 static void ngx_http_upstream_process_body_in_memory(ngx_event_t *rev);
27 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
28 ngx_http_upstream_t *u);
29 static void
30 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
31 static void ngx_http_upstream_process_non_buffered_body(ngx_event_t *ev);
32 static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
33 static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
34 ssize_t bytes);
35 static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
36 static void ngx_http_upstream_process_body(ngx_event_t *ev);
37 static void ngx_http_upstream_store(ngx_http_request_t *r,
38 ngx_http_upstream_t *u);
39 static void ngx_http_upstream_dummy_handler(ngx_event_t *wev);
40 static void ngx_http_upstream_next(ngx_http_request_t *r,
41 ngx_http_upstream_t *u, ngx_uint_t ft_type);
42 static void ngx_http_upstream_cleanup(void *data);
43 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
44 ngx_http_upstream_t *u, ngx_int_t rc);
46 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
47 ngx_table_elt_t *h, ngx_uint_t offset);
48 static ngx_int_t
49 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
50 ngx_table_elt_t *h, ngx_uint_t offset);
51 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
52 ngx_table_elt_t *h, ngx_uint_t offset);
53 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
54 ngx_table_elt_t *h, ngx_uint_t offset);
55 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
56 ngx_table_elt_t *h, ngx_uint_t offset);
57 static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
58 ngx_table_elt_t *h, ngx_uint_t offset);
59 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
60 ngx_table_elt_t *h, ngx_uint_t offset);
61 static ngx_int_t
62 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
63 ngx_table_elt_t *h, ngx_uint_t offset);
64 static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
65 ngx_table_elt_t *h, ngx_uint_t offset);
66 static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
67 ngx_table_elt_t *h, ngx_uint_t offset);
68 static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
69 ngx_table_elt_t *h, ngx_uint_t offset);
70 static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
71 ngx_table_elt_t *h, ngx_uint_t offset);
72 #if (NGX_HTTP_GZIP)
73 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
74 ngx_table_elt_t *h, ngx_uint_t offset);
75 #endif
77 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
78 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
79 ngx_http_variable_value_t *v, uintptr_t data);
80 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
81 ngx_http_variable_value_t *v, uintptr_t data);
82 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
83 ngx_http_variable_value_t *v, uintptr_t data);
85 static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
86 static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
87 void *conf);
89 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
90 static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
92 #if (NGX_HTTP_SSL)
93 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
94 ngx_http_upstream_t *u, ngx_connection_t *c);
95 static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
96 #endif
99 ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
101 { ngx_string("Status"),
102 ngx_http_upstream_process_header_line,
103 offsetof(ngx_http_upstream_headers_in_t, status),
104 ngx_http_upstream_copy_header_line, 0, 0 },
106 { ngx_string("Content-Type"),
107 ngx_http_upstream_process_header_line,
108 offsetof(ngx_http_upstream_headers_in_t, content_type),
109 ngx_http_upstream_copy_content_type, 0, 1 },
111 { ngx_string("Content-Length"),
112 ngx_http_upstream_process_header_line,
113 offsetof(ngx_http_upstream_headers_in_t, content_length),
114 ngx_http_upstream_copy_content_length, 0, 0 },
116 { ngx_string("Date"),
117 ngx_http_upstream_process_header_line,
118 offsetof(ngx_http_upstream_headers_in_t, date),
119 ngx_http_upstream_copy_header_line,
120 offsetof(ngx_http_headers_out_t, date), 0 },
122 { ngx_string("Last-Modified"),
123 ngx_http_upstream_process_header_line,
124 offsetof(ngx_http_upstream_headers_in_t, last_modified),
125 ngx_http_upstream_copy_header_line,
126 offsetof(ngx_http_headers_out_t, last_modified), 0 },
128 { ngx_string("Server"),
129 ngx_http_upstream_process_header_line,
130 offsetof(ngx_http_upstream_headers_in_t, server),
131 ngx_http_upstream_copy_header_line,
132 offsetof(ngx_http_headers_out_t, server), 0 },
134 { ngx_string("WWW-Authenticate"),
135 ngx_http_upstream_process_header_line,
136 offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
137 ngx_http_upstream_copy_header_line, 0, 0 },
139 { ngx_string("Location"),
140 ngx_http_upstream_process_header_line,
141 offsetof(ngx_http_upstream_headers_in_t, location),
142 ngx_http_upstream_rewrite_location, 0, 0 },
144 { ngx_string("Refresh"),
145 ngx_http_upstream_ignore_header_line, 0,
146 ngx_http_upstream_rewrite_refresh, 0, 0 },
148 { ngx_string("Set-Cookie"),
149 ngx_http_upstream_ignore_header_line, 0,
150 ngx_http_upstream_copy_header_line, 0, 1 },
152 { ngx_string("Content-Disposition"),
153 ngx_http_upstream_ignore_header_line, 0,
154 ngx_http_upstream_copy_header_line, 0, 1 },
156 { ngx_string("Cache-Control"),
157 ngx_http_upstream_process_multi_header_lines,
158 offsetof(ngx_http_upstream_headers_in_t, cache_control),
159 ngx_http_upstream_copy_multi_header_lines,
160 offsetof(ngx_http_headers_out_t, cache_control), 1 },
162 { ngx_string("Expires"),
163 ngx_http_upstream_process_header_line,
164 offsetof(ngx_http_upstream_headers_in_t, expires),
165 ngx_http_upstream_copy_header_line,
166 offsetof(ngx_http_headers_out_t, expires), 1 },
168 { ngx_string("Accept-Ranges"),
169 ngx_http_upstream_process_header_line,
170 offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
171 ngx_http_upstream_copy_header_line,
172 offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
174 { ngx_string("Connection"),
175 ngx_http_upstream_ignore_header_line, 0,
176 ngx_http_upstream_ignore_header_line, 0, 0 },
178 { ngx_string("Keep-Alive"),
179 ngx_http_upstream_ignore_header_line, 0,
180 ngx_http_upstream_ignore_header_line, 0, 0 },
182 { ngx_string("X-Powered-By"),
183 ngx_http_upstream_ignore_header_line, 0,
184 ngx_http_upstream_copy_header_line, 0, 0 },
186 { ngx_string("X-Accel-Expires"),
187 ngx_http_upstream_process_header_line,
188 offsetof(ngx_http_upstream_headers_in_t, x_accel_expires),
189 ngx_http_upstream_copy_header_line, 0, 0 },
191 { ngx_string("X-Accel-Redirect"),
192 ngx_http_upstream_process_header_line,
193 offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
194 ngx_http_upstream_ignore_header_line, 0, 0 },
196 { ngx_string("X-Accel-Limit-Rate"),
197 ngx_http_upstream_process_limit_rate, 0,
198 ngx_http_upstream_ignore_header_line, 0, 0 },
200 { ngx_string("X-Accel-Buffering"),
201 ngx_http_upstream_process_buffering, 0,
202 ngx_http_upstream_ignore_header_line, 0, 0 },
204 { ngx_string("X-Accel-Charset"),
205 ngx_http_upstream_process_charset, 0,
206 ngx_http_upstream_ignore_header_line, 0, 0 },
208 #if (NGX_HTTP_GZIP)
209 { ngx_string("Content-Encoding"),
210 ngx_http_upstream_process_header_line,
211 offsetof(ngx_http_upstream_headers_in_t, content_encoding),
212 ngx_http_upstream_copy_content_encoding, 0, 0 },
213 #endif
215 { ngx_null_string, NULL, 0, NULL, 0, 0 }
219 static ngx_command_t ngx_http_upstream_commands[] = {
221 { ngx_string("upstream"),
222 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
223 ngx_http_upstream,
226 NULL },
228 { ngx_string("server"),
229 NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
230 ngx_http_upstream_server,
231 NGX_HTTP_SRV_CONF_OFFSET,
233 NULL },
235 ngx_null_command
239 static ngx_http_module_t ngx_http_upstream_module_ctx = {
240 ngx_http_upstream_add_variables, /* preconfiguration */
241 NULL, /* postconfiguration */
243 ngx_http_upstream_create_main_conf, /* create main configuration */
244 ngx_http_upstream_init_main_conf, /* init main configuration */
246 NULL, /* create server configuration */
247 NULL, /* merge server configuration */
249 NULL, /* create location configuration */
250 NULL /* merge location configuration */
254 ngx_module_t ngx_http_upstream_module = {
255 NGX_MODULE_V1,
256 &ngx_http_upstream_module_ctx, /* module context */
257 ngx_http_upstream_commands, /* module directives */
258 NGX_HTTP_MODULE, /* module type */
259 NULL, /* init master */
260 NULL, /* init module */
261 NULL, /* init process */
262 NULL, /* init thread */
263 NULL, /* exit thread */
264 NULL, /* exit process */
265 NULL, /* exit master */
266 NGX_MODULE_V1_PADDING
270 static ngx_http_variable_t ngx_http_upstream_vars[] = {
272 { ngx_string("upstream_addr"), NULL,
273 ngx_http_upstream_addr_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
275 { ngx_string("upstream_status"), NULL,
276 ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
278 { ngx_string("upstream_response_time"), NULL,
279 ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
281 { ngx_null_string, NULL, NULL, 0, 0, 0 }
285 void
286 ngx_http_upstream_init(ngx_http_request_t *r)
288 ngx_str_t *host;
289 ngx_uint_t i;
290 ngx_connection_t *c;
291 ngx_resolver_ctx_t *ctx, temp;
292 ngx_http_cleanup_t *cln;
293 ngx_http_upstream_t *u;
294 ngx_http_core_loc_conf_t *clcf;
295 ngx_http_upstream_srv_conf_t *uscf, **uscfp;
296 ngx_http_upstream_main_conf_t *umcf;
298 c = r->connection;
300 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
301 "http init upstream, client timer: %d", c->read->timer_set);
303 if (c->read->timer_set) {
304 ngx_del_timer(c->read);
307 u = r->upstream;
309 if (!r->post_action && !u->conf->ignore_client_abort) {
310 r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
311 r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
314 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
316 if (!c->write->active) {
317 if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
318 == NGX_ERROR)
320 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
321 return;
326 if (r->request_body) {
327 u->request_bufs = r->request_body->bufs;
330 if (u->create_request(r) != NGX_OK) {
331 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
332 return;
335 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
337 u->output.pool = r->pool;
338 u->output.bufs.num = 1;
339 u->output.bufs.size = clcf->client_body_buffer_size;
340 u->output.output_filter = ngx_chain_writer;
341 u->output.filter_ctx = &u->writer;
343 u->writer.pool = r->pool;
345 if (r->upstream_states == NULL) {
347 r->upstream_states = ngx_array_create(r->pool, 1,
348 sizeof(ngx_http_upstream_state_t));
349 if (r->upstream_states == NULL) {
350 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
351 return;
354 } else {
356 u->state = ngx_array_push(r->upstream_states);
357 if (u->state == NULL) {
358 ngx_http_upstream_finalize_request(r, u,
359 NGX_HTTP_INTERNAL_SERVER_ERROR);
360 return;
363 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
366 cln = ngx_http_cleanup_add(r, 0);
367 if (cln == NULL) {
368 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
369 return;
372 cln->handler = ngx_http_upstream_cleanup;
373 cln->data = r;
374 u->cleanup = &cln->handler;
376 u->store = (u->conf->store || u->conf->store_lengths);
378 if (u->resolved == NULL) {
380 uscf = u->conf->upstream;
382 } else {
384 host = &u->resolved->host;
386 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
388 uscfp = umcf->upstreams.elts;
390 for (i = 0; i < umcf->upstreams.nelts; i++) {
392 uscf = uscfp[i];
394 if (uscf->host.len == host->len
395 && ((uscf->port == 0 && u->resolved->default_port)
396 || uscf->port == u->resolved->port)
397 && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
399 goto found;
403 temp.name = *host;
405 ctx = ngx_resolve_start(clcf->resolver, &temp);
406 if (ctx == NULL) {
407 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
408 return;
411 if (ctx == NGX_NO_RESOLVER) {
412 ngx_log_error(NGX_LOG_ERR, c->log, 0,
413 "no resolver defined to resolve %V", host);
415 ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
416 return;
419 ctx->name = *host;
420 ctx->type = NGX_RESOLVE_A;
421 ctx->handler = ngx_http_upstream_resolve_handler;
422 ctx->data = r;
423 ctx->timeout = clcf->resolver_timeout;
425 u->resolved->ctx = ctx;
427 if (ngx_resolve_name(ctx) != NGX_OK) {
428 u->resolved->ctx = NULL;
429 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
430 return;
433 return;
436 found:
438 if (uscf->peer.init(r, uscf) != NGX_OK) {
439 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
440 return;
443 ngx_http_upstream_connect(r, u);
447 static void
448 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
450 ngx_http_request_t *r;
451 ngx_http_upstream_resolved_t *ur;
453 r = ctx->data;
455 r->upstream->resolved->ctx = NULL;
457 if (ctx->state) {
458 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
459 "%V could not be resolved (%i: %s)",
460 &ctx->name, ctx->state,
461 ngx_resolver_strerror(ctx->state));
463 ngx_resolve_name_done(ctx);
464 ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
465 return;
468 ur = r->upstream->resolved;
469 ur->naddrs = ctx->naddrs;
470 ur->addrs = ctx->addrs;
472 #if (NGX_DEBUG)
474 in_addr_t addr;
475 ngx_uint_t i;
477 for (i = 0; i < ctx->naddrs; i++) {
478 addr = ntohl(ur->addrs[i]);
480 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
481 "name was resolved to %ud.%ud.%ud.%ud",
482 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
483 (addr >> 8) & 0xff, addr & 0xff);
486 #endif
488 if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
489 ngx_resolve_name_done(ctx);
490 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
491 return;
494 ngx_resolve_name_done(ctx);
496 ngx_http_upstream_connect(r, r->upstream);
500 static void
501 ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
503 ngx_http_upstream_check_broken_connection(r, r->connection->read);
507 static void
508 ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
510 ngx_http_upstream_check_broken_connection(r, r->connection->write);
514 static void
515 ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
516 ngx_event_t *ev)
518 int n;
519 char buf[1];
520 ngx_err_t err;
521 ngx_connection_t *c;
522 ngx_http_upstream_t *u;
524 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
525 "http upstream check client, write event:%d, \"%V\"",
526 ev->write, &r->uri);
528 c = r->connection;
529 u = r->upstream;
531 if (c->error) {
532 ngx_http_upstream_finalize_request(r, u,
533 NGX_HTTP_CLIENT_CLOSED_REQUEST);
534 return;
537 if (u->peer.connection == NULL) {
538 return;
541 #if (NGX_HAVE_KQUEUE)
543 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
545 if (!ev->pending_eof) {
546 return;
549 ev->eof = 1;
550 c->error = 1;
552 if (ev->kq_errno) {
553 ev->error = 1;
556 if (!u->cacheable && !u->store && u->peer.connection) {
557 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
558 "kevent() reported that client closed prematurely "
559 "connection, so upstream connection is closed too");
560 ngx_http_upstream_finalize_request(r, u,
561 NGX_HTTP_CLIENT_CLOSED_REQUEST);
562 return;
565 ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
566 "kevent() reported that client closed "
567 "prematurely connection");
569 if (u->peer.connection == NULL) {
570 ngx_http_upstream_finalize_request(r, u,
571 NGX_HTTP_CLIENT_CLOSED_REQUEST);
572 return;
575 return;
578 #endif
580 n = recv(c->fd, buf, 1, MSG_PEEK);
582 err = ngx_socket_errno;
584 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
585 "http upstream recv(): %d", n);
588 * we do not need to disable the write event because
589 * that event has NGX_USE_CLEAR_EVENT type
592 if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
593 return;
596 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
597 if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
598 ngx_http_upstream_finalize_request(r, u,
599 NGX_HTTP_INTERNAL_SERVER_ERROR);
600 return;
604 if (n > 0) {
605 return;
608 if (n == -1) {
609 if (err == NGX_EAGAIN) {
610 return;
613 ev->error = 1;
615 } else { /* n == 0 */
616 err = 0;
619 ev->eof = 1;
620 c->error = 1;
622 if (!u->cacheable && !u->store && u->peer.connection) {
623 ngx_log_error(NGX_LOG_INFO, ev->log, err,
624 "client closed prematurely connection, "
625 "so upstream connection is closed too");
626 ngx_http_upstream_finalize_request(r, u,
627 NGX_HTTP_CLIENT_CLOSED_REQUEST);
628 return;
631 ngx_log_error(NGX_LOG_INFO, ev->log, err,
632 "client closed prematurely connection");
634 if (u->peer.connection == NULL) {
635 ngx_http_upstream_finalize_request(r, u,
636 NGX_HTTP_CLIENT_CLOSED_REQUEST);
637 return;
642 static void
643 ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
645 ngx_int_t rc;
646 ngx_time_t *tp;
647 ngx_connection_t *c;
649 r->connection->log->action = "connecting to upstream";
651 r->connection->single_connection = 0;
653 if (u->state && u->state->response_sec) {
654 tp = ngx_timeofday();
655 u->state->response_sec = tp->sec - u->state->response_sec;
656 u->state->response_msec = tp->msec - u->state->response_msec;
659 u->state = ngx_array_push(r->upstream_states);
660 if (u->state == NULL) {
661 ngx_http_upstream_finalize_request(r, u,
662 NGX_HTTP_INTERNAL_SERVER_ERROR);
663 return;
666 ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
668 tp = ngx_timeofday();
669 u->state->response_sec = tp->sec;
670 u->state->response_msec = tp->msec;
672 rc = ngx_event_connect_peer(&u->peer);
674 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
675 "http upstream connect: %i", rc);
677 if (rc == NGX_ERROR) {
678 ngx_http_upstream_finalize_request(r, u,
679 NGX_HTTP_INTERNAL_SERVER_ERROR);
680 return;
683 u->state->peer = u->peer.name;
685 if (rc == NGX_BUSY) {
686 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
687 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
688 return;
691 if (rc == NGX_DECLINED) {
692 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
693 return;
696 /* rc == NGX_OK || rc == NGX_AGAIN */
698 c = u->peer.connection;
700 c->data = r;
702 c->write->handler = ngx_http_upstream_send_request_handler;
703 c->read->handler = ngx_http_upstream_process_header;
705 c->sendfile &= r->connection->sendfile;
706 u->output.sendfile = c->sendfile;
708 c->pool = r->pool;
709 c->read->log = c->write->log = c->log = r->connection->log;
711 /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
713 u->writer.out = NULL;
714 u->writer.last = &u->writer.out;
715 u->writer.connection = c;
716 u->writer.limit = 0;
718 if (u->request_sent) {
719 if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
720 ngx_http_upstream_finalize_request(r, u,
721 NGX_HTTP_INTERNAL_SERVER_ERROR);
722 return;
726 if (r->request_body
727 && r->request_body->buf
728 && r->request_body->temp_file
729 && r == r->main)
732 * the r->request_body->buf can be reused for one request only,
733 * the subrequests should allocate their own temporay bufs
736 u->output.free = ngx_alloc_chain_link(r->pool);
737 if (u->output.free == NULL) {
738 ngx_http_upstream_finalize_request(r, u,
739 NGX_HTTP_INTERNAL_SERVER_ERROR);
740 return;
743 u->output.free->buf = r->request_body->buf;
744 u->output.free->next = NULL;
745 u->output.allocated = 1;
747 r->request_body->buf->pos = r->request_body->buf->start;
748 r->request_body->buf->last = r->request_body->buf->start;
749 r->request_body->buf->tag = u->output.tag;
752 u->request_sent = 0;
754 if (rc == NGX_AGAIN) {
755 ngx_add_timer(c->write, u->conf->connect_timeout);
756 return;
759 #if (NGX_HTTP_SSL)
761 if (u->ssl && c->ssl == NULL) {
762 ngx_http_upstream_ssl_init_connection(r, u, c);
763 return;
766 #endif
768 ngx_http_upstream_send_request(r, u);
772 #if (NGX_HTTP_SSL)
774 static void
775 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
776 ngx_http_upstream_t *u, ngx_connection_t *c)
778 ngx_int_t rc;
780 if (ngx_ssl_create_connection(u->conf->ssl, c,
781 NGX_SSL_BUFFER|NGX_SSL_CLIENT)
782 == NGX_ERROR)
784 ngx_http_upstream_finalize_request(r, u,
785 NGX_HTTP_INTERNAL_SERVER_ERROR);
786 return;
789 c->sendfile = 0;
790 u->output.sendfile = 0;
792 if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
793 ngx_http_upstream_finalize_request(r, u,
794 NGX_HTTP_INTERNAL_SERVER_ERROR);
795 return;
798 r->connection->log->action = "SSL handshaking to upstream";
800 rc = ngx_ssl_handshake(c);
802 if (rc == NGX_AGAIN) {
803 c->ssl->handler = ngx_http_upstream_ssl_handshake;
804 return;
807 ngx_http_upstream_ssl_handshake(c);
811 static void
812 ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
814 ngx_http_request_t *r;
815 ngx_http_upstream_t *u;
817 r = c->data;
818 u = r->upstream;
820 if (c->ssl->handshaked) {
822 u->peer.save_session(&u->peer, u->peer.data);
824 c->write->handler = ngx_http_upstream_send_request_handler;
825 c->read->handler = ngx_http_upstream_process_header;
827 ngx_http_upstream_send_request(r, u);
829 return;
832 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
836 #endif
839 static ngx_int_t
840 ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
842 ngx_chain_t *cl;
844 if (u->reinit_request(r) != NGX_OK) {
845 return NGX_ERROR;
848 ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
850 if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
851 sizeof(ngx_table_elt_t))
852 != NGX_OK)
854 return NGX_ERROR;
857 /* reinit the request chain */
859 for (cl = u->request_bufs; cl; cl = cl->next) {
860 cl->buf->pos = cl->buf->start;
861 cl->buf->file_pos = 0;
864 /* reinit the subrequest's ngx_output_chain() context */
866 if (r->request_body && r->request_body->temp_file
867 && r != r->main && u->output.buf)
869 u->output.free = ngx_alloc_chain_link(r->pool);
870 if (u->output.free == NULL) {
871 return NGX_ERROR;
874 u->output.free->buf = u->output.buf;
875 u->output.free->next = NULL;
877 u->output.buf->pos = u->output.buf->start;
878 u->output.buf->last = u->output.buf->start;
881 u->output.buf = NULL;
882 u->output.in = NULL;
883 u->output.busy = NULL;
885 /* reinit u->buffer */
887 #if 0
888 if (u->cache) {
889 u->buffer.pos = u->buffer.start + u->cache->ctx.header_size;
890 u->buffer.last = u->buffer.pos;
892 } else {
893 u->buffer.pos = u->buffer.start;
894 u->buffer.last = u->buffer.start;
896 #else
898 u->buffer.pos = u->buffer.start;
899 u->buffer.last = u->buffer.start;
901 #endif
903 return NGX_OK;
907 static void
908 ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
910 ngx_int_t rc;
911 ngx_connection_t *c;
913 c = u->peer.connection;
915 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
916 "http upstream send request");
918 if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
919 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
920 return;
923 c->log->action = "sending request to upstream";
925 rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
927 u->request_sent = 1;
929 if (rc == NGX_ERROR) {
930 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
931 return;
934 if (c->write->timer_set) {
935 ngx_del_timer(c->write);
938 if (rc == NGX_AGAIN) {
939 ngx_add_timer(c->write, u->conf->send_timeout);
941 if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR)
943 ngx_http_upstream_finalize_request(r, u,
944 NGX_HTTP_INTERNAL_SERVER_ERROR);
945 return;
948 return;
951 /* rc == NGX_OK */
953 if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
954 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
955 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
956 ngx_tcp_push_n " failed");
957 ngx_http_upstream_finalize_request(r, u,
958 NGX_HTTP_INTERNAL_SERVER_ERROR);
959 return;
962 c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
965 ngx_add_timer(c->read, u->conf->read_timeout);
967 #if 1
968 if (c->read->ready) {
970 /* post aio operation */
973 * TODO comment
974 * although we can post aio operation just in the end
975 * of ngx_http_upstream_connect() CHECK IT !!!
976 * it's better to do here because we postpone header buffer allocation
979 ngx_http_upstream_process_header(c->read);
980 return;
982 #endif
984 c->write->handler = ngx_http_upstream_dummy_handler;
986 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
987 ngx_http_upstream_finalize_request(r, u,
988 NGX_HTTP_INTERNAL_SERVER_ERROR);
989 return;
994 static void
995 ngx_http_upstream_send_request_handler(ngx_event_t *wev)
997 ngx_connection_t *c;
998 ngx_http_request_t *r;
999 ngx_http_upstream_t *u;
1001 c = wev->data;
1002 r = c->data;
1003 u = r->upstream;
1005 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
1006 "http upstream send request handler");
1008 if (wev->timedout) {
1009 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1010 return;
1013 #if (NGX_HTTP_SSL)
1015 if (u->ssl && c->ssl == NULL) {
1016 ngx_http_upstream_ssl_init_connection(r, u, c);
1017 return;
1020 #endif
1022 if (u->header_sent) {
1023 wev->handler = ngx_http_upstream_dummy_handler;
1025 (void) ngx_handle_write_event(wev, 0);
1027 return;
1030 ngx_http_upstream_send_request(r, u);
1034 static void
1035 ngx_http_upstream_process_header(ngx_event_t *rev)
1037 ssize_t n;
1038 ngx_int_t rc;
1039 ngx_str_t *uri, args;
1040 ngx_uint_t i, flags;
1041 ngx_list_part_t *part;
1042 ngx_table_elt_t *h;
1043 ngx_connection_t *c;
1044 ngx_http_request_t *r;
1045 ngx_http_upstream_t *u;
1046 ngx_http_err_page_t *err_page;
1047 ngx_http_core_loc_conf_t *clcf;
1048 ngx_http_upstream_header_t *hh;
1049 ngx_http_upstream_main_conf_t *umcf;
1051 c = rev->data;
1052 r = c->data;
1053 u = r->upstream;
1055 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1056 "http upstream process header");
1058 c->log->action = "reading response header from upstream";
1060 if (rev->timedout) {
1061 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1062 return;
1065 if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1066 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1067 return;
1070 if (u->buffer.start == NULL) {
1071 u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
1072 if (u->buffer.start == NULL) {
1073 ngx_http_upstream_finalize_request(r, u,
1074 NGX_HTTP_INTERNAL_SERVER_ERROR);
1075 return;
1078 u->buffer.pos = u->buffer.start;
1079 u->buffer.last = u->buffer.start;
1080 u->buffer.end = u->buffer.start + u->conf->buffer_size;
1081 u->buffer.temporary = 1;
1083 u->buffer.tag = u->output.tag;
1085 if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1086 sizeof(ngx_table_elt_t))
1087 != NGX_OK)
1089 ngx_http_upstream_finalize_request(r, u,
1090 NGX_HTTP_INTERNAL_SERVER_ERROR);
1091 return;
1094 #if 0
1095 if (u->cache) {
1096 u->buffer.pos += u->cache->ctx.header_size;
1097 u->buffer.last = u->buffer.pos;
1099 #endif
1102 n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
1104 if (n == NGX_AGAIN) {
1105 #if 0
1106 ngx_add_timer(rev, u->read_timeout);
1107 #endif
1109 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
1110 ngx_http_upstream_finalize_request(r, u,
1111 NGX_HTTP_INTERNAL_SERVER_ERROR);
1112 return;
1115 return;
1118 if (n == 0) {
1119 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1120 "upstream prematurely closed connection");
1123 if (n == NGX_ERROR || n == 0) {
1124 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1125 return;
1128 u->buffer.last += n;
1130 #if 0
1131 u->valid_header_in = 0;
1133 u->peer.cached = 0;
1134 #endif
1136 rc = u->process_header(r);
1138 if (rc == NGX_AGAIN) {
1139 #if 0
1140 ngx_add_timer(rev, u->read_timeout);
1141 #endif
1143 if (u->buffer.pos == u->buffer.end) {
1144 ngx_log_error(NGX_LOG_ERR, rev->log, 0,
1145 "upstream sent too big header");
1147 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1148 return;
1151 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
1152 ngx_http_upstream_finalize_request(r, u,
1153 NGX_HTTP_INTERNAL_SERVER_ERROR);
1154 return;
1157 return;
1160 if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
1161 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1162 return;
1165 if (rc == NGX_ERROR) {
1166 ngx_http_upstream_finalize_request(r, u,
1167 NGX_HTTP_INTERNAL_SERVER_ERROR);
1168 return;
1171 /* rc == NGX_OK */
1173 if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST
1174 && r->subrequest_in_memory)
1176 u->buffer.last = u->buffer.pos;
1179 if (u->headers_in.status_n == NGX_HTTP_INTERNAL_SERVER_ERROR) {
1181 if (u->peer.tries > 1
1182 && (u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_500))
1184 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_500);
1185 return;
1188 #if (NGX_HTTP_CACHE)
1190 if (u->peer.tries == 0
1191 && u->stale
1192 && (u->conf->use_stale & NGX_HTTP_UPSTREAM_FT_HTTP_500))
1194 ngx_http_upstream_finalize_request(r, u,
1195 ngx_http_send_cached_response(r));
1196 return;
1199 #endif
1202 if (u->headers_in.status_n == NGX_HTTP_NOT_FOUND) {
1204 if (u->peer.tries > 1
1205 && u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_404)
1207 ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_404);
1208 return;
1211 if (u->conf->intercept_404) {
1212 ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
1213 return;
1218 if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST
1219 && u->conf->intercept_errors)
1221 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1223 if (clcf->error_pages) {
1225 err_page = clcf->error_pages->elts;
1226 for (i = 0; i < clcf->error_pages->nelts; i++) {
1227 if (err_page[i].status == (ngx_int_t) u->headers_in.status_n) {
1229 if (u->headers_in.status_n == NGX_HTTP_UNAUTHORIZED) {
1231 r->headers_out.www_authenticate =
1232 ngx_list_push(&r->headers_out.headers);
1234 if (r->headers_out.www_authenticate == NULL) {
1235 ngx_http_upstream_finalize_request(r, u,
1236 NGX_HTTP_INTERNAL_SERVER_ERROR);
1237 return;
1240 *r->headers_out.www_authenticate =
1241 *u->headers_in.www_authenticate;
1244 ngx_http_upstream_finalize_request(r, u,
1245 u->headers_in.status_n);
1246 return;
1252 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1254 if (u->headers_in.x_accel_redirect) {
1256 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
1258 part = &u->headers_in.headers.part;
1259 h = part->elts;
1261 for (i = 0; /* void */; i++) {
1263 if (i >= part->nelts) {
1264 if (part->next == NULL) {
1265 break;
1268 part = part->next;
1269 h = part->elts;
1270 i = 0;
1273 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1274 h[i].lowcase_key, h[i].key.len);
1276 if (hh && hh->redirect) {
1277 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1278 ngx_http_finalize_request(r,
1279 NGX_HTTP_INTERNAL_SERVER_ERROR);
1280 return;
1285 uri = &u->headers_in.x_accel_redirect->value;
1286 args.len = 0;
1287 args.data = NULL;
1288 flags = 0;
1290 if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
1291 ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
1292 return;
1295 if (flags & NGX_HTTP_ZERO_IN_URI) {
1296 r->zero_in_uri = 1;
1299 if (r->method != NGX_HTTP_HEAD) {
1300 r->method = NGX_HTTP_GET;
1303 ngx_http_internal_redirect(r, uri, &args);
1304 return;
1307 part = &u->headers_in.headers.part;
1308 h = part->elts;
1310 for (i = 0; /* void */; i++) {
1312 if (i >= part->nelts) {
1313 if (part->next == NULL) {
1314 break;
1317 part = part->next;
1318 h = part->elts;
1319 i = 0;
1322 if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
1323 h[i].lowcase_key, h[i].key.len))
1325 continue;
1328 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1329 h[i].lowcase_key, h[i].key.len);
1331 if (hh) {
1332 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1333 ngx_http_upstream_finalize_request(r, u,
1334 NGX_HTTP_INTERNAL_SERVER_ERROR);
1335 return;
1338 continue;
1341 if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
1342 ngx_http_upstream_finalize_request(r, u,
1343 NGX_HTTP_INTERNAL_SERVER_ERROR);
1344 return;
1348 if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
1349 r->headers_out.server->hash = 0;
1352 if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
1353 r->headers_out.date->hash = 0;
1356 r->headers_out.status = u->headers_in.status_n;
1357 r->headers_out.status_line = u->headers_in.status_line;
1359 u->headers_in.content_length_n = r->headers_out.content_length_n;
1361 if (r->headers_out.content_length_n != -1) {
1362 u->length = (size_t) r->headers_out.content_length_n;
1364 } else {
1365 u->length = NGX_MAX_SIZE_T_VALUE;
1368 if (!r->subrequest_in_memory) {
1369 ngx_http_upstream_send_response(r, u);
1370 return;
1373 /* subrequest content in memory */
1375 if (u->input_filter == NULL) {
1376 u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1377 u->input_filter = ngx_http_upstream_non_buffered_filter;
1378 u->input_filter_ctx = r;
1381 if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1382 ngx_http_upstream_finalize_request(r, u,
1383 NGX_HTTP_INTERNAL_SERVER_ERROR);
1384 return;
1387 if (u->buffer.last - u->buffer.pos >= (ssize_t) u->length) {
1388 if (u->input_filter(u->input_filter_ctx, 0) == NGX_ERROR) {
1389 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1390 return;
1393 ngx_http_upstream_finalize_request(r, u, 0);
1394 return;
1397 rev->handler = ngx_http_upstream_process_body_in_memory;
1399 ngx_http_upstream_process_body_in_memory(rev);
1403 static ngx_int_t
1404 ngx_http_upstream_test_connect(ngx_connection_t *c)
1406 int err;
1407 socklen_t len;
1409 #if (NGX_HAVE_KQUEUE)
1411 if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
1412 if (c->write->pending_eof) {
1413 c->log->action = "connecting to upstream";
1414 (void) ngx_connection_error(c, c->write->kq_errno,
1415 "kevent() reported that connect() failed");
1416 return NGX_ERROR;
1419 } else
1420 #endif
1422 err = 0;
1423 len = sizeof(int);
1426 * BSDs and Linux return 0 and set a pending error in err
1427 * Solaris returns -1 and sets errno
1430 if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1431 == -1)
1433 err = ngx_errno;
1436 if (err) {
1437 c->log->action = "connecting to upstream";
1438 (void) ngx_connection_error(c, err, "connect() failed");
1439 return NGX_ERROR;
1443 return NGX_OK;
1447 static void
1448 ngx_http_upstream_process_body_in_memory(ngx_event_t *rev)
1450 size_t size;
1451 ssize_t n;
1452 ngx_buf_t *b;
1453 ngx_connection_t *c;
1454 ngx_http_request_t *r;
1455 ngx_http_upstream_t *u;
1457 c = rev->data;
1458 r = c->data;
1459 u = r->upstream;
1461 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1462 "http upstream process body on memory");
1464 if (rev->timedout) {
1465 ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
1466 ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT);
1467 return;
1470 b = &u->buffer;
1472 for ( ;; ) {
1474 size = b->end - b->last;
1476 if (size == 0) {
1477 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
1478 "upstream buffer is too small to read repsonse");
1479 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1480 return;
1483 n = c->recv(c, b->last, size);
1485 if (n == NGX_AGAIN) {
1486 break;
1489 if (n == 0 || n == NGX_ERROR) {
1490 ngx_http_upstream_finalize_request(r, u, n);
1491 return;
1494 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1495 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1496 return;
1499 if (!rev->ready) {
1500 break;
1504 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
1505 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1506 return;
1509 if (rev->active) {
1510 ngx_add_timer(rev, u->conf->read_timeout);
1512 } else if (rev->timer_set) {
1513 ngx_del_timer(rev);
1518 static void
1519 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
1521 int tcp_nodelay;
1522 ssize_t size;
1523 ngx_int_t rc;
1524 ngx_event_pipe_t *p;
1525 ngx_connection_t *c;
1526 ngx_pool_cleanup_t *cl;
1527 ngx_pool_cleanup_file_t *clf;
1528 ngx_http_core_loc_conf_t *clcf;
1530 rc = ngx_http_send_header(r);
1532 if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) {
1533 ngx_http_upstream_finalize_request(r, u, rc);
1534 return;
1537 u->header_sent = 1;
1539 if (r->request_body && r->request_body->temp_file) {
1540 for (cl = r->pool->cleanup; cl; cl = cl->next) {
1541 if (cl->handler == ngx_pool_cleanup_file) {
1542 clf = cl->data;
1544 if (clf->fd == r->request_body->temp_file->file.fd) {
1545 cl->handler(clf);
1546 cl->handler = NULL;
1547 r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
1548 break;
1554 c = r->connection;
1556 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1558 if (!u->buffering) {
1560 if (u->input_filter == NULL) {
1561 u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1562 u->input_filter = ngx_http_upstream_non_buffered_filter;
1563 u->input_filter_ctx = r;
1566 u->peer.connection->read->handler =
1567 ngx_http_upstream_process_non_buffered_body;
1568 r->write_event_handler =
1569 ngx_http_upstream_process_non_buffered_downstream;
1571 r->limit_rate = 0;
1573 if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1574 ngx_http_upstream_finalize_request(r, u, 0);
1575 return;
1578 if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
1579 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
1581 tcp_nodelay = 1;
1583 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
1584 (const void *) &tcp_nodelay, sizeof(int)) == -1)
1586 ngx_connection_error(c, ngx_socket_errno,
1587 "setsockopt(TCP_NODELAY) failed");
1588 ngx_http_upstream_finalize_request(r, u, 0);
1589 return;
1592 c->tcp_nodelay = NGX_TCP_NODELAY_SET;
1595 size = u->buffer.last - u->buffer.pos;
1597 if (size) {
1598 u->buffer.last = u->buffer.pos;
1600 if (u->input_filter(u->input_filter_ctx, size) == NGX_ERROR) {
1601 ngx_http_upstream_finalize_request(r, u, 0);
1602 return;
1605 ngx_http_upstream_process_non_buffered_body(c->write);
1607 } else {
1608 u->buffer.pos = u->buffer.start;
1609 u->buffer.last = u->buffer.start;
1611 if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
1612 ngx_http_upstream_finalize_request(r, u, 0);
1613 return;
1616 if (u->peer.connection->read->ready) {
1617 ngx_http_upstream_process_non_buffered_body(
1618 u->peer.connection->read);
1622 return;
1625 /* TODO: preallocate event_pipe bufs, look "Content-Length" */
1627 #if 0
1629 if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
1630 if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
1631 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
1632 ngx_close_file_n " \"%s\" failed",
1633 u->cache->ctx.file.name.data);
1637 if (u->cacheable) {
1638 header = (ngx_http_cache_header_t *) u->buffer->start;
1640 header->expires = u->cache->ctx.expires;
1641 header->last_modified = u->cache->ctx.last_modified;
1642 header->date = u->cache->ctx.date;
1643 header->length = r->headers_out.content_length_n;
1644 u->cache->ctx.length = r->headers_out.content_length_n;
1646 header->key_len = u->cache->ctx.key0.len;
1647 ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len);
1648 header->key[header->key_len] = LF;
1651 #endif
1653 p = u->pipe;
1655 p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
1656 p->output_ctx = r;
1657 p->tag = u->output.tag;
1658 p->bufs = u->conf->bufs;
1659 p->busy_size = u->conf->busy_buffers_size;
1660 p->upstream = u->peer.connection;
1661 p->downstream = c;
1662 p->pool = r->pool;
1663 p->log = c->log;
1665 p->cacheable = u->cacheable || u->store;
1667 p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
1668 if (p->temp_file == NULL) {
1669 ngx_http_upstream_finalize_request(r, u, 0);
1670 return;
1673 p->temp_file->file.fd = NGX_INVALID_FILE;
1674 p->temp_file->file.log = c->log;
1675 p->temp_file->path = u->conf->temp_path;
1676 p->temp_file->pool = r->pool;
1678 if (u->cacheable || u->store) {
1679 p->temp_file->persistent = 1;
1681 } else {
1682 p->temp_file->log_level = NGX_LOG_WARN;
1683 p->temp_file->warn = "an upstream response is buffered "
1684 "to a temporary file";
1687 p->max_temp_file_size = u->conf->max_temp_file_size;
1688 p->temp_file_write_size = u->conf->temp_file_write_size;
1690 p->preread_bufs = ngx_alloc_chain_link(r->pool);
1691 if (p->preread_bufs == NULL) {
1692 ngx_http_upstream_finalize_request(r, u, 0);
1693 return;
1696 p->preread_bufs->buf = &u->buffer;
1697 p->preread_bufs->next = NULL;
1698 u->buffer.recycled = 1;
1700 p->preread_size = u->buffer.last - u->buffer.pos;
1702 if (u->cacheable) {
1704 p->buf_to_file = ngx_calloc_buf(r->pool);
1705 if (p->buf_to_file == NULL) {
1706 ngx_http_upstream_finalize_request(r, u, 0);
1707 return;
1710 p->buf_to_file->pos = u->buffer.start;
1711 p->buf_to_file->last = u->buffer.pos;
1712 p->buf_to_file->temporary = 1;
1715 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
1716 /* the posted aio operation may currupt a shadow buffer */
1717 p->single_buf = 1;
1720 /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
1721 p->free_bufs = 1;
1724 * event_pipe would do u->buffer.last += p->preread_size
1725 * as though these bytes were read
1727 u->buffer.last = u->buffer.pos;
1729 if (u->conf->cyclic_temp_file) {
1732 * we need to disable the use of sendfile() if we use cyclic temp file
1733 * because the writing a new data may interfere with sendfile()
1734 * that uses the same kernel file pages (at least on FreeBSD)
1737 p->cyclic_temp_file = 1;
1738 c->sendfile = 0;
1740 } else {
1741 p->cyclic_temp_file = 0;
1744 p->read_timeout = u->conf->read_timeout;
1745 p->send_timeout = clcf->send_timeout;
1746 p->send_lowat = clcf->send_lowat;
1748 u->peer.connection->read->handler = ngx_http_upstream_process_body;
1749 r->write_event_handler = ngx_http_upstream_process_downstream;
1751 ngx_http_upstream_process_body(u->peer.connection->read);
1755 static void
1756 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
1758 ngx_http_upstream_process_non_buffered_body(r->connection->write);
1762 static void
1763 ngx_http_upstream_process_non_buffered_body(ngx_event_t *ev)
1765 size_t size;
1766 ssize_t n;
1767 ngx_buf_t *b;
1768 ngx_int_t rc;
1769 ngx_uint_t do_write;
1770 ngx_connection_t *c, *downstream, *upstream;
1771 ngx_http_request_t *r;
1772 ngx_http_upstream_t *u;
1773 ngx_http_core_loc_conf_t *clcf;
1775 c = ev->data;
1776 r = c->data;
1777 u = r->upstream;
1779 if (ev->write) {
1780 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1781 "http upstream process non buffered downstream");
1782 c->log->action = "sending to client";
1784 } else {
1785 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1786 "http upstream process non buffered upstream");
1787 c->log->action = "reading upstream";
1790 if (ev->timedout) {
1791 if (ev->write) {
1792 c->timedout = 1;
1793 ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
1795 } else {
1796 ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
1799 ngx_http_upstream_finalize_request(r, u, 0);
1800 return;
1803 downstream = r->connection;
1804 upstream = u->peer.connection;
1806 b = &u->buffer;
1808 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1810 do_write = ev->write || u->length == 0;
1812 for ( ;; ) {
1814 if (do_write) {
1816 if (u->out_bufs || u->busy_bufs) {
1817 rc = ngx_http_output_filter(r, u->out_bufs);
1819 if (downstream->destroyed) {
1820 return;
1823 if (rc == NGX_ERROR) {
1824 ngx_http_upstream_finalize_request(r, u, 0);
1825 return;
1828 ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs,
1829 &u->out_bufs, u->output.tag);
1832 if (u->busy_bufs == NULL) {
1834 if (u->length == 0
1835 || upstream->read->eof
1836 || upstream->read->error)
1838 ngx_http_upstream_finalize_request(r, u, 0);
1839 return;
1842 b->pos = b->start;
1843 b->last = b->start;
1847 size = b->end - b->last;
1849 if (size > u->length) {
1850 size = u->length;
1853 if (size && upstream->read->ready) {
1855 n = upstream->recv(upstream, b->last, size);
1857 if (n == NGX_AGAIN) {
1858 break;
1861 if (n > 0) {
1862 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1863 ngx_http_upstream_finalize_request(r, u, 0);
1864 return;
1868 do_write = 1;
1870 continue;
1873 break;
1876 if (downstream->data == r) {
1877 if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
1878 == NGX_ERROR)
1880 ngx_http_upstream_finalize_request(r, u, 0);
1881 return;
1885 if (downstream->write->active && !downstream->write->ready) {
1886 ngx_add_timer(downstream->write, clcf->send_timeout);
1888 } else if (downstream->write->timer_set) {
1889 ngx_del_timer(downstream->write);
1892 if (ngx_handle_read_event(upstream->read, 0) == NGX_ERROR) {
1893 ngx_http_upstream_finalize_request(r, u, 0);
1894 return;
1897 if (upstream->read->active && !upstream->read->ready) {
1898 ngx_add_timer(upstream->read, u->conf->read_timeout);
1900 } else if (upstream->read->timer_set) {
1901 ngx_del_timer(upstream->read);
1906 static ngx_int_t
1907 ngx_http_upstream_non_buffered_filter_init(void *data)
1909 return NGX_OK;
1913 static ngx_int_t
1914 ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
1916 ngx_http_request_t *r = data;
1918 ngx_buf_t *b;
1919 ngx_chain_t *cl, **ll;
1920 ngx_http_upstream_t *u;
1922 u = r->upstream;
1924 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1925 ll = &cl->next;
1928 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1929 if (cl == NULL) {
1930 return NGX_ERROR;
1933 *ll = cl;
1935 cl->buf->flush = 1;
1936 cl->buf->memory = 1;
1938 b = &u->buffer;
1940 cl->buf->pos = b->last;
1941 b->last += bytes;
1942 cl->buf->last = b->last;
1943 cl->buf->tag = u->output.tag;
1945 if (u->length == NGX_MAX_SIZE_T_VALUE) {
1946 return NGX_OK;
1949 u->length -= bytes;
1951 return NGX_OK;
1955 static void
1956 ngx_http_upstream_process_downstream(ngx_http_request_t *r)
1958 ngx_http_upstream_process_body(r->connection->write);
1962 static void
1963 ngx_http_upstream_process_body(ngx_event_t *ev)
1965 ngx_temp_file_t *tf;
1966 ngx_event_pipe_t *p;
1967 ngx_connection_t *c, *downstream;
1968 ngx_http_log_ctx_t *ctx;
1969 ngx_http_request_t *r;
1970 ngx_http_upstream_t *u;
1972 c = ev->data;
1973 r = c->data;
1974 u = r->upstream;
1975 downstream = r->connection;
1977 if (ev->write) {
1978 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1979 "http upstream process downstream");
1980 c->log->action = "sending to client";
1982 } else {
1983 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1984 "http upstream process upstream");
1985 c->log->action = "reading upstream";
1987 ctx = c->log->data;
1988 ctx->current_request = r;
1991 p = u->pipe;
1993 if (ev->timedout) {
1994 if (ev->write) {
1995 if (ev->delayed) {
1997 ev->timedout = 0;
1998 ev->delayed = 0;
2000 if (!ev->ready) {
2001 ngx_add_timer(ev, p->send_timeout);
2003 if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR)
2005 ngx_http_upstream_finalize_request(r, u, 0);
2006 return;
2009 return;
2012 if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
2014 if (downstream->destroyed) {
2015 return;
2018 ngx_http_upstream_finalize_request(r, u, 0);
2019 return;
2022 } else {
2023 p->downstream_error = 1;
2024 c->timedout = 1;
2025 ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2028 } else {
2029 p->upstream_error = 1;
2030 ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2033 } else {
2034 if (ev->write && ev->delayed) {
2035 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2036 "http downstream delayed");
2038 if (ngx_handle_write_event(ev, p->send_lowat) == NGX_ERROR) {
2039 return;
2042 return;
2045 if (ngx_event_pipe(p, ev->write) == NGX_ABORT) {
2047 if (downstream->destroyed) {
2048 return;
2051 ngx_http_upstream_finalize_request(r, u, 0);
2052 return;
2056 if (u->peer.connection) {
2058 if (u->store) {
2060 tf = u->pipe->temp_file;
2062 if (p->upstream_eof
2063 && u->headers_in.status_n == NGX_HTTP_OK
2064 && (u->headers_in.content_length_n == -1
2065 || (u->headers_in.content_length_n == tf->offset)))
2067 ngx_http_upstream_store(r, u);
2069 } else if ((p->upstream_error
2070 || (p->upstream_eof
2071 && u->headers_in.status_n != NGX_HTTP_OK))
2072 && tf->file.fd != NGX_INVALID_FILE)
2074 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
2076 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
2077 ngx_delete_file_n " \"%s\" failed",
2078 u->pipe->temp_file->file.name.data);
2083 #if (NGX_HTTP_FILE_CACHE)
2085 if (p->upstream_done && u->cacheable) {
2086 if (ngx_http_cache_update(r) == NGX_ERROR) {
2087 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2088 ngx_http_upstream_finalize_request(r, u, 0);
2089 return;
2092 } else if (p->upstream_eof && u->cacheable) {
2094 /* TODO: check length & update cache */
2096 if (ngx_http_cache_update(r) == NGX_ERROR) {
2097 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2098 ngx_http_upstream_finalize_request(r, u, 0);
2099 return;
2103 #endif
2105 if (p->upstream_done || p->upstream_eof || p->upstream_error) {
2106 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
2107 "http upstream exit: %p", p->out);
2108 #if 0
2109 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2110 #endif
2111 ngx_http_upstream_finalize_request(r, u, 0);
2112 return;
2116 if (p->downstream_error) {
2117 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2118 "http upstream downstream error");
2120 if (!u->cacheable && u->peer.connection) {
2121 ngx_http_upstream_finalize_request(r, u, 0);
2127 static void
2128 ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
2130 size_t root;
2131 time_t lm;
2132 ngx_str_t path;
2133 ngx_temp_file_t *tf;
2134 ngx_ext_rename_file_t ext;
2136 tf = u->pipe->temp_file;
2138 if (tf->file.fd == NGX_INVALID_FILE) {
2140 /* create file for empty 200 response */
2142 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2143 if (tf == NULL) {
2144 return;
2147 tf->file.fd = NGX_INVALID_FILE;
2148 tf->file.log = r->connection->log;
2149 tf->path = u->conf->temp_path;
2150 tf->pool = r->pool;
2151 tf->persistent = 1;
2153 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
2154 tf->persistent, tf->clean, tf->access)
2155 != NGX_OK)
2157 return;
2160 u->pipe->temp_file = tf;
2163 ext.access = u->conf->store_access;
2164 ext.time = -1;
2165 ext.create_path = 1;
2166 ext.delete_file = 1;
2167 ext.log = r->connection->log;
2169 if (u->headers_in.last_modified) {
2171 lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
2172 u->headers_in.last_modified->value.len);
2174 if (lm != NGX_ERROR) {
2175 ext.time = lm;
2176 ext.fd = tf->file.fd;
2180 if (u->conf->store_lengths == NULL) {
2182 ngx_http_map_uri_to_path(r, &path, &root, 0);
2184 } else {
2185 if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
2186 u->conf->store_values->elts)
2187 == NULL)
2189 return;
2193 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2194 "upstream stores \"%s\" to \"%s\"",
2195 tf->file.name.data, path.data);
2197 (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
2201 static void
2202 ngx_http_upstream_dummy_handler(ngx_event_t *wev)
2204 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
2205 "http upstream dummy handler");
2209 static void
2210 ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
2211 ngx_uint_t ft_type)
2213 ngx_uint_t status, state;
2215 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2216 "http next upstream, %xi", ft_type);
2218 #if 0
2219 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2220 #endif
2222 if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
2223 state = NGX_PEER_NEXT;
2224 } else {
2225 state = NGX_PEER_FAILED;
2228 if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
2229 u->peer.free(&u->peer, u->peer.data, state);
2232 if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
2233 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
2234 "upstream timed out");
2237 if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
2238 status = 0;
2240 } else {
2241 switch(ft_type) {
2243 case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
2244 status = NGX_HTTP_GATEWAY_TIME_OUT;
2245 break;
2247 case NGX_HTTP_UPSTREAM_FT_HTTP_500:
2248 status = NGX_HTTP_INTERNAL_SERVER_ERROR;
2249 break;
2251 case NGX_HTTP_UPSTREAM_FT_HTTP_404:
2252 status = NGX_HTTP_NOT_FOUND;
2253 break;
2256 * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
2257 * never reach here
2260 default:
2261 status = NGX_HTTP_BAD_GATEWAY;
2265 if (r->connection->error) {
2266 ngx_http_upstream_finalize_request(r, u,
2267 NGX_HTTP_CLIENT_CLOSED_REQUEST);
2268 return;
2271 if (status) {
2272 u->state->status = status;
2274 if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
2276 #if (NGX_HTTP_CACHE)
2278 if (u->stale && (u->conf->use_stale & ft_type)) {
2279 ngx_http_upstream_finalize_request(r, u,
2280 ngx_http_send_cached_response(r));
2281 return;
2284 #endif
2286 ngx_http_upstream_finalize_request(r, u, status);
2287 return;
2291 if (u->peer.connection) {
2292 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2293 "close http upstream connection: %d",
2294 u->peer.connection->fd);
2295 #if (NGX_HTTP_SSL)
2297 if (u->peer.connection->ssl) {
2298 u->peer.connection->ssl->no_wait_shutdown = 1;
2299 u->peer.connection->ssl->no_send_shutdown = 1;
2301 (void) ngx_ssl_shutdown(u->peer.connection);
2303 #endif
2305 ngx_close_connection(u->peer.connection);
2308 #if 0
2309 if (u->conf->busy_lock && !u->busy_locked) {
2310 ngx_http_upstream_busy_lock(p);
2311 return;
2313 #endif
2315 ngx_http_upstream_connect(r, u);
2319 static void
2320 ngx_http_upstream_cleanup(void *data)
2322 ngx_http_request_t *r = data;
2324 ngx_http_upstream_t *u;
2326 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2327 "cleanup http upstream request: \"%V\"", &r->uri);
2329 u = r->upstream;
2331 if (u->resolved && u->resolved->ctx) {
2332 ngx_resolve_name_done(u->resolved->ctx);
2335 ngx_http_upstream_finalize_request(r, u, NGX_DONE);
2339 static void
2340 ngx_http_upstream_finalize_request(ngx_http_request_t *r,
2341 ngx_http_upstream_t *u, ngx_int_t rc)
2343 ngx_time_t *tp;
2345 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2346 "finalize http upstream request: %i", rc);
2348 *u->cleanup = NULL;
2350 if (u->state && u->state->response_sec) {
2351 tp = ngx_timeofday();
2352 u->state->response_sec = tp->sec - u->state->response_sec;
2353 u->state->response_msec = tp->msec - u->state->response_msec;
2356 u->finalize_request(r, rc);
2358 if (u->peer.free) {
2359 u->peer.free(&u->peer, u->peer.data, 0);
2362 if (u->peer.connection) {
2364 #if (NGX_HTTP_SSL)
2366 /* TODO: do not shutdown persistent connection */
2368 if (u->peer.connection->ssl) {
2371 * We send the "close notify" shutdown alert to the upstream only
2372 * and do not wait its "close notify" shutdown alert.
2373 * It is acceptable according to the TLS standard.
2376 u->peer.connection->ssl->no_wait_shutdown = 1;
2378 (void) ngx_ssl_shutdown(u->peer.connection);
2380 #endif
2382 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2383 "close http upstream connection: %d",
2384 u->peer.connection->fd);
2386 ngx_close_connection(u->peer.connection);
2389 u->peer.connection = NULL;
2391 if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
2393 rc = 0;
2396 if (u->pipe && u->pipe->temp_file) {
2397 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2398 "http upstream temp fd: %d",
2399 u->pipe->temp_file->file.fd);
2402 #if 0
2403 if (u->cache) {
2404 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2405 "http upstream cache fd: %d",
2406 u->cache->ctx.file.fd);
2408 #endif
2410 if (rc == NGX_DECLINED) {
2411 return;
2414 r->connection->log->action = "sending to client";
2416 if (rc == 0) {
2417 if (r == r->main) {
2418 if (!r->post_action) {
2419 rc = ngx_http_send_special(r, NGX_HTTP_LAST);
2422 } else {
2423 if (r->out) {
2424 rc = NGX_AGAIN;
2429 ngx_http_finalize_request(r, rc);
2433 static ngx_int_t
2434 ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2435 ngx_uint_t offset)
2437 ngx_table_elt_t **ph;
2439 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
2441 if (*ph == NULL) {
2442 *ph = h;
2445 return NGX_OK;
2449 static ngx_int_t
2450 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
2451 ngx_table_elt_t *h, ngx_uint_t offset)
2453 ngx_array_t *pa;
2454 ngx_table_elt_t **ph;
2456 pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset);
2458 if (pa->elts == NULL) {
2459 if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
2461 return NGX_ERROR;
2465 ph = ngx_array_push(pa);
2466 if (ph == NULL) {
2467 return NGX_ERROR;
2470 *ph = h;
2472 return NGX_OK;
2476 static ngx_int_t
2477 ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2478 ngx_uint_t offset)
2480 return NGX_OK;
2484 static ngx_int_t
2485 ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
2486 ngx_uint_t offset)
2488 ngx_int_t n;
2490 r->upstream->headers_in.x_accel_limit_rate = h;
2492 n = ngx_atoi(h->value.data, h->value.len);
2494 if (n != NGX_ERROR) {
2495 r->limit_rate = (size_t) n;
2498 return NGX_OK;
2502 static ngx_int_t
2503 ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
2504 ngx_uint_t offset)
2506 u_char c0, c1, c2;
2508 if (r->upstream->conf->change_buffering) {
2510 if (h->value.len == 2) {
2511 c0 = ngx_tolower(h->value.data[0]);
2512 c1 = ngx_tolower(h->value.data[1]);
2514 if (c0 == 'n' && c1 == 'o') {
2515 r->upstream->buffering = 0;
2518 } else if (h->value.len == 3) {
2519 c0 = ngx_tolower(h->value.data[0]);
2520 c1 = ngx_tolower(h->value.data[1]);
2521 c2 = ngx_tolower(h->value.data[2]);
2523 if (c0 == 'y' && c1 == 'e' && c2 == 's') {
2524 r->upstream->buffering = 1;
2529 return NGX_OK;
2533 static ngx_int_t
2534 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
2535 ngx_uint_t offset)
2537 r->headers_out.override_charset = &h->value;
2539 return NGX_OK;
2543 static ngx_int_t
2544 ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2545 ngx_uint_t offset)
2547 ngx_table_elt_t *ho, **ph;
2549 ho = ngx_list_push(&r->headers_out.headers);
2550 if (ho == NULL) {
2551 return NGX_ERROR;
2554 *ho = *h;
2556 if (offset) {
2557 ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
2558 *ph = ho;
2561 return NGX_OK;
2565 static ngx_int_t
2566 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
2567 ngx_table_elt_t *h, ngx_uint_t offset)
2569 ngx_array_t *pa;
2570 ngx_table_elt_t *ho, **ph;
2572 pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
2574 if (pa->elts == NULL) {
2575 if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
2577 return NGX_ERROR;
2581 ph = ngx_array_push(pa);
2582 if (ph == NULL) {
2583 return NGX_ERROR;
2586 ho = ngx_list_push(&r->headers_out.headers);
2587 if (ho == NULL) {
2588 return NGX_ERROR;
2591 *ho = *h;
2592 *ph = ho;
2594 return NGX_OK;
2598 static ngx_int_t
2599 ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
2600 ngx_uint_t offset)
2602 u_char *p, *last;
2604 r->headers_out.content_type_len = h->value.len;
2605 r->headers_out.content_type = h->value;
2607 for (p = h->value.data; *p; p++) {
2609 if (*p != ';') {
2610 continue;
2613 last = p;
2615 while (*++p == ' ') { /* void */ }
2617 if (*p == '\0') {
2618 return NGX_OK;
2621 if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
2622 continue;
2625 p += 8;
2627 r->headers_out.content_type_len = last - h->value.data;
2629 r->headers_out.charset.len = h->value.data + h->value.len - p;
2630 r->headers_out.charset.data = p;
2632 return NGX_OK;
2635 return NGX_OK;
2639 static ngx_int_t
2640 ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
2641 ngx_uint_t offset)
2643 ngx_table_elt_t *ho;
2645 ho = ngx_list_push(&r->headers_out.headers);
2646 if (ho == NULL) {
2647 return NGX_ERROR;
2650 *ho = *h;
2652 r->headers_out.content_length = ho;
2653 r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
2655 return NGX_OK;
2659 static ngx_int_t
2660 ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
2661 ngx_uint_t offset)
2663 ngx_int_t rc;
2664 ngx_table_elt_t *ho;
2666 ho = ngx_list_push(&r->headers_out.headers);
2667 if (ho == NULL) {
2668 return NGX_ERROR;
2671 *ho = *h;
2673 if (r->upstream->rewrite_redirect) {
2674 rc = r->upstream->rewrite_redirect(r, ho, 0);
2676 if (rc == NGX_DECLINED) {
2677 return NGX_OK;
2680 if (rc == NGX_OK) {
2681 r->headers_out.location = ho;
2683 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2684 "rewritten location: \"%V\"", &ho->value);
2687 return rc;
2690 if (ho->value.data[0] != '/') {
2691 r->headers_out.location = ho;
2695 * we do not set r->headers_out.location here to avoid the handling
2696 * the local redirects without a host name by ngx_http_header_filter()
2699 return NGX_OK;
2703 static ngx_int_t
2704 ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
2705 ngx_uint_t offset)
2707 u_char *p;
2708 ngx_int_t rc;
2709 ngx_table_elt_t *ho;
2711 ho = ngx_list_push(&r->headers_out.headers);
2712 if (ho == NULL) {
2713 return NGX_ERROR;
2716 *ho = *h;
2718 if (r->upstream->rewrite_redirect) {
2720 p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
2722 if (p) {
2723 rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
2725 } else {
2726 return NGX_OK;
2729 if (rc == NGX_DECLINED) {
2730 return NGX_OK;
2733 if (rc == NGX_OK) {
2734 r->headers_out.refresh = ho;
2736 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2737 "rewritten refresh: \"%V\"", &ho->value);
2740 return rc;
2743 r->headers_out.refresh = ho;
2745 return NGX_OK;
2749 #if (NGX_HTTP_GZIP)
2751 static ngx_int_t
2752 ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
2753 ngx_table_elt_t *h, ngx_uint_t offset)
2755 ngx_table_elt_t *ho;
2757 ho = ngx_list_push(&r->headers_out.headers);
2758 if (ho == NULL) {
2759 return NGX_ERROR;
2762 *ho = *h;
2764 r->headers_out.content_encoding = ho;
2766 return NGX_OK;
2769 #endif
2772 static ngx_int_t
2773 ngx_http_upstream_add_variables(ngx_conf_t *cf)
2775 ngx_http_variable_t *var, *v;
2777 for (v = ngx_http_upstream_vars; v->name.len; v++) {
2778 var = ngx_http_add_variable(cf, &v->name, v->flags);
2779 if (var == NULL) {
2780 return NGX_ERROR;
2783 var->get_handler = v->get_handler;
2784 var->data = v->data;
2787 return NGX_OK;
2791 static ngx_int_t
2792 ngx_http_upstream_addr_variable(ngx_http_request_t *r,
2793 ngx_http_variable_value_t *v, uintptr_t data)
2795 u_char *p;
2796 size_t len;
2797 ngx_uint_t i;
2798 ngx_http_upstream_state_t *state;
2800 v->valid = 1;
2801 v->no_cacheable = 0;
2802 v->not_found = 0;
2804 if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
2805 v->not_found = 1;
2806 return NGX_OK;
2809 len = 0;
2810 state = r->upstream_states->elts;
2812 for (i = 0; i < r->upstream_states->nelts; i++) {
2813 if (state[i].peer) {
2814 len += state[i].peer->len + 2;
2816 } else {
2817 len += 3;
2821 p = ngx_pnalloc(r->pool, len);
2822 if (p == NULL) {
2823 return NGX_ERROR;
2826 v->data = p;
2828 i = 0;
2830 for ( ;; ) {
2831 if (state[i].peer) {
2832 p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
2835 if (++i == r->upstream_states->nelts) {
2836 break;
2839 if (state[i].peer) {
2840 *p++ = ',';
2841 *p++ = ' ';
2843 } else {
2844 *p++ = ' ';
2845 *p++ = ':';
2846 *p++ = ' ';
2848 if (++i == r->upstream_states->nelts) {
2849 break;
2852 continue;
2856 v->len = p - v->data;
2858 return NGX_OK;
2862 static ngx_int_t
2863 ngx_http_upstream_status_variable(ngx_http_request_t *r,
2864 ngx_http_variable_value_t *v, uintptr_t data)
2866 u_char *p;
2867 size_t len;
2868 ngx_uint_t i;
2869 ngx_http_upstream_state_t *state;
2871 v->valid = 1;
2872 v->no_cacheable = 0;
2873 v->not_found = 0;
2875 if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
2876 v->not_found = 1;
2877 return NGX_OK;
2880 len = r->upstream_states->nelts * (3 + 2);
2882 p = ngx_pnalloc(r->pool, len);
2883 if (p == NULL) {
2884 return NGX_ERROR;
2887 v->data = p;
2889 i = 0;
2890 state = r->upstream_states->elts;
2892 for ( ;; ) {
2893 if (state[i].status) {
2894 p = ngx_sprintf(p, "%ui", state[i].status);
2896 } else {
2897 *p++ = '-';
2900 if (++i == r->upstream_states->nelts) {
2901 break;
2904 if (state[i].peer) {
2905 *p++ = ',';
2906 *p++ = ' ';
2908 } else {
2909 *p++ = ' ';
2910 *p++ = ':';
2911 *p++ = ' ';
2913 if (++i == r->upstream_states->nelts) {
2914 break;
2917 continue;
2921 v->len = p - v->data;
2923 return NGX_OK;
2927 static ngx_int_t
2928 ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
2929 ngx_http_variable_value_t *v, uintptr_t data)
2931 u_char *p;
2932 size_t len;
2933 ngx_uint_t i;
2934 ngx_msec_int_t ms;
2935 ngx_http_upstream_state_t *state;
2937 v->valid = 1;
2938 v->no_cacheable = 0;
2939 v->not_found = 0;
2941 if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
2942 v->not_found = 1;
2943 return NGX_OK;
2946 len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
2948 p = ngx_pnalloc(r->pool, len);
2949 if (p == NULL) {
2950 return NGX_ERROR;
2953 v->data = p;
2955 i = 0;
2956 state = r->upstream_states->elts;
2958 for ( ;; ) {
2959 if (state[i].status) {
2960 ms = (ngx_msec_int_t)
2961 (state[i].response_sec * 1000 + state[i].response_msec);
2962 ms = (ms >= 0) ? ms : 0;
2963 p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
2965 } else {
2966 *p++ = '-';
2969 if (++i == r->upstream_states->nelts) {
2970 break;
2973 if (state[i].peer) {
2974 *p++ = ',';
2975 *p++ = ' ';
2977 } else {
2978 *p++ = ' ';
2979 *p++ = ':';
2980 *p++ = ' ';
2982 if (++i == r->upstream_states->nelts) {
2983 break;
2986 continue;
2990 v->len = p - v->data;
2992 return NGX_OK;
2996 ngx_int_t
2997 ngx_http_upstream_header_variable(ngx_http_request_t *r,
2998 ngx_http_variable_value_t *v, uintptr_t data)
3000 if (r->upstream == NULL) {
3001 v->not_found = 1;
3002 return NGX_OK;
3005 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
3006 &r->upstream->headers_in.headers.part,
3007 sizeof("upstream_http_") - 1);
3011 static char *
3012 ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
3014 char *rv;
3015 void *mconf;
3016 ngx_str_t *value;
3017 ngx_url_t u;
3018 ngx_uint_t m;
3019 ngx_conf_t pcf;
3020 ngx_http_module_t *module;
3021 ngx_http_conf_ctx_t *ctx, *http_ctx;
3022 ngx_http_upstream_srv_conf_t *uscf;
3024 ngx_memzero(&u, sizeof(ngx_url_t));
3026 value = cf->args->elts;
3027 u.host = value[1];
3028 u.no_resolve = 1;
3030 uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
3031 |NGX_HTTP_UPSTREAM_WEIGHT
3032 |NGX_HTTP_UPSTREAM_MAX_FAILS
3033 |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
3034 |NGX_HTTP_UPSTREAM_DOWN
3035 |NGX_HTTP_UPSTREAM_BACKUP);
3036 if (uscf == NULL) {
3037 return NGX_CONF_ERROR;
3041 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
3042 if (ctx == NULL) {
3043 return NGX_CONF_ERROR;
3046 http_ctx = cf->ctx;
3047 ctx->main_conf = http_ctx->main_conf;
3049 /* the upstream{}'s srv_conf */
3051 ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3052 if (ctx->srv_conf == NULL) {
3053 return NGX_CONF_ERROR;
3056 ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
3058 uscf->srv_conf = ctx->srv_conf;
3061 /* the upstream{}'s loc_conf */
3063 ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3064 if (ctx->loc_conf == NULL) {
3065 return NGX_CONF_ERROR;
3068 for (m = 0; ngx_modules[m]; m++) {
3069 if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
3070 continue;
3073 module = ngx_modules[m]->ctx;
3075 if (module->create_srv_conf) {
3076 mconf = module->create_srv_conf(cf);
3077 if (mconf == NULL) {
3078 return NGX_CONF_ERROR;
3081 ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
3084 if (module->create_loc_conf) {
3085 mconf = module->create_loc_conf(cf);
3086 if (mconf == NULL) {
3087 return NGX_CONF_ERROR;
3090 ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
3095 /* parse inside upstream{} */
3097 pcf = *cf;
3098 cf->ctx = ctx;
3099 cf->cmd_type = NGX_HTTP_UPS_CONF;
3101 rv = ngx_conf_parse(cf, NULL);
3103 *cf = pcf;
3105 if (rv != NGX_CONF_OK) {
3106 return rv;
3109 if (uscf->servers == NULL) {
3110 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3111 "no servers are inside upstream");
3112 return NGX_CONF_ERROR;
3115 return rv;
3119 static char *
3120 ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3122 ngx_http_upstream_srv_conf_t *uscf = conf;
3124 time_t fail_timeout;
3125 ngx_str_t *value, s;
3126 ngx_url_t u;
3127 ngx_int_t weight, max_fails;
3128 ngx_uint_t i;
3129 ngx_http_upstream_server_t *us;
3131 if (uscf->servers == NULL) {
3132 uscf->servers = ngx_array_create(cf->pool, 4,
3133 sizeof(ngx_http_upstream_server_t));
3134 if (uscf->servers == NULL) {
3135 return NGX_CONF_ERROR;
3139 us = ngx_array_push(uscf->servers);
3140 if (us == NULL) {
3141 return NGX_CONF_ERROR;
3144 ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
3146 value = cf->args->elts;
3148 ngx_memzero(&u, sizeof(ngx_url_t));
3150 u.url = value[1];
3151 u.default_port = 80;
3153 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
3154 if (u.err) {
3155 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3156 "%s in upstream \"%V\"", u.err, &u.url);
3159 return NGX_CONF_ERROR;
3162 weight = 1;
3163 max_fails = 1;
3164 fail_timeout = 10;
3166 for (i = 2; i < cf->args->nelts; i++) {
3168 if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
3170 if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
3171 goto invalid;
3174 weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
3176 if (weight == NGX_ERROR || weight == 0) {
3177 goto invalid;
3180 continue;
3183 if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
3185 if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
3186 goto invalid;
3189 max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
3191 if (max_fails == NGX_ERROR) {
3192 goto invalid;
3195 continue;
3198 if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
3200 if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
3201 goto invalid;
3204 s.len = value[i].len - 13;
3205 s.data = &value[i].data[13];
3207 fail_timeout = ngx_parse_time(&s, 1);
3209 if (fail_timeout == NGX_ERROR) {
3210 goto invalid;
3213 continue;
3216 if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
3218 if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
3219 goto invalid;
3222 us->backup = 1;
3224 continue;
3227 if (ngx_strncmp(value[i].data, "down", 4) == 0) {
3229 if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
3230 goto invalid;
3233 us->down = 1;
3235 continue;
3238 goto invalid;
3241 us->addrs = u.addrs;
3242 us->naddrs = u.naddrs;
3243 us->weight = weight;
3244 us->max_fails = max_fails;
3245 us->fail_timeout = fail_timeout;
3247 return NGX_CONF_OK;
3249 invalid:
3251 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3252 "invalid parameter \"%V\"", &value[i]);
3254 return NGX_CONF_ERROR;
3258 ngx_http_upstream_srv_conf_t *
3259 ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
3261 ngx_uint_t i;
3262 ngx_http_upstream_server_t *us;
3263 ngx_http_upstream_srv_conf_t *uscf, **uscfp;
3264 ngx_http_upstream_main_conf_t *umcf;
3266 if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
3268 if (ngx_parse_url(cf->pool, u) != NGX_OK) {
3269 if (u->err) {
3270 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3271 "%s in upstream \"%V\"", u->err, &u->url);
3274 return NULL;
3278 umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
3280 uscfp = umcf->upstreams.elts;
3282 for (i = 0; i < umcf->upstreams.nelts; i++) {
3284 if (uscfp[i]->host.len != u->host.len
3285 || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
3286 != 0)
3288 continue;
3291 if ((flags & NGX_HTTP_UPSTREAM_CREATE)
3292 && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
3294 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3295 "duplicate upstream \"%V\"", &u->host);
3296 return NULL;
3299 if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && u->port) {
3300 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3301 "upstream \"%V\" may not have port %d",
3302 &u->host, u->port);
3303 return NULL;
3306 if ((flags & NGX_HTTP_UPSTREAM_CREATE) && uscfp[i]->port) {
3307 ngx_log_error(NGX_LOG_WARN, cf->log, 0,
3308 "upstream \"%V\" may not have port %d in %s:%ui",
3309 &u->host, uscfp[i]->port,
3310 uscfp[i]->file_name, uscfp[i]->line);
3311 return NULL;
3314 if (uscfp[i]->port != u->port) {
3315 continue;
3318 if (uscfp[i]->default_port && u->default_port
3319 && uscfp[i]->default_port != u->default_port)
3321 continue;
3324 return uscfp[i];
3327 uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
3328 if (uscf == NULL) {
3329 return NULL;
3332 uscf->flags = flags;
3333 uscf->host = u->host;
3334 uscf->file_name = cf->conf_file->file.name.data;
3335 uscf->line = cf->conf_file->line;
3336 uscf->port = u->port;
3337 uscf->default_port = u->default_port;
3339 if (u->naddrs == 1) {
3340 uscf->servers = ngx_array_create(cf->pool, 1,
3341 sizeof(ngx_http_upstream_server_t));
3342 if (uscf->servers == NULL) {
3343 return NGX_CONF_ERROR;
3346 us = ngx_array_push(uscf->servers);
3347 if (us == NULL) {
3348 return NGX_CONF_ERROR;
3351 ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
3353 us->addrs = u->addrs;
3354 us->naddrs = u->naddrs;
3357 uscfp = ngx_array_push(&umcf->upstreams);
3358 if (uscfp == NULL) {
3359 return NULL;
3362 *uscfp = uscf;
3364 return uscf;
3368 ngx_int_t
3369 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
3370 ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
3371 ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
3373 ngx_str_t *h;
3374 ngx_uint_t i, j;
3375 ngx_array_t hide_headers;
3376 ngx_hash_key_t *hk;
3378 if (conf->hide_headers == NGX_CONF_UNSET_PTR
3379 && conf->pass_headers == NGX_CONF_UNSET_PTR)
3381 conf->hide_headers_hash = prev->hide_headers_hash;
3383 if (conf->hide_headers_hash.buckets) {
3384 return NGX_OK;
3387 conf->hide_headers = prev->hide_headers;
3388 conf->pass_headers = prev->pass_headers;
3390 } else {
3391 if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
3392 conf->hide_headers = prev->hide_headers;
3395 if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
3396 conf->pass_headers = prev->pass_headers;
3400 if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3401 != NGX_OK)
3403 return NGX_ERROR;
3406 for (h = default_hide_headers; h->len; h++) {
3407 hk = ngx_array_push(&hide_headers);
3408 if (hk == NULL) {
3409 return NGX_ERROR;
3412 hk->key = *h;
3413 hk->key_hash = ngx_hash_key_lc(h->data, h->len);
3414 hk->value = (void *) 1;
3417 if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
3419 h = conf->hide_headers->elts;
3421 for (i = 0; i < conf->hide_headers->nelts; i++) {
3423 hk = hide_headers.elts;
3425 for (j = 0; j < hide_headers.nelts; j++) {
3426 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
3427 goto exist;
3431 hk = ngx_array_push(&hide_headers);
3432 if (hk == NULL) {
3433 return NGX_ERROR;
3436 hk->key = h[i];
3437 hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
3438 hk->value = (void *) 1;
3440 exist:
3442 continue;
3446 if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
3448 h = conf->pass_headers->elts;
3449 hk = hide_headers.elts;
3451 for (i = 0; i < conf->pass_headers->nelts; i++) {
3452 for (j = 0; j < hide_headers.nelts; j++) {
3454 if (hk[j].key.data == NULL) {
3455 continue;
3458 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
3459 hk[j].key.data = NULL;
3460 break;
3466 hash->hash = &conf->hide_headers_hash;
3467 hash->key = ngx_hash_key_lc;
3468 hash->pool = cf->pool;
3469 hash->temp_pool = NULL;
3471 return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
3475 static void *
3476 ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
3478 ngx_http_upstream_main_conf_t *umcf;
3480 umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
3481 if (umcf == NULL) {
3482 return NULL;
3485 if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
3486 sizeof(ngx_http_upstream_srv_conf_t *))
3487 != NGX_OK)
3489 return NGX_CONF_ERROR;
3492 return umcf;
3496 static char *
3497 ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
3499 ngx_http_upstream_main_conf_t *umcf = conf;
3501 ngx_uint_t i;
3502 ngx_array_t headers_in;
3503 ngx_hash_key_t *hk;
3504 ngx_hash_init_t hash;
3505 ngx_http_upstream_init_pt init;
3506 ngx_http_upstream_header_t *header;
3507 ngx_http_upstream_srv_conf_t **uscfp;
3509 uscfp = umcf->upstreams.elts;
3511 for (i = 0; i < umcf->upstreams.nelts; i++) {
3513 init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
3514 ngx_http_upstream_init_round_robin;
3516 if (init(cf, uscfp[i]) != NGX_OK) {
3517 return NGX_CONF_ERROR;
3522 /* upstream_headers_in_hash */
3524 if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
3525 != NGX_OK)
3527 return NGX_CONF_ERROR;
3530 for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
3531 hk = ngx_array_push(&headers_in);
3532 if (hk == NULL) {
3533 return NGX_CONF_ERROR;
3536 hk->key = header->name;
3537 hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
3538 hk->value = header;
3541 hash.hash = &umcf->headers_in_hash;
3542 hash.key = ngx_hash_key_lc;
3543 hash.max_size = 512;
3544 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3545 hash.name = "upstream_headers_in_hash";
3546 hash.pool = cf->pool;
3547 hash.temp_pool = NULL;
3549 if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
3550 return NGX_CONF_ERROR;
3553 return NGX_CONF_OK;