upstream nginx-0.7.43
[nginx.git] / nginx / src / http / ngx_http_upstream.c
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
11
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_http_request_t *r,
24     ngx_http_upstream_t *u);
25 static void ngx_http_upstream_process_header(ngx_http_request_t *r,
26     ngx_http_upstream_t *u);
27 static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
28     ngx_http_upstream_t *u);
29 static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
30     ngx_http_upstream_t *u);
31 static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
32 static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
33     ngx_http_upstream_t *u);
34 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
35     ngx_http_upstream_t *u);
36 static void
37     ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
38 static void
39     ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
40     ngx_http_upstream_t *u);
41 static void
42     ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
43     ngx_uint_t do_write);
44 static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
45 static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
46     ssize_t bytes);
47 static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
48 static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
49     ngx_http_upstream_t *u);
50 static void ngx_http_upstream_process_request(ngx_http_request_t *r);
51 static void ngx_http_upstream_store(ngx_http_request_t *r,
52     ngx_http_upstream_t *u);
53 static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
54     ngx_http_upstream_t *u);
55 static void ngx_http_upstream_next(ngx_http_request_t *r,
56     ngx_http_upstream_t *u, ngx_uint_t ft_type);
57 static void ngx_http_upstream_cleanup(void *data);
58 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
59     ngx_http_upstream_t *u, ngx_int_t rc);
60
61 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
62     ngx_table_elt_t *h, ngx_uint_t offset);
63 static ngx_int_t
64     ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
65     ngx_table_elt_t *h, ngx_uint_t offset);
66 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
67     ngx_table_elt_t *h, ngx_uint_t offset);
68 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
69     ngx_table_elt_t *h, ngx_uint_t offset);
70 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
71     ngx_table_elt_t *h, ngx_uint_t offset);
72 static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
73     ngx_table_elt_t *h, ngx_uint_t offset);
74 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
75     ngx_table_elt_t *h, ngx_uint_t offset);
76 static ngx_int_t
77     ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
78     ngx_table_elt_t *h, ngx_uint_t offset);
79 static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
80     ngx_table_elt_t *h, ngx_uint_t offset);
81 static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
82     ngx_table_elt_t *h, ngx_uint_t offset);
83 static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
84     ngx_table_elt_t *h, ngx_uint_t offset);
85 static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
86     ngx_table_elt_t *h, ngx_uint_t offset);
87 #if (NGX_HTTP_GZIP)
88 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
89     ngx_table_elt_t *h, ngx_uint_t offset);
90 #endif
91
92 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
93 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
94     ngx_http_variable_value_t *v, uintptr_t data);
95 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
96     ngx_http_variable_value_t *v, uintptr_t data);
97 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
98     ngx_http_variable_value_t *v, uintptr_t data);
99 static ngx_int_t ngx_http_upstream_response_length_variable(
100     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
101
102 static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
103 static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
104     void *conf);
105
106 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
107 static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
108
109 #if (NGX_HTTP_SSL)
110 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
111     ngx_http_upstream_t *u, ngx_connection_t *c);
112 static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
113 #endif
114
115
116 ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {
117
118     { ngx_string("Status"),
119                  ngx_http_upstream_process_header_line,
120                  offsetof(ngx_http_upstream_headers_in_t, status),
121                  ngx_http_upstream_copy_header_line, 0, 0 },
122
123     { ngx_string("Content-Type"),
124                  ngx_http_upstream_process_header_line,
125                  offsetof(ngx_http_upstream_headers_in_t, content_type),
126                  ngx_http_upstream_copy_content_type, 0, 1 },
127
128     { ngx_string("Content-Length"),
129                  ngx_http_upstream_process_header_line,
130                  offsetof(ngx_http_upstream_headers_in_t, content_length),
131                  ngx_http_upstream_copy_content_length, 0, 0 },
132
133     { ngx_string("Date"),
134                  ngx_http_upstream_process_header_line,
135                  offsetof(ngx_http_upstream_headers_in_t, date),
136                  ngx_http_upstream_copy_header_line,
137                  offsetof(ngx_http_headers_out_t, date), 0 },
138
139     { ngx_string("Last-Modified"),
140                  ngx_http_upstream_process_header_line,
141                  offsetof(ngx_http_upstream_headers_in_t, last_modified),
142                  ngx_http_upstream_copy_header_line,
143                  offsetof(ngx_http_headers_out_t, last_modified), 0 },
144
145     { ngx_string("Server"),
146                  ngx_http_upstream_process_header_line,
147                  offsetof(ngx_http_upstream_headers_in_t, server),
148                  ngx_http_upstream_copy_header_line,
149                  offsetof(ngx_http_headers_out_t, server), 0 },
150
151     { ngx_string("WWW-Authenticate"),
152                  ngx_http_upstream_process_header_line,
153                  offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
154                  ngx_http_upstream_copy_header_line, 0, 0 },
155
156     { ngx_string("Location"),
157                  ngx_http_upstream_process_header_line,
158                  offsetof(ngx_http_upstream_headers_in_t, location),
159                  ngx_http_upstream_rewrite_location, 0, 0 },
160
161     { ngx_string("Refresh"),
162                  ngx_http_upstream_ignore_header_line, 0,
163                  ngx_http_upstream_rewrite_refresh, 0, 0 },
164
165     { ngx_string("Set-Cookie"),
166                  ngx_http_upstream_ignore_header_line, 0,
167                  ngx_http_upstream_copy_header_line, 0, 1 },
168
169     { ngx_string("Content-Disposition"),
170                  ngx_http_upstream_ignore_header_line, 0,
171                  ngx_http_upstream_copy_header_line, 0, 1 },
172
173     { ngx_string("Cache-Control"),
174                  ngx_http_upstream_process_multi_header_lines,
175                  offsetof(ngx_http_upstream_headers_in_t, cache_control),
176                  ngx_http_upstream_copy_multi_header_lines,
177                  offsetof(ngx_http_headers_out_t, cache_control), 1 },
178
179     { ngx_string("Expires"),
180                  ngx_http_upstream_process_header_line,
181                  offsetof(ngx_http_upstream_headers_in_t, expires),
182                  ngx_http_upstream_copy_header_line,
183                  offsetof(ngx_http_headers_out_t, expires), 1 },
184
185     { ngx_string("Accept-Ranges"),
186                  ngx_http_upstream_process_header_line,
187                  offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
188                  ngx_http_upstream_copy_header_line,
189                  offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
190
191     { ngx_string("Connection"),
192                  ngx_http_upstream_ignore_header_line, 0,
193                  ngx_http_upstream_ignore_header_line, 0, 0 },
194
195     { ngx_string("Keep-Alive"),
196                  ngx_http_upstream_ignore_header_line, 0,
197                  ngx_http_upstream_ignore_header_line, 0, 0 },
198
199     { ngx_string("X-Powered-By"),
200                  ngx_http_upstream_ignore_header_line, 0,
201                  ngx_http_upstream_copy_header_line, 0, 0 },
202
203     { ngx_string("X-Accel-Expires"),
204                  ngx_http_upstream_process_header_line,
205                  offsetof(ngx_http_upstream_headers_in_t, x_accel_expires),
206                  ngx_http_upstream_copy_header_line, 0, 0 },
207
208     { ngx_string("X-Accel-Redirect"),
209                  ngx_http_upstream_process_header_line,
210                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
211                  ngx_http_upstream_ignore_header_line, 0, 0 },
212
213     { ngx_string("X-Accel-Limit-Rate"),
214                  ngx_http_upstream_process_limit_rate, 0,
215                  ngx_http_upstream_ignore_header_line, 0, 0 },
216
217     { ngx_string("X-Accel-Buffering"),
218                  ngx_http_upstream_process_buffering, 0,
219                  ngx_http_upstream_ignore_header_line, 0, 0 },
220
221     { ngx_string("X-Accel-Charset"),
222                  ngx_http_upstream_process_charset, 0,
223                  ngx_http_upstream_ignore_header_line, 0, 0 },
224
225 #if (NGX_HTTP_GZIP)
226     { ngx_string("Content-Encoding"),
227                  ngx_http_upstream_process_header_line,
228                  offsetof(ngx_http_upstream_headers_in_t, content_encoding),
229                  ngx_http_upstream_copy_content_encoding, 0, 0 },
230 #endif
231
232     { ngx_null_string, NULL, 0, NULL, 0, 0 }
233 };
234
235
236 static ngx_command_t  ngx_http_upstream_commands[] = {
237
238     { ngx_string("upstream"),
239       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
240       ngx_http_upstream,
241       0,
242       0,
243       NULL },
244
245     { ngx_string("server"),
246       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
247       ngx_http_upstream_server,
248       NGX_HTTP_SRV_CONF_OFFSET,
249       0,
250       NULL },
251
252       ngx_null_command
253 };
254
255
256 static ngx_http_module_t  ngx_http_upstream_module_ctx = {
257     ngx_http_upstream_add_variables,       /* preconfiguration */
258     NULL,                                  /* postconfiguration */
259
260     ngx_http_upstream_create_main_conf,    /* create main configuration */
261     ngx_http_upstream_init_main_conf,      /* init main configuration */
262
263     NULL,                                  /* create server configuration */
264     NULL,                                  /* merge server configuration */
265
266     NULL,                                  /* create location configuration */
267     NULL                                   /* merge location configuration */
268 };
269
270
271 ngx_module_t  ngx_http_upstream_module = {
272     NGX_MODULE_V1,
273     &ngx_http_upstream_module_ctx,         /* module context */
274     ngx_http_upstream_commands,            /* module directives */
275     NGX_HTTP_MODULE,                       /* module type */
276     NULL,                                  /* init master */
277     NULL,                                  /* init module */
278     NULL,                                  /* init process */
279     NULL,                                  /* init thread */
280     NULL,                                  /* exit thread */
281     NULL,                                  /* exit process */
282     NULL,                                  /* exit master */
283     NGX_MODULE_V1_PADDING
284 };
285
286
287 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
288
289     { ngx_string("upstream_addr"), NULL,
290       ngx_http_upstream_addr_variable, 0,
291       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
292
293     { ngx_string("upstream_status"), NULL,
294       ngx_http_upstream_status_variable, 0,
295       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
296
297     { ngx_string("upstream_response_time"), NULL,
298       ngx_http_upstream_response_time_variable, 0,
299       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
300
301     { ngx_string("upstream_response_length"), NULL,
302       ngx_http_upstream_response_length_variable, 0,
303       NGX_HTTP_VAR_NOHASH|NGX_HTTP_VAR_NOCACHEABLE, 0 },
304
305     { ngx_null_string, NULL, NULL, 0, 0, 0 }
306 };
307
308
309 static ngx_http_upstream_next_t  ngx_http_upstream_next_errors[] = {
310     { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
311     { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
312     { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
313     { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
314     { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
315     { 0, 0 }
316 };
317
318 void
319 ngx_http_upstream_init(ngx_http_request_t *r)
320 {
321     ngx_str_t                      *host;
322     ngx_uint_t                      i;
323     ngx_connection_t               *c;
324     ngx_resolver_ctx_t             *ctx, temp;
325     ngx_http_cleanup_t             *cln;
326     ngx_http_upstream_t            *u;
327     ngx_http_core_loc_conf_t       *clcf;
328     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
329     ngx_http_upstream_main_conf_t  *umcf;
330
331     c = r->connection;
332
333     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
334                    "http init upstream, client timer: %d", c->read->timer_set);
335
336     if (c->read->timer_set) {
337         ngx_del_timer(c->read);
338     }
339
340     u = r->upstream;
341
342     if (!r->post_action && !u->conf->ignore_client_abort) {
343         r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
344         r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
345     }
346
347     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
348
349         if (!c->write->active) {
350             if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
351                 == NGX_ERROR)
352             {
353                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
354                 return;
355             }
356         }
357     }
358
359     if (r->request_body) {
360         u->request_bufs = r->request_body->bufs;
361     }
362
363     if (u->create_request(r) != NGX_OK) {
364         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
365         return;
366     }
367
368     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
369
370     u->output.pool = r->pool;
371     u->output.bufs.num = 1;
372     u->output.bufs.size = clcf->client_body_buffer_size;
373     u->output.output_filter = ngx_chain_writer;
374     u->output.filter_ctx = &u->writer;
375
376     u->writer.pool = r->pool;
377
378     if (r->upstream_states == NULL) {
379
380         r->upstream_states = ngx_array_create(r->pool, 1,
381                                             sizeof(ngx_http_upstream_state_t));
382         if (r->upstream_states == NULL) {
383             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
384             return;
385         }
386
387     } else {
388
389         u->state = ngx_array_push(r->upstream_states);
390         if (u->state == NULL) {
391             ngx_http_upstream_finalize_request(r, u,
392                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
393             return;
394         }
395
396         ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
397     }
398
399     cln = ngx_http_cleanup_add(r, 0);
400     if (cln == NULL) {
401         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
402         return;
403     }
404
405     cln->handler = ngx_http_upstream_cleanup;
406     cln->data = r;
407     u->cleanup = &cln->handler;
408
409     u->store = (u->conf->store || u->conf->store_lengths);
410
411     if (u->resolved == NULL) {
412
413         uscf = u->conf->upstream;
414
415     } else {
416
417         if (u->resolved->sockaddr) {
418
419             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
420                 != NGX_OK)
421             {
422                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
423                 return;
424             }
425
426             ngx_http_upstream_connect(r, u);
427
428             return;
429         }
430
431         host = &u->resolved->host;
432
433         umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
434
435         uscfp = umcf->upstreams.elts;
436
437         for (i = 0; i < umcf->upstreams.nelts; i++) {
438
439             uscf = uscfp[i];
440
441             if (uscf->host.len == host->len
442                 && ((uscf->port == 0 && u->resolved->no_port)
443                      || uscf->port == u->resolved->port)
444                 && ngx_memcmp(uscf->host.data, host->data, host->len) == 0)
445             {
446                 goto found;
447             }
448         }
449
450         temp.name = *host;
451
452         ctx = ngx_resolve_start(clcf->resolver, &temp);
453         if (ctx == NULL) {
454             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
455             return;
456         }
457
458         if (ctx == NGX_NO_RESOLVER) {
459             ngx_log_error(NGX_LOG_ERR, c->log, 0,
460                           "no resolver defined to resolve %V", host);
461
462             ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
463             return;
464         }
465
466         ctx->name = *host;
467         ctx->type = NGX_RESOLVE_A;
468         ctx->handler = ngx_http_upstream_resolve_handler;
469         ctx->data = r;
470         ctx->timeout = clcf->resolver_timeout;
471
472         u->resolved->ctx = ctx;
473
474         if (ngx_resolve_name(ctx) != NGX_OK) {
475             u->resolved->ctx = NULL;
476             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
477             return;
478         }
479
480         return;
481     }
482
483 found:
484
485     if (uscf->peer.init(r, uscf) != NGX_OK) {
486         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
487         return;
488     }
489
490     ngx_http_upstream_connect(r, u);
491 }
492
493
494 static void
495 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
496 {
497     ngx_http_request_t            *r;
498     ngx_http_upstream_resolved_t  *ur;
499
500     r = ctx->data;
501
502     r->upstream->resolved->ctx = NULL;
503
504     if (ctx->state) {
505         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
506                       "%V could not be resolved (%i: %s)",
507                       &ctx->name, ctx->state,
508                       ngx_resolver_strerror(ctx->state));
509
510         ngx_resolve_name_done(ctx);
511         ngx_http_finalize_request(r, NGX_HTTP_BAD_GATEWAY);
512         return;
513     }
514
515     ur = r->upstream->resolved;
516     ur->naddrs = ctx->naddrs;
517     ur->addrs = ctx->addrs;
518
519 #if (NGX_DEBUG)
520     {
521     in_addr_t   addr;
522     ngx_uint_t  i;
523
524     for (i = 0; i < ctx->naddrs; i++) {
525         addr = ntohl(ur->addrs[i]);
526
527         ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
528                        "name was resolved to %ud.%ud.%ud.%ud",
529                        (addr >> 24) & 0xff, (addr >> 16) & 0xff,
530                        (addr >> 8) & 0xff, addr & 0xff);
531     }
532     }
533 #endif
534
535     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
536         ngx_resolve_name_done(ctx);
537         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
538         return;
539     }
540
541     ngx_resolve_name_done(ctx);
542
543     ngx_http_upstream_connect(r, r->upstream);
544 }
545
546
547 static void
548 ngx_http_upstream_handler(ngx_event_t *ev)
549 {
550     ngx_connection_t     *c;
551     ngx_http_request_t   *r;
552     ngx_http_log_ctx_t   *ctx;
553     ngx_http_upstream_t  *u;
554
555     c = ev->data;
556     r = c->data;
557
558     u = r->upstream;
559     c = r->connection;
560
561     ctx = c->log->data;
562     ctx->current_request = r;
563
564     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
565                    "http upstream request: \"%V?%V\"", &r->uri, &r->args);
566
567     if (ev->write) {
568         u->write_event_handler(r, u);
569
570     } else {
571         u->read_event_handler(r, u);
572     }
573
574     ngx_http_run_posted_requests(c);
575 }
576
577
578 static void
579 ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
580 {
581     ngx_http_upstream_check_broken_connection(r, r->connection->read);
582 }
583
584
585 static void
586 ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
587 {
588     ngx_http_upstream_check_broken_connection(r, r->connection->write);
589 }
590
591
592 static void
593 ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
594     ngx_event_t *ev)
595 {
596     int                  n;
597     char                 buf[1];
598     ngx_err_t            err;
599     ngx_connection_t     *c;
600     ngx_http_upstream_t  *u;
601
602     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
603                    "http upstream check client, write event:%d, \"%V\"",
604                    ev->write, &r->uri);
605
606     c = r->connection;
607     u = r->upstream;
608
609     if (c->error) {
610         ngx_http_upstream_finalize_request(r, u,
611                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
612         return;
613     }
614
615     if (u->peer.connection == NULL) {
616         return;
617     }
618
619 #if (NGX_HAVE_KQUEUE)
620
621     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
622
623         if (!ev->pending_eof) {
624             return;
625         }
626
627         ev->eof = 1;
628         c->error = 1;
629
630         if (ev->kq_errno) {
631             ev->error = 1;
632         }
633
634         if (!u->cacheable && !u->store && u->peer.connection) {
635             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
636                           "kevent() reported that client closed prematurely "
637                           "connection, so upstream connection is closed too");
638             ngx_http_upstream_finalize_request(r, u,
639                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
640             return;
641         }
642
643         ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
644                       "kevent() reported that client closed "
645                       "prematurely connection");
646
647         if (u->peer.connection == NULL) {
648             ngx_http_upstream_finalize_request(r, u,
649                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
650             return;
651         }
652
653         return;
654     }
655
656 #endif
657
658     n = recv(c->fd, buf, 1, MSG_PEEK);
659
660     err = ngx_socket_errno;
661
662     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
663                    "http upstream recv(): %d", n);
664
665     /*
666      * we do not need to disable the write event because
667      * that event has NGX_USE_CLEAR_EVENT type
668      */
669
670     if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
671         return;
672     }
673
674     if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
675         if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
676             ngx_http_upstream_finalize_request(r, u,
677                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
678             return;
679         }
680     }
681
682     if (n > 0) {
683         return;
684     }
685
686     if (n == -1) {
687         if (err == NGX_EAGAIN) {
688             return;
689         }
690
691         ev->error = 1;
692
693     } else { /* n == 0 */
694         err = 0;
695     }
696
697     ev->eof = 1;
698     c->error = 1;
699
700     if (!u->cacheable && !u->store && u->peer.connection) {
701         ngx_log_error(NGX_LOG_INFO, ev->log, err,
702                       "client closed prematurely connection, "
703                       "so upstream connection is closed too");
704         ngx_http_upstream_finalize_request(r, u,
705                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
706         return;
707     }
708
709     ngx_log_error(NGX_LOG_INFO, ev->log, err,
710                   "client closed prematurely connection");
711
712     if (u->peer.connection == NULL) {
713         ngx_http_upstream_finalize_request(r, u,
714                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
715         return;
716     }
717 }
718
719
720 static void
721 ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
722 {
723     ngx_int_t          rc;
724     ngx_time_t        *tp;
725     ngx_connection_t  *c;
726
727     r->connection->log->action = "connecting to upstream";
728
729     r->connection->single_connection = 0;
730
731     if (u->state && u->state->response_sec) {
732         tp = ngx_timeofday();
733         u->state->response_sec = tp->sec - u->state->response_sec;
734         u->state->response_msec = tp->msec - u->state->response_msec;
735     }
736
737     u->state = ngx_array_push(r->upstream_states);
738     if (u->state == NULL) {
739         ngx_http_upstream_finalize_request(r, u,
740                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
741         return;
742     }
743
744     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
745
746     tp = ngx_timeofday();
747     u->state->response_sec = tp->sec;
748     u->state->response_msec = tp->msec;
749
750     rc = ngx_event_connect_peer(&u->peer);
751
752     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
753                    "http upstream connect: %i", rc);
754
755     if (rc == NGX_ERROR) {
756         ngx_http_upstream_finalize_request(r, u,
757                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
758         return;
759     }
760
761     u->state->peer = u->peer.name;
762
763     if (rc == NGX_BUSY) {
764         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
765         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
766         return;
767     }
768
769     if (rc == NGX_DECLINED) {
770         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
771         return;
772     }
773
774     /* rc == NGX_OK || rc == NGX_AGAIN */
775
776     c = u->peer.connection;
777
778     c->data = r;
779
780     c->write->handler = ngx_http_upstream_handler;
781     c->read->handler = ngx_http_upstream_handler;
782
783     u->write_event_handler = ngx_http_upstream_send_request_handler;
784     u->read_event_handler = ngx_http_upstream_process_header;
785
786     c->sendfile &= r->connection->sendfile;
787     u->output.sendfile = c->sendfile;
788
789     c->pool = r->pool;
790     c->read->log = c->write->log = c->log = r->connection->log;
791
792     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
793
794     u->writer.out = NULL;
795     u->writer.last = &u->writer.out;
796     u->writer.connection = c;
797     u->writer.limit = 0;
798
799     if (u->request_sent) {
800         if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
801             ngx_http_upstream_finalize_request(r, u,
802                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
803             return;
804         }
805     }
806
807     if (r->request_body
808         && r->request_body->buf
809         && r->request_body->temp_file
810         && r == r->main)
811     {
812         /*
813          * the r->request_body->buf can be reused for one request only,
814          * the subrequests should allocate their own temporay bufs
815          */
816
817         u->output.free = ngx_alloc_chain_link(r->pool);
818         if (u->output.free == NULL) {
819             ngx_http_upstream_finalize_request(r, u,
820                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
821             return;
822         }
823
824         u->output.free->buf = r->request_body->buf;
825         u->output.free->next = NULL;
826         u->output.allocated = 1;
827
828         r->request_body->buf->pos = r->request_body->buf->start;
829         r->request_body->buf->last = r->request_body->buf->start;
830         r->request_body->buf->tag = u->output.tag;
831     }
832
833     u->request_sent = 0;
834
835     if (rc == NGX_AGAIN) {
836         ngx_add_timer(c->write, u->conf->connect_timeout);
837         return;
838     }
839
840 #if (NGX_HTTP_SSL)
841
842     if (u->ssl && c->ssl == NULL) {
843         ngx_http_upstream_ssl_init_connection(r, u, c);
844         return;
845     }
846
847 #endif
848
849     ngx_http_upstream_send_request(r, u);
850 }
851
852
853 #if (NGX_HTTP_SSL)
854
855 static void
856 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
857     ngx_http_upstream_t *u, ngx_connection_t *c)
858 {
859     ngx_int_t   rc;
860
861     if (ngx_ssl_create_connection(u->conf->ssl, c,
862                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
863         != NGX_OK)
864     {
865         ngx_http_upstream_finalize_request(r, u,
866                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
867         return;
868     }
869
870     c->sendfile = 0;
871     u->output.sendfile = 0;
872
873     if (u->conf->ssl_session_reuse) {
874         if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
875             ngx_http_upstream_finalize_request(r, u,
876                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
877             return;
878         }
879     }
880
881     r->connection->log->action = "SSL handshaking to upstream";
882
883     rc = ngx_ssl_handshake(c);
884
885     if (rc == NGX_AGAIN) {
886         c->ssl->handler = ngx_http_upstream_ssl_handshake;
887         return;
888     }
889
890     ngx_http_upstream_ssl_handshake(c);
891 }
892
893
894 static void
895 ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
896 {
897     ngx_http_request_t   *r;
898     ngx_http_upstream_t  *u;
899
900     r = c->data;
901     u = r->upstream;
902
903     if (c->ssl->handshaked) {
904
905         if (u->conf->ssl_session_reuse) {
906             u->peer.save_session(&u->peer, u->peer.data);
907         }
908
909         c->write->handler = ngx_http_upstream_handler;
910         c->read->handler = ngx_http_upstream_handler;
911
912         ngx_http_upstream_send_request(r, u);
913
914         return;
915     }
916
917     ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
918
919 }
920
921 #endif
922
923
924 static ngx_int_t
925 ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
926 {
927     ngx_chain_t  *cl;
928
929     if (u->reinit_request(r) != NGX_OK) {
930         return NGX_ERROR;
931     }
932
933     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
934
935     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
936                       sizeof(ngx_table_elt_t))
937         != NGX_OK)
938     {
939         return NGX_ERROR;
940     }
941
942     /* reinit the request chain */
943
944     for (cl = u->request_bufs; cl; cl = cl->next) {
945         cl->buf->pos = cl->buf->start;
946         cl->buf->file_pos = 0;
947     }
948
949     /* reinit the subrequest's ngx_output_chain() context */
950
951     if (r->request_body && r->request_body->temp_file
952         && r != r->main && u->output.buf)
953     {
954         u->output.free = ngx_alloc_chain_link(r->pool);
955         if (u->output.free == NULL) {
956             return NGX_ERROR;
957         }
958
959         u->output.free->buf = u->output.buf;
960         u->output.free->next = NULL;
961
962         u->output.buf->pos = u->output.buf->start;
963         u->output.buf->last = u->output.buf->start;
964     }
965
966     u->output.buf = NULL;
967     u->output.in = NULL;
968     u->output.busy = NULL;
969
970     /* reinit u->buffer */
971
972 #if 0
973     if (u->cache) {
974         u->buffer.pos = u->buffer.start + u->cache->ctx.header_size;
975         u->buffer.last = u->buffer.pos;
976
977     } else {
978         u->buffer.pos = u->buffer.start;
979         u->buffer.last = u->buffer.start;
980     }
981 #else
982
983         u->buffer.pos = u->buffer.start;
984         u->buffer.last = u->buffer.start;
985
986 #endif
987
988     return NGX_OK;
989 }
990
991
992 static void
993 ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
994 {
995     ngx_int_t          rc;
996     ngx_connection_t  *c;
997
998     c = u->peer.connection;
999
1000     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1001                    "http upstream send request");
1002
1003     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1004         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1005         return;
1006     }
1007
1008     c->log->action = "sending request to upstream";
1009
1010     rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
1011
1012     u->request_sent = 1;
1013
1014     if (rc == NGX_ERROR) {
1015         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1016         return;
1017     }
1018
1019     if (c->write->timer_set) {
1020         ngx_del_timer(c->write);
1021     }
1022
1023     if (rc == NGX_AGAIN) {
1024         ngx_add_timer(c->write, u->conf->send_timeout);
1025
1026         if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
1027             ngx_http_upstream_finalize_request(r, u,
1028                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1029             return;
1030         }
1031
1032         return;
1033     }
1034
1035     /* rc == NGX_OK */
1036
1037     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
1038         if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1039             ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1040                           ngx_tcp_push_n " failed");
1041             ngx_http_upstream_finalize_request(r, u,
1042                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1043             return;
1044         }
1045
1046         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
1047     }
1048
1049     ngx_add_timer(c->read, u->conf->read_timeout);
1050
1051 #if 1
1052     if (c->read->ready) {
1053
1054         /* post aio operation */
1055
1056         /*
1057          * TODO comment
1058          * although we can post aio operation just in the end
1059          * of ngx_http_upstream_connect() CHECK IT !!!
1060          * it's better to do here because we postpone header buffer allocation
1061          */
1062
1063         ngx_http_upstream_process_header(r, u);
1064         return;
1065     }
1066 #endif
1067
1068     u->write_event_handler = ngx_http_upstream_dummy_handler;
1069
1070     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1071         ngx_http_upstream_finalize_request(r, u,
1072                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1073         return;
1074     }
1075 }
1076
1077
1078 static void
1079 ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
1080     ngx_http_upstream_t *u)
1081 {
1082     ngx_connection_t  *c;
1083
1084     c = u->peer.connection;
1085
1086     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1087                    "http upstream send request handler");
1088
1089     if (c->write->timedout) {
1090         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1091         return;
1092     }
1093
1094 #if (NGX_HTTP_SSL)
1095
1096     if (u->ssl && c->ssl == NULL) {
1097         ngx_http_upstream_ssl_init_connection(r, u, c);
1098         return;
1099     }
1100
1101 #endif
1102
1103     if (u->header_sent) {
1104         u->write_event_handler = ngx_http_upstream_dummy_handler;
1105
1106         (void) ngx_handle_write_event(c->write, 0);
1107
1108         return;
1109     }
1110
1111     ngx_http_upstream_send_request(r, u);
1112 }
1113
1114
1115 static void
1116 ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
1117 {
1118     ssize_t                         n;
1119     ngx_int_t                       rc;
1120     ngx_str_t                      *uri, args;
1121     ngx_uint_t                      i, flags;
1122     ngx_list_part_t                *part;
1123     ngx_table_elt_t                *h;
1124     ngx_connection_t               *c;
1125     ngx_http_upstream_header_t     *hh;
1126     ngx_http_upstream_main_conf_t  *umcf;
1127
1128     c = u->peer.connection;
1129
1130     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1131                    "http upstream process header");
1132
1133     c->log->action = "reading response header from upstream";
1134
1135     if (c->read->timedout) {
1136         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1137         return;
1138     }
1139
1140     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1141         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1142         return;
1143     }
1144
1145     if (u->buffer.start == NULL) {
1146         u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
1147         if (u->buffer.start == NULL) {
1148             ngx_http_upstream_finalize_request(r, u,
1149                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1150             return;
1151         }
1152
1153         u->buffer.pos = u->buffer.start;
1154         u->buffer.last = u->buffer.start;
1155         u->buffer.end = u->buffer.start + u->conf->buffer_size;
1156         u->buffer.temporary = 1;
1157
1158         u->buffer.tag = u->output.tag;
1159
1160         if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1161                           sizeof(ngx_table_elt_t))
1162             != NGX_OK)
1163         {
1164             ngx_http_upstream_finalize_request(r, u,
1165                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1166             return;
1167         }
1168
1169 #if 0
1170         if (u->cache) {
1171             u->buffer.pos += u->cache->ctx.header_size;
1172             u->buffer.last = u->buffer.pos;
1173         }
1174 #endif
1175     }
1176
1177     for ( ;; ) {
1178
1179         n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
1180
1181         if (n == NGX_AGAIN) {
1182 #if 0
1183             ngx_add_timer(rev, u->read_timeout);
1184 #endif
1185
1186             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1187                 ngx_http_upstream_finalize_request(r, u,
1188                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1189                 return;
1190             }
1191
1192             return;
1193         }
1194
1195         if (n == 0) {
1196             ngx_log_error(NGX_LOG_ERR, c->log, 0,
1197                           "upstream prematurely closed connection");
1198         }
1199
1200         if (n == NGX_ERROR || n == 0) {
1201             ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1202             return;
1203         }
1204
1205         u->buffer.last += n;
1206
1207 #if 0
1208         u->valid_header_in = 0;
1209
1210         u->peer.cached = 0;
1211 #endif
1212
1213         rc = u->process_header(r);
1214
1215         if (rc == NGX_AGAIN) {
1216
1217             if (u->buffer.pos == u->buffer.end) {
1218                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1219                               "upstream sent too big header");
1220
1221                 ngx_http_upstream_next(r, u,
1222                                        NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1223                 return;
1224             }
1225
1226             continue;
1227         }
1228
1229         break;
1230     }
1231
1232     if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
1233         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1234         return;
1235     }
1236
1237     if (rc == NGX_ERROR) {
1238         ngx_http_upstream_finalize_request(r, u,
1239                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1240         return;
1241     }
1242
1243     /* rc == NGX_OK */
1244
1245     if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) {
1246
1247         if (r->subrequest_in_memory) {
1248             u->buffer.last = u->buffer.pos;
1249         }
1250
1251         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
1252             return;
1253         }
1254
1255         if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
1256             return;
1257         }
1258     }
1259
1260     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1261
1262     if (u->headers_in.x_accel_redirect) {
1263
1264         ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
1265
1266         part = &u->headers_in.headers.part;
1267         h = part->elts;
1268
1269         for (i = 0; /* void */; i++) {
1270
1271             if (i >= part->nelts) {
1272                 if (part->next == NULL) {
1273                     break;
1274                 }
1275
1276                 part = part->next;
1277                 h = part->elts;
1278                 i = 0;
1279             }
1280
1281             hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1282                                h[i].lowcase_key, h[i].key.len);
1283
1284             if (hh && hh->redirect) {
1285                 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1286                     ngx_http_finalize_request(r,
1287                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1288                     return;
1289                 }
1290             }
1291         }
1292
1293         uri = &u->headers_in.x_accel_redirect->value;
1294         args.len = 0;
1295         args.data = NULL;
1296         flags = 0;
1297
1298         if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
1299             ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
1300             return;
1301         }
1302
1303         if (flags & NGX_HTTP_ZERO_IN_URI) {
1304             r->zero_in_uri = 1;
1305         }
1306
1307         if (r->method != NGX_HTTP_HEAD) {
1308             r->method = NGX_HTTP_GET;
1309         }
1310
1311         r->valid_unparsed_uri = 0;
1312
1313         ngx_http_internal_redirect(r, uri, &args);
1314         return;
1315     }
1316
1317     part = &u->headers_in.headers.part;
1318     h = part->elts;
1319
1320     for (i = 0; /* void */; i++) {
1321
1322         if (i >= part->nelts) {
1323             if (part->next == NULL) {
1324                 break;
1325             }
1326
1327             part = part->next;
1328             h = part->elts;
1329             i = 0;
1330         }
1331
1332         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
1333                           h[i].lowcase_key, h[i].key.len))
1334         {
1335             continue;
1336         }
1337
1338         hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
1339                            h[i].lowcase_key, h[i].key.len);
1340
1341         if (hh) {
1342             if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
1343                 ngx_http_upstream_finalize_request(r, u,
1344                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1345                 return;
1346             }
1347
1348             continue;
1349         }
1350
1351         if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
1352             ngx_http_upstream_finalize_request(r, u,
1353                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1354             return;
1355         }
1356     }
1357
1358     if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
1359         r->headers_out.server->hash = 0;
1360     }
1361
1362     if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
1363         r->headers_out.date->hash = 0;
1364     }
1365
1366     r->headers_out.status = u->headers_in.status_n;
1367     r->headers_out.status_line = u->headers_in.status_line;
1368
1369     u->headers_in.content_length_n = r->headers_out.content_length_n;
1370
1371     if (r->headers_out.content_length_n != -1) {
1372         u->length = (size_t) r->headers_out.content_length_n;
1373
1374     } else {
1375         u->length = NGX_MAX_SIZE_T_VALUE;
1376     }
1377
1378     if (!r->subrequest_in_memory) {
1379         ngx_http_upstream_send_response(r, u);
1380         return;
1381     }
1382
1383     /* subrequest content in memory */
1384
1385     if (u->input_filter == NULL) {
1386         u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1387         u->input_filter = ngx_http_upstream_non_buffered_filter;
1388         u->input_filter_ctx = r;
1389     }
1390
1391     if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1392         ngx_http_upstream_finalize_request(r, u,
1393                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1394         return;
1395     }
1396
1397     n = u->buffer.last - u->buffer.pos;
1398
1399     if (n) {
1400         u->buffer.last -= n;
1401
1402         u->state->response_length += n;
1403
1404         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1405             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1406             return;
1407         }
1408
1409         if (u->length == 0) {
1410             ngx_http_upstream_finalize_request(r, u, 0);
1411             return;
1412         }
1413     }
1414
1415     u->read_event_handler = ngx_http_upstream_process_body_in_memory;
1416
1417     ngx_http_upstream_process_body_in_memory(r, u);
1418 }
1419
1420
1421 static ngx_int_t
1422 ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
1423 {
1424     ngx_uint_t                 status;
1425     ngx_http_upstream_next_t  *un;
1426
1427     if (!(u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_STATUS)) {
1428         return NGX_DECLINED;
1429     }
1430
1431     status = u->headers_in.status_n;
1432
1433     for (un = ngx_http_upstream_next_errors; un->status; un++) {
1434
1435         if (status != un->status) {
1436             continue;
1437         }
1438
1439         if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
1440             ngx_http_upstream_next(r, u, un->mask);
1441             return NGX_OK;
1442         }
1443
1444 #if (NGX_HTTP_CACHE)
1445
1446         if (u->peer.tries == 0 && u->stale && (u->conf->use_stale & un->mask)) {
1447             ngx_http_upstream_finalize_request(r, u,
1448                                               ngx_http_send_cached_response(r));
1449             return NGX_OK;
1450         }
1451
1452 #endif
1453     }
1454
1455     return NGX_DECLINED;
1456 }
1457
1458
1459 static ngx_int_t
1460 ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
1461     ngx_http_upstream_t *u)
1462 {
1463     ngx_int_t                  status;
1464     ngx_uint_t                 i;
1465     ngx_table_elt_t           *h;
1466     ngx_http_err_page_t       *err_page;
1467     ngx_http_core_loc_conf_t  *clcf;
1468
1469     status = u->headers_in.status_n;
1470
1471     if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
1472         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
1473         return NGX_OK;
1474     }
1475
1476     if (!u->conf->intercept_errors) {
1477         return NGX_DECLINED;
1478     }
1479
1480     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1481
1482     if (clcf->error_pages == NULL) {
1483         return NGX_DECLINED;
1484     }
1485
1486     err_page = clcf->error_pages->elts;
1487     for (i = 0; i < clcf->error_pages->nelts; i++) {
1488
1489         if (err_page[i].status == status) {
1490
1491             if (status == NGX_HTTP_UNAUTHORIZED) {
1492
1493                 h = ngx_list_push(&r->headers_out.headers);
1494
1495                 if (h == NULL) {
1496                     ngx_http_upstream_finalize_request(r, u,
1497                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1498                     return NGX_OK;
1499                 }
1500
1501                 *h = *u->headers_in.www_authenticate;
1502
1503                 r->headers_out.www_authenticate = h;
1504             }
1505
1506             ngx_http_upstream_finalize_request(r, u, status);
1507
1508             return NGX_OK;
1509         }
1510     }
1511
1512     return NGX_DECLINED;
1513 }
1514
1515
1516 static ngx_int_t
1517 ngx_http_upstream_test_connect(ngx_connection_t *c)
1518 {
1519     int        err;
1520     socklen_t  len;
1521
1522 #if (NGX_HAVE_KQUEUE)
1523
1524     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
1525         if (c->write->pending_eof) {
1526             c->log->action = "connecting to upstream";
1527             (void) ngx_connection_error(c, c->write->kq_errno,
1528                                     "kevent() reported that connect() failed");
1529             return NGX_ERROR;
1530         }
1531
1532     } else
1533 #endif
1534     {
1535         err = 0;
1536         len = sizeof(int);
1537
1538         /*
1539          * BSDs and Linux return 0 and set a pending error in err
1540          * Solaris returns -1 and sets errno
1541          */
1542
1543         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1544             == -1)
1545         {
1546             err = ngx_errno;
1547         }
1548
1549         if (err) {
1550             c->log->action = "connecting to upstream";
1551             (void) ngx_connection_error(c, err, "connect() failed");
1552             return NGX_ERROR;
1553         }
1554     }
1555
1556     return NGX_OK;
1557 }
1558
1559
1560 static void
1561 ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
1562     ngx_http_upstream_t *u)
1563 {
1564     size_t             size;
1565     ssize_t            n;
1566     ngx_buf_t         *b;
1567     ngx_event_t       *rev;
1568     ngx_connection_t  *c;
1569
1570     c = u->peer.connection;
1571     rev = c->read;
1572
1573     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1574                    "http upstream process body on memory");
1575
1576     if (rev->timedout) {
1577         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
1578         ngx_http_upstream_finalize_request(r, u, NGX_ETIMEDOUT);
1579         return;
1580     }
1581
1582     b = &u->buffer;
1583
1584     for ( ;; ) {
1585
1586         size = b->end - b->last;
1587
1588         if (size == 0) {
1589             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
1590                           "upstream buffer is too small to read repsonse");
1591             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1592             return;
1593         }
1594
1595         n = c->recv(c, b->last, size);
1596
1597         if (n == NGX_AGAIN) {
1598             break;
1599         }
1600
1601         if (n == 0 || n == NGX_ERROR) {
1602             ngx_http_upstream_finalize_request(r, u, n);
1603             return;
1604         }
1605
1606         u->state->response_length += n;
1607
1608         if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1609             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1610             return;
1611         }
1612
1613         if (!rev->ready) {
1614             break;
1615         }
1616     }
1617
1618     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1619         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1620         return;
1621     }
1622
1623     if (rev->active) {
1624         ngx_add_timer(rev, u->conf->read_timeout);
1625
1626     } else if (rev->timer_set) {
1627         ngx_del_timer(rev);
1628     }
1629 }
1630
1631
1632 static void
1633 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
1634 {
1635     int                        tcp_nodelay;
1636     ssize_t                    n;
1637     ngx_int_t                  rc;
1638     ngx_event_pipe_t          *p;
1639     ngx_connection_t          *c;
1640     ngx_pool_cleanup_t        *cl;
1641     ngx_pool_cleanup_file_t   *clf;
1642     ngx_http_core_loc_conf_t  *clcf;
1643
1644     rc = ngx_http_send_header(r);
1645
1646     if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) {
1647         ngx_http_upstream_finalize_request(r, u, rc);
1648         return;
1649     }
1650
1651     u->header_sent = 1;
1652
1653     if (r->request_body && r->request_body->temp_file) {
1654         for (cl = r->pool->cleanup; cl; cl = cl->next) {
1655             if (cl->handler == ngx_pool_cleanup_file) {
1656                 clf = cl->data;
1657
1658                 if (clf->fd == r->request_body->temp_file->file.fd) {
1659                     cl->handler(clf);
1660                     cl->handler = NULL;
1661                     r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
1662                     break;
1663                 }
1664             }
1665         }
1666     }
1667
1668     c = r->connection;
1669
1670     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1671
1672     if (!u->buffering) {
1673
1674         if (u->input_filter == NULL) {
1675             u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1676             u->input_filter = ngx_http_upstream_non_buffered_filter;
1677             u->input_filter_ctx = r;
1678         }
1679
1680         u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
1681         r->write_event_handler =
1682                              ngx_http_upstream_process_non_buffered_downstream;
1683
1684         r->limit_rate = 0;
1685
1686         if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1687             ngx_http_upstream_finalize_request(r, u, 0);
1688             return;
1689         }
1690
1691         if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
1692             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
1693
1694             tcp_nodelay = 1;
1695
1696             if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
1697                                (const void *) &tcp_nodelay, sizeof(int)) == -1)
1698             {
1699                 ngx_connection_error(c, ngx_socket_errno,
1700                                      "setsockopt(TCP_NODELAY) failed");
1701                 ngx_http_upstream_finalize_request(r, u, 0);
1702                 return;
1703             }
1704
1705             c->tcp_nodelay = NGX_TCP_NODELAY_SET;
1706         }
1707
1708         n = u->buffer.last - u->buffer.pos;
1709
1710         if (n) {
1711             u->buffer.last = u->buffer.pos;
1712
1713             u->state->response_length += n;
1714
1715             if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1716                 ngx_http_upstream_finalize_request(r, u, 0);
1717                 return;
1718             }
1719
1720             ngx_http_upstream_process_non_buffered_downstream(r);
1721
1722         } else {
1723             u->buffer.pos = u->buffer.start;
1724             u->buffer.last = u->buffer.start;
1725
1726             if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
1727                 ngx_http_upstream_finalize_request(r, u, 0);
1728                 return;
1729             }
1730
1731             if (u->peer.connection->read->ready) {
1732                 ngx_http_upstream_process_non_buffered_upstream(r, u);
1733             }
1734         }
1735
1736         return;
1737     }
1738
1739     /* TODO: preallocate event_pipe bufs, look "Content-Length" */
1740
1741 #if 0
1742
1743     if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
1744         if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
1745             ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
1746                           ngx_close_file_n " \"%s\" failed",
1747                           u->cache->ctx.file.name.data);
1748         }
1749     }
1750
1751     if (u->cacheable) {
1752         header = (ngx_http_cache_header_t *) u->buffer->start;
1753
1754         header->expires = u->cache->ctx.expires;
1755         header->last_modified = u->cache->ctx.last_modified;
1756         header->date = u->cache->ctx.date;
1757         header->length = r->headers_out.content_length_n;
1758         u->cache->ctx.length = r->headers_out.content_length_n;
1759
1760         header->key_len = u->cache->ctx.key0.len;
1761         ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len);
1762         header->key[header->key_len] = LF;
1763     }
1764
1765 #endif
1766
1767     p = u->pipe;
1768
1769     p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
1770     p->output_ctx = r;
1771     p->tag = u->output.tag;
1772     p->bufs = u->conf->bufs;
1773     p->busy_size = u->conf->busy_buffers_size;
1774     p->upstream = u->peer.connection;
1775     p->downstream = c;
1776     p->pool = r->pool;
1777     p->log = c->log;
1778
1779     p->cacheable = u->cacheable || u->store;
1780
1781     p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
1782     if (p->temp_file == NULL) {
1783         ngx_http_upstream_finalize_request(r, u, 0);
1784         return;
1785     }
1786
1787     p->temp_file->file.fd = NGX_INVALID_FILE;
1788     p->temp_file->file.log = c->log;
1789     p->temp_file->path = u->conf->temp_path;
1790     p->temp_file->pool = r->pool;
1791
1792     if (u->cacheable || u->store) {
1793         p->temp_file->persistent = 1;
1794
1795     } else {
1796         p->temp_file->log_level = NGX_LOG_WARN;
1797         p->temp_file->warn = "an upstream response is buffered "
1798                              "to a temporary file";
1799     }
1800
1801     p->max_temp_file_size = u->conf->max_temp_file_size;
1802     p->temp_file_write_size = u->conf->temp_file_write_size;
1803
1804     p->preread_bufs = ngx_alloc_chain_link(r->pool);
1805     if (p->preread_bufs == NULL) {
1806         ngx_http_upstream_finalize_request(r, u, 0);
1807         return;
1808     }
1809
1810     p->preread_bufs->buf = &u->buffer;
1811     p->preread_bufs->next = NULL;
1812     u->buffer.recycled = 1;
1813
1814     p->preread_size = u->buffer.last - u->buffer.pos;
1815
1816     if (u->cacheable) {
1817
1818         p->buf_to_file = ngx_calloc_buf(r->pool);
1819         if (p->buf_to_file == NULL) {
1820             ngx_http_upstream_finalize_request(r, u, 0);
1821             return;
1822         }
1823
1824         p->buf_to_file->pos = u->buffer.start;
1825         p->buf_to_file->last = u->buffer.pos;
1826         p->buf_to_file->temporary = 1;
1827     }
1828
1829     if (ngx_event_flags & NGX_USE_AIO_EVENT) {
1830         /* the posted aio operation may currupt a shadow buffer */
1831         p->single_buf = 1;
1832     }
1833
1834     /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
1835     p->free_bufs = 1;
1836
1837     /*
1838      * event_pipe would do u->buffer.last += p->preread_size
1839      * as though these bytes were read
1840      */
1841     u->buffer.last = u->buffer.pos;
1842
1843     if (u->conf->cyclic_temp_file) {
1844
1845         /*
1846          * we need to disable the use of sendfile() if we use cyclic temp file
1847          * because the writing a new data may interfere with sendfile()
1848          * that uses the same kernel file pages (at least on FreeBSD)
1849          */
1850
1851         p->cyclic_temp_file = 1;
1852         c->sendfile = 0;
1853
1854     } else {
1855         p->cyclic_temp_file = 0;
1856     }
1857
1858     p->read_timeout = u->conf->read_timeout;
1859     p->send_timeout = clcf->send_timeout;
1860     p->send_lowat = clcf->send_lowat;
1861
1862     u->read_event_handler = ngx_http_upstream_process_upstream;
1863     r->write_event_handler = ngx_http_upstream_process_downstream;
1864
1865     ngx_http_upstream_process_upstream(r, u);
1866 }
1867
1868
1869 static void
1870 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
1871 {
1872     ngx_event_t          *wev;
1873     ngx_connection_t     *c;
1874     ngx_http_upstream_t  *u;
1875
1876     c = r->connection;
1877     u = r->upstream;
1878     wev = c->write;
1879
1880     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1881                    "http upstream process non buffered downstream");
1882
1883     c->log->action = "sending to client";
1884
1885     if (wev->timedout) {
1886         c->timedout = 1;
1887         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
1888         ngx_http_upstream_finalize_request(r, u, 0);
1889         return;
1890     }
1891
1892     ngx_http_upstream_process_non_buffered_request(r, 1);
1893 }
1894
1895
1896 static void
1897 ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
1898     ngx_http_upstream_t *u)
1899 {
1900     ngx_connection_t  *c;
1901
1902     c = u->peer.connection;
1903
1904     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1905                    "http upstream process non buffered upstream");
1906
1907     c->log->action = "reading upstream";
1908
1909     if (c->read->timedout) {
1910         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
1911         ngx_http_upstream_finalize_request(r, u, 0);
1912         return;
1913     }
1914
1915     ngx_http_upstream_process_non_buffered_request(r, 0);
1916 }
1917
1918
1919 static void
1920 ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
1921     ngx_uint_t do_write)
1922 {
1923     size_t                     size;
1924     ssize_t                    n;
1925     ngx_buf_t                 *b;
1926     ngx_int_t                  rc;
1927     ngx_connection_t          *downstream, *upstream;
1928     ngx_http_upstream_t       *u;
1929     ngx_http_core_loc_conf_t  *clcf;
1930
1931     u = r->upstream;
1932     downstream = r->connection;
1933     upstream = u->peer.connection;
1934
1935     b = &u->buffer;
1936
1937     do_write = do_write || u->length == 0;
1938
1939     for ( ;; ) {
1940
1941         if (do_write) {
1942
1943             if (u->out_bufs || u->busy_bufs) {
1944                 rc = ngx_http_output_filter(r, u->out_bufs);
1945
1946                 if (downstream->destroyed) {
1947                     return;
1948                 }
1949
1950                 if (rc == NGX_ERROR) {
1951                     ngx_http_upstream_finalize_request(r, u, 0);
1952                     return;
1953                 }
1954
1955                 ngx_chain_update_chains(&u->free_bufs, &u->busy_bufs,
1956                                         &u->out_bufs, u->output.tag);
1957             }
1958
1959             if (u->busy_bufs == NULL) {
1960
1961                 if (u->length == 0
1962                     || upstream->read->eof
1963                     || upstream->read->error)
1964                 {
1965                     ngx_http_upstream_finalize_request(r, u, 0);
1966                     return;
1967                 }
1968
1969                 b->pos = b->start;
1970                 b->last = b->start;
1971             }
1972         }
1973
1974         size = b->end - b->last;
1975
1976         if (size > u->length) {
1977             size = u->length;
1978         }
1979
1980         if (size && upstream->read->ready) {
1981
1982             n = upstream->recv(upstream, b->last, size);
1983
1984             if (n == NGX_AGAIN) {
1985                 break;
1986             }
1987
1988             if (n > 0) {
1989                 u->state->response_length += n;
1990
1991                 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1992                     ngx_http_upstream_finalize_request(r, u, 0);
1993                     return;
1994                 }
1995             }
1996
1997             do_write = 1;
1998
1999             continue;
2000         }
2001
2002         break;
2003     }
2004
2005     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2006
2007     if (downstream->data == r) {
2008         if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
2009             != NGX_OK)
2010         {
2011             ngx_http_upstream_finalize_request(r, u, 0);
2012             return;
2013         }
2014     }
2015
2016     if (downstream->write->active && !downstream->write->ready) {
2017         ngx_add_timer(downstream->write, clcf->send_timeout);
2018
2019     } else if (downstream->write->timer_set) {
2020         ngx_del_timer(downstream->write);
2021     }
2022
2023     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
2024         ngx_http_upstream_finalize_request(r, u, 0);
2025         return;
2026     }
2027
2028     if (upstream->read->active && !upstream->read->ready) {
2029         ngx_add_timer(upstream->read, u->conf->read_timeout);
2030
2031     } else if (upstream->read->timer_set) {
2032         ngx_del_timer(upstream->read);
2033     }
2034 }
2035
2036
2037 static ngx_int_t
2038 ngx_http_upstream_non_buffered_filter_init(void *data)
2039 {
2040     return NGX_OK;
2041 }
2042
2043
2044 static ngx_int_t
2045 ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
2046 {
2047     ngx_http_request_t  *r = data;
2048
2049     ngx_buf_t            *b;
2050     ngx_chain_t          *cl, **ll;
2051     ngx_http_upstream_t  *u;
2052
2053     u = r->upstream;
2054
2055     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2056         ll = &cl->next;
2057     }
2058
2059     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2060     if (cl == NULL) {
2061         return NGX_ERROR;
2062     }
2063
2064     *ll = cl;
2065
2066     cl->buf->flush = 1;
2067     cl->buf->memory = 1;
2068
2069     b = &u->buffer;
2070
2071     cl->buf->pos = b->last;
2072     b->last += bytes;
2073     cl->buf->last = b->last;
2074     cl->buf->tag = u->output.tag;
2075
2076     if (u->length == NGX_MAX_SIZE_T_VALUE) {
2077         return NGX_OK;
2078     }
2079
2080     u->length -= bytes;
2081
2082     return NGX_OK;
2083 }
2084
2085
2086 static void
2087 ngx_http_upstream_process_downstream(ngx_http_request_t *r)
2088 {
2089     ngx_event_t          *wev;
2090     ngx_connection_t     *c;
2091     ngx_event_pipe_t     *p;
2092     ngx_http_upstream_t  *u;
2093
2094     c = r->connection;
2095     u = r->upstream;
2096     p = u->pipe;
2097     wev = c->write;
2098
2099     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2100                    "http upstream process downstream");
2101
2102     c->log->action = "sending to client";
2103
2104     if (wev->timedout) {
2105
2106         if (wev->delayed) {
2107
2108             wev->timedout = 0;
2109             wev->delayed = 0;
2110
2111             if (!wev->ready) {
2112                 ngx_add_timer(wev, p->send_timeout);
2113
2114                 if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
2115                     ngx_http_upstream_finalize_request(r, u, 0);
2116                 }
2117
2118                 return;
2119             }
2120
2121             if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
2122
2123                 if (c->destroyed) {
2124                     return;
2125                 }
2126
2127                 ngx_http_upstream_finalize_request(r, u, 0);
2128                 return;
2129             }
2130
2131         } else {
2132             p->downstream_error = 1;
2133             c->timedout = 1;
2134             ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2135         }
2136
2137     } else {
2138
2139         if (wev->delayed) {
2140
2141             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2142                            "http downstream delayed");
2143
2144             if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
2145                 ngx_http_upstream_finalize_request(r, u, 0);
2146             }
2147
2148             return;
2149         }
2150
2151         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
2152
2153             if (c->destroyed) {
2154                 return;
2155             }
2156
2157             ngx_http_upstream_finalize_request(r, u, 0);
2158             return;
2159         }
2160     }
2161
2162     ngx_http_upstream_process_request(r);
2163 }
2164
2165
2166 static void
2167 ngx_http_upstream_process_upstream(ngx_http_request_t *r,
2168     ngx_http_upstream_t *u)
2169 {
2170     ngx_connection_t  *c;
2171
2172     c = u->peer.connection;
2173
2174     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2175                    "http upstream process upstream");
2176
2177     c->log->action = "reading upstream";
2178
2179     if (c->read->timedout) {
2180         u->pipe->upstream_error = 1;
2181         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2182
2183     } else {
2184         c = r->connection;
2185
2186         if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
2187
2188             if (c->destroyed) {
2189                 return;
2190             }
2191
2192             ngx_http_upstream_finalize_request(r, u, 0);
2193             return;
2194         }
2195     }
2196
2197     ngx_http_upstream_process_request(r);
2198 }
2199
2200
2201 static void
2202 ngx_http_upstream_process_request(ngx_http_request_t *r)
2203 {
2204     ngx_uint_t            del;
2205     ngx_temp_file_t      *tf;
2206     ngx_event_pipe_t     *p;
2207     ngx_http_upstream_t  *u;
2208
2209     u = r->upstream;
2210     p = u->pipe;
2211
2212     if (u->peer.connection) {
2213
2214         if (u->store) {
2215
2216             del = p->upstream_error;
2217
2218             tf = u->pipe->temp_file;
2219
2220             if (p->upstream_eof || p->upstream_done) {
2221
2222                 if (u->headers_in.status_n == NGX_HTTP_OK
2223                     && (u->headers_in.content_length_n == -1
2224                         || (u->headers_in.content_length_n == tf->offset)))
2225                 {
2226                     ngx_http_upstream_store(r, u);
2227
2228                 } else {
2229                     del = 1;
2230                 }
2231             }
2232
2233             if (del && tf->file.fd != NGX_INVALID_FILE) {
2234
2235                 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
2236
2237                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
2238                                   ngx_delete_file_n " \"%s\" failed",
2239                                   u->pipe->temp_file->file.name.data);
2240                 }
2241             }
2242         }
2243
2244 #if (NGX_HTTP_FILE_CACHE)
2245
2246         if (p->upstream_done && u->cacheable) {
2247             if (ngx_http_cache_update(r) == NGX_ERROR) {
2248                 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2249                 ngx_http_upstream_finalize_request(r, u, 0);
2250                 return;
2251             }
2252
2253         } else if (p->upstream_eof && u->cacheable) {
2254
2255             /* TODO: check length & update cache */
2256
2257             if (ngx_http_cache_update(r) == NGX_ERROR) {
2258                 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2259                 ngx_http_upstream_finalize_request(r, u, 0);
2260                 return;
2261             }
2262         }
2263
2264 #endif
2265
2266         if (p->upstream_done || p->upstream_eof || p->upstream_error) {
2267             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2268                            "http upstream exit: %p", p->out);
2269 #if 0
2270             ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2271 #endif
2272             ngx_http_upstream_finalize_request(r, u, 0);
2273             return;
2274         }
2275     }
2276
2277     if (p->downstream_error) {
2278         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2279                        "http upstream downstream error");
2280
2281         if (!u->cacheable && u->peer.connection) {
2282             ngx_http_upstream_finalize_request(r, u, 0);
2283         }
2284     }
2285 }
2286
2287
2288 static void
2289 ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
2290 {
2291     size_t                  root;
2292     time_t                  lm;
2293     ngx_str_t               path;
2294     ngx_temp_file_t        *tf;
2295     ngx_ext_rename_file_t   ext;
2296
2297     tf = u->pipe->temp_file;
2298
2299     if (tf->file.fd == NGX_INVALID_FILE) {
2300
2301         /* create file for empty 200 response */
2302
2303         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2304         if (tf == NULL) {
2305             return;
2306         }
2307
2308         tf->file.fd = NGX_INVALID_FILE;
2309         tf->file.log = r->connection->log;
2310         tf->path = u->conf->temp_path;
2311         tf->pool = r->pool;
2312         tf->persistent = 1;
2313
2314         if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
2315                                  tf->persistent, tf->clean, tf->access)
2316             != NGX_OK)
2317         {
2318             return;
2319         }
2320
2321         u->pipe->temp_file = tf;
2322     }
2323
2324     ext.access = u->conf->store_access;
2325     ext.path_access = u->conf->store_access;
2326     ext.time = -1;
2327     ext.create_path = 1;
2328     ext.delete_file = 1;
2329     ext.log_rename_error = 1;
2330     ext.log = r->connection->log;
2331
2332     if (u->headers_in.last_modified) {
2333
2334         lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
2335                                  u->headers_in.last_modified->value.len);
2336
2337         if (lm != NGX_ERROR) {
2338             ext.time = lm;
2339             ext.fd = tf->file.fd;
2340         }
2341     }
2342
2343     if (u->conf->store_lengths == NULL) {
2344
2345         ngx_http_map_uri_to_path(r, &path, &root, 0);
2346
2347     } else {
2348         if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
2349                                 u->conf->store_values->elts)
2350             == NULL)
2351         {
2352             return;
2353         }
2354     }
2355
2356     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2357                    "upstream stores \"%s\" to \"%s\"",
2358                    tf->file.name.data, path.data);
2359
2360     (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
2361 }
2362
2363
2364 static void
2365 ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
2366 {
2367     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2368                    "http upstream dummy handler");
2369 }
2370
2371
2372 static void
2373 ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
2374     ngx_uint_t ft_type)
2375 {
2376     ngx_uint_t  status, state;
2377
2378     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2379                    "http next upstream, %xi", ft_type);
2380
2381 #if 0
2382     ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
2383 #endif
2384
2385     if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
2386         state = NGX_PEER_NEXT;
2387     } else {
2388         state = NGX_PEER_FAILED;
2389     }
2390
2391     if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) {
2392         u->peer.free(&u->peer, u->peer.data, state);
2393     }
2394
2395     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
2396         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
2397                       "upstream timed out");
2398     }
2399
2400     if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
2401         status = 0;
2402
2403     } else {
2404         switch(ft_type) {
2405
2406         case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
2407             status = NGX_HTTP_GATEWAY_TIME_OUT;
2408             break;
2409
2410         case NGX_HTTP_UPSTREAM_FT_HTTP_500:
2411             status = NGX_HTTP_INTERNAL_SERVER_ERROR;
2412             break;
2413
2414         case NGX_HTTP_UPSTREAM_FT_HTTP_404:
2415             status = NGX_HTTP_NOT_FOUND;
2416             break;
2417
2418         /*
2419          * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
2420          * never reach here
2421          */
2422
2423         default:
2424             status = NGX_HTTP_BAD_GATEWAY;
2425         }
2426     }
2427
2428     if (r->connection->error) {
2429         ngx_http_upstream_finalize_request(r, u,
2430                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
2431         return;
2432     }
2433
2434     if (status) {
2435         u->state->status = status;
2436
2437         if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
2438
2439 #if (NGX_HTTP_CACHE)
2440
2441             if (u->stale && (u->conf->use_stale & ft_type)) {
2442                 ngx_http_upstream_finalize_request(r, u,
2443                                              ngx_http_send_cached_response(r));
2444                 return;
2445             }
2446
2447 #endif
2448
2449             ngx_http_upstream_finalize_request(r, u, status);
2450             return;
2451         }
2452     }
2453
2454     if (u->peer.connection) {
2455         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2456                        "close http upstream connection: %d",
2457                        u->peer.connection->fd);
2458 #if (NGX_HTTP_SSL)
2459
2460         if (u->peer.connection->ssl) {
2461             u->peer.connection->ssl->no_wait_shutdown = 1;
2462             u->peer.connection->ssl->no_send_shutdown = 1;
2463
2464             (void) ngx_ssl_shutdown(u->peer.connection);
2465         }
2466 #endif
2467
2468         ngx_close_connection(u->peer.connection);
2469     }
2470
2471 #if 0
2472     if (u->conf->busy_lock && !u->busy_locked) {
2473         ngx_http_upstream_busy_lock(p);
2474         return;
2475     }
2476 #endif
2477
2478     ngx_http_upstream_connect(r, u);
2479 }
2480
2481
2482 static void
2483 ngx_http_upstream_cleanup(void *data)
2484 {
2485     ngx_http_request_t *r = data;
2486
2487     ngx_http_upstream_t  *u;
2488
2489     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2490                    "cleanup http upstream request: \"%V\"", &r->uri);
2491
2492     u = r->upstream;
2493
2494     if (u->resolved && u->resolved->ctx) {
2495         ngx_resolve_name_done(u->resolved->ctx);
2496     }
2497
2498     ngx_http_upstream_finalize_request(r, u, NGX_DONE);
2499 }
2500
2501
2502 static void
2503 ngx_http_upstream_finalize_request(ngx_http_request_t *r,
2504     ngx_http_upstream_t *u, ngx_int_t rc)
2505 {
2506     ngx_time_t  *tp;
2507
2508     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2509                    "finalize http upstream request: %i", rc);
2510
2511     if (u->cleanup) {
2512         *u->cleanup = NULL;
2513     }
2514
2515     if (u->state && u->state->response_sec) {
2516         tp = ngx_timeofday();
2517         u->state->response_sec = tp->sec - u->state->response_sec;
2518         u->state->response_msec = tp->msec - u->state->response_msec;
2519
2520         if (u->pipe) {
2521             u->state->response_length = u->pipe->read_length;
2522         }
2523     }
2524
2525     u->finalize_request(r, rc);
2526
2527     if (u->peer.free) {
2528         u->peer.free(&u->peer, u->peer.data, 0);
2529     }
2530
2531     if (u->peer.connection) {
2532
2533 #if (NGX_HTTP_SSL)
2534
2535         /* TODO: do not shutdown persistent connection */
2536
2537         if (u->peer.connection->ssl) {
2538
2539             /*
2540              * We send the "close notify" shutdown alert to the upstream only
2541              * and do not wait its "close notify" shutdown alert.
2542              * It is acceptable according to the TLS standard.
2543              */
2544
2545             u->peer.connection->ssl->no_wait_shutdown = 1;
2546
2547             (void) ngx_ssl_shutdown(u->peer.connection);
2548         }
2549 #endif
2550
2551         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2552                        "close http upstream connection: %d",
2553                        u->peer.connection->fd);
2554
2555         ngx_close_connection(u->peer.connection);
2556     }
2557
2558     u->peer.connection = NULL;
2559
2560     if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
2561     {
2562         rc = 0;
2563     }
2564
2565     if (u->pipe && u->pipe->temp_file) {
2566         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2567                        "http upstream temp fd: %d",
2568                        u->pipe->temp_file->file.fd);
2569     }
2570
2571 #if 0
2572     if (u->cache) {
2573         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2574                        "http upstream cache fd: %d",
2575                        u->cache->ctx.file.fd);
2576     }
2577 #endif
2578
2579     if (rc == NGX_DECLINED) {
2580         return;
2581     }
2582
2583     r->connection->log->action = "sending to client";
2584
2585     if (rc == 0 && r == r->main && !r->post_action) {
2586         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
2587     }
2588
2589     ngx_http_finalize_request(r, rc);
2590 }
2591
2592
2593 static ngx_int_t
2594 ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2595     ngx_uint_t offset)
2596 {
2597     ngx_table_elt_t  **ph;
2598
2599     ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
2600
2601     if (*ph == NULL) {
2602         *ph = h;
2603     }
2604
2605     return NGX_OK;
2606 }
2607
2608
2609 static ngx_int_t
2610 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
2611     ngx_table_elt_t *h, ngx_uint_t offset)
2612 {
2613     ngx_array_t       *pa;
2614     ngx_table_elt_t  **ph;
2615
2616     pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset);
2617
2618     if (pa->elts == NULL) {
2619        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
2620        {
2621            return NGX_ERROR;
2622        }
2623     }
2624
2625     ph = ngx_array_push(pa);
2626     if (ph == NULL) {
2627         return NGX_ERROR;
2628     }
2629
2630     *ph = h;
2631
2632     return NGX_OK;
2633 }
2634
2635
2636 static ngx_int_t
2637 ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2638     ngx_uint_t offset)
2639 {
2640     return NGX_OK;
2641 }
2642
2643
2644 static ngx_int_t
2645 ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
2646     ngx_uint_t offset)
2647 {
2648     ngx_int_t  n;
2649
2650     r->upstream->headers_in.x_accel_limit_rate = h;
2651
2652     n = ngx_atoi(h->value.data, h->value.len);
2653
2654     if (n != NGX_ERROR) {
2655         r->limit_rate = (size_t) n;
2656     }
2657
2658     return NGX_OK;
2659 }
2660
2661
2662 static ngx_int_t
2663 ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
2664     ngx_uint_t offset)
2665 {
2666     u_char  c0, c1, c2;
2667
2668     if (r->upstream->conf->change_buffering) {
2669
2670         if (h->value.len == 2) {
2671             c0 = ngx_tolower(h->value.data[0]);
2672             c1 = ngx_tolower(h->value.data[1]);
2673
2674             if (c0 == 'n' && c1 == 'o') {
2675                 r->upstream->buffering = 0;
2676             }
2677
2678         } else if (h->value.len == 3) {
2679             c0 = ngx_tolower(h->value.data[0]);
2680             c1 = ngx_tolower(h->value.data[1]);
2681             c2 = ngx_tolower(h->value.data[2]);
2682
2683             if (c0 == 'y' && c1 == 'e' && c2 == 's') {
2684                 r->upstream->buffering = 1;
2685             }
2686         }
2687     }
2688
2689     return NGX_OK;
2690 }
2691
2692
2693 static ngx_int_t
2694 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
2695     ngx_uint_t offset)
2696 {
2697     r->headers_out.override_charset = &h->value;
2698
2699     return NGX_OK;
2700 }
2701
2702
2703 static ngx_int_t
2704 ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
2705     ngx_uint_t offset)
2706 {
2707     ngx_table_elt_t  *ho, **ph;
2708
2709     ho = ngx_list_push(&r->headers_out.headers);
2710     if (ho == NULL) {
2711         return NGX_ERROR;
2712     }
2713
2714     *ho = *h;
2715
2716     if (offset) {
2717         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
2718         *ph = ho;
2719     }
2720
2721     return NGX_OK;
2722 }
2723
2724
2725 static ngx_int_t
2726 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
2727     ngx_table_elt_t *h, ngx_uint_t offset)
2728 {
2729     ngx_array_t      *pa;
2730     ngx_table_elt_t  *ho, **ph;
2731
2732     pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
2733
2734     if (pa->elts == NULL) {
2735         if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
2736         {
2737             return NGX_ERROR;
2738         }
2739     }
2740
2741     ph = ngx_array_push(pa);
2742     if (ph == NULL) {
2743         return NGX_ERROR;
2744     }
2745
2746     ho = ngx_list_push(&r->headers_out.headers);
2747     if (ho == NULL) {
2748         return NGX_ERROR;
2749     }
2750
2751     *ho = *h;
2752     *ph = ho;
2753
2754     return NGX_OK;
2755 }
2756
2757
2758 static ngx_int_t
2759 ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
2760     ngx_uint_t offset)
2761 {
2762     u_char  *p, *last;
2763
2764     r->headers_out.content_type_len = h->value.len;
2765     r->headers_out.content_type = h->value;
2766
2767     for (p = h->value.data; *p; p++) {
2768
2769         if (*p != ';') {
2770             continue;
2771         }
2772
2773         last = p;
2774
2775         while (*++p == ' ') { /* void */ }
2776
2777         if (*p == '\0') {
2778             return NGX_OK;
2779         }
2780
2781         if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
2782             continue;
2783         }
2784
2785         p += 8;
2786
2787         r->headers_out.content_type_len = last - h->value.data;
2788
2789         if (*p == '"') {
2790             p++;
2791         }
2792
2793         last = h->value.data + h->value.len;
2794
2795         if (*(last - 1) == '"') {
2796             last--;
2797         }
2798
2799         r->headers_out.charset.len = last - p;
2800         r->headers_out.charset.data = p;
2801
2802         return NGX_OK;
2803     }
2804
2805     return NGX_OK;
2806 }
2807
2808
2809 static ngx_int_t
2810 ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
2811     ngx_uint_t offset)
2812 {
2813     ngx_table_elt_t  *ho;
2814
2815     ho = ngx_list_push(&r->headers_out.headers);
2816     if (ho == NULL) {
2817         return NGX_ERROR;
2818     }
2819
2820     *ho = *h;
2821
2822     r->headers_out.content_length = ho;
2823     r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len);
2824
2825     return NGX_OK;
2826 }
2827
2828
2829 static ngx_int_t
2830 ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
2831     ngx_uint_t offset)
2832 {
2833     ngx_int_t         rc;
2834     ngx_table_elt_t  *ho;
2835
2836     ho = ngx_list_push(&r->headers_out.headers);
2837     if (ho == NULL) {
2838         return NGX_ERROR;
2839     }
2840
2841     *ho = *h;
2842
2843     if (r->upstream->rewrite_redirect) {
2844         rc = r->upstream->rewrite_redirect(r, ho, 0);
2845
2846         if (rc == NGX_DECLINED) {
2847             return NGX_OK;
2848         }
2849
2850         if (rc == NGX_OK) {
2851             r->headers_out.location = ho;
2852
2853             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2854                            "rewritten location: \"%V\"", &ho->value);
2855         }
2856
2857         return rc;
2858     }
2859
2860     if (ho->value.data[0] != '/') {
2861         r->headers_out.location = ho;
2862     }
2863
2864     /*
2865      * we do not set r->headers_out.location here to avoid the handling
2866      * the local redirects without a host name by ngx_http_header_filter()
2867      */
2868
2869     return NGX_OK;
2870 }
2871
2872
2873 static ngx_int_t
2874 ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
2875     ngx_uint_t offset)
2876 {
2877     u_char           *p;
2878     ngx_int_t         rc;
2879     ngx_table_elt_t  *ho;
2880
2881     ho = ngx_list_push(&r->headers_out.headers);
2882     if (ho == NULL) {
2883         return NGX_ERROR;
2884     }
2885
2886     *ho = *h;
2887
2888     if (r->upstream->rewrite_redirect) {
2889
2890         p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
2891
2892         if (p) {
2893             rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
2894
2895         } else {
2896             return NGX_OK;
2897         }
2898
2899         if (rc == NGX_DECLINED) {
2900             return NGX_OK;
2901         }
2902
2903         if (rc == NGX_OK) {
2904             r->headers_out.refresh = ho;
2905
2906             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2907                            "rewritten refresh: \"%V\"", &ho->value);
2908         }
2909
2910         return rc;
2911     }
2912
2913     r->headers_out.refresh = ho;
2914
2915     return NGX_OK;
2916 }
2917
2918
2919 #if (NGX_HTTP_GZIP)
2920
2921 static ngx_int_t
2922 ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
2923     ngx_table_elt_t *h, ngx_uint_t offset)
2924 {
2925     ngx_table_elt_t  *ho;
2926
2927     ho = ngx_list_push(&r->headers_out.headers);
2928     if (ho == NULL) {
2929         return NGX_ERROR;
2930     }
2931
2932     *ho = *h;
2933
2934     r->headers_out.content_encoding = ho;
2935
2936     return NGX_OK;
2937 }
2938
2939 #endif
2940
2941
2942 static ngx_int_t
2943 ngx_http_upstream_add_variables(ngx_conf_t *cf)
2944 {
2945     ngx_http_variable_t  *var, *v;
2946
2947     for (v = ngx_http_upstream_vars; v->name.len; v++) {
2948         var = ngx_http_add_variable(cf, &v->name, v->flags);
2949         if (var == NULL) {
2950             return NGX_ERROR;
2951         }
2952
2953         var->get_handler = v->get_handler;
2954         var->data = v->data;
2955     }
2956
2957     return NGX_OK;
2958 }
2959
2960
2961 static ngx_int_t
2962 ngx_http_upstream_addr_variable(ngx_http_request_t *r,
2963     ngx_http_variable_value_t *v, uintptr_t data)
2964 {
2965     u_char                     *p;
2966     size_t                      len;
2967     ngx_uint_t                  i;
2968     ngx_http_upstream_state_t  *state;
2969
2970     v->valid = 1;
2971     v->no_cacheable = 0;
2972     v->not_found = 0;
2973
2974     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
2975         v->not_found = 1;
2976         return NGX_OK;
2977     }
2978
2979     len = 0;
2980     state = r->upstream_states->elts;
2981
2982     for (i = 0; i < r->upstream_states->nelts; i++) {
2983         if (state[i].peer) {
2984             len += state[i].peer->len + 2;
2985
2986         } else {
2987             len += 3;
2988         }
2989     }
2990
2991     p = ngx_pnalloc(r->pool, len);
2992     if (p == NULL) {
2993         return NGX_ERROR;
2994     }
2995
2996     v->data = p;
2997
2998     i = 0;
2999
3000     for ( ;; ) {
3001         if (state[i].peer) {
3002             p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
3003         }
3004
3005         if (++i == r->upstream_states->nelts) {
3006             break;
3007         }
3008
3009         if (state[i].peer) {
3010             *p++ = ',';
3011             *p++ = ' ';
3012
3013         } else {
3014             *p++ = ' ';
3015             *p++ = ':';
3016             *p++ = ' ';
3017
3018             if (++i == r->upstream_states->nelts) {
3019                 break;
3020             }
3021
3022             continue;
3023         }
3024     }
3025
3026     v->len = p - v->data;
3027
3028     return NGX_OK;
3029 }
3030
3031
3032 static ngx_int_t
3033 ngx_http_upstream_status_variable(ngx_http_request_t *r,
3034     ngx_http_variable_value_t *v, uintptr_t data)
3035 {
3036     u_char                     *p;
3037     size_t                      len;
3038     ngx_uint_t                  i;
3039     ngx_http_upstream_state_t  *state;
3040
3041     v->valid = 1;
3042     v->no_cacheable = 0;
3043     v->not_found = 0;
3044
3045     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3046         v->not_found = 1;
3047         return NGX_OK;
3048     }
3049
3050     len = r->upstream_states->nelts * (3 + 2);
3051
3052     p = ngx_pnalloc(r->pool, len);
3053     if (p == NULL) {
3054         return NGX_ERROR;
3055     }
3056
3057     v->data = p;
3058
3059     i = 0;
3060     state = r->upstream_states->elts;
3061
3062     for ( ;; ) {
3063         if (state[i].status) {
3064             p = ngx_sprintf(p, "%ui", state[i].status);
3065
3066         } else {
3067             *p++ = '-';
3068         }
3069
3070         if (++i == r->upstream_states->nelts) {
3071             break;
3072         }
3073
3074         if (state[i].peer) {
3075             *p++ = ',';
3076             *p++ = ' ';
3077
3078         } else {
3079             *p++ = ' ';
3080             *p++ = ':';
3081             *p++ = ' ';
3082
3083             if (++i == r->upstream_states->nelts) {
3084                 break;
3085             }
3086
3087             continue;
3088         }
3089     }
3090
3091     v->len = p - v->data;
3092
3093     return NGX_OK;
3094 }
3095
3096
3097 static ngx_int_t
3098 ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
3099     ngx_http_variable_value_t *v, uintptr_t data)
3100 {
3101     u_char                     *p;
3102     size_t                      len;
3103     ngx_uint_t                  i;
3104     ngx_msec_int_t              ms;
3105     ngx_http_upstream_state_t  *state;
3106
3107     v->valid = 1;
3108     v->no_cacheable = 0;
3109     v->not_found = 0;
3110
3111     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3112         v->not_found = 1;
3113         return NGX_OK;
3114     }
3115
3116     len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
3117
3118     p = ngx_pnalloc(r->pool, len);
3119     if (p == NULL) {
3120         return NGX_ERROR;
3121     }
3122
3123     v->data = p;
3124
3125     i = 0;
3126     state = r->upstream_states->elts;
3127
3128     for ( ;; ) {
3129         if (state[i].status) {
3130             ms = (ngx_msec_int_t)
3131                      (state[i].response_sec * 1000 + state[i].response_msec);
3132             ms = (ms >= 0) ? ms : 0;
3133             p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
3134
3135         } else {
3136             *p++ = '-';
3137         }
3138
3139         if (++i == r->upstream_states->nelts) {
3140             break;
3141         }
3142
3143         if (state[i].peer) {
3144             *p++ = ',';
3145             *p++ = ' ';
3146
3147         } else {
3148             *p++ = ' ';
3149             *p++ = ':';
3150             *p++ = ' ';
3151
3152             if (++i == r->upstream_states->nelts) {
3153                 break;
3154             }
3155
3156             continue;
3157         }
3158     }
3159
3160     v->len = p - v->data;
3161
3162     return NGX_OK;
3163 }
3164
3165
3166 static ngx_int_t
3167 ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
3168     ngx_http_variable_value_t *v, uintptr_t data)
3169 {
3170     u_char                     *p;
3171     size_t                      len;
3172     ngx_uint_t                  i;
3173     ngx_http_upstream_state_t  *state;
3174
3175     v->valid = 1;
3176     v->no_cacheable = 0;
3177     v->not_found = 0;
3178
3179     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
3180         v->not_found = 1;
3181         return NGX_OK;
3182     }
3183
3184     len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
3185
3186     p = ngx_pnalloc(r->pool, len);
3187     if (p == NULL) {
3188         return NGX_ERROR;
3189     }
3190
3191     v->data = p;
3192
3193     i = 0;
3194     state = r->upstream_states->elts;
3195
3196     for ( ;; ) {
3197         p = ngx_sprintf(p, "%O", state[i].response_length);
3198
3199         if (++i == r->upstream_states->nelts) {
3200             break;
3201         }
3202
3203         if (state[i].peer) {
3204             *p++ = ',';
3205             *p++ = ' ';
3206
3207         } else {
3208             *p++ = ' ';
3209             *p++ = ':';
3210             *p++ = ' ';
3211
3212             if (++i == r->upstream_states->nelts) {
3213                 break;
3214             }
3215
3216             continue;
3217         }
3218     }
3219
3220     v->len = p - v->data;
3221
3222     return NGX_OK;
3223 }
3224
3225
3226 ngx_int_t
3227 ngx_http_upstream_header_variable(ngx_http_request_t *r,
3228     ngx_http_variable_value_t *v, uintptr_t data)
3229 {
3230     if (r->upstream == NULL) {
3231         v->not_found = 1;
3232         return NGX_OK;
3233     }
3234
3235     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
3236                                          &r->upstream->headers_in.headers.part,
3237                                          sizeof("upstream_http_") - 1);
3238 }
3239
3240
3241 static char *
3242 ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
3243 {
3244     char                          *rv;
3245     void                          *mconf;
3246     ngx_str_t                     *value;
3247     ngx_url_t                      u;
3248     ngx_uint_t                     m;
3249     ngx_conf_t                     pcf;
3250     ngx_http_module_t             *module;
3251     ngx_http_conf_ctx_t           *ctx, *http_ctx;
3252     ngx_http_upstream_srv_conf_t  *uscf;
3253
3254     ngx_memzero(&u, sizeof(ngx_url_t));
3255
3256     value = cf->args->elts;
3257     u.host = value[1];
3258     u.no_resolve = 1;
3259
3260     uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
3261                                          |NGX_HTTP_UPSTREAM_WEIGHT
3262                                          |NGX_HTTP_UPSTREAM_MAX_FAILS
3263                                          |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
3264                                          |NGX_HTTP_UPSTREAM_DOWN
3265                                          |NGX_HTTP_UPSTREAM_BACKUP);
3266     if (uscf == NULL) {
3267         return NGX_CONF_ERROR;
3268     }
3269
3270
3271     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
3272     if (ctx == NULL) {
3273         return NGX_CONF_ERROR;
3274     }
3275
3276     http_ctx = cf->ctx;
3277     ctx->main_conf = http_ctx->main_conf;
3278
3279     /* the upstream{}'s srv_conf */
3280
3281     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3282     if (ctx->srv_conf == NULL) {
3283         return NGX_CONF_ERROR;
3284     }
3285
3286     ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
3287
3288     uscf->srv_conf = ctx->srv_conf;
3289
3290
3291     /* the upstream{}'s loc_conf */
3292
3293     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
3294     if (ctx->loc_conf == NULL) {
3295         return NGX_CONF_ERROR;
3296     }
3297
3298     for (m = 0; ngx_modules[m]; m++) {
3299         if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
3300             continue;
3301         }
3302
3303         module = ngx_modules[m]->ctx;
3304
3305         if (module->create_srv_conf) {
3306             mconf = module->create_srv_conf(cf);
3307             if (mconf == NULL) {
3308                 return NGX_CONF_ERROR;
3309             }
3310
3311             ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
3312         }
3313
3314         if (module->create_loc_conf) {
3315             mconf = module->create_loc_conf(cf);
3316             if (mconf == NULL) {
3317                 return NGX_CONF_ERROR;
3318             }
3319
3320             ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
3321         }
3322     }
3323
3324
3325     /* parse inside upstream{} */
3326
3327     pcf = *cf;
3328     cf->ctx = ctx;
3329     cf->cmd_type = NGX_HTTP_UPS_CONF;
3330
3331     rv = ngx_conf_parse(cf, NULL);
3332
3333     *cf = pcf;
3334
3335     if (rv != NGX_CONF_OK) {
3336         return rv;
3337     }
3338
3339     if (uscf->servers == NULL) {
3340         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3341                            "no servers are inside upstream");
3342         return NGX_CONF_ERROR;
3343     }
3344
3345     return rv;
3346 }
3347
3348
3349 static char *
3350 ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3351 {
3352     ngx_http_upstream_srv_conf_t  *uscf = conf;
3353
3354     time_t                       fail_timeout;
3355     ngx_str_t                   *value, s;
3356     ngx_url_t                    u;
3357     ngx_int_t                    weight, max_fails;
3358     ngx_uint_t                   i;
3359     ngx_http_upstream_server_t  *us;
3360
3361     if (uscf->servers == NULL) {
3362         uscf->servers = ngx_array_create(cf->pool, 4,
3363                                          sizeof(ngx_http_upstream_server_t));
3364         if (uscf->servers == NULL) {
3365             return NGX_CONF_ERROR;
3366         }
3367     }
3368
3369     us = ngx_array_push(uscf->servers);
3370     if (us == NULL) {
3371         return NGX_CONF_ERROR;
3372     }
3373
3374     ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
3375
3376     value = cf->args->elts;
3377
3378     ngx_memzero(&u, sizeof(ngx_url_t));
3379
3380     u.url = value[1];
3381     u.default_port = 80;
3382
3383     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
3384         if (u.err) {
3385             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3386                                "%s in upstream \"%V\"", u.err, &u.url);
3387         }
3388
3389         return NGX_CONF_ERROR;
3390     }
3391
3392     weight = 1;
3393     max_fails = 1;
3394     fail_timeout = 10;
3395
3396     for (i = 2; i < cf->args->nelts; i++) {
3397
3398         if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
3399
3400             if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
3401                 goto invalid;
3402             }
3403
3404             weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
3405
3406             if (weight == NGX_ERROR || weight == 0) {
3407                 goto invalid;
3408             }
3409
3410             continue;
3411         }
3412
3413         if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
3414
3415             if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
3416                 goto invalid;
3417             }
3418
3419             max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
3420
3421             if (max_fails == NGX_ERROR) {
3422                 goto invalid;
3423             }
3424
3425             continue;
3426         }
3427
3428         if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
3429
3430             if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
3431                 goto invalid;
3432             }
3433
3434             s.len = value[i].len - 13;
3435             s.data = &value[i].data[13];
3436
3437             fail_timeout = ngx_parse_time(&s, 1);
3438
3439             if (fail_timeout == NGX_ERROR) {
3440                 goto invalid;
3441             }
3442
3443             continue;
3444         }
3445
3446         if (ngx_strncmp(value[i].data, "backup", 6) == 0) {
3447
3448             if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
3449                 goto invalid;
3450             }
3451
3452             us->backup = 1;
3453
3454             continue;
3455         }
3456
3457         if (ngx_strncmp(value[i].data, "down", 4) == 0) {
3458
3459             if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
3460                 goto invalid;
3461             }
3462
3463             us->down = 1;
3464
3465             continue;
3466         }
3467
3468         goto invalid;
3469     }
3470
3471     us->addrs = u.addrs;
3472     us->naddrs = u.naddrs;
3473     us->weight = weight;
3474     us->max_fails = max_fails;
3475     us->fail_timeout = fail_timeout;
3476
3477     return NGX_CONF_OK;
3478
3479 invalid:
3480
3481     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3482                        "invalid parameter \"%V\"", &value[i]);
3483
3484     return NGX_CONF_ERROR;
3485 }
3486
3487
3488 ngx_http_upstream_srv_conf_t *
3489 ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
3490 {
3491     ngx_uint_t                      i;
3492     ngx_http_upstream_server_t     *us;
3493     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
3494     ngx_http_upstream_main_conf_t  *umcf;
3495
3496     if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
3497
3498         if (ngx_parse_url(cf->pool, u) != NGX_OK) {
3499             if (u->err) {
3500                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3501                                    "%s in upstream \"%V\"", u->err, &u->url);
3502             }
3503
3504             return NULL;
3505         }
3506     }
3507
3508     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
3509
3510     uscfp = umcf->upstreams.elts;
3511
3512     for (i = 0; i < umcf->upstreams.nelts; i++) {
3513
3514         if (uscfp[i]->host.len != u->host.len
3515             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
3516                != 0)
3517         {
3518             continue;
3519         }
3520
3521         if ((flags & NGX_HTTP_UPSTREAM_CREATE)
3522              && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
3523         {
3524             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3525                                "duplicate upstream \"%V\"", &u->host);
3526             return NULL;
3527         }
3528
3529         if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && u->port) {
3530             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3531                                "upstream \"%V\" may not have port %d",
3532                                &u->host, u->port);
3533             return NULL;
3534         }
3535
3536         if ((flags & NGX_HTTP_UPSTREAM_CREATE) && uscfp[i]->port) {
3537             ngx_log_error(NGX_LOG_WARN, cf->log, 0,
3538                           "upstream \"%V\" may not have port %d in %s:%ui",
3539                           &u->host, uscfp[i]->port,
3540                           uscfp[i]->file_name, uscfp[i]->line);
3541             return NULL;
3542         }
3543
3544         if (uscfp[i]->port != u->port) {
3545             continue;
3546         }
3547
3548         if (uscfp[i]->default_port && u->default_port
3549             && uscfp[i]->default_port != u->default_port)
3550         {
3551             continue;
3552         }
3553
3554         return uscfp[i];
3555     }
3556
3557     uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
3558     if (uscf == NULL) {
3559         return NULL;
3560     }
3561
3562     uscf->flags = flags;
3563     uscf->host = u->host;
3564     uscf->file_name = cf->conf_file->file.name.data;
3565     uscf->line = cf->conf_file->line;
3566     uscf->port = u->port;
3567     uscf->default_port = u->default_port;
3568
3569     if (u->naddrs == 1) {
3570         uscf->servers = ngx_array_create(cf->pool, 1,
3571                                          sizeof(ngx_http_upstream_server_t));
3572         if (uscf->servers == NULL) {
3573             return NGX_CONF_ERROR;
3574         }
3575
3576         us = ngx_array_push(uscf->servers);
3577         if (us == NULL) {
3578             return NGX_CONF_ERROR;
3579         }
3580
3581         ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
3582
3583         us->addrs = u->addrs;
3584         us->naddrs = u->naddrs;
3585     }
3586
3587     uscfp = ngx_array_push(&umcf->upstreams);
3588     if (uscfp == NULL) {
3589         return NULL;
3590     }
3591
3592     *uscfp = uscf;
3593
3594     return uscf;
3595 }
3596
3597
3598 ngx_int_t
3599 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
3600     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
3601     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
3602 {
3603     ngx_str_t       *h;
3604     ngx_uint_t       i, j;
3605     ngx_array_t      hide_headers;
3606     ngx_hash_key_t  *hk;
3607
3608     if (conf->hide_headers == NGX_CONF_UNSET_PTR
3609         && conf->pass_headers == NGX_CONF_UNSET_PTR)
3610     {
3611         conf->hide_headers_hash = prev->hide_headers_hash;
3612
3613         if (conf->hide_headers_hash.buckets) {
3614             return NGX_OK;
3615         }
3616
3617         conf->hide_headers = prev->hide_headers;
3618         conf->pass_headers = prev->pass_headers;
3619
3620     } else {
3621         if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
3622             conf->hide_headers = prev->hide_headers;
3623         }
3624
3625         if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
3626             conf->pass_headers = prev->pass_headers;
3627         }
3628     }
3629
3630     if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3631         != NGX_OK)
3632     {
3633         return NGX_ERROR;
3634     }
3635
3636     for (h = default_hide_headers; h->len; h++) {
3637         hk = ngx_array_push(&hide_headers);
3638         if (hk == NULL) {
3639             return NGX_ERROR;
3640         }
3641
3642         hk->key = *h;
3643         hk->key_hash = ngx_hash_key_lc(h->data, h->len);
3644         hk->value = (void *) 1;
3645     }
3646
3647     if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
3648
3649         h = conf->hide_headers->elts;
3650
3651         for (i = 0; i < conf->hide_headers->nelts; i++) {
3652
3653             hk = hide_headers.elts;
3654
3655             for (j = 0; j < hide_headers.nelts; j++) {
3656                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
3657                     goto exist;
3658                 }
3659             }
3660
3661             hk = ngx_array_push(&hide_headers);
3662             if (hk == NULL) {
3663                 return NGX_ERROR;
3664             }
3665
3666             hk->key = h[i];
3667             hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
3668             hk->value = (void *) 1;
3669
3670         exist:
3671
3672             continue;
3673         }
3674     }
3675
3676     if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
3677
3678         h = conf->pass_headers->elts;
3679         hk = hide_headers.elts;
3680
3681         for (i = 0; i < conf->pass_headers->nelts; i++) {
3682             for (j = 0; j < hide_headers.nelts; j++) {
3683
3684                 if (hk[j].key.data == NULL) {
3685                     continue;
3686                 }
3687
3688                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
3689                     hk[j].key.data = NULL;
3690                     break;
3691                 }
3692             }
3693         }
3694     }
3695
3696     hash->hash = &conf->hide_headers_hash;
3697     hash->key = ngx_hash_key_lc;
3698     hash->pool = cf->pool;
3699     hash->temp_pool = NULL;
3700
3701     return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
3702 }
3703
3704
3705 static void *
3706 ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
3707 {
3708     ngx_http_upstream_main_conf_t  *umcf;
3709
3710     umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
3711     if (umcf == NULL) {
3712         return NULL;
3713     }
3714
3715     if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
3716                        sizeof(ngx_http_upstream_srv_conf_t *))
3717         != NGX_OK)
3718     {
3719         return NGX_CONF_ERROR;
3720     }
3721
3722     return umcf;
3723 }
3724
3725
3726 static char *
3727 ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
3728 {
3729     ngx_http_upstream_main_conf_t  *umcf = conf;
3730
3731     ngx_uint_t                      i;
3732     ngx_array_t                     headers_in;
3733     ngx_hash_key_t                 *hk;
3734     ngx_hash_init_t                 hash;
3735     ngx_http_upstream_init_pt       init;
3736     ngx_http_upstream_header_t     *header;
3737     ngx_http_upstream_srv_conf_t  **uscfp;
3738
3739     uscfp = umcf->upstreams.elts;
3740
3741     for (i = 0; i < umcf->upstreams.nelts; i++) {
3742
3743         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
3744                                             ngx_http_upstream_init_round_robin;
3745
3746         if (init(cf, uscfp[i]) != NGX_OK) {
3747             return NGX_CONF_ERROR;
3748         }
3749     }
3750
3751
3752     /* upstream_headers_in_hash */
3753
3754     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
3755         != NGX_OK)
3756     {
3757         return NGX_CONF_ERROR;
3758     }
3759
3760     for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
3761         hk = ngx_array_push(&headers_in);
3762         if (hk == NULL) {
3763             return NGX_CONF_ERROR;
3764         }
3765
3766         hk->key = header->name;
3767         hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
3768         hk->value = header;
3769     }
3770
3771     hash.hash = &umcf->headers_in_hash;
3772     hash.key = ngx_hash_key_lc;
3773     hash.max_size = 512;
3774     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3775     hash.name = "upstream_headers_in_hash";
3776     hash.pool = cf->pool;
3777     hash.temp_pool = NULL;
3778
3779     if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
3780         return NGX_CONF_ERROR;
3781     }
3782
3783     return NGX_CONF_OK;
3784 }