Annotation of embedaddon/nginx/src/http/ngx_http_upstream.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>