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