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