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