source: nginx/src/http/ngx_http_upstream.c @ 5581:4dee5ad51e9e

Last change on this file since 5581:4dee5ad51e9e was 5581:4dee5ad51e9e, checked in by Konstantin Pavlov <thresh@…>, 4 years ago

Upstream: fixed error message wording.

File size: 133.1 KB
Line 
1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11
12
13#if (NGX_HTTP_CACHE)
14static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
15    ngx_http_upstream_t *u);
16static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
17    ngx_http_upstream_t *u);
18static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
19    ngx_http_variable_value_t *v, uintptr_t data);
20static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
21    ngx_http_variable_value_t *v, uintptr_t data);
22#endif
23
24static void ngx_http_upstream_init_request(ngx_http_request_t *r);
25static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
26static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
27static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
28static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
29    ngx_event_t *ev);
30static void ngx_http_upstream_connect(ngx_http_request_t *r,
31    ngx_http_upstream_t *u);
32static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
33    ngx_http_upstream_t *u);
34static void ngx_http_upstream_send_request(ngx_http_request_t *r,
35    ngx_http_upstream_t *u);
36static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
37    ngx_http_upstream_t *u);
38static void ngx_http_upstream_process_header(ngx_http_request_t *r,
39    ngx_http_upstream_t *u);
40static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
41    ngx_http_upstream_t *u);
42static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
43    ngx_http_upstream_t *u);
44static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
45static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
46    ngx_http_upstream_t *u);
47static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
48    ngx_http_upstream_t *u);
49static void ngx_http_upstream_send_response(ngx_http_request_t *r,
50    ngx_http_upstream_t *u);
51static void ngx_http_upstream_upgrade(ngx_http_request_t *r,
52    ngx_http_upstream_t *u);
53static void ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r);
54static void ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r);
55static void ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
56    ngx_http_upstream_t *u);
57static void ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
58    ngx_http_upstream_t *u);
59static void ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
60    ngx_uint_t from_upstream, ngx_uint_t do_write);
61static void
62    ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
63static void
64    ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
65    ngx_http_upstream_t *u);
66static void
67    ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
68    ngx_uint_t do_write);
69static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
70static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
71    ssize_t bytes);
72static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
73static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
74    ngx_http_upstream_t *u);
75static void ngx_http_upstream_process_request(ngx_http_request_t *r);
76static void ngx_http_upstream_store(ngx_http_request_t *r,
77    ngx_http_upstream_t *u);
78static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
79    ngx_http_upstream_t *u);
80static void ngx_http_upstream_next(ngx_http_request_t *r,
81    ngx_http_upstream_t *u, ngx_uint_t ft_type);
82static void ngx_http_upstream_cleanup(void *data);
83static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
84    ngx_http_upstream_t *u, ngx_int_t rc);
85
86static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
87    ngx_table_elt_t *h, ngx_uint_t offset);
88static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
89    ngx_table_elt_t *h, ngx_uint_t offset);
90static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r,
91    ngx_table_elt_t *h, ngx_uint_t offset);
92static ngx_int_t
93    ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
94    ngx_table_elt_t *h, ngx_uint_t offset);
95static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
96    ngx_table_elt_t *h, ngx_uint_t offset);
97static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
98    ngx_table_elt_t *h, ngx_uint_t offset);
99static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
100    ngx_table_elt_t *h, ngx_uint_t offset);
101static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
102    ngx_table_elt_t *h, ngx_uint_t offset);
103static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
104    ngx_table_elt_t *h, ngx_uint_t offset);
105static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
106    ngx_table_elt_t *h, ngx_uint_t offset);
107static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r,
108    ngx_table_elt_t *h, ngx_uint_t offset);
109static ngx_int_t
110    ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
111    ngx_table_elt_t *h, ngx_uint_t offset);
112static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
113    ngx_table_elt_t *h, ngx_uint_t offset);
114static ngx_int_t
115    ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
116    ngx_table_elt_t *h, ngx_uint_t offset);
117static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
118    ngx_table_elt_t *h, ngx_uint_t offset);
119static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
120    ngx_table_elt_t *h, ngx_uint_t offset);
121static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
122    ngx_table_elt_t *h, ngx_uint_t offset);
123static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
124    ngx_table_elt_t *h, ngx_uint_t offset);
125static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
126    ngx_table_elt_t *h, ngx_uint_t offset);
127static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
128    ngx_table_elt_t *h, ngx_uint_t offset);
129
130#if (NGX_HTTP_GZIP)
131static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
132    ngx_table_elt_t *h, ngx_uint_t offset);
133#endif
134
135static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
136static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
137    ngx_http_variable_value_t *v, uintptr_t data);
138static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
139    ngx_http_variable_value_t *v, uintptr_t data);
140static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
141    ngx_http_variable_value_t *v, uintptr_t data);
142static ngx_int_t ngx_http_upstream_response_length_variable(
143    ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
144
145static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
146static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
147    void *conf);
148
149static ngx_addr_t *ngx_http_upstream_get_local(ngx_http_request_t *r,
150    ngx_http_upstream_local_t *local);
151
152static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
153static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
154
155#if (NGX_HTTP_SSL)
156static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
157    ngx_http_upstream_t *u, ngx_connection_t *c);
158static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
159#endif
160
161
162ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {
163
164    { ngx_string("Status"),
165                 ngx_http_upstream_process_header_line,
166                 offsetof(ngx_http_upstream_headers_in_t, status),
167                 ngx_http_upstream_copy_header_line, 0, 0 },
168
169    { ngx_string("Content-Type"),
170                 ngx_http_upstream_process_header_line,
171                 offsetof(ngx_http_upstream_headers_in_t, content_type),
172                 ngx_http_upstream_copy_content_type, 0, 1 },
173
174    { ngx_string("Content-Length"),
175                 ngx_http_upstream_process_content_length,
176                 offsetof(ngx_http_upstream_headers_in_t, content_length),
177                 ngx_http_upstream_ignore_header_line, 0, 0 },
178
179    { ngx_string("Date"),
180                 ngx_http_upstream_process_header_line,
181                 offsetof(ngx_http_upstream_headers_in_t, date),
182                 ngx_http_upstream_copy_header_line,
183                 offsetof(ngx_http_headers_out_t, date), 0 },
184
185    { ngx_string("Last-Modified"),
186                 ngx_http_upstream_process_header_line,
187                 offsetof(ngx_http_upstream_headers_in_t, last_modified),
188                 ngx_http_upstream_copy_last_modified, 0, 0 },
189
190    { ngx_string("ETag"),
191                 ngx_http_upstream_process_header_line,
192                 offsetof(ngx_http_upstream_headers_in_t, etag),
193                 ngx_http_upstream_copy_header_line,
194                 offsetof(ngx_http_headers_out_t, etag), 0 },
195
196    { ngx_string("Server"),
197                 ngx_http_upstream_process_header_line,
198                 offsetof(ngx_http_upstream_headers_in_t, server),
199                 ngx_http_upstream_copy_header_line,
200                 offsetof(ngx_http_headers_out_t, server), 0 },
201
202    { ngx_string("WWW-Authenticate"),
203                 ngx_http_upstream_process_header_line,
204                 offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
205                 ngx_http_upstream_copy_header_line, 0, 0 },
206
207    { ngx_string("Location"),
208                 ngx_http_upstream_process_header_line,
209                 offsetof(ngx_http_upstream_headers_in_t, location),
210                 ngx_http_upstream_rewrite_location, 0, 0 },
211
212    { ngx_string("Refresh"),
213                 ngx_http_upstream_ignore_header_line, 0,
214                 ngx_http_upstream_rewrite_refresh, 0, 0 },
215
216    { ngx_string("Set-Cookie"),
217                 ngx_http_upstream_process_set_cookie, 0,
218                 ngx_http_upstream_rewrite_set_cookie, 0, 1 },
219
220    { ngx_string("Content-Disposition"),
221                 ngx_http_upstream_ignore_header_line, 0,
222                 ngx_http_upstream_copy_header_line, 0, 1 },
223
224    { ngx_string("Cache-Control"),
225                 ngx_http_upstream_process_cache_control, 0,
226                 ngx_http_upstream_copy_multi_header_lines,
227                 offsetof(ngx_http_headers_out_t, cache_control), 1 },
228
229    { ngx_string("Expires"),
230                 ngx_http_upstream_process_expires, 0,
231                 ngx_http_upstream_copy_header_line,
232                 offsetof(ngx_http_headers_out_t, expires), 1 },
233
234    { ngx_string("Accept-Ranges"),
235                 ngx_http_upstream_process_header_line,
236                 offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
237                 ngx_http_upstream_copy_allow_ranges,
238                 offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
239
240    { ngx_string("Connection"),
241                 ngx_http_upstream_process_connection, 0,
242                 ngx_http_upstream_ignore_header_line, 0, 0 },
243
244    { ngx_string("Keep-Alive"),
245                 ngx_http_upstream_ignore_header_line, 0,
246                 ngx_http_upstream_ignore_header_line, 0, 0 },
247
248    { ngx_string("X-Powered-By"),
249                 ngx_http_upstream_ignore_header_line, 0,
250                 ngx_http_upstream_copy_header_line, 0, 0 },
251
252    { ngx_string("X-Accel-Expires"),
253                 ngx_http_upstream_process_accel_expires, 0,
254                 ngx_http_upstream_copy_header_line, 0, 0 },
255
256    { ngx_string("X-Accel-Redirect"),
257                 ngx_http_upstream_process_header_line,
258                 offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
259                 ngx_http_upstream_copy_header_line, 0, 0 },
260
261    { ngx_string("X-Accel-Limit-Rate"),
262                 ngx_http_upstream_process_limit_rate, 0,
263                 ngx_http_upstream_copy_header_line, 0, 0 },
264
265    { ngx_string("X-Accel-Buffering"),
266                 ngx_http_upstream_process_buffering, 0,
267                 ngx_http_upstream_copy_header_line, 0, 0 },
268
269    { ngx_string("X-Accel-Charset"),
270                 ngx_http_upstream_process_charset, 0,
271                 ngx_http_upstream_copy_header_line, 0, 0 },
272
273    { ngx_string("Transfer-Encoding"),
274                 ngx_http_upstream_process_transfer_encoding, 0,
275                 ngx_http_upstream_ignore_header_line, 0, 0 },
276
277#if (NGX_HTTP_GZIP)
278    { ngx_string("Content-Encoding"),
279                 ngx_http_upstream_process_header_line,
280                 offsetof(ngx_http_upstream_headers_in_t, content_encoding),
281                 ngx_http_upstream_copy_content_encoding, 0, 0 },
282#endif
283
284    { ngx_null_string, NULL, 0, NULL, 0, 0 }
285};
286
287
288static ngx_command_t  ngx_http_upstream_commands[] = {
289
290    { ngx_string("upstream"),
291      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
292      ngx_http_upstream,
293      0,
294      0,
295      NULL },
296
297    { ngx_string("server"),
298      NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
299      ngx_http_upstream_server,
300      NGX_HTTP_SRV_CONF_OFFSET,
301      0,
302      NULL },
303
304      ngx_null_command
305};
306
307
308static ngx_http_module_t  ngx_http_upstream_module_ctx = {
309    ngx_http_upstream_add_variables,       /* preconfiguration */
310    NULL,                                  /* postconfiguration */
311
312    ngx_http_upstream_create_main_conf,    /* create main configuration */
313    ngx_http_upstream_init_main_conf,      /* init main configuration */
314
315    NULL,                                  /* create server configuration */
316    NULL,                                  /* merge server configuration */
317
318    NULL,                                  /* create location configuration */
319    NULL                                   /* merge location configuration */
320};
321
322
323ngx_module_t  ngx_http_upstream_module = {
324    NGX_MODULE_V1,
325    &ngx_http_upstream_module_ctx,         /* module context */
326    ngx_http_upstream_commands,            /* module directives */
327    NGX_HTTP_MODULE,                       /* module type */
328    NULL,                                  /* init master */
329    NULL,                                  /* init module */
330    NULL,                                  /* init process */
331    NULL,                                  /* init thread */
332    NULL,                                  /* exit thread */
333    NULL,                                  /* exit process */
334    NULL,                                  /* exit master */
335    NGX_MODULE_V1_PADDING
336};
337
338
339static ngx_http_variable_t  ngx_http_upstream_vars[] = {
340
341    { ngx_string("upstream_addr"), NULL,
342      ngx_http_upstream_addr_variable, 0,
343      NGX_HTTP_VAR_NOCACHEABLE, 0 },
344
345    { ngx_string("upstream_status"), NULL,
346      ngx_http_upstream_status_variable, 0,
347      NGX_HTTP_VAR_NOCACHEABLE, 0 },
348
349    { ngx_string("upstream_response_time"), NULL,
350      ngx_http_upstream_response_time_variable, 0,
351      NGX_HTTP_VAR_NOCACHEABLE, 0 },
352
353    { ngx_string("upstream_response_length"), NULL,
354      ngx_http_upstream_response_length_variable, 0,
355      NGX_HTTP_VAR_NOCACHEABLE, 0 },
356
357#if (NGX_HTTP_CACHE)
358
359    { ngx_string("upstream_cache_status"), NULL,
360      ngx_http_upstream_cache_status, 0,
361      NGX_HTTP_VAR_NOCACHEABLE, 0 },
362
363    { ngx_string("upstream_cache_last_modified"), NULL,
364      ngx_http_upstream_cache_last_modified, 0,
365      NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
366
367#endif
368
369    { ngx_null_string, NULL, NULL, 0, 0, 0 }
370};
371
372
373static ngx_http_upstream_next_t  ngx_http_upstream_next_errors[] = {
374    { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
375    { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
376    { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
377    { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
378    { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 },
379    { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
380    { 0, 0 }
381};
382
383
384ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[] = {
385   { ngx_string("GET"),  NGX_HTTP_GET},
386   { ngx_string("HEAD"), NGX_HTTP_HEAD },
387   { ngx_string("POST"), NGX_HTTP_POST },
388   { ngx_null_string, 0 }
389};
390
391
392ngx_conf_bitmask_t  ngx_http_upstream_ignore_headers_masks[] = {
393    { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT },
394    { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES },
395    { ngx_string("X-Accel-Limit-Rate"), NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE },
396    { ngx_string("X-Accel-Buffering"), NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING },
397    { ngx_string("X-Accel-Charset"), NGX_HTTP_UPSTREAM_IGN_XA_CHARSET },
398    { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
399    { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
400    { ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE },
401    { ngx_null_string, 0 }
402};
403
404
405ngx_int_t
406ngx_http_upstream_create(ngx_http_request_t *r)
407{
408    ngx_http_upstream_t  *u;
409
410    u = r->upstream;
411
412    if (u && u->cleanup) {
413        r->main->count++;
414        ngx_http_upstream_cleanup(r);
415    }
416
417    u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
418    if (u == NULL) {
419        return NGX_ERROR;
420    }
421
422    r->upstream = u;
423
424    u->peer.log = r->connection->log;
425    u->peer.log_error = NGX_ERROR_ERR;
426#if (NGX_THREADS)
427    u->peer.lock = &r->connection->lock;
428#endif
429
430#if (NGX_HTTP_CACHE)
431    r->cache = NULL;
432#endif
433
434    u->headers_in.content_length_n = -1;
435
436    return NGX_OK;
437}
438
439
440void
441ngx_http_upstream_init(ngx_http_request_t *r)
442{
443    ngx_connection_t     *c;
444
445    c = r->connection;
446
447    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
448                   "http init upstream, client timer: %d", c->read->timer_set);
449
450#if (NGX_HTTP_SPDY)
451    if (r->spdy_stream) {
452        ngx_http_upstream_init_request(r);
453        return;
454    }
455#endif
456
457    if (c->read->timer_set) {
458        ngx_del_timer(c->read);
459    }
460
461    if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
462
463        if (!c->write->active) {
464            if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
465                == NGX_ERROR)
466            {
467                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
468                return;
469            }
470        }
471    }
472
473    ngx_http_upstream_init_request(r);
474}
475
476
477static void
478ngx_http_upstream_init_request(ngx_http_request_t *r)
479{
480    ngx_str_t                      *host;
481    ngx_uint_t                      i;
482    ngx_resolver_ctx_t             *ctx, temp;
483    ngx_http_cleanup_t             *cln;
484    ngx_http_upstream_t            *u;
485    ngx_http_core_loc_conf_t       *clcf;
486    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
487    ngx_http_upstream_main_conf_t  *umcf;
488
489    if (r->aio) {
490        return;
491    }
492
493    u = r->upstream;
494
495#if (NGX_HTTP_CACHE)
496
497    if (u->conf->cache) {
498        ngx_int_t  rc;
499
500        rc = ngx_http_upstream_cache(r, u);
501
502        if (rc == NGX_BUSY) {
503            r->write_event_handler = ngx_http_upstream_init_request;
504            return;
505        }
506
507        r->write_event_handler = ngx_http_request_empty_handler;
508
509        if (rc == NGX_DONE) {
510            return;
511        }
512
513        if (rc != NGX_DECLINED) {
514            ngx_http_finalize_request(r, rc);
515            return;
516        }
517    }
518
519#endif
520
521    u->store = (u->conf->store || u->conf->store_lengths);
522
523    if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
524        r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
525        r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
526    }
527
528    if (r->request_body) {
529        u->request_bufs = r->request_body->bufs;
530    }
531
532    if (u->create_request(r) != NGX_OK) {
533        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
534        return;
535    }
536
537    u->peer.local = ngx_http_upstream_get_local(r, u->conf->local);
538
539    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
540
541    u->output.alignment = clcf->directio_alignment;
542    u->output.pool = r->pool;
543    u->output.bufs.num = 1;
544    u->output.bufs.size = clcf->client_body_buffer_size;
545    u->output.output_filter = ngx_chain_writer;
546    u->output.filter_ctx = &u->writer;
547
548    u->writer.pool = r->pool;
549
550    if (r->upstream_states == NULL) {
551
552        r->upstream_states = ngx_array_create(r->pool, 1,
553                                            sizeof(ngx_http_upstream_state_t));
554        if (r->upstream_states == NULL) {
555            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
556            return;
557        }
558
559    } else {
560
561        u->state = ngx_array_push(r->upstream_states);
562        if (u->state == NULL) {
563            ngx_http_upstream_finalize_request(r, u,
564                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
565            return;
566        }
567
568        ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
569    }
570
571    cln = ngx_http_cleanup_add(r, 0);
572    if (cln == NULL) {
573        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
574        return;
575    }
576
577    cln->handler = ngx_http_upstream_cleanup;
578    cln->data = r;
579    u->cleanup = &cln->handler;
580
581    if (u->resolved == NULL) {
582
583        uscf = u->conf->upstream;
584
585    } else {
586
587        if (u->resolved->sockaddr) {
588
589            if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
590                != NGX_OK)
591            {
592                ngx_http_upstream_finalize_request(r, u,
593                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
594                return;
595            }
596
597            ngx_http_upstream_connect(r, u);
598
599            return;
600        }
601
602        host = &u->resolved->host;
603
604        umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
605
606        uscfp = umcf->upstreams.elts;
607
608        for (i = 0; i < umcf->upstreams.nelts; i++) {
609
610            uscf = uscfp[i];
611
612            if (uscf->host.len == host->len
613                && ((uscf->port == 0 && u->resolved->no_port)
614                     || uscf->port == u->resolved->port)
615                && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
616            {
617                goto found;
618            }
619        }
620
621        if (u->resolved->port == 0) {
622            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
623                          "no port in upstream \"%V\"", host);
624            ngx_http_upstream_finalize_request(r, u,
625                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
626            return;
627        }
628
629        temp.name = *host;
630
631        ctx = ngx_resolve_start(clcf->resolver, &temp);
632        if (ctx == NULL) {
633            ngx_http_upstream_finalize_request(r, u,
634                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
635            return;
636        }
637
638        if (ctx == NGX_NO_RESOLVER) {
639            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
640                          "no resolver defined to resolve %V", host);
641
642            ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
643            return;
644        }
645
646        ctx->name = *host;
647        ctx->handler = ngx_http_upstream_resolve_handler;
648        ctx->data = r;
649        ctx->timeout = clcf->resolver_timeout;
650
651        u->resolved->ctx = ctx;
652
653        if (ngx_resolve_name(ctx) != NGX_OK) {
654            u->resolved->ctx = NULL;
655            ngx_http_upstream_finalize_request(r, u,
656                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
657            return;
658        }
659
660        return;
661    }
662
663found:
664
665    if (uscf == NULL) {
666        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
667                      "no upstream configuration");
668        ngx_http_upstream_finalize_request(r, u,
669                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
670        return;
671    }
672
673    if (uscf->peer.init(r, uscf) != NGX_OK) {
674        ngx_http_upstream_finalize_request(r, u,
675                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
676        return;
677    }
678
679    ngx_http_upstream_connect(r, u);
680}
681
682
683#if (NGX_HTTP_CACHE)
684
685static ngx_int_t
686ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
687{
688    ngx_int_t          rc;
689    ngx_http_cache_t  *c;
690
691    c = r->cache;
692
693    if (c == NULL) {
694
695        if (!(r->method & u->conf->cache_methods)) {
696            return NGX_DECLINED;
697        }
698
699        if (r->method & NGX_HTTP_HEAD) {
700            u->method = ngx_http_core_get_method;
701        }
702
703        if (ngx_http_file_cache_new(r) != NGX_OK) {
704            return NGX_ERROR;
705        }
706
707        if (u->create_key(r) != NGX_OK) {
708            return NGX_ERROR;
709        }
710
711        /* TODO: add keys */
712
713        ngx_http_file_cache_create_key(r);
714
715        if (r->cache->header_start + 256 >= u->conf->buffer_size) {
716            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
717                          "%V_buffer_size %uz is not enough for cache key, "
718                          "it should be increased to at least %uz",
719                          &u->conf->module, u->conf->buffer_size,
720                          ngx_align(r->cache->header_start + 256, 1024));
721
722            r->cache = NULL;
723            return NGX_DECLINED;
724        }
725
726        u->cacheable = 1;
727
728        switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {
729
730        case NGX_ERROR:
731            return NGX_ERROR;
732
733        case NGX_DECLINED:
734            u->cache_status = NGX_HTTP_CACHE_BYPASS;
735            return NGX_DECLINED;
736
737        default: /* NGX_OK */
738            break;
739        }
740
741        c = r->cache;
742
743        c->min_uses = u->conf->cache_min_uses;
744        c->body_start = u->conf->buffer_size;
745        c->file_cache = u->conf->cache->data;
746
747        c->lock = u->conf->cache_lock;
748        c->lock_timeout = u->conf->cache_lock_timeout;
749
750        u->cache_status = NGX_HTTP_CACHE_MISS;
751    }
752
753    rc = ngx_http_file_cache_open(r);
754
755    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
756                   "http upstream cache: %i", rc);
757
758    switch (rc) {
759
760    case NGX_HTTP_CACHE_UPDATING:
761
762        if (u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) {
763            u->cache_status = rc;
764            rc = NGX_OK;
765
766        } else {
767            rc = NGX_HTTP_CACHE_STALE;
768        }
769
770        break;
771
772    case NGX_OK:
773        u->cache_status = NGX_HTTP_CACHE_HIT;
774    }
775
776    switch (rc) {
777
778    case NGX_OK:
779
780        rc = ngx_http_upstream_cache_send(r, u);
781
782        if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
783            return rc;
784        }
785
786        break;
787
788    case NGX_HTTP_CACHE_STALE:
789
790        c->valid_sec = 0;
791        u->buffer.start = NULL;
792        u->cache_status = NGX_HTTP_CACHE_EXPIRED;
793
794        break;
795
796    case NGX_DECLINED:
797
798        if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
799            u->buffer.start = NULL;
800
801        } else {
802            u->buffer.pos = u->buffer.start + c->header_start;
803            u->buffer.last = u->buffer.pos;
804        }
805
806        break;
807
808    case NGX_HTTP_CACHE_SCARCE:
809
810        u->cacheable = 0;
811
812        break;
813
814    case NGX_AGAIN:
815
816        return NGX_BUSY;
817
818    case NGX_ERROR:
819
820        return NGX_ERROR;
821
822    default:
823
824        /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
825
826        u->cache_status = NGX_HTTP_CACHE_HIT;
827
828        return rc;
829    }
830
831    r->cached = 0;
832
833    return NGX_DECLINED;
834}
835
836
837static ngx_int_t
838ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
839{
840    ngx_int_t          rc;
841    ngx_http_cache_t  *c;
842
843    r->cached = 1;
844    c = r->cache;
845
846    if (c->header_start == c->body_start) {
847        r->http_version = NGX_HTTP_VERSION_9;
848        return ngx_http_cache_send(r);
849    }
850
851    /* TODO: cache stack */
852
853    u->buffer = *c->buf;
854    u->buffer.pos += c->header_start;
855
856    ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
857    u->headers_in.content_length_n = -1;
858
859    if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
860                      sizeof(ngx_table_elt_t))
861        != NGX_OK)
862    {
863        return NGX_ERROR;
864    }
865
866    rc = u->process_header(r);
867
868    if (rc == NGX_OK) {
869
870        if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
871            return NGX_DONE;
872        }
873
874        return ngx_http_cache_send(r);
875    }
876
877    if (rc == NGX_ERROR) {
878        return NGX_ERROR;
879    }
880
881    /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */
882
883    /* TODO: delete file */
884
885    return rc;
886}
887
888#endif
889
890
891static void
892ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
893{
894    ngx_connection_t              *c;
895    ngx_http_request_t            *r;
896    ngx_http_upstream_t           *u;
897    ngx_http_upstream_resolved_t  *ur;
898
899    r = ctx->data;
900    c = r->connection;
901
902    u = r->upstream;
903    ur = u->resolved;
904
905    if (ctx->state) {
906        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
907                      "%V could not be resolved (%i: %s)",
908                      &ctx->name, ctx->state,
909                      ngx_resolver_strerror(ctx->state));
910
911        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
912        goto failed;
913    }
914
915    ur->naddrs = ctx->naddrs;
916    ur->addrs = ctx->addrs;
917
918#if (NGX_DEBUG)
919    {
920    u_char      text[NGX_SOCKADDR_STRLEN];
921    ngx_str_t   addr;
922    ngx_uint_t  i;
923
924    addr.data = text;
925
926    for (i = 0; i < ctx->naddrs; i++) {
927        addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
928                                 text, NGX_SOCKADDR_STRLEN, 0);
929
930        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
931                       "name was resolved to %V", &addr);
932    }
933    }
934#endif
935
936    if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
937        ngx_http_upstream_finalize_request(r, u,
938                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
939        goto failed;
940    }
941
942    ngx_resolve_name_done(ctx);
943    ur->ctx = NULL;
944
945    ngx_http_upstream_connect(r, u);
946
947failed:
948
949    ngx_http_run_posted_requests(c);
950}
951
952
953static void
954ngx_http_upstream_handler(ngx_event_t *ev)
955{
956    ngx_connection_t     *c;
957    ngx_http_request_t   *r;
958    ngx_http_log_ctx_t   *ctx;
959    ngx_http_upstream_t  *u;
960
961    c = ev->data;
962    r = c->data;
963
964    u = r->upstream;
965    c = r->connection;
966
967    ctx = c->log->data;
968    ctx->current_request = r;
969
970    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
971                   "http upstream request: \"%V?%V\"", &r->uri, &r->args);
972
973    if (ev->write) {
974        u->write_event_handler(r, u);
975
976    } else {
977        u->read_event_handler(r, u);
978    }
979
980    ngx_http_run_posted_requests(c);
981}
982
983
984static void
985ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
986{
987    ngx_http_upstream_check_broken_connection(r, r->connection->read);
988}
989
990
991static void
992ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
993{
994    ngx_http_upstream_check_broken_connection(r, r->connection->write);
995}
996
997
998static void
999ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
1000    ngx_event_t *ev)
1001{
1002    int                  n;
1003    char                 buf[1];
1004    ngx_err_t            err;
1005    ngx_int_t            event;
1006    ngx_connection_t     *c;
1007    ngx_http_upstream_t  *u;
1008
1009    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1010                   "http upstream check client, write event:%d, \"%V\"",
1011                   ev->write, &r->uri);
1012
1013    c = r->connection;
1014    u = r->upstream;
1015
1016    if (c->error) {
1017        if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
1018
1019            event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
1020
1021            if (ngx_del_event(ev, event, 0) != NGX_OK) {
1022                ngx_http_upstream_finalize_request(r, u,
1023                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1024                return;
1025            }
1026        }
1027
1028        if (!u->cacheable) {
1029            ngx_http_upstream_finalize_request(r, u,
1030                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
1031        }
1032
1033        return;
1034    }
1035
1036#if (NGX_HTTP_SPDY)
1037    if (r->spdy_stream) {
1038        return;
1039    }
1040#endif
1041
1042#if (NGX_HAVE_KQUEUE)
1043
1044    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
1045
1046        if (!ev->pending_eof) {
1047            return;
1048        }
1049
1050        ev->eof = 1;
1051        c->error = 1;
1052
1053        if (ev->kq_errno) {
1054            ev->error = 1;
1055        }
1056
1057        if (!u->cacheable && u->peer.connection) {
1058            ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
1059                          "kevent() reported that client prematurely closed "
1060                          "connection, so upstream connection is closed too");
1061            ngx_http_upstream_finalize_request(r, u,
1062                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
1063            return;
1064        }
1065
1066        ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
1067                      "kevent() reported that client prematurely closed "
1068                      "connection");
1069
1070        if (u->peer.connection == NULL) {
1071            ngx_http_upstream_finalize_request(r, u,
1072                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
1073        }
1074
1075        return;
1076    }
1077
1078#endif
1079
1080#if (NGX_HAVE_EPOLLRDHUP)
1081
1082    if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ev->pending_eof) {
1083        socklen_t  len;
1084
1085        ev->eof = 1;
1086        c->error = 1;
1087
1088        err = 0;
1089        len = sizeof(ngx_err_t);
1090
1091        /*
1092         * BSDs and Linux return 0 and set a pending error in err
1093         * Solaris returns -1 and sets errno
1094         */
1095
1096        if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1097            == -1)
1098        {
1099            err = ngx_socket_errno;
1100        }
1101
1102        if (err) {
1103            ev->error = 1;
1104        }
1105
1106        if (!u->cacheable && u->peer.connection) {
1107            ngx_log_error(NGX_LOG_INFO, ev->log, err,
1108                        "epoll_wait() reported that client prematurely closed "
1109                        "connection, so upstream connection is closed too");
1110            ngx_http_upstream_finalize_request(r, u,
1111                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
1112            return;
1113        }
1114
1115        ngx_log_error(NGX_LOG_INFO, ev->log, err,
1116                      "epoll_wait() reported that client prematurely closed "
1117                      "connection");
1118
1119        if (u->peer.connection == NULL) {
1120            ngx_http_upstream_finalize_request(r, u,
1121                                               NGX_HTTP_CLIENT_CLOSED_REQUEST);
1122        }
1123
1124        return;
1125    }
1126
1127#endif
1128
1129    n = recv(c->fd, buf, 1, MSG_PEEK);
1130
1131    err = ngx_socket_errno;
1132
1133    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
1134                   "http upstream recv(): %d", n);
1135
1136    if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
1137        return;
1138    }
1139
1140    if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
1141
1142        event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
1143
1144        if (ngx_del_event(ev, event, 0) != NGX_OK) {
1145            ngx_http_upstream_finalize_request(r, u,
1146                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1147            return;
1148        }
1149    }
1150
1151    if (n > 0) {
1152        return;
1153    }
1154
1155    if (n == -1) {
1156        if (err == NGX_EAGAIN) {
1157            return;
1158        }
1159
1160        ev->error = 1;
1161
1162    } else { /* n == 0 */
1163        err = 0;
1164    }
1165
1166    ev->eof = 1;
1167    c->error = 1;
1168
1169    if (!u->cacheable && u->peer.connection) {
1170        ngx_log_error(NGX_LOG_INFO, ev->log, err,
1171                      "client prematurely closed connection, "
1172                      "so upstream connection is closed too");
1173        ngx_http_upstream_finalize_request(r, u,
1174                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
1175        return;
1176    }
1177
1178    ngx_log_error(NGX_LOG_INFO, ev->log, err,
1179                  "client prematurely closed connection");
1180
1181    if (u->peer.connection == NULL) {
1182        ngx_http_upstream_finalize_request(r, u,
1183                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
1184    }
1185}
1186
1187
1188static void
1189ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
1190{
1191    ngx_int_t          rc;
1192    ngx_time_t        *tp;
1193    ngx_connection_t  *c;
1194
1195    r->connection->log->action = "connecting to upstream";
1196
1197    if (u->state && u->state->response_sec) {
1198        tp = ngx_timeofday();
1199        u->state->response_sec = tp->sec - u->state->response_sec;
1200        u->state->response_msec = tp->msec - u->state->response_msec;
1201    }
1202
1203    u->state = ngx_array_push(r->upstream_states);
1204    if (u->state == NULL) {
1205        ngx_http_upstream_finalize_request(r, u,
1206                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
1207        return;
1208    }
1209
1210    ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
1211
1212    tp = ngx_timeofday();
1213    u->state->response_sec = tp->sec;
1214    u->state->response_msec = tp->msec;
1215
1216    rc = ngx_event_connect_peer(&u->peer);
1217
1218    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1219                   "http upstream connect: %i", rc);
1220
1221    if (rc == NGX_ERROR) {
1222        ngx_http_upstream_finalize_request(r, u,
1223                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
1224        return;
1225    }
1226
1227    u->state->peer = u->peer.name;
1228
1229    if (rc == NGX_BUSY) {
1230        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
1231        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
1232        return;
1233    }
1234
1235    if (rc == NGX_DECLINED) {
1236        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1237        return;
1238    }
1239
1240    /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */
1241
1242    c = u->peer.connection;
1243
1244    c->data = r;
1245
1246    c->write->handler = ngx_http_upstream_handler;
1247    c->read->handler = ngx_http_upstream_handler;
1248
1249    u->write_event_handler = ngx_http_upstream_send_request_handler;
1250    u->read_event_handler = ngx_http_upstream_process_header;
1251
1252    c->sendfile &= r->connection->sendfile;
1253    u->output.sendfile = c->sendfile;
1254
1255    if (c->pool == NULL) {
1256
1257        /* we need separate pool here to be able to cache SSL connections */
1258
1259        c->pool = ngx_create_pool(128, r->connection->log);
1260        if (c->pool == NULL) {
1261            ngx_http_upstream_finalize_request(r, u,
1262                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1263            return;
1264        }
1265    }
1266
1267    c->log = r->connection->log;
1268    c->pool->log = c->log;
1269    c->read->log = c->log;
1270    c->write->log = c->log;
1271
1272    /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
1273
1274    u->writer.out = NULL;
1275    u->writer.last = &u->writer.out;
1276    u->writer.connection = c;
1277    u->writer.limit = 0;
1278
1279    if (u->request_sent) {
1280        if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
1281            ngx_http_upstream_finalize_request(r, u,
1282                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1283            return;
1284        }
1285    }
1286
1287    if (r->request_body
1288        && r->request_body->buf
1289        && r->request_body->temp_file
1290        && r == r->main)
1291    {
1292        /*
1293         * the r->request_body->buf can be reused for one request only,
1294         * the subrequests should allocate their own temporary bufs
1295         */
1296
1297        u->output.free = ngx_alloc_chain_link(r->pool);
1298        if (u->output.free == NULL) {
1299            ngx_http_upstream_finalize_request(r, u,
1300                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1301            return;
1302        }
1303
1304        u->output.free->buf = r->request_body->buf;
1305        u->output.free->next = NULL;
1306        u->output.allocated = 1;
1307
1308        r->request_body->buf->pos = r->request_body->buf->start;
1309        r->request_body->buf->last = r->request_body->buf->start;
1310        r->request_body->buf->tag = u->output.tag;
1311    }
1312
1313    u->request_sent = 0;
1314
1315    if (rc == NGX_AGAIN) {
1316        ngx_add_timer(c->write, u->conf->connect_timeout);
1317        return;
1318    }
1319
1320#if (NGX_HTTP_SSL)
1321
1322    if (u->ssl && c->ssl == NULL) {
1323        ngx_http_upstream_ssl_init_connection(r, u, c);
1324        return;
1325    }
1326
1327#endif
1328
1329    ngx_http_upstream_send_request(r, u);
1330}
1331
1332
1333#if (NGX_HTTP_SSL)
1334
1335static void
1336ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
1337    ngx_http_upstream_t *u, ngx_connection_t *c)
1338{
1339    ngx_int_t   rc;
1340
1341    if (ngx_http_upstream_test_connect(c) != NGX_OK) {
1342        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1343        return;
1344    }
1345
1346    if (ngx_ssl_create_connection(u->conf->ssl, c,
1347                                  NGX_SSL_BUFFER|NGX_SSL_CLIENT)
1348        != NGX_OK)
1349    {
1350        ngx_http_upstream_finalize_request(r, u,
1351                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
1352        return;
1353    }
1354
1355    c->sendfile = 0;
1356    u->output.sendfile = 0;
1357
1358    if (u->conf->ssl_session_reuse) {
1359        if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
1360            ngx_http_upstream_finalize_request(r, u,
1361                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1362            return;
1363        }
1364    }
1365
1366    r->connection->log->action = "SSL handshaking to upstream";
1367
1368    rc = ngx_ssl_handshake(c);
1369
1370    if (rc == NGX_AGAIN) {
1371        c->ssl->handler = ngx_http_upstream_ssl_handshake;
1372        return;
1373    }
1374
1375    ngx_http_upstream_ssl_handshake(c);
1376}
1377
1378
1379static void
1380ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
1381{
1382    ngx_http_request_t   *r;
1383    ngx_http_upstream_t  *u;
1384
1385    r = c->data;
1386    u = r->upstream;
1387
1388    if (c->ssl->handshaked) {
1389
1390        if (u->conf->ssl_session_reuse) {
1391            u->peer.save_session(&u->peer, u->peer.data);
1392        }
1393
1394        c->write->handler = ngx_http_upstream_handler;
1395        c->read->handler = ngx_http_upstream_handler;
1396
1397        c = r->connection;
1398
1399        ngx_http_upstream_send_request(r, u);
1400
1401        ngx_http_run_posted_requests(c);
1402        return;
1403    }
1404
1405    c = r->connection;
1406
1407    ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1408
1409    ngx_http_run_posted_requests(c);
1410}
1411
1412#endif
1413
1414
1415static ngx_int_t
1416ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
1417{
1418    ngx_chain_t  *cl;
1419
1420    if (u->reinit_request(r) != NGX_OK) {
1421        return NGX_ERROR;
1422    }
1423
1424    u->keepalive = 0;
1425    u->upgrade = 0;
1426
1427    ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
1428    u->headers_in.content_length_n = -1;
1429
1430    if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1431                      sizeof(ngx_table_elt_t))
1432        != NGX_OK)
1433    {
1434        return NGX_ERROR;
1435    }
1436
1437    /* reinit the request chain */
1438
1439    for (cl = u->request_bufs; cl; cl = cl->next) {
1440        cl->buf->pos = cl->buf->start;
1441        cl->buf->file_pos = 0;
1442    }
1443
1444    /* reinit the subrequest's ngx_output_chain() context */
1445
1446    if (r->request_body && r->request_body->temp_file
1447        && r != r->main && u->output.buf)
1448    {
1449        u->output.free = ngx_alloc_chain_link(r->pool);
1450        if (u->output.free == NULL) {
1451            return NGX_ERROR;
1452        }
1453
1454        u->output.free->buf = u->output.buf;
1455        u->output.free->next = NULL;
1456
1457        u->output.buf->pos = u->output.buf->start;
1458        u->output.buf->last = u->output.buf->start;
1459    }
1460
1461    u->output.buf = NULL;
1462    u->output.in = NULL;
1463    u->output.busy = NULL;
1464
1465    /* reinit u->buffer */
1466
1467    u->buffer.pos = u->buffer.start;
1468
1469#if (NGX_HTTP_CACHE)
1470
1471    if (r->cache) {
1472        u->buffer.pos += r->cache->header_start;
1473    }
1474
1475#endif
1476
1477    u->buffer.last = u->buffer.pos;
1478
1479    return NGX_OK;
1480}
1481
1482
1483static void
1484ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u)
1485{
1486    ngx_int_t          rc;
1487    ngx_connection_t  *c;
1488
1489    c = u->peer.connection;
1490
1491    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1492                   "http upstream send request");
1493
1494    if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1495        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1496        return;
1497    }
1498
1499    c->log->action = "sending request to upstream";
1500
1501    rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs);
1502
1503    u->request_sent = 1;
1504
1505    if (rc == NGX_ERROR) {
1506        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1507        return;
1508    }
1509
1510    if (c->write->timer_set) {
1511        ngx_del_timer(c->write);
1512    }
1513
1514    if (rc == NGX_AGAIN) {
1515        ngx_add_timer(c->write, u->conf->send_timeout);
1516
1517        if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
1518            ngx_http_upstream_finalize_request(r, u,
1519                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1520            return;
1521        }
1522
1523        return;
1524    }
1525
1526    /* rc == NGX_OK */
1527
1528    if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
1529        if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1530            ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1531                          ngx_tcp_push_n " failed");
1532            ngx_http_upstream_finalize_request(r, u,
1533                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1534            return;
1535        }
1536
1537        c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
1538    }
1539
1540    ngx_add_timer(c->read, u->conf->read_timeout);
1541
1542    if (c->read->ready) {
1543        ngx_http_upstream_process_header(r, u);
1544        return;
1545    }
1546
1547    u->write_event_handler = ngx_http_upstream_dummy_handler;
1548
1549    if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1550        ngx_http_upstream_finalize_request(r, u,
1551                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
1552        return;
1553    }
1554}
1555
1556
1557static void
1558ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
1559    ngx_http_upstream_t *u)
1560{
1561    ngx_connection_t  *c;
1562
1563    c = u->peer.connection;
1564
1565    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1566                   "http upstream send request handler");
1567
1568    if (c->write->timedout) {
1569        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1570        return;
1571    }
1572
1573#if (NGX_HTTP_SSL)
1574
1575    if (u->ssl && c->ssl == NULL) {
1576        ngx_http_upstream_ssl_init_connection(r, u, c);
1577        return;
1578    }
1579
1580#endif
1581
1582    if (u->header_sent) {
1583        u->write_event_handler = ngx_http_upstream_dummy_handler;
1584
1585        (void) ngx_handle_write_event(c->write, 0);
1586
1587        return;
1588    }
1589
1590    ngx_http_upstream_send_request(r, u);
1591}
1592
1593
1594static void
1595ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
1596{
1597    ssize_t            n;
1598    ngx_int_t          rc;
1599    ngx_connection_t  *c;
1600
1601    c = u->peer.connection;
1602
1603    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1604                   "http upstream process header");
1605
1606    c->log->action = "reading response header from upstream";
1607
1608    if (c->read->timedout) {
1609        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1610        return;
1611    }
1612
1613    if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1614        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1615        return;
1616    }
1617
1618    if (u->buffer.start == NULL) {
1619        u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
1620        if (u->buffer.start == NULL) {
1621            ngx_http_upstream_finalize_request(r, u,
1622                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1623            return;
1624        }
1625
1626        u->buffer.pos = u->buffer.start;
1627        u->buffer.last = u->buffer.start;
1628        u->buffer.end = u->buffer.start + u->conf->buffer_size;
1629        u->buffer.temporary = 1;
1630
1631        u->buffer.tag = u->output.tag;
1632
1633        if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1634                          sizeof(ngx_table_elt_t))
1635            != NGX_OK)
1636        {
1637            ngx_http_upstream_finalize_request(r, u,
1638                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1639            return;
1640        }
1641
1642#if (NGX_HTTP_CACHE)
1643
1644        if (r->cache) {
1645            u->buffer.pos += r->cache->header_start;
1646            u->buffer.last = u->buffer.pos;
1647        }
1648#endif
1649    }
1650
1651    for ( ;; ) {
1652
1653        n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
1654
1655        if (n == NGX_AGAIN) {
1656#if 0
1657            ngx_add_timer(rev, u->read_timeout);
1658#endif
1659
1660            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1661                ngx_http_upstream_finalize_request(r, u,
1662                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1663                return;
1664            }
1665
1666            return;
1667        }
1668
1669        if (n == 0) {
1670            ngx_log_error(NGX_LOG_ERR, c->log, 0,
1671                          "upstream prematurely closed connection");
1672        }
1673
1674        if (n == NGX_ERROR || n == 0) {
1675            ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1676            return;
1677        }
1678
1679        u->buffer.last += n;
1680
1681#if 0
1682        u->valid_header_in = 0;
1683
1684        u->peer.cached = 0;
1685#endif
1686
1687        rc = u->process_header(r);
1688
1689        if (rc == NGX_AGAIN) {
1690
1691            if (u->buffer.last == u->buffer.end) {
1692                ngx_log_error(NGX_LOG_ERR, c->log, 0,
1693                              "upstream sent too big header");
1694
1695                ngx_http_upstream_next(r, u,
1696                                       NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1697                return;
1698            }
1699
1700            continue;
1701        }
1702
1703        break;
1704    }
1705
1706    if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
1707        ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
1708        return;
1709    }
1710
1711    if (rc == NGX_ERROR) {
1712        ngx_http_upstream_finalize_request(r, u,
1713                                           NGX_HTTP_INTERNAL_SERVER_ERROR);
1714        return;
1715    }
1716
1717    /* rc == NGX_OK */
1718
1719    if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) {
1720
1721        if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
1722            return;
1723        }
1724
1725        if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
1726            return;
1727        }
1728    }
1729
1730    if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
1731        return;
1732    }
1733
1734    if (!r->subrequest_in_memory) {
1735        ngx_http_upstream_send_response(r, u);
1736        return;
1737    }
1738
1739    /* subrequest content in memory */
1740
1741    if (u->input_filter == NULL) {
1742        u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
1743        u->input_filter = ngx_http_upstream_non_buffered_filter;
1744        u->input_filter_ctx = r;
1745    }
1746
1747    if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
1748        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1749        return;
1750    }
1751
1752    n = u->buffer.last - u->buffer.pos;
1753
1754    if (n) {
1755        u->buffer.last = u->buffer.pos;
1756
1757        u->state->response_length += n;
1758
1759        if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
1760            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
1761            return;
1762        }
1763    }
1764
1765    if (u->length == 0) {
1766        ngx_http_upstream_finalize_request(r, u, 0);
1767        return;
1768    }
1769
1770    u->read_event_handler = ngx_http_upstream_process_body_in_memory;
1771
1772    ngx_http_upstream_process_body_in_memory(r, u);
1773}
1774
1775
1776static ngx_int_t
1777ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
1778{
1779    ngx_uint_t                 status;
1780    ngx_http_upstream_next_t  *un;
1781
1782    status = u->headers_in.status_n;
1783
1784    for (un = ngx_http_upstream_next_errors; un->status; un++) {
1785
1786        if (status != un->status) {
1787            continue;
1788        }
1789
1790        if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
1791            ngx_http_upstream_next(r, u, un->mask);
1792            return NGX_OK;
1793        }
1794
1795#if (NGX_HTTP_CACHE)
1796
1797        if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
1798            && (u->conf->cache_use_stale & un->mask))
1799        {
1800            ngx_int_t  rc;
1801
1802            rc = u->reinit_request(r);
1803
1804            if (rc == NGX_OK) {
1805                u->cache_status = NGX_HTTP_CACHE_STALE;
1806                rc = ngx_http_upstream_cache_send(r, u);
1807            }
1808
1809            ngx_http_upstream_finalize_request(r, u, rc);
1810            return NGX_OK;
1811        }
1812
1813#endif
1814    }
1815
1816#if (NGX_HTTP_CACHE)
1817
1818    if (status == NGX_HTTP_NOT_MODIFIED
1819        && u->cache_status == NGX_HTTP_CACHE_EXPIRED
1820        && u->conf->cache_revalidate)
1821    {
1822        time_t     now, valid;
1823        ngx_int_t  rc;
1824
1825        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1826                       "http upstream not modified");
1827
1828        now = ngx_time();
1829        valid = r->cache->valid_sec;
1830
1831        rc = u->reinit_request(r);
1832
1833        if (rc != NGX_OK) {
1834            ngx_http_upstream_finalize_request(r, u, rc);
1835            return NGX_OK;
1836        }
1837
1838        u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
1839        rc = ngx_http_upstream_cache_send(r, u);
1840
1841        if (valid == 0) {
1842            valid = r->cache->valid_sec;
1843        }
1844
1845        if (valid == 0) {
1846            valid = ngx_http_file_cache_valid(u->conf->cache_valid,
1847                                              u->headers_in.status_n);
1848            if (valid) {
1849                valid = now + valid;
1850            }
1851        }
1852
1853        if (valid) {
1854            r->cache->valid_sec = valid;
1855            r->cache->date = now;
1856
1857            ngx_http_file_cache_update_header(r);
1858        }
1859
1860        ngx_http_upstream_finalize_request(r, u, rc);
1861        return NGX_OK;
1862    }
1863
1864#endif
1865
1866    return NGX_DECLINED;
1867}
1868
1869
1870static ngx_int_t
1871ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
1872    ngx_http_upstream_t *u)
1873{
1874    ngx_int_t                  status;
1875    ngx_uint_t                 i;
1876    ngx_table_elt_t           *h;
1877    ngx_http_err_page_t       *err_page;
1878    ngx_http_core_loc_conf_t  *clcf;
1879
1880    status = u->headers_in.status_n;
1881
1882    if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
1883        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
1884        return NGX_OK;
1885    }
1886
1887    if (!u->conf->intercept_errors) {
1888        return NGX_DECLINED;
1889    }
1890
1891    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1892
1893    if (clcf->error_pages == NULL) {
1894        return NGX_DECLINED;
1895    }
1896
1897    err_page = clcf->error_pages->elts;
1898    for (i = 0; i < clcf->error_pages->nelts; i++) {
1899
1900        if (err_page[i].status == status) {
1901
1902            if (status == NGX_HTTP_UNAUTHORIZED
1903                && u->headers_in.www_authenticate)
1904            {
1905                h = ngx_list_push(&r->headers_out.headers);
1906
1907                if (h == NULL) {
1908                    ngx_http_upstream_finalize_request(r, u,
1909                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
1910                    return NGX_OK;
1911                }
1912
1913                *h = *u->headers_in.www_authenticate;
1914
1915                r->headers_out.www_authenticate = h;
1916            }
1917
1918#if (NGX_HTTP_CACHE)
1919
1920            if (r->cache) {
1921                time_t  valid;
1922
1923                valid = ngx_http_file_cache_valid(u->conf->cache_valid, status);
1924
1925                if (valid) {
1926                    r->cache->valid_sec = ngx_time() + valid;
1927                    r->cache->error = status;
1928                }
1929
1930                ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
1931            }
1932#endif
1933            ngx_http_upstream_finalize_request(r, u, status);
1934
1935            return NGX_OK;
1936        }
1937    }
1938
1939    return NGX_DECLINED;
1940}
1941
1942
1943static ngx_int_t
1944ngx_http_upstream_test_connect(ngx_connection_t *c)
1945{
1946    int        err;
1947    socklen_t  len;
1948
1949#if (NGX_HAVE_KQUEUE)
1950
1951    if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
1952        if (c->write->pending_eof || c->read->pending_eof) {
1953            if (c->write->pending_eof) {
1954                err = c->write->kq_errno;
1955
1956            } else {
1957                err = c->read->kq_errno;
1958            }
1959
1960            c->log->action = "connecting to upstream";
1961            (void) ngx_connection_error(c, err,
1962                                    "kevent() reported that connect() failed");
1963            return NGX_ERROR;
1964        }
1965
1966    } else
1967#endif
1968    {
1969        err = 0;
1970        len = sizeof(int);
1971
1972        /*
1973         * BSDs and Linux return 0 and set a pending error in err
1974         * Solaris returns -1 and sets errno
1975         */
1976
1977        if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1978            == -1)
1979        {
1980            err = ngx_socket_errno;
1981        }
1982
1983        if (err) {
1984            c->log->action = "connecting to upstream";
1985            (void) ngx_connection_error(c, err, "connect() failed");
1986            return NGX_ERROR;
1987        }
1988    }
1989
1990    return NGX_OK;
1991}
1992
1993
1994static ngx_int_t
1995ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
1996{
1997    ngx_str_t                       uri, args;
1998    ngx_uint_t                      i, flags;
1999    ngx_list_part_t                *part;
2000    ngx_table_elt_t                *h;
2001    ngx_http_upstream_header_t     *hh;
2002    ngx_http_upstream_main_conf_t  *umcf;
2003
2004    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
2005
2006    if (u->headers_in.x_accel_redirect
2007        && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
2008    {
2009        ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
2010
2011        part = &u->headers_in.headers.part;
2012        h = part->elts;
2013
2014        for (i = 0; /* void */; i++) {
2015
2016            if (i >= part->nelts) {
2017                if (part->next == NULL) {
2018                    break;
2019                }
2020
2021                part = part->next;
2022                h = part->elts;
2023                i = 0;
2024            }
2025
2026            hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2027                               h[i].lowcase_key, h[i].key.len);
2028
2029            if (hh && hh->redirect) {
2030                if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
2031                    ngx_http_finalize_request(r,
2032                                              NGX_HTTP_INTERNAL_SERVER_ERROR);
2033                    return NGX_DONE;
2034                }
2035            }
2036        }
2037
2038        uri = u->headers_in.x_accel_redirect->value;
2039        ngx_str_null(&args);
2040        flags = NGX_HTTP_LOG_UNSAFE;
2041
2042        if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
2043            ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
2044            return NGX_DONE;
2045        }
2046
2047        if (r->method != NGX_HTTP_HEAD) {
2048            r->method = NGX_HTTP_GET;
2049        }
2050
2051        ngx_http_internal_redirect(r, &uri, &args);
2052        ngx_http_finalize_request(r, NGX_DONE);
2053        return NGX_DONE;
2054    }
2055
2056    part = &u->headers_in.headers.part;
2057    h = part->elts;
2058
2059    for (i = 0; /* void */; i++) {
2060
2061        if (i >= part->nelts) {
2062            if (part->next == NULL) {
2063                break;
2064            }
2065
2066            part = part->next;
2067            h = part->elts;
2068            i = 0;
2069        }
2070
2071        if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
2072                          h[i].lowcase_key, h[i].key.len))
2073        {
2074            continue;
2075        }
2076
2077        hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2078                           h[i].lowcase_key, h[i].key.len);
2079
2080        if (hh) {
2081            if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
2082                ngx_http_upstream_finalize_request(r, u,
2083                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
2084                return NGX_DONE;
2085            }
2086
2087            continue;
2088        }
2089
2090        if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
2091            ngx_http_upstream_finalize_request(r, u,
2092                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
2093            return NGX_DONE;
2094        }
2095    }
2096
2097    if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
2098        r->headers_out.server->hash = 0;
2099    }
2100
2101    if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
2102        r->headers_out.date->hash = 0;
2103    }
2104
2105    r->headers_out.status = u->headers_in.status_n;
2106    r->headers_out.status_line = u->headers_in.status_line;
2107
2108    r->headers_out.content_length_n = u->headers_in.content_length_n;
2109
2110    u->length = -1;
2111
2112    return NGX_OK;
2113}
2114
2115
2116static void
2117ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
2118    ngx_http_upstream_t *u)
2119{
2120    size_t             size;
2121    ssize_t            n;
2122    ngx_buf_t         *b;
2123    ngx_event_t       *rev;
2124    ngx_connection_t  *c;
2125
2126    c = u->peer.connection;
2127    rev = c->read;
2128
2129    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2130                   "http upstream process body on memory");
2131
2132    if (rev->timedout) {
2133        ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2134        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
2135        return;
2136    }
2137
2138    b = &u->buffer;
2139
2140    for ( ;; ) {
2141
2142        size = b->end - b->last;
2143
2144        if (size == 0) {
2145            ngx_log_error(NGX_LOG_ALERT, c->log, 0,
2146                          "upstream buffer is too small to read response");
2147            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2148            return;
2149        }
2150
2151        n = c->recv(c, b->last, size);
2152
2153        if (n == NGX_AGAIN) {
2154            break;
2155        }
2156
2157        if (n == 0 || n == NGX_ERROR) {
2158            ngx_http_upstream_finalize_request(r, u, n);
2159            return;
2160        }
2161
2162        u->state->response_length += n;
2163
2164        if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2165            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2166            return;
2167        }
2168
2169        if (!rev->ready) {
2170            break;
2171        }
2172    }
2173
2174    if (u->length == 0) {
2175        ngx_http_upstream_finalize_request(r, u, 0);
2176        return;
2177    }
2178
2179    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
2180        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2181        return;
2182    }
2183
2184    if (rev->active) {
2185        ngx_add_timer(rev, u->conf->read_timeout);
2186
2187    } else if (rev->timer_set) {
2188        ngx_del_timer(rev);
2189    }
2190}
2191
2192
2193static void
2194ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
2195{
2196    int                        tcp_nodelay;
2197    ssize_t                    n;
2198    ngx_int_t                  rc;
2199    ngx_event_pipe_t          *p;
2200    ngx_connection_t          *c;
2201    ngx_http_core_loc_conf_t  *clcf;
2202
2203    rc = ngx_http_send_header(r);
2204
2205    if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
2206        ngx_http_upstream_finalize_request(r, u, rc);
2207        return;
2208    }
2209
2210    u->header_sent = 1;
2211
2212    if (u->upgrade) {
2213        ngx_http_upstream_upgrade(r, u);
2214        return;
2215    }
2216
2217    c = r->connection;
2218
2219    if (r->header_only) {
2220
2221        if (u->cacheable || u->store) {
2222
2223            if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
2224                ngx_connection_error(c, ngx_socket_errno,
2225                                     ngx_shutdown_socket_n " failed");
2226            }
2227
2228            r->read_event_handler = ngx_http_request_empty_handler;
2229            r->write_event_handler = ngx_http_request_empty_handler;
2230            c->error = 1;
2231
2232        } else {
2233            ngx_http_upstream_finalize_request(r, u, rc);
2234            return;
2235        }
2236    }
2237
2238    if (r->request_body && r->request_body->temp_file) {
2239        ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
2240        r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
2241    }
2242
2243    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2244
2245    if (!u->buffering) {
2246
2247        if (u->input_filter == NULL) {
2248            u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
2249            u->input_filter = ngx_http_upstream_non_buffered_filter;
2250            u->input_filter_ctx = r;
2251        }
2252
2253        u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
2254        r->write_event_handler =
2255                             ngx_http_upstream_process_non_buffered_downstream;
2256
2257        r->limit_rate = 0;
2258
2259        if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
2260            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2261            return;
2262        }
2263
2264        if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
2265            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
2266
2267            tcp_nodelay = 1;
2268
2269            if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
2270                               (const void *) &tcp_nodelay, sizeof(int)) == -1)
2271            {
2272                ngx_connection_error(c, ngx_socket_errno,
2273                                     "setsockopt(TCP_NODELAY) failed");
2274                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2275                return;
2276            }
2277
2278            c->tcp_nodelay = NGX_TCP_NODELAY_SET;
2279        }
2280
2281        n = u->buffer.last - u->buffer.pos;
2282
2283        if (n) {
2284            u->buffer.last = u->buffer.pos;
2285
2286            u->state->response_length += n;
2287
2288            if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2289                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2290                return;
2291            }
2292
2293            ngx_http_upstream_process_non_buffered_downstream(r);
2294
2295        } else {
2296            u->buffer.pos = u->buffer.start;
2297            u->buffer.last = u->buffer.start;
2298
2299            if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
2300                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2301                return;
2302            }
2303
2304            if (u->peer.connection->read->ready || u->length == 0) {
2305                ngx_http_upstream_process_non_buffered_upstream(r, u);
2306            }
2307        }
2308
2309        return;
2310    }
2311
2312    /* TODO: preallocate event_pipe bufs, look "Content-Length" */
2313
2314#if (NGX_HTTP_CACHE)
2315
2316    if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
2317        ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
2318        r->cache->file.fd = NGX_INVALID_FILE;
2319    }
2320
2321    switch (ngx_http_test_predicates(r, u->conf->no_cache)) {
2322
2323    case NGX_ERROR:
2324        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2325        return;
2326
2327    case NGX_DECLINED:
2328        u->cacheable = 0;
2329        break;
2330
2331    default: /* NGX_OK */
2332
2333        if (u->cache_status == NGX_HTTP_CACHE_BYPASS) {
2334
2335            r->cache->min_uses = u->conf->cache_min_uses;
2336            r->cache->body_start = u->conf->buffer_size;
2337            r->cache->file_cache = u->conf->cache->data;
2338
2339            if (ngx_http_file_cache_create(r) != NGX_OK) {
2340                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2341                return;
2342            }
2343        }
2344
2345        break;
2346    }
2347
2348    if (u->cacheable) {
2349        time_t  now, valid;
2350
2351        now = ngx_time();
2352
2353        valid = r->cache->valid_sec;
2354
2355        if (valid == 0) {
2356            valid = ngx_http_file_cache_valid(u->conf->cache_valid,
2357                                              u->headers_in.status_n);
2358            if (valid) {
2359                r->cache->valid_sec = now + valid;
2360            }
2361        }
2362
2363        if (valid) {
2364            r->cache->last_modified = r->headers_out.last_modified_time;
2365            r->cache->date = now;
2366            r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
2367
2368            ngx_http_file_cache_set_header(r, u->buffer.start);
2369
2370        } else {
2371            u->cacheable = 0;
2372            r->headers_out.last_modified_time = -1;
2373        }
2374    }
2375
2376    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
2377                   "http cacheable: %d", u->cacheable);
2378
2379    if (u->cacheable == 0 && r->cache) {
2380        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
2381    }
2382
2383#endif
2384
2385    p = u->pipe;
2386
2387    p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter;
2388    p->output_ctx = r;
2389    p->tag = u->output.tag;
2390    p->bufs = u->conf->bufs;
2391    p->busy_size = u->conf->busy_buffers_size;
2392    p->upstream = u->peer.connection;
2393    p->downstream = c;
2394    p->pool = r->pool;
2395    p->log = c->log;
2396
2397    p->cacheable = u->cacheable || u->store;
2398
2399    p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
2400    if (p->temp_file == NULL) {
2401        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2402        return;
2403    }
2404
2405    p->temp_file->file.fd = NGX_INVALID_FILE;
2406    p->temp_file->file.log = c->log;
2407    p->temp_file->path = u->conf->temp_path;
2408    p->temp_file->pool = r->pool;
2409
2410    if (p->cacheable) {
2411        p->temp_file->persistent = 1;
2412
2413    } else {
2414        p->temp_file->log_level = NGX_LOG_WARN;
2415        p->temp_file->warn = "an upstream response is buffered "
2416                             "to a temporary file";
2417    }
2418
2419    p->max_temp_file_size = u->conf->max_temp_file_size;
2420    p->temp_file_write_size = u->conf->temp_file_write_size;
2421
2422    p->preread_bufs = ngx_alloc_chain_link(r->pool);
2423    if (p->preread_bufs == NULL) {
2424        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2425        return;
2426    }
2427
2428    p->preread_bufs->buf = &u->buffer;
2429    p->preread_bufs->next = NULL;
2430    u->buffer.recycled = 1;
2431
2432    p->preread_size = u->buffer.last - u->buffer.pos;
2433
2434    if (u->cacheable) {
2435
2436        p->buf_to_file = ngx_calloc_buf(r->pool);
2437        if (p->buf_to_file == NULL) {
2438            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2439            return;
2440        }
2441
2442        p->buf_to_file->start = u->buffer.start;
2443        p->buf_to_file->pos = u->buffer.start;
2444        p->buf_to_file->last = u->buffer.pos;
2445        p->buf_to_file->temporary = 1;
2446    }
2447
2448    if (ngx_event_flags & NGX_USE_AIO_EVENT) {
2449        /* the posted aio operation may corrupt a shadow buffer */
2450        p->single_buf = 1;
2451    }
2452
2453    /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
2454    p->free_bufs = 1;
2455
2456    /*
2457     * event_pipe would do u->buffer.last += p->preread_size
2458     * as though these bytes were read
2459     */
2460    u->buffer.last = u->buffer.pos;
2461
2462    if (u->conf->cyclic_temp_file) {
2463
2464        /*
2465         * we need to disable the use of sendfile() if we use cyclic temp file
2466         * because the writing a new data may interfere with sendfile()
2467         * that uses the same kernel file pages (at least on FreeBSD)
2468         */
2469
2470        p->cyclic_temp_file = 1;
2471        c->sendfile = 0;
2472
2473    } else {
2474        p->cyclic_temp_file = 0;
2475    }
2476
2477    p->read_timeout = u->conf->read_timeout;
2478    p->send_timeout = clcf->send_timeout;
2479    p->send_lowat = clcf->send_lowat;
2480
2481    p->length = -1;
2482
2483    if (u->input_filter_init
2484        && u->input_filter_init(p->input_ctx) != NGX_OK)
2485    {
2486        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2487        return;
2488    }
2489
2490    u->read_event_handler = ngx_http_upstream_process_upstream;
2491    r->write_event_handler = ngx_http_upstream_process_downstream;
2492
2493    ngx_http_upstream_process_upstream(r, u);
2494}
2495
2496
2497static void
2498ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
2499{
2500    int                        tcp_nodelay;
2501    ngx_connection_t          *c;
2502    ngx_http_core_loc_conf_t  *clcf;
2503
2504    c = r->connection;
2505    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2506
2507    /* TODO: prevent upgrade if not requested or not possible */
2508
2509    r->keepalive = 0;
2510    c->log->action = "proxying upgraded connection";
2511
2512    u->read_event_handler = ngx_http_upstream_upgraded_read_upstream;
2513    u->write_event_handler = ngx_http_upstream_upgraded_write_upstream;
2514    r->read_event_handler = ngx_http_upstream_upgraded_read_downstream;
2515    r->write_event_handler = ngx_http_upstream_upgraded_write_downstream;
2516
2517    if (clcf->tcp_nodelay) {
2518        tcp_nodelay = 1;
2519
2520        if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
2521            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
2522
2523            if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
2524                           (const void *) &tcp_nodelay, sizeof(int)) == -1)
2525            {
2526                ngx_connection_error(c, ngx_socket_errno,
2527                                     "setsockopt(TCP_NODELAY) failed");
2528                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2529                return;
2530            }
2531
2532            c->tcp_nodelay = NGX_TCP_NODELAY_SET;
2533        }
2534
2535        if (u->peer.connection->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
2536            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->peer.connection->log, 0,
2537                           "tcp_nodelay");
2538
2539            if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY,
2540                           (const void *) &tcp_nodelay, sizeof(int)) == -1)
2541            {
2542                ngx_connection_error(u->peer.connection, ngx_socket_errno,
2543                                     "setsockopt(TCP_NODELAY) failed");
2544                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2545                return;
2546            }
2547
2548            u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET;
2549        }
2550    }
2551
2552    if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
2553        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2554        return;
2555    }
2556
2557    if (u->peer.connection->read->ready
2558        || u->buffer.pos != u->buffer.last)
2559    {
2560        ngx_post_event(c->read, &ngx_posted_events);
2561        ngx_http_upstream_process_upgraded(r, 1, 1);
2562        return;
2563    }
2564
2565    ngx_http_upstream_process_upgraded(r, 0, 1);
2566}
2567
2568
2569static void
2570ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r)
2571{
2572    ngx_http_upstream_process_upgraded(r, 0, 0);
2573}
2574
2575
2576static void
2577ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r)
2578{
2579    ngx_http_upstream_process_upgraded(r, 1, 1);
2580}
2581
2582
2583static void
2584ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
2585    ngx_http_upstream_t *u)
2586{
2587    ngx_http_upstream_process_upgraded(r, 1, 0);
2588}
2589
2590
2591static void
2592ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
2593    ngx_http_upstream_t *u)
2594{
2595    ngx_http_upstream_process_upgraded(r, 0, 1);
2596}
2597
2598
2599static void
2600ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
2601    ngx_uint_t from_upstream, ngx_uint_t do_write)
2602{
2603    size_t                     size;
2604    ssize_t                    n;
2605    ngx_buf_t                 *b;
2606    ngx_connection_t          *c, *downstream, *upstream, *dst, *src;
2607    ngx_http_upstream_t       *u;
2608    ngx_http_core_loc_conf_t  *clcf;
2609
2610    c = r->connection;
2611    u = r->upstream;
2612
2613    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
2614                   "http upstream process upgraded, fu:%ui", from_upstream);
2615
2616    downstream = c;
2617    upstream = u->peer.connection;
2618
2619    if (downstream->write->timedout) {
2620        c->timedout = 1;
2621        ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2622        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
2623        return;
2624    }
2625
2626    if (upstream->read->timedout || upstream->write->timedout) {
2627        ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2628        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
2629        return;
2630    }
2631
2632    if (from_upstream) {
2633        src = upstream;
2634        dst = downstream;
2635        b = &u->buffer;
2636
2637    } else {
2638        src = downstream;
2639        dst = upstream;
2640        b = &u->from_client;
2641
2642        if (r->header_in->last > r->header_in->pos) {
2643            b = r->header_in;
2644            b->end = b->last;
2645            do_write = 1;
2646        }
2647
2648        if (b->start == NULL) {
2649            b->start = ngx_palloc(r->pool, u->conf->buffer_size);
2650            if (b->start == NULL) {
2651                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2652                return;
2653            }
2654
2655            b->pos = b->start;
2656            b->last = b->start;
2657            b->end = b->start + u->conf->buffer_size;
2658            b->temporary = 1;
2659            b->tag = u->output.tag;
2660        }
2661    }
2662
2663    for ( ;; ) {
2664
2665        if (do_write) {
2666
2667            size = b->last - b->pos;
2668
2669            if (size && dst->write->ready) {
2670
2671                n = dst->send(dst, b->pos, size);
2672
2673                if (n == NGX_ERROR) {
2674                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2675                    return;
2676                }
2677
2678                if (n > 0) {
2679                    b->pos += n;
2680
2681                    if (b->pos == b->last) {
2682                        b->pos = b->start;
2683                        b->last = b->start;
2684                    }
2685                }
2686            }
2687        }
2688
2689        size = b->end - b->last;
2690
2691        if (size && src->read->ready) {
2692
2693            n = src->recv(src, b->last, size);
2694
2695            if (n == NGX_AGAIN || n == 0) {
2696                break;
2697            }
2698
2699            if (n > 0) {
2700                do_write = 1;
2701                b->last += n;
2702
2703                continue;
2704            }
2705
2706            if (n == NGX_ERROR) {
2707                src->read->eof = 1;
2708            }
2709        }
2710
2711        break;
2712    }
2713
2714    if ((upstream->read->eof && u->buffer.pos == u->buffer.last)
2715        || (downstream->read->eof && u->from_client.pos == u->from_client.last)
2716        || (downstream->read->eof && upstream->read->eof))
2717    {
2718        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2719                       "http upstream upgraded done");
2720        ngx_http_upstream_finalize_request(r, u, 0);
2721        return;
2722    }
2723
2724    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2725
2726    if (ngx_handle_write_event(upstream->write, u->conf->send_lowat)
2727        != NGX_OK)
2728    {
2729        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2730        return;
2731    }
2732
2733    if (upstream->write->active && !upstream->write->ready) {
2734        ngx_add_timer(upstream->write, u->conf->send_timeout);
2735
2736    } else if (upstream->write->timer_set) {
2737        ngx_del_timer(upstream->write);
2738    }
2739
2740    if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
2741        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2742        return;
2743    }
2744
2745    if (upstream->read->active && !upstream->read->ready) {
2746        ngx_add_timer(upstream->read, u->conf->read_timeout);
2747
2748    } else if (upstream->read->timer_set) {
2749        ngx_del_timer(upstream->read);
2750    }
2751
2752    if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
2753        != NGX_OK)
2754    {
2755        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2756        return;
2757    }
2758
2759    if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) {
2760        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2761        return;
2762    }
2763
2764    if (downstream->write->active && !downstream->write->ready) {
2765        ngx_add_timer(downstream->write, clcf->send_timeout);
2766
2767    } else if (downstream->write->timer_set) {
2768        ngx_del_timer(downstream->write);
2769    }
2770}
2771
2772
2773static void
2774ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
2775{
2776    ngx_event_t          *wev;
2777    ngx_connection_t     *c;
2778    ngx_http_upstream_t  *u;
2779
2780    c = r->connection;
2781    u = r->upstream;
2782    wev = c->write;
2783
2784    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2785                   "http upstream process non buffered downstream");
2786
2787    c->log->action = "sending to client";
2788
2789    if (wev->timedout) {
2790        c->timedout = 1;
2791        ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
2792        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
2793        return;
2794    }
2795
2796    ngx_http_upstream_process_non_buffered_request(r, 1);
2797}
2798
2799
2800static void
2801ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
2802    ngx_http_upstream_t *u)
2803{
2804    ngx_connection_t  *c;
2805
2806    c = u->peer.connection;
2807
2808    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2809                   "http upstream process non buffered upstream");
2810
2811    c->log->action = "reading upstream";
2812
2813    if (c->read->timedout) {
2814        ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
2815        ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
2816        return;
2817    }
2818
2819    ngx_http_upstream_process_non_buffered_request(r, 0);
2820}
2821
2822
2823static void
2824ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
2825    ngx_uint_t do_write)
2826{
2827    size_t                     size;
2828    ssize_t                    n;
2829    ngx_buf_t                 *b;
2830    ngx_int_t                  rc;
2831    ngx_connection_t          *downstream, *upstream;
2832    ngx_http_upstream_t       *u;
2833    ngx_http_core_loc_conf_t  *clcf;
2834
2835    u = r->upstream;
2836    downstream = r->connection;
2837    upstream = u->peer.connection;
2838
2839    b = &u->buffer;
2840
2841    do_write = do_write || u->length == 0;
2842
2843    for ( ;; ) {
2844
2845        if (do_write) {
2846
2847            if (u->out_bufs || u->busy_bufs) {
2848                rc = ngx_http_output_filter(r, u->out_bufs);
2849
2850                if (rc == NGX_ERROR) {
2851                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2852                    return;
2853                }
2854
2855                ngx_chain_update_chains(r->pool, &u->free_bufs, &u->busy_bufs,
2856                                        &u->out_bufs, u->output.tag);
2857            }
2858
2859            if (u->busy_bufs == NULL) {
2860
2861                if (u->length == 0
2862                    || (upstream->read->eof && u->length == -1))
2863                {
2864                    ngx_http_upstream_finalize_request(r, u, 0);
2865                    return;
2866                }
2867
2868                if (upstream->read->eof) {
2869                    ngx_log_error(NGX_LOG_ERR, upstream->log, 0,
2870                                  "upstream prematurely closed connection");
2871
2872                    ngx_http_upstream_finalize_request(r, u,
2873                                                       NGX_HTTP_BAD_GATEWAY);
2874                    return;
2875                }
2876
2877                if (upstream->read->error) {
2878                    ngx_http_upstream_finalize_request(r, u,
2879                                                       NGX_HTTP_BAD_GATEWAY);
2880                    return;
2881                }
2882
2883                b->pos = b->start;
2884                b->last = b->start;
2885            }
2886        }
2887
2888        size = b->end - b->last;
2889
2890        if (size && upstream->read->ready) {
2891
2892            n = upstream->recv(upstream, b->last, size);
2893
2894            if (n == NGX_AGAIN) {
2895                break;
2896            }
2897
2898            if (n > 0) {
2899                u->state->response_length += n;
2900
2901                if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2902                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2903                    return;
2904                }
2905            }
2906
2907            do_write = 1;
2908
2909            continue;
2910        }
2911
2912        break;
2913    }
2914
2915    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2916
2917    if (downstream->data == r) {
2918        if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
2919            != NGX_OK)
2920        {
2921            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2922            return;
2923        }
2924    }
2925
2926    if (downstream->write->active && !downstream->write->ready) {
2927        ngx_add_timer(downstream->write, clcf->send_timeout);
2928
2929    } else if (downstream->write->timer_set) {
2930        ngx_del_timer(downstream->write);
2931    }
2932
2933    if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
2934        ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2935        return;
2936    }
2937
2938    if (upstream->read->active && !upstream->read->ready) {
2939        ngx_add_timer(upstream->read, u->conf->read_timeout);
2940
2941    } else if (upstream->read->timer_set) {
2942        ngx_del_timer(upstream->read);
2943    }
2944}
2945
2946
2947static ngx_int_t
2948ngx_http_upstream_non_buffered_filter_init(void *data)
2949{
2950    return NGX_OK;
2951}
2952
2953
2954static ngx_int_t
2955ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
2956{
2957    ngx_http_request_t  *r = data;
2958
2959    ngx_buf_t            *b;
2960    ngx_chain_t          *cl, **ll;
2961    ngx_http_upstream_t  *u;
2962
2963    u = r->upstream;
2964
2965    for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2966        ll = &cl->next;
2967    }
2968
2969    cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2970    if (cl == NULL) {
2971        return NGX_ERROR;
2972    }
2973
2974    *ll = cl;
2975
2976    cl->buf->flush = 1;
2977    cl->buf->memory = 1;
2978
2979    b = &u->buffer;
2980
2981    cl->buf->pos = b->last;
2982    b->last += bytes;
2983    cl->buf->last = b->last;
2984    cl->buf->tag = u->output.tag;
2985
2986    if (u->length == -1) {
2987        return NGX_OK;
2988    }
2989
2990    u->length -= bytes;
2991
2992    return NGX_OK;
2993}
2994
2995
2996static void
2997ngx_http_upstream_process_downstream(ngx_http_request_t *r)
2998{
2999    ngx_event_t          *wev;
3000    ngx_connection_t     *c;
3001    ngx_event_pipe_t     *p;
3002    ngx_http_upstream_t  *u;
3003
3004    c = r->connection;
3005    u = r->upstream;
3006    p = u->pipe;
3007    wev = c->write;
3008
3009    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3010                   "http upstream process downstream");
3011
3012    c->log->action = "sending to client";
3013
3014    if (wev->timedout) {
3015
3016        if (wev->delayed) {
3017
3018            wev->timedout = 0;
3019            wev->delayed = 0;
3020
3021            if (!wev->ready) {
3022                ngx_add_timer(wev, p->send_timeout);
3023
3024                if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
3025                    ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3026                }
3027
3028                return;
3029            }
3030
3031            if (ngx_event_pipe(p, wev->write) == NGX_ABORT) {
3032                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3033                return;
3034            }
3035
3036        } else {
3037            p->downstream_error = 1;
3038            c->timedout = 1;
3039            ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
3040        }
3041
3042    } else {
3043
3044        if (wev->delayed) {
3045
3046            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3047                           "http downstream delayed");
3048
3049            if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
3050                ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3051            }
3052
3053            return;
3054        }
3055
3056        if (ngx_event_pipe(p, 1) == NGX_ABORT) {
3057            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3058            return;
3059        }
3060    }
3061
3062    ngx_http_upstream_process_request(r);
3063}
3064
3065
3066static void
3067ngx_http_upstream_process_upstream(ngx_http_request_t *r,
3068    ngx_http_upstream_t *u)
3069{
3070    ngx_connection_t  *c;
3071
3072    c = u->peer.connection;
3073
3074    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3075                   "http upstream process upstream");
3076
3077    c->log->action = "reading upstream";
3078
3079    if (c->read->timedout) {
3080        u->pipe->upstream_error = 1;
3081        ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
3082
3083    } else {
3084        if (ngx_event_pipe(u->pipe, 0) == NGX_ABORT) {
3085            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3086            return;
3087        }
3088    }
3089
3090    ngx_http_upstream_process_request(r);
3091}
3092
3093
3094static void
3095ngx_http_upstream_process_request(ngx_http_request_t *r)
3096{
3097    ngx_temp_file_t      *tf;
3098    ngx_event_pipe_t     *p;
3099    ngx_http_upstream_t  *u;
3100
3101    u = r->upstream;
3102    p = u->pipe;
3103
3104    if (u->peer.connection) {
3105
3106        if (u->store) {
3107
3108            if (p->upstream_eof || p->upstream_done) {
3109
3110                tf = p->temp_file;
3111
3112                if (u->headers_in.status_n == NGX_HTTP_OK
3113                    && (p->upstream_done || p->length == -1)
3114                    && (u->headers_in.content_length_n == -1
3115                        || u->headers_in.content_length_n == tf->offset))
3116                {
3117                    ngx_http_upstream_store(r, u);
3118                    u->store = 0;
3119                }
3120            }
3121        }
3122
3123#if (NGX_HTTP_CACHE)
3124
3125        if (u->cacheable) {
3126
3127            if (p->upstream_done) {
3128                ngx_http_file_cache_update(r, p->temp_file);
3129
3130            } else if (p->upstream_eof) {
3131
3132                tf = p->temp_file;
3133
3134                if (p->length == -1
3135                    && (u->headers_in.content_length_n == -1
3136                        || u->headers_in.content_length_n
3137                           == tf->offset - (off_t) r->cache->body_start))
3138                {
3139                    ngx_http_file_cache_update(r, tf);
3140
3141                } else {
3142                    ngx_http_file_cache_free(r->cache, tf);
3143                }
3144
3145            } else if (p->upstream_error) {
3146                ngx_http_file_cache_free(r->cache, p->temp_file);
3147            }
3148        }
3149
3150#endif
3151
3152        if (p->upstream_done || p->upstream_eof || p->upstream_error) {
3153            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3154                           "http upstream exit: %p", p->out);
3155
3156            if (p->upstream_done
3157                || (p->upstream_eof && p->length == -1))
3158            {
3159                ngx_http_upstream_finalize_request(r, u, 0);
3160                return;
3161            }
3162
3163            if (p->upstream_eof) {
3164                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3165                              "upstream prematurely closed connection");
3166            }
3167
3168            ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
3169            return;
3170        }
3171    }
3172
3173    if (p->downstream_error) {
3174        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3175                       "http upstream downstream error");
3176
3177        if (!u->cacheable && !u->store && u->peer.connection) {
3178            ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3179        }
3180    }
3181}
3182
3183
3184static void
3185ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
3186{
3187    size_t                  root;
3188    time_t                  lm;
3189    ngx_str_t               path;
3190    ngx_temp_file_t        *tf;
3191    ngx_ext_rename_file_t   ext;
3192
3193    tf = u->pipe->temp_file;
3194
3195    if (tf->file.fd == NGX_INVALID_FILE) {
3196
3197        /* create file for empty 200 response */
3198
3199        tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
3200        if (tf == NULL) {
3201            return;
3202        }
3203
3204        tf->file.fd = NGX_INVALID_FILE;
3205        tf->file.log = r->connection->log;
3206        tf->path = u->conf->temp_path;
3207        tf->pool = r->pool;
3208        tf->persistent = 1;
3209
3210        if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
3211                                 tf->persistent, tf->clean, tf->access)
3212            != NGX_OK)
3213        {
3214            return;
3215        }
3216
3217        u->pipe->temp_file = tf;
3218    }
3219
3220    ext.access = u->conf->store_access;
3221    ext.path_access = u->conf->store_access;
3222    ext.time = -1;
3223    ext.create_path = 1;
3224    ext.delete_file = 1;
3225    ext.log = r->connection->log;
3226
3227    if (u->headers_in.last_modified) {
3228
3229        lm = ngx_http_parse_time(u->headers_in.last_modified->value.data,
3230                                 u->headers_in.last_modified->value.len);
3231
3232        if (lm != NGX_ERROR) {
3233            ext.time = lm;
3234            ext.fd = tf->file.fd;
3235        }
3236    }
3237
3238    if (u->conf->store_lengths == NULL) {
3239
3240        ngx_http_map_uri_to_path(r, &path, &root, 0);
3241
3242    } else {
3243        if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
3244                                u->conf->store_values->elts)
3245            == NULL)
3246        {
3247            return;
3248        }
3249    }
3250
3251    path.len--;
3252
3253    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3254                   "upstream stores \"%s\" to \"%s\"",
3255                   tf->file.name.data, path.data);
3256
3257    (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
3258}
3259
3260
3261static void
3262ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
3263{
3264    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3265                   "http upstream dummy handler");
3266}
3267
3268
3269static void
3270ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
3271    ngx_uint_t ft_type)
3272{
3273    ngx_uint_t  status, state;
3274
3275    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3276                   "http next upstream, %xi", ft_type);
3277
3278    if (u->peer.sockaddr) {
3279
3280        if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
3281            || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
3282        {
3283            state = NGX_PEER_NEXT;
3284
3285        } else {
3286            state = NGX_PEER_FAILED;
3287        }
3288
3289        u->peer.free(&u->peer, u->peer.data, state);
3290        u->peer.sockaddr = NULL;
3291    }
3292
3293    if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
3294        ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
3295                      "upstream timed out");
3296    }
3297
3298    if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
3299        status = 0;
3300
3301        /* TODO: inform balancer instead */
3302
3303        u->peer.tries++;
3304
3305    } else {
3306        switch(ft_type) {
3307
3308        case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
3309            status = NGX_HTTP_GATEWAY_TIME_OUT;
3310            break;
3311
3312        case NGX_HTTP_UPSTREAM_FT_HTTP_500:
3313            status = NGX_HTTP_INTERNAL_SERVER_ERROR;
3314            break;
3315
3316        case NGX_HTTP_UPSTREAM_FT_HTTP_403:
3317            status = NGX_HTTP_FORBIDDEN;
3318            break;
3319
3320        case NGX_HTTP_UPSTREAM_FT_HTTP_404:
3321            status = NGX_HTTP_NOT_FOUND;
3322            break;
3323
3324        /*
3325         * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
3326         * never reach here
3327         */
3328
3329        default:
3330            status = NGX_HTTP_BAD_GATEWAY;
3331        }
3332    }
3333
3334    if (r->connection->error) {
3335        ngx_http_upstream_finalize_request(r, u,
3336                                           NGX_HTTP_CLIENT_CLOSED_REQUEST);
3337        return;
3338    }
3339
3340    if (status) {
3341        u->state->status = status;
3342
3343        if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) {
3344
3345#if (NGX_HTTP_CACHE)
3346
3347            if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
3348                && (u->conf->cache_use_stale & ft_type))
3349            {
3350                ngx_int_t  rc;
3351
3352                rc = u->reinit_request(r);
3353
3354                if (rc == NGX_OK) {
3355                    u->cache_status = NGX_HTTP_CACHE_STALE;
3356                    rc = ngx_http_upstream_cache_send(r, u);
3357                }
3358
3359                ngx_http_upstream_finalize_request(r, u, rc);
3360                return;
3361            }
3362#endif
3363
3364            ngx_http_upstream_finalize_request(r, u, status);
3365            return;
3366        }
3367    }
3368
3369    if (u->peer.connection) {
3370        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3371                       "close http upstream connection: %d",
3372                       u->peer.connection->fd);
3373#if (NGX_HTTP_SSL)
3374
3375        if (u->peer.connection->ssl) {
3376            u->peer.connection->ssl->no_wait_shutdown = 1;
3377            u->peer.connection->ssl->no_send_shutdown = 1;
3378
3379            (void) ngx_ssl_shutdown(u->peer.connection);
3380        }
3381#endif
3382
3383        if (u->peer.connection->pool) {
3384            ngx_destroy_pool(u->peer.connection->pool);
3385        }
3386
3387        ngx_close_connection(u->peer.connection);
3388        u->peer.connection = NULL;
3389    }
3390
3391    ngx_http_upstream_connect(r, u);
3392}
3393
3394
3395static void
3396ngx_http_upstream_cleanup(void *data)
3397{
3398    ngx_http_request_t *r = data;
3399
3400    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3401                   "cleanup http upstream request: \"%V\"", &r->uri);
3402
3403    ngx_http_upstream_finalize_request(r, r->upstream, NGX_DONE);
3404}
3405
3406
3407static void
3408ngx_http_upstream_finalize_request(ngx_http_request_t *r,
3409    ngx_http_upstream_t *u, ngx_int_t rc)
3410{
3411    ngx_uint_t   flush;
3412    ngx_time_t  *tp;
3413
3414    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3415                   "finalize http upstream request: %i", rc);
3416
3417    if (u->cleanup) {
3418        *u->cleanup = NULL;
3419        u->cleanup = NULL;
3420    }
3421
3422    if (u->resolved && u->resolved->ctx) {
3423        ngx_resolve_name_done(u->resolved->ctx);
3424        u->resolved->ctx = NULL;
3425    }
3426
3427    if (u->state && u->state->response_sec) {
3428        tp = ngx_timeofday();
3429        u->state->response_sec = tp->sec - u->state->response_sec;
3430        u->state->response_msec = tp->msec - u->state->response_msec;
3431
3432        if (u->pipe && u->pipe->read_length) {
3433            u->state->response_length = u->pipe->read_length;
3434        }
3435    }
3436
3437    u->finalize_request(r, rc);
3438
3439    if (u->peer.free && u->peer.sockaddr) {
3440        u->peer.free(&u->peer, u->peer.data, 0);
3441        u->peer.sockaddr = NULL;
3442    }
3443
3444    if (u->peer.connection) {
3445
3446#if (NGX_HTTP_SSL)
3447
3448        /* TODO: do not shutdown persistent connection */
3449
3450        if (u->peer.connection->ssl) {
3451
3452            /*
3453             * We send the "close notify" shutdown alert to the upstream only
3454             * and do not wait its "close notify" shutdown alert.
3455             * It is acceptable according to the TLS standard.
3456             */
3457
3458            u->peer.connection->ssl->no_wait_shutdown = 1;
3459
3460            (void) ngx_ssl_shutdown(u->peer.connection);
3461        }
3462#endif
3463
3464        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3465                       "close http upstream connection: %d",
3466                       u->peer.connection->fd);
3467
3468        if (u->peer.connection->pool) {
3469            ngx_destroy_pool(u->peer.connection->pool);
3470        }
3471
3472        ngx_close_connection(u->peer.connection);
3473    }
3474
3475    u->peer.connection = NULL;
3476
3477    if (u->pipe && u->pipe->temp_file) {
3478        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3479                       "http upstream temp fd: %d",
3480                       u->pipe->temp_file->file.fd);
3481    }
3482
3483    if (u->store && u->pipe && u->pipe->temp_file
3484        && u->pipe->temp_file->file.fd != NGX_INVALID_FILE)
3485    {
3486        if (ngx_delete_file(u->pipe->temp_file->file.name.data)
3487            == NGX_FILE_ERROR)
3488        {
3489            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
3490                          ngx_delete_file_n " \"%s\" failed",
3491                          u->pipe->temp_file->file.name.data);
3492        }
3493    }
3494
3495#if (NGX_HTTP_CACHE)
3496
3497    if (r->cache) {
3498
3499        if (u->cacheable) {
3500
3501            if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
3502                time_t  valid;
3503
3504                valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
3505
3506                if (valid) {
3507                    r->cache->valid_sec = ngx_time() + valid;
3508                    r->cache->error = rc;
3509                }
3510            }
3511        }
3512
3513        ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
3514    }
3515
3516#endif
3517
3518    if (r->subrequest_in_memory
3519        && u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE)
3520    {
3521        u->buffer.last = u->buffer.pos;
3522    }
3523
3524    if (rc == NGX_DECLINED) {
3525        return;
3526    }
3527
3528    r->connection->log->action = "sending to client";
3529
3530    if (!u->header_sent
3531        || rc == NGX_HTTP_REQUEST_TIME_OUT
3532        || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST)
3533    {
3534        ngx_http_finalize_request(r, rc);
3535        return;
3536    }
3537
3538    flush = 0;
3539
3540    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
3541        rc = NGX_ERROR;
3542        flush = 1;
3543    }
3544
3545    if (r->header_only) {
3546        ngx_http_finalize_request(r, rc);
3547        return;
3548    }
3549
3550    if (rc == 0) {
3551        rc = ngx_http_send_special(r, NGX_HTTP_LAST);
3552
3553    } else if (flush) {
3554        r->keepalive = 0;
3555        rc = ngx_http_send_special(r, NGX_HTTP_FLUSH);
3556    }
3557
3558    ngx_http_finalize_request(r, rc);
3559}
3560
3561
3562static ngx_int_t
3563ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
3564    ngx_uint_t offset)
3565{
3566    ngx_table_elt_t  **ph;
3567
3568    ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
3569
3570    if (*ph == NULL) {
3571        *ph = h;
3572    }
3573
3574    return NGX_OK;
3575}
3576
3577
3578static ngx_int_t
3579ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
3580    ngx_uint_t offset)
3581{
3582    return NGX_OK;
3583}
3584
3585
3586static ngx_int_t
3587ngx_http_upstream_process_content_length(ngx_http_request_t *r,
3588    ngx_table_elt_t *h, ngx_uint_t offset)
3589{
3590    ngx_http_upstream_t  *u;
3591
3592    u = r->upstream;
3593
3594    u->headers_in.content_length = h;
3595    u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
3596
3597    return NGX_OK;
3598}
3599
3600
3601static ngx_int_t
3602ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
3603    ngx_uint_t offset)
3604{
3605#if (NGX_HTTP_CACHE)
3606    ngx_http_upstream_t  *u;
3607
3608    u = r->upstream;
3609
3610    if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
3611        u->cacheable = 0;
3612    }
3613#endif
3614
3615    return NGX_OK;
3616}
3617
3618
3619static ngx_int_t
3620ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
3621    ngx_table_elt_t *h, ngx_uint_t offset)
3622{
3623    ngx_array_t          *pa;
3624    ngx_table_elt_t     **ph;
3625    ngx_http_upstream_t  *u;
3626
3627    u = r->upstream;
3628    pa = &u->headers_in.cache_control;
3629
3630    if (pa->elts == NULL) {
3631       if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
3632       {
3633           return NGX_ERROR;
3634       }
3635    }
3636
3637    ph = ngx_array_push(pa);
3638    if (ph == NULL) {
3639        return NGX_ERROR;
3640    }
3641
3642    *ph = h;
3643
3644#if (NGX_HTTP_CACHE)
3645    {
3646    u_char     *p, *last;
3647    ngx_int_t   n;
3648
3649    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
3650        return NGX_OK;
3651    }
3652
3653    if (r->cache == NULL) {
3654        return NGX_OK;
3655    }
3656
3657    if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
3658        return NGX_OK;
3659    }
3660
3661    p = h->value.data;
3662    last = p + h->value.len;
3663
3664    if (ngx_strlcasestrn(p, last, (u_char *) "no-cache", 8 - 1) != NULL
3665        || ngx_strlcasestrn(p, last, (u_char *) "no-store", 8 - 1) != NULL
3666        || ngx_strlcasestrn(p, last, (u_char *) "private", 7 - 1) != NULL)
3667    {
3668        u->cacheable = 0;
3669        return NGX_OK;
3670    }
3671
3672    p = ngx_strlcasestrn(p, last, (u_char *) "max-age=", 8 - 1);
3673
3674    if (p == NULL) {
3675        return NGX_OK;
3676    }
3677
3678    n = 0;
3679
3680    for (p += 8; p < last; p++) {
3681        if (*p == ',' || *p == ';' || *p == ' ') {
3682            break;
3683        }
3684
3685        if (*p >= '0' && *p <= '9') {
3686            n = n * 10 + *p - '0';
3687            continue;
3688        }
3689
3690        u->cacheable = 0;
3691        return NGX_OK;
3692    }
3693
3694    if (n == 0) {
3695        u->cacheable = 0;
3696        return NGX_OK;
3697    }
3698
3699    r->cache->valid_sec = ngx_time() + n;
3700    }
3701#endif
3702
3703    return NGX_OK;
3704}
3705
3706
3707static ngx_int_t
3708ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
3709    ngx_uint_t offset)
3710{
3711    ngx_http_upstream_t  *u;
3712
3713    u = r->upstream;
3714    u->headers_in.expires = h;
3715
3716#if (NGX_HTTP_CACHE)
3717    {
3718    time_t  expires;
3719
3720    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
3721        return NGX_OK;
3722    }
3723
3724    if (r->cache == NULL) {
3725        return NGX_OK;
3726    }
3727
3728    if (r->cache->valid_sec != 0) {
3729        return NGX_OK;
3730    }
3731
3732    expires = ngx_http_parse_time(h->value.data, h->value.len);
3733
3734    if (expires == NGX_ERROR || expires < ngx_time()) {
3735        u->cacheable = 0;
3736        return NGX_OK;
3737    }
3738
3739    r->cache->valid_sec = expires;
3740    }
3741#endif
3742
3743    return NGX_OK;
3744}
3745
3746
3747static ngx_int_t
3748ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
3749    ngx_table_elt_t *h, ngx_uint_t offset)
3750{
3751    ngx_http_upstream_t  *u;
3752
3753    u = r->upstream;
3754    u->headers_in.x_accel_expires = h;
3755
3756#if (NGX_HTTP_CACHE)
3757    {
3758    u_char     *p;
3759    size_t      len;
3760    ngx_int_t   n;
3761
3762    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
3763        return NGX_OK;
3764    }
3765
3766    if (r->cache == NULL) {
3767        return NGX_OK;
3768    }
3769
3770    len = h->value.len;
3771    p = h->value.data;
3772
3773    if (p[0] != '@') {
3774        n = ngx_atoi(p, len);
3775
3776        switch (n) {
3777        case 0:
3778            u->cacheable = 0;
3779            /* fall through */
3780
3781        case NGX_ERROR:
3782            return NGX_OK;
3783
3784        default:
3785            r->cache->valid_sec = ngx_time() + n;
3786            return NGX_OK;
3787        }
3788    }
3789
3790    p++;
3791    len--;
3792
3793    n = ngx_atoi(p, len);
3794
3795    if (n != NGX_ERROR) {
3796        r->cache->valid_sec = n;
3797    }
3798    }
3799#endif
3800
3801    return NGX_OK;
3802}
3803
3804
3805static ngx_int_t
3806ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
3807    ngx_uint_t offset)
3808{
3809    ngx_int_t             n;
3810    ngx_http_upstream_t  *u;
3811
3812    u = r->upstream;
3813    u->headers_in.x_accel_limit_rate = h;
3814
3815    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
3816        return NGX_OK;
3817    }
3818
3819    n = ngx_atoi(h->value.data, h->value.len);
3820
3821    if (n != NGX_ERROR) {
3822        r->limit_rate = (size_t) n;
3823    }
3824
3825    return NGX_OK;
3826}
3827
3828
3829static ngx_int_t
3830ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
3831    ngx_uint_t offset)
3832{
3833    u_char                c0, c1, c2;
3834    ngx_http_upstream_t  *u;
3835
3836    u = r->upstream;
3837
3838    if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING) {
3839        return NGX_OK;
3840    }
3841
3842    if (u->conf->change_buffering) {
3843
3844        if (h->value.len == 2) {
3845            c0 = ngx_tolower(h->value.data[0]);
3846            c1 = ngx_tolower(h->value.data[1]);
3847
3848            if (c0 == 'n' && c1 == 'o') {
3849                u->buffering = 0;
3850            }
3851
3852        } else if (h->value.len == 3) {
3853            c0 = ngx_tolower(h->value.data[0]);
3854            c1 = ngx_tolower(h->value.data[1]);
3855            c2 = ngx_tolower(h->value.data[2]);
3856
3857            if (c0 == 'y' && c1 == 'e' && c2 == 's') {
3858                u->buffering = 1;
3859            }
3860        }
3861    }
3862
3863    return NGX_OK;
3864}
3865
3866
3867static ngx_int_t
3868ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
3869    ngx_uint_t offset)
3870{
3871    if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
3872        return NGX_OK;
3873    }
3874
3875    r->headers_out.override_charset = &h->value;
3876
3877    return NGX_OK;
3878}
3879
3880
3881static ngx_int_t
3882ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
3883    ngx_uint_t offset)
3884{
3885    r->upstream->headers_in.connection = h;
3886
3887    if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
3888                         (u_char *) "close", 5 - 1)
3889        != NULL)
3890    {
3891        r->upstream->headers_in.connection_close = 1;
3892    }
3893
3894    return NGX_OK;
3895}
3896
3897
3898static ngx_int_t
3899ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
3900    ngx_table_elt_t *h, ngx_uint_t offset)
3901{
3902    r->upstream->headers_in.transfer_encoding = h;
3903
3904    if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
3905                         (u_char *) "chunked", 7 - 1)
3906        != NULL)
3907    {
3908        r->upstream->headers_in.chunked = 1;
3909    }
3910
3911    return NGX_OK;
3912}
3913
3914
3915static ngx_int_t
3916ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
3917    ngx_uint_t offset)
3918{
3919    ngx_table_elt_t  *ho, **ph;
3920
3921    ho = ngx_list_push(&r->headers_out.headers);
3922    if (ho == NULL) {
3923        return NGX_ERROR;
3924    }
3925
3926    *ho = *h;
3927
3928    if (offset) {
3929        ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
3930        *ph = ho;
3931    }
3932
3933    return NGX_OK;
3934}
3935
3936
3937static ngx_int_t
3938ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
3939    ngx_table_elt_t *h, ngx_uint_t offset)
3940{
3941    ngx_array_t      *pa;
3942    ngx_table_elt_t  *ho, **ph;
3943
3944    pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
3945
3946    if (pa->elts == NULL) {
3947        if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
3948        {
3949            return NGX_ERROR;
3950        }
3951    }
3952
3953    ph = ngx_array_push(pa);
3954    if (ph == NULL) {
3955        return NGX_ERROR;
3956    }
3957
3958    ho = ngx_list_push(&r->headers_out.headers);
3959    if (ho == NULL) {
3960        return NGX_ERROR;
3961    }
3962
3963    *ho = *h;
3964    *ph = ho;
3965
3966    return NGX_OK;
3967}
3968
3969
3970static ngx_int_t
3971ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
3972    ngx_uint_t offset)
3973{
3974    u_char  *p, *last;
3975
3976    r->headers_out.content_type_len = h->value.len;
3977    r->headers_out.content_type = h->value;
3978    r->headers_out.content_type_lowcase = NULL;
3979
3980    for (p = h->value.data; *p; p++) {
3981
3982        if (*p != ';') {
3983            continue;
3984        }
3985
3986        last = p;
3987
3988        while (*++p == ' ') { /* void */ }
3989
3990        if (*p == '\0') {
3991            return NGX_OK;
3992        }
3993
3994        if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
3995            continue;
3996        }
3997
3998        p += 8;
3999
4000        r->headers_out.content_type_len = last - h->value.data;
4001
4002        if (*p == '"') {
4003            p++;
4004        }
4005
4006        last = h->value.data + h->value.len;
4007
4008        if (*(last - 1) == '"') {
4009            last--;
4010        }
4011
4012        r->headers_out.charset.len = last - p;
4013        r->headers_out.charset.data = p;
4014
4015        return NGX_OK;
4016    }
4017
4018    return NGX_OK;
4019}
4020
4021
4022static ngx_int_t
4023ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
4024    ngx_uint_t offset)
4025{
4026    ngx_table_elt_t  *ho;
4027
4028    ho = ngx_list_push(&r->headers_out.headers);
4029    if (ho == NULL) {
4030        return NGX_ERROR;
4031    }
4032
4033    *ho = *h;
4034
4035    r->headers_out.last_modified = ho;
4036
4037#if (NGX_HTTP_CACHE)
4038
4039    if (r->upstream->cacheable) {
4040        r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
4041                                                                h->value.len);
4042    }
4043
4044#endif
4045
4046    return NGX_OK;
4047}
4048
4049
4050static ngx_int_t
4051ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
4052    ngx_uint_t offset)
4053{
4054    ngx_int_t         rc;
4055    ngx_table_elt_t  *ho;
4056
4057    ho = ngx_list_push(&r->headers_out.headers);
4058    if (ho == NULL) {
4059        return NGX_ERROR;
4060    }
4061
4062    *ho = *h;
4063
4064    if (r->upstream->rewrite_redirect) {
4065        rc = r->upstream->rewrite_redirect(r, ho, 0);
4066
4067        if (rc == NGX_DECLINED) {
4068            return NGX_OK;
4069        }
4070
4071        if (rc == NGX_OK) {
4072            r->headers_out.location = ho;
4073
4074            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4075                           "rewritten location: \"%V\"", &ho->value);
4076        }
4077
4078        return rc;
4079    }
4080
4081    if (ho->value.data[0] != '/') {
4082        r->headers_out.location = ho;
4083    }
4084
4085    /*
4086     * we do not set r->headers_out.location here to avoid the handling
4087     * the local redirects without a host name by ngx_http_header_filter()
4088     */
4089
4090    return NGX_OK;
4091}
4092
4093
4094static ngx_int_t
4095ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
4096    ngx_uint_t offset)
4097{
4098    u_char           *p;
4099    ngx_int_t         rc;
4100    ngx_table_elt_t  *ho;
4101
4102    ho = ngx_list_push(&r->headers_out.headers);
4103    if (ho == NULL) {
4104        return NGX_ERROR;
4105    }
4106
4107    *ho = *h;
4108
4109    if (r->upstream->rewrite_redirect) {
4110
4111        p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
4112
4113        if (p) {
4114            rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
4115
4116        } else {
4117            return NGX_OK;
4118        }
4119
4120        if (rc == NGX_DECLINED) {
4121            return NGX_OK;
4122        }
4123
4124        if (rc == NGX_OK) {
4125            r->headers_out.refresh = ho;
4126
4127            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4128                           "rewritten refresh: \"%V\"", &ho->value);
4129        }
4130
4131        return rc;
4132    }
4133
4134    r->headers_out.refresh = ho;
4135
4136    return NGX_OK;
4137}
4138
4139
4140static ngx_int_t
4141ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
4142    ngx_uint_t offset)
4143{
4144    ngx_int_t         rc;
4145    ngx_table_elt_t  *ho;
4146
4147    ho = ngx_list_push(&r->headers_out.headers);
4148    if (ho == NULL) {
4149        return NGX_ERROR;
4150    }
4151
4152    *ho = *h;
4153
4154    if (r->upstream->rewrite_cookie) {
4155        rc = r->upstream->rewrite_cookie(r, ho);
4156
4157        if (rc == NGX_DECLINED) {
4158            return NGX_OK;
4159        }
4160
4161#if (NGX_DEBUG)
4162        if (rc == NGX_OK) {
4163            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4164                           "rewritten cookie: \"%V\"", &ho->value);
4165        }
4166#endif
4167
4168        return rc;
4169    }
4170
4171    return NGX_OK;
4172}
4173
4174
4175static ngx_int_t
4176ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
4177    ngx_table_elt_t *h, ngx_uint_t offset)
4178{
4179    ngx_table_elt_t  *ho;
4180
4181#if (NGX_HTTP_CACHE)
4182
4183    if (r->cached) {
4184        r->allow_ranges = 1;
4185        return NGX_OK;
4186
4187    }
4188
4189#endif
4190
4191    ho = ngx_list_push(&r->headers_out.headers);
4192    if (ho == NULL) {
4193        return NGX_ERROR;
4194    }
4195
4196    *ho = *h;
4197
4198    r->headers_out.accept_ranges = ho;
4199
4200    return NGX_OK;
4201}
4202
4203
4204#if (NGX_HTTP_GZIP)
4205
4206static ngx_int_t
4207ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
4208    ngx_table_elt_t *h, ngx_uint_t offset)
4209{
4210    ngx_table_elt_t  *ho;
4211
4212    ho = ngx_list_push(&r->headers_out.headers);
4213    if (ho == NULL) {
4214        return NGX_ERROR;
4215    }
4216
4217    *ho = *h;
4218
4219    r->headers_out.content_encoding = ho;
4220
4221    return NGX_OK;
4222}
4223
4224#endif
4225
4226
4227static ngx_int_t
4228ngx_http_upstream_add_variables(ngx_conf_t *cf)
4229{
4230    ngx_http_variable_t  *var, *v;
4231
4232    for (v = ngx_http_upstream_vars; v->name.len; v++) {
4233        var = ngx_http_add_variable(cf, &v->name, v->flags);
4234        if (var == NULL) {
4235            return NGX_ERROR;
4236        }
4237
4238        var->get_handler = v->get_handler;
4239        var->data = v->data;
4240    }
4241
4242    return NGX_OK;
4243}
4244
4245
4246static ngx_int_t
4247ngx_http_upstream_addr_variable(ngx_http_request_t *r,
4248    ngx_http_variable_value_t *v, uintptr_t data)
4249{
4250    u_char                     *p;
4251    size_t                      len;
4252    ngx_uint_t                  i;
4253    ngx_http_upstream_state_t  *state;
4254
4255    v->valid = 1;
4256    v->no_cacheable = 0;
4257    v->not_found = 0;
4258
4259    if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
4260        v->not_found = 1;
4261        return NGX_OK;
4262    }
4263
4264    len = 0;
4265    state = r->upstream_states->elts;
4266
4267    for (i = 0; i < r->upstream_states->nelts; i++) {
4268        if (state[i].peer) {
4269            len += state[i].peer->len + 2;
4270
4271        } else {
4272            len += 3;
4273        }
4274    }
4275
4276    p = ngx_pnalloc(r->pool, len);
4277    if (p == NULL) {
4278        return NGX_ERROR;
4279    }
4280
4281    v->data = p;
4282
4283    i = 0;
4284
4285    for ( ;; ) {
4286        if (state[i].peer) {
4287            p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
4288        }
4289
4290        if (++i == r->upstream_states->nelts) {
4291            break;
4292        }
4293
4294        if (state[i].peer) {
4295            *p++ = ',';
4296            *p++ = ' ';
4297
4298        } else {
4299            *p++ = ' ';
4300            *p++ = ':';
4301            *p++ = ' ';
4302
4303            if (++i == r->upstream_states->nelts) {
4304                break;
4305            }
4306
4307            continue;
4308        }
4309    }
4310
4311    v->len = p - v->data;
4312
4313    return NGX_OK;
4314}
4315
4316
4317static ngx_int_t
4318ngx_http_upstream_status_variable(ngx_http_request_t *r,
4319    ngx_http_variable_value_t *v, uintptr_t data)
4320{
4321    u_char                     *p;
4322    size_t                      len;
4323    ngx_uint_t                  i;
4324    ngx_http_upstream_state_t  *state;
4325
4326    v->valid = 1;
4327    v->no_cacheable = 0;
4328    v->not_found = 0;
4329
4330    if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
4331        v->not_found = 1;
4332        return NGX_OK;
4333    }
4334
4335    len = r->upstream_states->nelts * (3 + 2);
4336
4337    p = ngx_pnalloc(r->pool, len);
4338    if (p == NULL) {
4339        return NGX_ERROR;
4340    }
4341
4342    v->data = p;
4343
4344    i = 0;
4345    state = r->upstream_states->elts;
4346
4347    for ( ;; ) {
4348        if (state[i].status) {
4349            p = ngx_sprintf(p, "%ui", state[i].status);
4350
4351        } else {
4352            *p++ = '-';
4353        }
4354
4355        if (++i == r->upstream_states->nelts) {
4356            break;
4357        }
4358
4359        if (state[i].peer) {
4360            *p++ = ',';
4361            *p++ = ' ';
4362
4363        } else {
4364            *p++ = ' ';
4365            *p++ = ':';
4366            *p++ = ' ';
4367
4368            if (++i == r->upstream_states->nelts) {
4369                break;
4370            }
4371
4372            continue;
4373        }
4374    }
4375
4376    v->len = p - v->data;
4377
4378    return NGX_OK;
4379}
4380
4381
4382static ngx_int_t
4383ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
4384    ngx_http_variable_value_t *v, uintptr_t data)
4385{
4386    u_char                     *p;
4387    size_t                      len;
4388    ngx_uint_t                  i;
4389    ngx_msec_int_t              ms;
4390    ngx_http_upstream_state_t  *state;
4391
4392    v->valid = 1;
4393    v->no_cacheable = 0;
4394    v->not_found = 0;
4395
4396    if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
4397        v->not_found = 1;
4398        return NGX_OK;
4399    }
4400
4401    len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
4402
4403    p = ngx_pnalloc(r->pool, len);
4404    if (p == NULL) {
4405        return NGX_ERROR;
4406    }
4407
4408    v->data = p;
4409
4410    i = 0;
4411    state = r->upstream_states->elts;
4412
4413    for ( ;; ) {
4414        if (state[i].status) {
4415            ms = (ngx_msec_int_t)
4416                     (state[i].response_sec * 1000 + state[i].response_msec);
4417            ms = ngx_max(ms, 0);
4418            p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000);
4419
4420        } else {
4421            *p++ = '-';
4422        }
4423
4424        if (++i == r->upstream_states->nelts) {
4425            break;
4426        }
4427
4428        if (state[i].peer) {
4429            *p++ = ',';
4430            *p++ = ' ';
4431
4432        } else {
4433            *p++ = ' ';
4434            *p++ = ':';
4435            *p++ = ' ';
4436
4437            if (++i == r->upstream_states->nelts) {
4438                break;
4439            }
4440
4441            continue;
4442        }
4443    }
4444
4445    v->len = p - v->data;
4446
4447    return NGX_OK;
4448}
4449
4450
4451static ngx_int_t
4452ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
4453    ngx_http_variable_value_t *v, uintptr_t data)
4454{
4455    u_char                     *p;
4456    size_t                      len;
4457    ngx_uint_t                  i;
4458    ngx_http_upstream_state_t  *state;
4459
4460    v->valid = 1;
4461    v->no_cacheable = 0;
4462    v->not_found = 0;
4463
4464    if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
4465        v->not_found = 1;
4466        return NGX_OK;
4467    }
4468
4469    len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
4470
4471    p = ngx_pnalloc(r->pool, len);
4472    if (p == NULL) {
4473        return NGX_ERROR;
4474    }
4475
4476    v->data = p;
4477
4478    i = 0;
4479    state = r->upstream_states->elts;
4480
4481    for ( ;; ) {
4482        p = ngx_sprintf(p, "%O", state[i].response_length);
4483
4484        if (++i == r->upstream_states->nelts) {
4485            break;
4486        }
4487
4488        if (state[i].peer) {
4489            *p++ = ',';
4490            *p++ = ' ';
4491
4492        } else {
4493            *p++ = ' ';
4494            *p++ = ':';
4495            *p++ = ' ';
4496
4497            if (++i == r->upstream_states->nelts) {
4498                break;
4499            }
4500
4501            continue;
4502        }
4503    }
4504
4505    v->len = p - v->data;
4506
4507    return NGX_OK;
4508}
4509
4510
4511ngx_int_t
4512ngx_http_upstream_header_variable(ngx_http_request_t *r,
4513    ngx_http_variable_value_t *v, uintptr_t data)
4514{
4515    if (r->upstream == NULL) {
4516        v->not_found = 1;
4517        return NGX_OK;
4518    }
4519
4520    return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
4521                                         &r->upstream->headers_in.headers.part,
4522                                         sizeof("upstream_http_") - 1);
4523}
4524
4525
4526#if (NGX_HTTP_CACHE)
4527
4528ngx_int_t
4529ngx_http_upstream_cache_status(ngx_http_request_t *r,
4530    ngx_http_variable_value_t *v, uintptr_t data)
4531{
4532    ngx_uint_t  n;
4533
4534    if (r->upstream == NULL || r->upstream->cache_status == 0) {
4535        v->not_found = 1;
4536        return NGX_OK;
4537    }
4538
4539    n = r->upstream->cache_status - 1;
4540
4541    v->valid = 1;
4542    v->no_cacheable = 0;
4543    v->not_found = 0;
4544    v->len = ngx_http_cache_status[n].len;
4545    v->data = ngx_http_cache_status[n].data;
4546
4547    return NGX_OK;
4548}
4549
4550
4551static ngx_int_t
4552ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
4553    ngx_http_variable_value_t *v, uintptr_t data)
4554{
4555    u_char  *p;
4556
4557    if (r->upstream == NULL
4558        || !r->upstream->conf->cache_revalidate
4559        || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
4560        || r->cache->last_modified == -1)
4561    {
4562        v->not_found = 1;
4563        return NGX_OK;
4564    }
4565
4566    p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
4567    if (p == NULL) {
4568        return NGX_ERROR;
4569    }
4570
4571    v->len = ngx_http_time(p, r->cache->last_modified) - p;
4572    v->valid = 1;
4573    v->no_cacheable = 0;
4574    v->not_found = 0;
4575    v->data = p;
4576
4577    return NGX_OK;
4578}
4579
4580#endif
4581
4582
4583static char *
4584ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
4585{
4586    char                          *rv;
4587    void                          *mconf;
4588    ngx_str_t                     *value;
4589    ngx_url_t                      u;
4590    ngx_uint_t                     m;
4591    ngx_conf_t                     pcf;
4592    ngx_http_module_t             *module;
4593    ngx_http_conf_ctx_t           *ctx, *http_ctx;
4594    ngx_http_upstream_srv_conf_t  *uscf;
4595
4596    ngx_memzero(&u, sizeof(ngx_url_t));
4597
4598    value = cf->args->elts;
4599    u.host = value[1];
4600    u.no_resolve = 1;
4601    u.no_port = 1;
4602
4603    uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
4604                                         |NGX_HTTP_UPSTREAM_WEIGHT
4605                                         |NGX_HTTP_UPSTREAM_MAX_FAILS
4606                                         |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
4607                                         |NGX_HTTP_UPSTREAM_DOWN
4608                                         |NGX_HTTP_UPSTREAM_BACKUP);
4609    if (uscf == NULL) {
4610        return NGX_CONF_ERROR;
4611    }
4612
4613
4614    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
4615    if (ctx == NULL) {
4616        return NGX_CONF_ERROR;
4617    }
4618
4619    http_ctx = cf->ctx;
4620    ctx->main_conf = http_ctx->main_conf;
4621
4622    /* the upstream{}'s srv_conf */
4623
4624    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
4625    if (ctx->srv_conf == NULL) {
4626        return NGX_CONF_ERROR;
4627    }
4628
4629    ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
4630
4631    uscf->srv_conf = ctx->srv_conf;
4632
4633
4634    /* the upstream{}'s loc_conf */
4635
4636    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
4637    if (ctx->loc_conf == NULL) {
4638        return NGX_CONF_ERROR;
4639    }
4640
4641    for (m = 0; ngx_modules[m]; m++) {
4642        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
4643            continue;
4644        }
4645
4646        module = ngx_modules[m]->ctx;
4647
4648        if (module->create_srv_conf) {
4649            mconf = module->create_srv_conf(cf);
4650            if (mconf == NULL) {
4651                return NGX_CONF_ERROR;
4652            }
4653
4654            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
4655        }
4656
4657        if (module->create_loc_conf) {
4658            mconf = module->create_loc_conf(cf);
4659            if (mconf == NULL) {
4660                return NGX_CONF_ERROR;
4661            }
4662
4663            ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
4664        }
4665    }
4666
4667
4668    /* parse inside upstream{} */
4669
4670    pcf = *cf;
4671    cf->ctx = ctx;
4672    cf->cmd_type = NGX_HTTP_UPS_CONF;
4673
4674    rv = ngx_conf_parse(cf, NULL);
4675
4676    *cf = pcf;
4677
4678    if (rv != NGX_CONF_OK) {
4679        return rv;
4680    }
4681
4682    if (uscf->servers == NULL) {
4683        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4684                           "no servers are inside upstream");
4685        return NGX_CONF_ERROR;
4686    }
4687
4688    return rv;
4689}
4690
4691
4692static char *
4693ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4694{
4695    ngx_http_upstream_srv_conf_t  *uscf = conf;
4696
4697    time_t                       fail_timeout;
4698    ngx_str_t                   *value, s;
4699    ngx_url_t                    u;
4700    ngx_int_t                    weight, max_fails;
4701    ngx_uint_t                   i;
4702    ngx_http_upstream_server_t  *us;
4703
4704    if (uscf->servers == NULL) {
4705        uscf->servers = ngx_array_create(cf->pool, 4,
4706                                         sizeof(ngx_http_upstream_server_t));
4707        if (uscf->servers == NULL) {
4708            return NGX_CONF_ERROR;
4709        }
4710    }
4711
4712    us = ngx_array_push(uscf->servers);
4713    if (us == NULL) {
4714        return NGX_CONF_ERROR;
4715    }
4716
4717    ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
4718
4719    value = cf->args->elts;
4720
4721    ngx_memzero(&u, sizeof(ngx_url_t));
4722
4723    u.url = value[1];
4724    u.default_port = 80;
4725
4726    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
4727        if (u.err) {
4728            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4729                               "%s in upstream \"%V\"", u.err, &u.url);
4730        }
4731
4732        return NGX_CONF_ERROR;
4733    }
4734
4735    weight = 1;
4736    max_fails = 1;
4737    fail_timeout = 10;
4738
4739    for (i = 2; i < cf->args->nelts; i++) {
4740
4741        if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
4742
4743            if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
4744                goto invalid;
4745            }
4746
4747            weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
4748
4749            if (weight == NGX_ERROR || weight == 0) {
4750                goto invalid;
4751            }
4752
4753            continue;
4754        }
4755
4756        if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
4757
4758            if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
4759                goto invalid;
4760            }
4761
4762            max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
4763
4764            if (max_fails == NGX_ERROR) {
4765                goto invalid;
4766            }
4767
4768            continue;
4769        }
4770
4771        if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
4772
4773            if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
4774                goto invalid;
4775            }
4776
4777            s.len = value[i].len - 13;
4778            s.data = &value[i].data[13];
4779
4780            fail_timeout = ngx_parse_time(&s, 1);
4781
4782            if (fail_timeout == (time_t) NGX_ERROR) {
4783                goto invalid;
4784            }
4785
4786            continue;
4787        }
4788
4789        if (ngx_strcmp(value[i].data, "backup") == 0) {
4790
4791            if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
4792                goto invalid;
4793            }
4794
4795            us->backup = 1;
4796
4797            continue;
4798        }
4799
4800        if (ngx_strcmp(value[i].data, "down") == 0) {
4801
4802            if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
4803                goto invalid;
4804            }
4805
4806            us->down = 1;
4807
4808            continue;
4809        }
4810
4811        goto invalid;
4812    }
4813
4814    us->addrs = u.addrs;
4815    us->naddrs = u.naddrs;
4816    us->weight = weight;
4817    us->max_fails = max_fails;
4818    us->fail_timeout = fail_timeout;
4819
4820    return NGX_CONF_OK;
4821
4822invalid:
4823
4824    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4825                       "invalid parameter \"%V\"", &value[i]);
4826
4827    return NGX_CONF_ERROR;
4828}
4829
4830
4831ngx_http_upstream_srv_conf_t *
4832ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
4833{
4834    ngx_uint_t                      i;
4835    ngx_http_upstream_server_t     *us;
4836    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
4837    ngx_http_upstream_main_conf_t  *umcf;
4838
4839    if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
4840
4841        if (ngx_parse_url(cf->pool, u) != NGX_OK) {
4842            if (u->err) {
4843                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4844                                   "%s in upstream \"%V\"", u->err, &u->url);
4845            }
4846
4847            return NULL;
4848        }
4849    }
4850
4851    umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
4852
4853    uscfp = umcf->upstreams.elts;
4854
4855    for (i = 0; i < umcf->upstreams.nelts; i++) {
4856
4857        if (uscfp[i]->host.len != u->host.len
4858            || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
4859               != 0)
4860        {
4861            continue;
4862        }
4863
4864        if ((flags & NGX_HTTP_UPSTREAM_CREATE)
4865             && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
4866        {
4867            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4868                               "duplicate upstream \"%V\"", &u->host);
4869            return NULL;
4870        }
4871
4872        if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && !u->no_port) {
4873            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
4874                               "upstream \"%V\" may not have port %d",
4875                               &u->host, u->port);
4876            return NULL;
4877        }
4878
4879        if ((flags & NGX_HTTP_UPSTREAM_CREATE) && !uscfp[i]->no_port) {
4880            ngx_log_error(NGX_LOG_WARN, cf->log, 0,
4881                          "upstream \"%V\" may not have port %d in %s:%ui",
4882                          &u->host, uscfp[i]->port,
4883                          uscfp[i]->file_name, uscfp[i]->line);
4884            return NULL;
4885        }
4886
4887        if (uscfp[i]->port && u->port
4888            && uscfp[i]->port != u->port)
4889        {
4890            continue;
4891        }
4892
4893        if (uscfp[i]->default_port && u->default_port
4894            && uscfp[i]->default_port != u->default_port)
4895        {
4896            continue;
4897        }
4898
4899        if (flags & NGX_HTTP_UPSTREAM_CREATE) {
4900            uscfp[i]->flags = flags;
4901        }
4902
4903        return uscfp[i];
4904    }
4905
4906    uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
4907    if (uscf == NULL) {
4908        return NULL;
4909    }
4910
4911    uscf->flags = flags;
4912    uscf->host = u->host;
4913    uscf->file_name = cf->conf_file->file.name.data;
4914    uscf->line = cf->conf_file->line;
4915    uscf->port = u->port;
4916    uscf->default_port = u->default_port;
4917    uscf->no_port = u->no_port;
4918
4919    if (u->naddrs == 1) {
4920        uscf->servers = ngx_array_create(cf->pool, 1,
4921                                         sizeof(ngx_http_upstream_server_t));
4922        if (uscf->servers == NULL) {
4923            return NULL;
4924        }
4925
4926        us = ngx_array_push(uscf->servers);
4927        if (us == NULL) {
4928            return NULL;
4929        }
4930
4931        ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
4932
4933        us->addrs = u->addrs;
4934        us->naddrs = 1;
4935    }
4936
4937    uscfp = ngx_array_push(&umcf->upstreams);
4938    if (uscfp == NULL) {
4939        return NULL;
4940    }
4941
4942    *uscfp = uscf;
4943
4944    return uscf;
4945}
4946
4947
4948char *
4949ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
4950    void *conf)
4951{
4952    char  *p = conf;
4953
4954    ngx_int_t                           rc;
4955    ngx_str_t                          *value;
4956    ngx_http_complex_value_t            cv;
4957    ngx_http_upstream_local_t         **plocal, *local;
4958    ngx_http_compile_complex_value_t    ccv;
4959
4960    plocal = (ngx_http_upstream_local_t **) (p + cmd->offset);
4961
4962    if (*plocal != NGX_CONF_UNSET_PTR) {
4963        return "is duplicate";
4964    }
4965
4966    value = cf->args->elts;
4967
4968    if (ngx_strcmp(value[1].data, "off") == 0) {
4969        *plocal = NULL;
4970        return NGX_CONF_OK;
4971    }
4972
4973    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4974
4975    ccv.cf = cf;
4976    ccv.value = &value[1];
4977    ccv.complex_value = &cv;
4978
4979    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4980        return NGX_CONF_ERROR;
4981    }
4982
4983    local = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_local_t));
4984    if (local == NULL) {
4985        return NGX_CONF_ERROR;
4986    }
4987
4988    *plocal = local;
4989
4990    if (cv.lengths) {
4991        local->value = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
4992        if (local->value == NULL) {
4993            return NGX_CONF_ERROR;
4994        }
4995
4996        *local->value = cv;
4997
4998        return NGX_CONF_OK;
4999    }
5000
5001    local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
5002    if (local->addr == NULL) {
5003        return NGX_CONF_ERROR;
5004    }
5005
5006    rc = ngx_parse_addr(cf->pool, local->addr, value[1].data, value[1].len);
5007
5008    switch (rc) {
5009    case NGX_OK:
5010        local->addr->name = value[1];
5011        return NGX_CONF_OK;
5012
5013    case NGX_DECLINED:
5014        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5015                           "invalid address \"%V\"", &value[1]);
5016        /* fall through */
5017
5018    default:
5019        return NGX_CONF_ERROR;
5020    }
5021}
5022
5023
5024static ngx_addr_t *
5025ngx_http_upstream_get_local(ngx_http_request_t *r,
5026    ngx_http_upstream_local_t *local)
5027{
5028    ngx_int_t    rc;
5029    ngx_str_t    val;
5030    ngx_addr_t  *addr;
5031
5032    if (local == NULL) {
5033        return NULL;
5034    }
5035
5036    if (local->value == NULL) {
5037        return local->addr;
5038    }
5039
5040    if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) {
5041        return NULL;
5042    }
5043
5044    if (val.len == 0) {
5045        return NULL;
5046    }
5047
5048    addr = ngx_palloc(r->pool, sizeof(ngx_addr_t));
5049    if (addr == NULL) {
5050        return NULL;
5051    }
5052
5053    rc = ngx_parse_addr(r->pool, addr, val.data, val.len);
5054
5055    switch (rc) {
5056    case NGX_OK:
5057        addr->name = val;
5058        return addr;
5059
5060    case NGX_DECLINED:
5061        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
5062                      "invalid local address \"%V\"", &val);
5063        /* fall through */
5064
5065    default:
5066        return NULL;
5067    }
5068}
5069
5070
5071char *
5072ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
5073    void *conf)
5074{
5075    char  *p = conf;
5076
5077    ngx_str_t                   *value;
5078    ngx_array_t                **a;
5079    ngx_http_upstream_param_t   *param;
5080
5081    a = (ngx_array_t **) (p + cmd->offset);
5082
5083    if (*a == NULL) {
5084        *a = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_param_t));
5085        if (*a == NULL) {
5086            return NGX_CONF_ERROR;
5087        }
5088    }
5089
5090    param = ngx_array_push(*a);
5091    if (param == NULL) {
5092        return NGX_CONF_ERROR;
5093    }
5094
5095    value = cf->args->elts;
5096
5097    param->key = value[1];
5098    param->value = value[2];
5099    param->skip_empty = 0;
5100
5101    if (cf->args->nelts == 4) {
5102        if (ngx_strcmp(value[3].data, "if_not_empty") != 0) {
5103            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5104                               "invalid parameter \"%V\"", &value[3]);
5105            return NGX_CONF_ERROR;
5106        }
5107
5108        param->skip_empty = 1;
5109    }
5110
5111    return NGX_CONF_OK;
5112}
5113
5114
5115ngx_int_t
5116ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
5117    ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
5118    ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
5119{
5120    ngx_str_t       *h;
5121    ngx_uint_t       i, j;
5122    ngx_array_t      hide_headers;
5123    ngx_hash_key_t  *hk;
5124
5125    if (conf->hide_headers == NGX_CONF_UNSET_PTR
5126        && conf->pass_headers == NGX_CONF_UNSET_PTR)
5127    {
5128        conf->hide_headers = prev->hide_headers;
5129        conf->pass_headers = prev->pass_headers;
5130
5131        conf->hide_headers_hash = prev->hide_headers_hash;
5132
5133        if (conf->hide_headers_hash.buckets
5134#if (NGX_HTTP_CACHE)
5135            && ((conf->cache == NULL) == (prev->cache == NULL))
5136#endif
5137           )
5138        {
5139            return NGX_OK;
5140        }
5141
5142    } else {
5143        if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
5144            conf->hide_headers = prev->hide_headers;
5145        }
5146
5147        if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
5148            conf->pass_headers = prev->pass_headers;
5149        }
5150    }
5151
5152    if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
5153        != NGX_OK)
5154    {
5155        return NGX_ERROR;
5156    }
5157
5158    for (h = default_hide_headers; h->len; h++) {
5159        hk = ngx_array_push(&hide_headers);
5160        if (hk == NULL) {
5161            return NGX_ERROR;
5162        }
5163
5164        hk->key = *h;
5165        hk->key_hash = ngx_hash_key_lc(h->data, h->len);
5166        hk->value = (void *) 1;
5167    }
5168
5169    if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
5170
5171        h = conf->hide_headers->elts;
5172
5173        for (i = 0; i < conf->hide_headers->nelts; i++) {
5174
5175            hk = hide_headers.elts;
5176
5177            for (j = 0; j < hide_headers.nelts; j++) {
5178                if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
5179                    goto exist;
5180                }
5181            }
5182
5183            hk = ngx_array_push(&hide_headers);
5184            if (hk == NULL) {
5185                return NGX_ERROR;
5186            }
5187
5188            hk->key = h[i];
5189            hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
5190            hk->value = (void *) 1;
5191
5192        exist:
5193
5194            continue;
5195        }
5196    }
5197
5198    if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
5199
5200        h = conf->pass_headers->elts;
5201        hk = hide_headers.elts;
5202
5203        for (i = 0; i < conf->pass_headers->nelts; i++) {
5204            for (j = 0; j < hide_headers.nelts; j++) {
5205
5206                if (hk[j].key.data == NULL) {
5207                    continue;
5208                }
5209
5210                if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
5211                    hk[j].key.data = NULL;
5212                    break;
5213                }
5214            }
5215        }
5216    }
5217
5218    hash->hash = &conf->hide_headers_hash;
5219    hash->key = ngx_hash_key_lc;
5220    hash->pool = cf->pool;
5221    hash->temp_pool = NULL;
5222
5223    return ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts);
5224}
5225
5226
5227static void *
5228ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
5229{
5230    ngx_http_upstream_main_conf_t  *umcf;
5231
5232    umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
5233    if (umcf == NULL) {
5234        return NULL;
5235    }
5236
5237    if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
5238                       sizeof(ngx_http_upstream_srv_conf_t *))
5239        != NGX_OK)
5240    {
5241        return NULL;
5242    }
5243
5244    return umcf;
5245}
5246
5247
5248static char *
5249ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
5250{
5251    ngx_http_upstream_main_conf_t  *umcf = conf;
5252
5253    ngx_uint_t                      i;
5254    ngx_array_t                     headers_in;
5255    ngx_hash_key_t                 *hk;
5256    ngx_hash_init_t                 hash;
5257    ngx_http_upstream_init_pt       init;
5258    ngx_http_upstream_header_t     *header;
5259    ngx_http_upstream_srv_conf_t  **uscfp;
5260
5261    uscfp = umcf->upstreams.elts;
5262
5263    for (i = 0; i < umcf->upstreams.nelts; i++) {
5264
5265        init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
5266                                            ngx_http_upstream_init_round_robin;
5267
5268        if (init(cf, uscfp[i]) != NGX_OK) {
5269            return NGX_CONF_ERROR;
5270        }
5271    }
5272
5273
5274    /* upstream_headers_in_hash */
5275
5276    if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
5277        != NGX_OK)
5278    {
5279        return NGX_CONF_ERROR;
5280    }
5281
5282    for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
5283        hk = ngx_array_push(&headers_in);
5284        if (hk == NULL) {
5285            return NGX_CONF_ERROR;
5286        }
5287
5288        hk->key = header->name;
5289        hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
5290        hk->value = header;
5291    }
5292
5293    hash.hash = &umcf->headers_in_hash;
5294    hash.key = ngx_hash_key_lc;
5295    hash.max_size = 512;
5296    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
5297    hash.name = "upstream_headers_in_hash";
5298    hash.pool = cf->pool;
5299    hash.temp_pool = NULL;
5300
5301    if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
5302        return NGX_CONF_ERROR;
5303    }
5304
5305    return NGX_CONF_OK;
5306}
Note: See TracBrowser for help on using the repository browser.