Annotation of embedaddon/nginx/src/http/ngx_http_upstream.c, revision 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>