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