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