Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 #if (NGX_HTTP_CACHE)
0014 static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
0015     ngx_http_upstream_t *u);
0016 static ngx_int_t ngx_http_upstream_cache_get(ngx_http_request_t *r,
0017     ngx_http_upstream_t *u, ngx_http_file_cache_t **cache);
0018 static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
0019     ngx_http_upstream_t *u);
0020 static ngx_int_t ngx_http_upstream_cache_background_update(
0021     ngx_http_request_t *r, ngx_http_upstream_t *u);
0022 static ngx_int_t ngx_http_upstream_cache_check_range(ngx_http_request_t *r,
0023     ngx_http_upstream_t *u);
0024 static ngx_int_t ngx_http_upstream_cache_status(ngx_http_request_t *r,
0025     ngx_http_variable_value_t *v, uintptr_t data);
0026 static ngx_int_t ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
0027     ngx_http_variable_value_t *v, uintptr_t data);
0028 static ngx_int_t ngx_http_upstream_cache_etag(ngx_http_request_t *r,
0029     ngx_http_variable_value_t *v, uintptr_t data);
0030 #endif
0031 
0032 static void ngx_http_upstream_init_request(ngx_http_request_t *r);
0033 static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
0034 static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
0035 static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
0036 static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
0037     ngx_event_t *ev);
0038 static void ngx_http_upstream_connect(ngx_http_request_t *r,
0039     ngx_http_upstream_t *u);
0040 static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r,
0041     ngx_http_upstream_t *u);
0042 static void ngx_http_upstream_send_request(ngx_http_request_t *r,
0043     ngx_http_upstream_t *u, ngx_uint_t do_write);
0044 static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r,
0045     ngx_http_upstream_t *u, ngx_uint_t do_write);
0046 static void ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
0047     ngx_http_upstream_t *u);
0048 static void ngx_http_upstream_read_request_handler(ngx_http_request_t *r);
0049 static void ngx_http_upstream_process_header(ngx_http_request_t *r,
0050     ngx_http_upstream_t *u);
0051 static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
0052     ngx_http_upstream_t *u);
0053 static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
0054     ngx_http_upstream_t *u);
0055 static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
0056 static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
0057     ngx_http_upstream_t *u);
0058 static ngx_int_t ngx_http_upstream_process_trailers(ngx_http_request_t *r,
0059     ngx_http_upstream_t *u);
0060 static void ngx_http_upstream_send_response(ngx_http_request_t *r,
0061     ngx_http_upstream_t *u);
0062 static void ngx_http_upstream_upgrade(ngx_http_request_t *r,
0063     ngx_http_upstream_t *u);
0064 static void ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r);
0065 static void ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r);
0066 static void ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
0067     ngx_http_upstream_t *u);
0068 static void ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
0069     ngx_http_upstream_t *u);
0070 static void ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
0071     ngx_uint_t from_upstream, ngx_uint_t do_write);
0072 static void
0073     ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r);
0074 static void
0075     ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
0076     ngx_http_upstream_t *u);
0077 static void
0078     ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
0079     ngx_uint_t do_write);
0080 static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
0081 static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
0082     ssize_t bytes);
0083 #if (NGX_THREADS)
0084 static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task,
0085     ngx_file_t *file);
0086 static void ngx_http_upstream_thread_event_handler(ngx_event_t *ev);
0087 #endif
0088 static ngx_int_t ngx_http_upstream_output_filter(void *data,
0089     ngx_chain_t *chain);
0090 static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
0091 static void ngx_http_upstream_process_upstream(ngx_http_request_t *r,
0092     ngx_http_upstream_t *u);
0093 static void ngx_http_upstream_process_request(ngx_http_request_t *r,
0094     ngx_http_upstream_t *u);
0095 static void ngx_http_upstream_store(ngx_http_request_t *r,
0096     ngx_http_upstream_t *u);
0097 static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r,
0098     ngx_http_upstream_t *u);
0099 static void ngx_http_upstream_next(ngx_http_request_t *r,
0100     ngx_http_upstream_t *u, ngx_uint_t ft_type);
0101 static void ngx_http_upstream_cleanup(void *data);
0102 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r,
0103     ngx_http_upstream_t *u, ngx_int_t rc);
0104 
0105 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r,
0106     ngx_table_elt_t *h, ngx_uint_t offset);
0107 static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r,
0108     ngx_table_elt_t *h, ngx_uint_t offset);
0109 static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
0110     ngx_table_elt_t *h, ngx_uint_t offset);
0111 static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r,
0112     ngx_table_elt_t *h, ngx_uint_t offset);
0113 static ngx_int_t
0114     ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
0115     ngx_table_elt_t *h, ngx_uint_t offset);
0116 static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r,
0117     ngx_table_elt_t *h, ngx_uint_t offset);
0118 static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r,
0119     ngx_table_elt_t *h, ngx_uint_t offset);
0120 static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
0121     ngx_table_elt_t *h, ngx_uint_t offset);
0122 static ngx_int_t ngx_http_upstream_process_limit_rate(ngx_http_request_t *r,
0123     ngx_table_elt_t *h, ngx_uint_t offset);
0124 static ngx_int_t ngx_http_upstream_process_buffering(ngx_http_request_t *r,
0125     ngx_table_elt_t *h, ngx_uint_t offset);
0126 static ngx_int_t ngx_http_upstream_process_charset(ngx_http_request_t *r,
0127     ngx_table_elt_t *h, ngx_uint_t offset);
0128 static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r,
0129     ngx_table_elt_t *h, ngx_uint_t offset);
0130 static ngx_int_t
0131     ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
0132     ngx_table_elt_t *h, ngx_uint_t offset);
0133 static ngx_int_t ngx_http_upstream_process_vary(ngx_http_request_t *r,
0134     ngx_table_elt_t *h, ngx_uint_t offset);
0135 static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r,
0136     ngx_table_elt_t *h, ngx_uint_t offset);
0137 static ngx_int_t
0138     ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
0139     ngx_table_elt_t *h, ngx_uint_t offset);
0140 static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
0141     ngx_table_elt_t *h, ngx_uint_t offset);
0142 static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
0143     ngx_table_elt_t *h, ngx_uint_t offset);
0144 static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
0145     ngx_table_elt_t *h, ngx_uint_t offset);
0146 static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
0147     ngx_table_elt_t *h, ngx_uint_t offset);
0148 static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
0149     ngx_table_elt_t *h, ngx_uint_t offset);
0150 static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
0151     ngx_table_elt_t *h, ngx_uint_t offset);
0152 
0153 #if (NGX_HTTP_GZIP)
0154 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
0155     ngx_table_elt_t *h, ngx_uint_t offset);
0156 #endif
0157 
0158 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
0159 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
0160     ngx_http_variable_value_t *v, uintptr_t data);
0161 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
0162     ngx_http_variable_value_t *v, uintptr_t data);
0163 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
0164     ngx_http_variable_value_t *v, uintptr_t data);
0165 static ngx_int_t ngx_http_upstream_response_length_variable(
0166     ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
0167 static ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
0168     ngx_http_variable_value_t *v, uintptr_t data);
0169 static ngx_int_t ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
0170     ngx_http_variable_value_t *v, uintptr_t data);
0171 static ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
0172     ngx_http_variable_value_t *v, uintptr_t data);
0173 
0174 static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
0175 static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
0176     void *conf);
0177 
0178 static ngx_int_t ngx_http_upstream_set_local(ngx_http_request_t *r,
0179   ngx_http_upstream_t *u, ngx_http_upstream_local_t *local);
0180 
0181 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
0182 static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
0183 
0184 #if (NGX_HTTP_SSL)
0185 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
0186     ngx_http_upstream_t *u, ngx_connection_t *c);
0187 static void ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c);
0188 static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *,
0189     ngx_http_upstream_t *u, ngx_connection_t *c);
0190 static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r,
0191     ngx_http_upstream_t *u, ngx_connection_t *c);
0192 #endif
0193 
0194 
0195 static ngx_http_upstream_header_t  ngx_http_upstream_headers_in[] = {
0196 
0197     { ngx_string("Status"),
0198                  ngx_http_upstream_process_header_line,
0199                  offsetof(ngx_http_upstream_headers_in_t, status),
0200                  ngx_http_upstream_copy_header_line, 0, 0 },
0201 
0202     { ngx_string("Content-Type"),
0203                  ngx_http_upstream_process_header_line,
0204                  offsetof(ngx_http_upstream_headers_in_t, content_type),
0205                  ngx_http_upstream_copy_content_type, 0, 1 },
0206 
0207     { ngx_string("Content-Length"),
0208                  ngx_http_upstream_process_content_length, 0,
0209                  ngx_http_upstream_ignore_header_line, 0, 0 },
0210 
0211     { ngx_string("Date"),
0212                  ngx_http_upstream_process_header_line,
0213                  offsetof(ngx_http_upstream_headers_in_t, date),
0214                  ngx_http_upstream_copy_header_line,
0215                  offsetof(ngx_http_headers_out_t, date), 0 },
0216 
0217     { ngx_string("Last-Modified"),
0218                  ngx_http_upstream_process_last_modified, 0,
0219                  ngx_http_upstream_copy_last_modified, 0, 0 },
0220 
0221     { ngx_string("ETag"),
0222                  ngx_http_upstream_process_header_line,
0223                  offsetof(ngx_http_upstream_headers_in_t, etag),
0224                  ngx_http_upstream_copy_header_line,
0225                  offsetof(ngx_http_headers_out_t, etag), 0 },
0226 
0227     { ngx_string("Server"),
0228                  ngx_http_upstream_process_header_line,
0229                  offsetof(ngx_http_upstream_headers_in_t, server),
0230                  ngx_http_upstream_copy_header_line,
0231                  offsetof(ngx_http_headers_out_t, server), 0 },
0232 
0233     { ngx_string("WWW-Authenticate"),
0234                  ngx_http_upstream_process_header_line,
0235                  offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
0236                  ngx_http_upstream_copy_header_line, 0, 0 },
0237 
0238     { ngx_string("Location"),
0239                  ngx_http_upstream_process_header_line,
0240                  offsetof(ngx_http_upstream_headers_in_t, location),
0241                  ngx_http_upstream_rewrite_location, 0, 0 },
0242 
0243     { ngx_string("Refresh"),
0244                  ngx_http_upstream_ignore_header_line, 0,
0245                  ngx_http_upstream_rewrite_refresh, 0, 0 },
0246 
0247     { ngx_string("Set-Cookie"),
0248                  ngx_http_upstream_process_set_cookie,
0249                  offsetof(ngx_http_upstream_headers_in_t, cookies),
0250                  ngx_http_upstream_rewrite_set_cookie, 0, 1 },
0251 
0252     { ngx_string("Content-Disposition"),
0253                  ngx_http_upstream_ignore_header_line, 0,
0254                  ngx_http_upstream_copy_header_line, 0, 1 },
0255 
0256     { ngx_string("Cache-Control"),
0257                  ngx_http_upstream_process_cache_control, 0,
0258                  ngx_http_upstream_copy_multi_header_lines,
0259                  offsetof(ngx_http_headers_out_t, cache_control), 1 },
0260 
0261     { ngx_string("Expires"),
0262                  ngx_http_upstream_process_expires, 0,
0263                  ngx_http_upstream_copy_header_line,
0264                  offsetof(ngx_http_headers_out_t, expires), 1 },
0265 
0266     { ngx_string("Accept-Ranges"),
0267                  ngx_http_upstream_process_header_line,
0268                  offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
0269                  ngx_http_upstream_copy_allow_ranges,
0270                  offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
0271 
0272     { ngx_string("Content-Range"),
0273                  ngx_http_upstream_ignore_header_line, 0,
0274                  ngx_http_upstream_copy_header_line,
0275                  offsetof(ngx_http_headers_out_t, content_range), 0 },
0276 
0277     { ngx_string("Connection"),
0278                  ngx_http_upstream_process_connection, 0,
0279                  ngx_http_upstream_ignore_header_line, 0, 0 },
0280 
0281     { ngx_string("Keep-Alive"),
0282                  ngx_http_upstream_ignore_header_line, 0,
0283                  ngx_http_upstream_ignore_header_line, 0, 0 },
0284 
0285     { ngx_string("Vary"),
0286                  ngx_http_upstream_process_vary, 0,
0287                  ngx_http_upstream_copy_header_line, 0, 0 },
0288 
0289     { ngx_string("Link"),
0290                  ngx_http_upstream_ignore_header_line, 0,
0291                  ngx_http_upstream_copy_multi_header_lines,
0292                  offsetof(ngx_http_headers_out_t, link), 0 },
0293 
0294     { ngx_string("X-Accel-Expires"),
0295                  ngx_http_upstream_process_accel_expires, 0,
0296                  ngx_http_upstream_copy_header_line, 0, 0 },
0297 
0298     { ngx_string("X-Accel-Redirect"),
0299                  ngx_http_upstream_process_header_line,
0300                  offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect),
0301                  ngx_http_upstream_copy_header_line, 0, 0 },
0302 
0303     { ngx_string("X-Accel-Limit-Rate"),
0304                  ngx_http_upstream_process_limit_rate, 0,
0305                  ngx_http_upstream_copy_header_line, 0, 0 },
0306 
0307     { ngx_string("X-Accel-Buffering"),
0308                  ngx_http_upstream_process_buffering, 0,
0309                  ngx_http_upstream_copy_header_line, 0, 0 },
0310 
0311     { ngx_string("X-Accel-Charset"),
0312                  ngx_http_upstream_process_charset, 0,
0313                  ngx_http_upstream_copy_header_line, 0, 0 },
0314 
0315     { ngx_string("Transfer-Encoding"),
0316                  ngx_http_upstream_process_transfer_encoding, 0,
0317                  ngx_http_upstream_ignore_header_line, 0, 0 },
0318 
0319 #if (NGX_HTTP_GZIP)
0320     { ngx_string("Content-Encoding"),
0321                  ngx_http_upstream_process_header_line,
0322                  offsetof(ngx_http_upstream_headers_in_t, content_encoding),
0323                  ngx_http_upstream_copy_content_encoding, 0, 0 },
0324 #endif
0325 
0326     { ngx_null_string, NULL, 0, NULL, 0, 0 }
0327 };
0328 
0329 
0330 static ngx_command_t  ngx_http_upstream_commands[] = {
0331 
0332     { ngx_string("upstream"),
0333       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
0334       ngx_http_upstream,
0335       0,
0336       0,
0337       NULL },
0338 
0339     { ngx_string("server"),
0340       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
0341       ngx_http_upstream_server,
0342       NGX_HTTP_SRV_CONF_OFFSET,
0343       0,
0344       NULL },
0345 
0346       ngx_null_command
0347 };
0348 
0349 
0350 static ngx_http_module_t  ngx_http_upstream_module_ctx = {
0351     ngx_http_upstream_add_variables,       /* preconfiguration */
0352     NULL,                                  /* postconfiguration */
0353 
0354     ngx_http_upstream_create_main_conf,    /* create main configuration */
0355     ngx_http_upstream_init_main_conf,      /* init main configuration */
0356 
0357     NULL,                                  /* create server configuration */
0358     NULL,                                  /* merge server configuration */
0359 
0360     NULL,                                  /* create location configuration */
0361     NULL                                   /* merge location configuration */
0362 };
0363 
0364 
0365 ngx_module_t  ngx_http_upstream_module = {
0366     NGX_MODULE_V1,
0367     &ngx_http_upstream_module_ctx,         /* module context */
0368     ngx_http_upstream_commands,            /* module directives */
0369     NGX_HTTP_MODULE,                       /* module type */
0370     NULL,                                  /* init master */
0371     NULL,                                  /* init module */
0372     NULL,                                  /* init process */
0373     NULL,                                  /* init thread */
0374     NULL,                                  /* exit thread */
0375     NULL,                                  /* exit process */
0376     NULL,                                  /* exit master */
0377     NGX_MODULE_V1_PADDING
0378 };
0379 
0380 
0381 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
0382 
0383     { ngx_string("upstream_addr"), NULL,
0384       ngx_http_upstream_addr_variable, 0,
0385       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0386 
0387     { ngx_string("upstream_status"), NULL,
0388       ngx_http_upstream_status_variable, 0,
0389       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0390 
0391     { ngx_string("upstream_connect_time"), NULL,
0392       ngx_http_upstream_response_time_variable, 2,
0393       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0394 
0395     { ngx_string("upstream_header_time"), NULL,
0396       ngx_http_upstream_response_time_variable, 1,
0397       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0398 
0399     { ngx_string("upstream_response_time"), NULL,
0400       ngx_http_upstream_response_time_variable, 0,
0401       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0402 
0403     { ngx_string("upstream_response_length"), NULL,
0404       ngx_http_upstream_response_length_variable, 0,
0405       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0406 
0407     { ngx_string("upstream_bytes_received"), NULL,
0408       ngx_http_upstream_response_length_variable, 1,
0409       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0410 
0411 #if (NGX_HTTP_CACHE)
0412 
0413     { ngx_string("upstream_cache_status"), NULL,
0414       ngx_http_upstream_cache_status, 0,
0415       NGX_HTTP_VAR_NOCACHEABLE, 0 },
0416 
0417     { ngx_string("upstream_cache_last_modified"), NULL,
0418       ngx_http_upstream_cache_last_modified, 0,
0419       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0420 
0421     { ngx_string("upstream_cache_etag"), NULL,
0422       ngx_http_upstream_cache_etag, 0,
0423       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0424 
0425 #endif
0426 
0427     { ngx_string("upstream_http_"), NULL, ngx_http_upstream_header_variable,
0428       0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
0429 
0430     { ngx_string("upstream_trailer_"), NULL, ngx_http_upstream_trailer_variable,
0431       0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
0432 
0433     { ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable,
0434       0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
0435 
0436       ngx_http_null_variable
0437 };
0438 
0439 
0440 static ngx_http_upstream_next_t  ngx_http_upstream_next_errors[] = {
0441     { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
0442     { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
0443     { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
0444     { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
0445     { 403, NGX_HTTP_UPSTREAM_FT_HTTP_403 },
0446     { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0447     { 429, NGX_HTTP_UPSTREAM_FT_HTTP_429 },
0448     { 0, 0 }
0449 };
0450 
0451 
0452 ngx_conf_bitmask_t  ngx_http_upstream_cache_method_mask[] = {
0453     { ngx_string("GET"), NGX_HTTP_GET },
0454     { ngx_string("HEAD"), NGX_HTTP_HEAD },
0455     { ngx_string("POST"), NGX_HTTP_POST },
0456     { ngx_null_string, 0 }
0457 };
0458 
0459 
0460 ngx_conf_bitmask_t  ngx_http_upstream_ignore_headers_masks[] = {
0461     { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT },
0462     { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES },
0463     { ngx_string("X-Accel-Limit-Rate"), NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE },
0464     { ngx_string("X-Accel-Buffering"), NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING },
0465     { ngx_string("X-Accel-Charset"), NGX_HTTP_UPSTREAM_IGN_XA_CHARSET },
0466     { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES },
0467     { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL },
0468     { ngx_string("Set-Cookie"), NGX_HTTP_UPSTREAM_IGN_SET_COOKIE },
0469     { ngx_string("Vary"), NGX_HTTP_UPSTREAM_IGN_VARY },
0470     { ngx_null_string, 0 }
0471 };
0472 
0473 
0474 ngx_int_t
0475 ngx_http_upstream_create(ngx_http_request_t *r)
0476 {
0477     ngx_http_upstream_t  *u;
0478 
0479     u = r->upstream;
0480 
0481     if (u && u->cleanup) {
0482         r->main->count++;
0483         ngx_http_upstream_cleanup(r);
0484     }
0485 
0486     u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
0487     if (u == NULL) {
0488         return NGX_ERROR;
0489     }
0490 
0491     r->upstream = u;
0492 
0493     u->peer.log = r->connection->log;
0494     u->peer.log_error = NGX_ERROR_ERR;
0495 
0496 #if (NGX_HTTP_CACHE)
0497     r->cache = NULL;
0498 #endif
0499 
0500     u->headers_in.content_length_n = -1;
0501     u->headers_in.last_modified_time = -1;
0502 
0503     return NGX_OK;
0504 }
0505 
0506 
0507 void
0508 ngx_http_upstream_init(ngx_http_request_t *r)
0509 {
0510     ngx_connection_t     *c;
0511 
0512     c = r->connection;
0513 
0514     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
0515                    "http init upstream, client timer: %d", c->read->timer_set);
0516 
0517 #if (NGX_HTTP_V2)
0518     if (r->stream) {
0519         ngx_http_upstream_init_request(r);
0520         return;
0521     }
0522 #endif
0523 
0524     if (c->read->timer_set) {
0525         ngx_del_timer(c->read);
0526     }
0527 
0528     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
0529 
0530         if (!c->write->active) {
0531             if (ngx_add_event(c->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
0532                 == NGX_ERROR)
0533             {
0534                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0535                 return;
0536             }
0537         }
0538     }
0539 
0540     ngx_http_upstream_init_request(r);
0541 }
0542 
0543 
0544 static void
0545 ngx_http_upstream_init_request(ngx_http_request_t *r)
0546 {
0547     ngx_str_t                      *host;
0548     ngx_uint_t                      i;
0549     ngx_resolver_ctx_t             *ctx, temp;
0550     ngx_http_cleanup_t             *cln;
0551     ngx_http_upstream_t            *u;
0552     ngx_http_core_loc_conf_t       *clcf;
0553     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
0554     ngx_http_upstream_main_conf_t  *umcf;
0555 
0556     if (r->aio) {
0557         return;
0558     }
0559 
0560     u = r->upstream;
0561 
0562 #if (NGX_HTTP_CACHE)
0563 
0564     if (u->conf->cache) {
0565         ngx_int_t  rc;
0566 
0567         rc = ngx_http_upstream_cache(r, u);
0568 
0569         if (rc == NGX_BUSY) {
0570             r->write_event_handler = ngx_http_upstream_init_request;
0571             return;
0572         }
0573 
0574         r->write_event_handler = ngx_http_request_empty_handler;
0575 
0576         if (rc == NGX_ERROR) {
0577             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0578             return;
0579         }
0580 
0581         if (rc == NGX_OK) {
0582             rc = ngx_http_upstream_cache_send(r, u);
0583 
0584             if (rc == NGX_DONE) {
0585                 return;
0586             }
0587 
0588             if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
0589                 rc = NGX_DECLINED;
0590                 r->cached = 0;
0591                 u->buffer.start = NULL;
0592                 u->cache_status = NGX_HTTP_CACHE_MISS;
0593                 u->request_sent = 1;
0594             }
0595 
0596             if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) {
0597                 rc = NGX_ERROR;
0598             }
0599         }
0600 
0601         if (rc != NGX_DECLINED) {
0602             ngx_http_finalize_request(r, rc);
0603             return;
0604         }
0605     }
0606 
0607 #endif
0608 
0609     u->store = u->conf->store;
0610 
0611     if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
0612         r->read_event_handler = ngx_http_upstream_rd_check_broken_connection;
0613         r->write_event_handler = ngx_http_upstream_wr_check_broken_connection;
0614     }
0615 
0616     if (r->request_body) {
0617         u->request_bufs = r->request_body->bufs;
0618     }
0619 
0620     if (u->create_request(r) != NGX_OK) {
0621         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0622         return;
0623     }
0624 
0625     if (ngx_http_upstream_set_local(r, u, u->conf->local) != NGX_OK) {
0626         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0627         return;
0628     }
0629 
0630     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0631 
0632     u->output.alignment = clcf->directio_alignment;
0633     u->output.pool = r->pool;
0634     u->output.bufs.num = 1;
0635     u->output.bufs.size = clcf->client_body_buffer_size;
0636 
0637     if (u->output.output_filter == NULL) {
0638         u->output.output_filter = ngx_chain_writer;
0639         u->output.filter_ctx = &u->writer;
0640     }
0641 
0642     u->writer.pool = r->pool;
0643 
0644     if (r->upstream_states == NULL) {
0645 
0646         r->upstream_states = ngx_array_create(r->pool, 1,
0647                                             sizeof(ngx_http_upstream_state_t));
0648         if (r->upstream_states == NULL) {
0649             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0650             return;
0651         }
0652 
0653     } else {
0654 
0655         u->state = ngx_array_push(r->upstream_states);
0656         if (u->state == NULL) {
0657             ngx_http_upstream_finalize_request(r, u,
0658                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0659             return;
0660         }
0661 
0662         ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
0663     }
0664 
0665     cln = ngx_http_cleanup_add(r, 0);
0666     if (cln == NULL) {
0667         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
0668         return;
0669     }
0670 
0671     cln->handler = ngx_http_upstream_cleanup;
0672     cln->data = r;
0673     u->cleanup = &cln->handler;
0674 
0675     if (u->resolved == NULL) {
0676 
0677         uscf = u->conf->upstream;
0678 
0679     } else {
0680 
0681 #if (NGX_HTTP_SSL)
0682         u->ssl_name = u->resolved->host;
0683 #endif
0684 
0685         host = &u->resolved->host;
0686 
0687         umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
0688 
0689         uscfp = umcf->upstreams.elts;
0690 
0691         for (i = 0; i < umcf->upstreams.nelts; i++) {
0692 
0693             uscf = uscfp[i];
0694 
0695             if (uscf->host.len == host->len
0696                 && ((uscf->port == 0 && u->resolved->no_port)
0697                      || uscf->port == u->resolved->port)
0698                 && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0)
0699             {
0700                 goto found;
0701             }
0702         }
0703 
0704         if (u->resolved->sockaddr) {
0705 
0706             if (u->resolved->port == 0
0707                 && u->resolved->sockaddr->sa_family != AF_UNIX)
0708             {
0709                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0710                               "no port in upstream \"%V\"", host);
0711                 ngx_http_upstream_finalize_request(r, u,
0712                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0713                 return;
0714             }
0715 
0716             if (ngx_http_upstream_create_round_robin_peer(r, u->resolved)
0717                 != NGX_OK)
0718             {
0719                 ngx_http_upstream_finalize_request(r, u,
0720                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0721                 return;
0722             }
0723 
0724             ngx_http_upstream_connect(r, u);
0725 
0726             return;
0727         }
0728 
0729         if (u->resolved->port == 0) {
0730             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0731                           "no port in upstream \"%V\"", host);
0732             ngx_http_upstream_finalize_request(r, u,
0733                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0734             return;
0735         }
0736 
0737         temp.name = *host;
0738 
0739         ctx = ngx_resolve_start(clcf->resolver, &temp);
0740         if (ctx == NULL) {
0741             ngx_http_upstream_finalize_request(r, u,
0742                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0743             return;
0744         }
0745 
0746         if (ctx == NGX_NO_RESOLVER) {
0747             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0748                           "no resolver defined to resolve %V", host);
0749 
0750             ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
0751             return;
0752         }
0753 
0754         ctx->name = *host;
0755         ctx->handler = ngx_http_upstream_resolve_handler;
0756         ctx->data = r;
0757         ctx->timeout = clcf->resolver_timeout;
0758 
0759         u->resolved->ctx = ctx;
0760 
0761         if (ngx_resolve_name(ctx) != NGX_OK) {
0762             u->resolved->ctx = NULL;
0763             ngx_http_upstream_finalize_request(r, u,
0764                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
0765             return;
0766         }
0767 
0768         return;
0769     }
0770 
0771 found:
0772 
0773     if (uscf == NULL) {
0774         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
0775                       "no upstream configuration");
0776         ngx_http_upstream_finalize_request(r, u,
0777                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
0778         return;
0779     }
0780 
0781     u->upstream = uscf;
0782 
0783 #if (NGX_HTTP_SSL)
0784     u->ssl_name = uscf->host;
0785 #endif
0786 
0787     if (uscf->peer.init(r, uscf) != NGX_OK) {
0788         ngx_http_upstream_finalize_request(r, u,
0789                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
0790         return;
0791     }
0792 
0793     u->peer.start_time = ngx_current_msec;
0794 
0795     if (u->conf->next_upstream_tries
0796         && u->peer.tries > u->conf->next_upstream_tries)
0797     {
0798         u->peer.tries = u->conf->next_upstream_tries;
0799     }
0800 
0801     ngx_http_upstream_connect(r, u);
0802 }
0803 
0804 
0805 #if (NGX_HTTP_CACHE)
0806 
0807 static ngx_int_t
0808 ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
0809 {
0810     ngx_int_t               rc;
0811     ngx_http_cache_t       *c;
0812     ngx_http_file_cache_t  *cache;
0813 
0814     c = r->cache;
0815 
0816     if (c == NULL) {
0817 
0818         if (!(r->method & u->conf->cache_methods)) {
0819             return NGX_DECLINED;
0820         }
0821 
0822         rc = ngx_http_upstream_cache_get(r, u, &cache);
0823 
0824         if (rc != NGX_OK) {
0825             return rc;
0826         }
0827 
0828         if (r->method == NGX_HTTP_HEAD && u->conf->cache_convert_head) {
0829             u->method = ngx_http_core_get_method;
0830         }
0831 
0832         if (ngx_http_file_cache_new(r) != NGX_OK) {
0833             return NGX_ERROR;
0834         }
0835 
0836         if (u->create_key(r) != NGX_OK) {
0837             return NGX_ERROR;
0838         }
0839 
0840         /* TODO: add keys */
0841 
0842         ngx_http_file_cache_create_key(r);
0843 
0844         if (r->cache->header_start + 256 >= u->conf->buffer_size) {
0845             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0846                           "%V_buffer_size %uz is not enough for cache key, "
0847                           "it should be increased to at least %uz",
0848                           &u->conf->module, u->conf->buffer_size,
0849                           ngx_align(r->cache->header_start + 256, 1024));
0850 
0851             r->cache = NULL;
0852             return NGX_DECLINED;
0853         }
0854 
0855         u->cacheable = 1;
0856 
0857         c = r->cache;
0858 
0859         c->body_start = u->conf->buffer_size;
0860         c->min_uses = u->conf->cache_min_uses;
0861         c->file_cache = cache;
0862 
0863         switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {
0864 
0865         case NGX_ERROR:
0866             return NGX_ERROR;
0867 
0868         case NGX_DECLINED:
0869             u->cache_status = NGX_HTTP_CACHE_BYPASS;
0870             return NGX_DECLINED;
0871 
0872         default: /* NGX_OK */
0873             break;
0874         }
0875 
0876         c->lock = u->conf->cache_lock;
0877         c->lock_timeout = u->conf->cache_lock_timeout;
0878         c->lock_age = u->conf->cache_lock_age;
0879 
0880         u->cache_status = NGX_HTTP_CACHE_MISS;
0881     }
0882 
0883     rc = ngx_http_file_cache_open(r);
0884 
0885     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0886                    "http upstream cache: %i", rc);
0887 
0888     switch (rc) {
0889 
0890     case NGX_HTTP_CACHE_STALE:
0891 
0892         if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
0893              || c->stale_updating) && !r->background
0894             && u->conf->cache_background_update)
0895         {
0896             r->cache->background = 1;
0897             u->cache_status = rc;
0898             rc = NGX_OK;
0899         }
0900 
0901         break;
0902 
0903     case NGX_HTTP_CACHE_UPDATING:
0904 
0905         if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
0906              || c->stale_updating) && !r->background)
0907         {
0908             u->cache_status = rc;
0909             rc = NGX_OK;
0910 
0911         } else {
0912             rc = NGX_HTTP_CACHE_STALE;
0913         }
0914 
0915         break;
0916 
0917     case NGX_OK:
0918         u->cache_status = NGX_HTTP_CACHE_HIT;
0919     }
0920 
0921     switch (rc) {
0922 
0923     case NGX_OK:
0924 
0925         return NGX_OK;
0926 
0927     case NGX_HTTP_CACHE_STALE:
0928 
0929         c->valid_sec = 0;
0930         c->updating_sec = 0;
0931         c->error_sec = 0;
0932 
0933         u->buffer.start = NULL;
0934         u->cache_status = NGX_HTTP_CACHE_EXPIRED;
0935 
0936         break;
0937 
0938     case NGX_DECLINED:
0939 
0940         if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
0941             u->buffer.start = NULL;
0942 
0943         } else {
0944             u->buffer.pos = u->buffer.start + c->header_start;
0945             u->buffer.last = u->buffer.pos;
0946         }
0947 
0948         break;
0949 
0950     case NGX_HTTP_CACHE_SCARCE:
0951 
0952         u->cacheable = 0;
0953 
0954         break;
0955 
0956     case NGX_AGAIN:
0957 
0958         return NGX_BUSY;
0959 
0960     case NGX_ERROR:
0961 
0962         return NGX_ERROR;
0963 
0964     default:
0965 
0966         /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
0967 
0968         u->cache_status = NGX_HTTP_CACHE_HIT;
0969 
0970         return rc;
0971     }
0972 
0973     if (ngx_http_upstream_cache_check_range(r, u) == NGX_DECLINED) {
0974         u->cacheable = 0;
0975     }
0976 
0977     r->cached = 0;
0978 
0979     return NGX_DECLINED;
0980 }
0981 
0982 
0983 static ngx_int_t
0984 ngx_http_upstream_cache_get(ngx_http_request_t *r, ngx_http_upstream_t *u,
0985     ngx_http_file_cache_t **cache)
0986 {
0987     ngx_str_t               *name, val;
0988     ngx_uint_t               i;
0989     ngx_http_file_cache_t  **caches;
0990 
0991     if (u->conf->cache_zone) {
0992         *cache = u->conf->cache_zone->data;
0993         return NGX_OK;
0994     }
0995 
0996     if (ngx_http_complex_value(r, u->conf->cache_value, &val) != NGX_OK) {
0997         return NGX_ERROR;
0998     }
0999 
1000     if (val.len == 0
1001         || (val.len == 3 && ngx_strncmp(val.data, "off", 3) == 0))
1002     {
1003         return NGX_DECLINED;
1004     }
1005 
1006     caches = u->caches->elts;
1007 
1008     for (i = 0; i < u->caches->nelts; i++) {
1009         name = &caches[i]->shm_zone->shm.name;
1010 
1011         if (name->len == val.len
1012             && ngx_strncmp(name->data, val.data, val.len) == 0)
1013         {
1014             *cache = caches[i];
1015             return NGX_OK;
1016         }
1017     }
1018 
1019     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1020                   "cache \"%V\" not found", &val);
1021 
1022     return NGX_ERROR;
1023 }
1024 
1025 
1026 static ngx_int_t
1027 ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
1028 {
1029     ngx_int_t          rc;
1030     ngx_http_cache_t  *c;
1031 
1032     r->cached = 1;
1033     c = r->cache;
1034 
1035     if (c->header_start == c->body_start) {
1036         r->http_version = NGX_HTTP_VERSION_9;
1037         return ngx_http_cache_send(r);
1038     }
1039 
1040     /* TODO: cache stack */
1041 
1042     u->buffer = *c->buf;
1043     u->buffer.pos += c->header_start;
1044 
1045     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
1046     u->headers_in.content_length_n = -1;
1047     u->headers_in.last_modified_time = -1;
1048 
1049     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1050                       sizeof(ngx_table_elt_t))
1051         != NGX_OK)
1052     {
1053         return NGX_ERROR;
1054     }
1055 
1056     if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
1057                       sizeof(ngx_table_elt_t))
1058         != NGX_OK)
1059     {
1060         return NGX_ERROR;
1061     }
1062 
1063     rc = u->process_header(r);
1064 
1065     if (rc == NGX_OK) {
1066 
1067         if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
1068             return NGX_DONE;
1069         }
1070 
1071         return ngx_http_cache_send(r);
1072     }
1073 
1074     if (rc == NGX_ERROR) {
1075         return NGX_ERROR;
1076     }
1077 
1078     if (rc == NGX_AGAIN) {
1079         rc = NGX_HTTP_UPSTREAM_INVALID_HEADER;
1080     }
1081 
1082     /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */
1083 
1084     ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
1085                   "cache file \"%s\" contains invalid header",
1086                   c->file.name.data);
1087 
1088     /* TODO: delete file */
1089 
1090     return rc;
1091 }
1092 
1093 
1094 static ngx_int_t
1095 ngx_http_upstream_cache_background_update(ngx_http_request_t *r,
1096     ngx_http_upstream_t *u)
1097 {
1098     ngx_http_request_t  *sr;
1099 
1100     if (!r->cached || !r->cache->background) {
1101         return NGX_OK;
1102     }
1103 
1104     if (r == r->main) {
1105         r->preserve_body = 1;
1106     }
1107 
1108     if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL,
1109                             NGX_HTTP_SUBREQUEST_CLONE
1110                             |NGX_HTTP_SUBREQUEST_BACKGROUND)
1111         != NGX_OK)
1112     {
1113         return NGX_ERROR;
1114     }
1115 
1116     sr->header_only = 1;
1117 
1118     return NGX_OK;
1119 }
1120 
1121 
1122 static ngx_int_t
1123 ngx_http_upstream_cache_check_range(ngx_http_request_t *r,
1124     ngx_http_upstream_t *u)
1125 {
1126     off_t             offset;
1127     u_char           *p, *start;
1128     ngx_table_elt_t  *h;
1129 
1130     h = r->headers_in.range;
1131 
1132     if (h == NULL
1133         || !u->cacheable
1134         || u->conf->cache_max_range_offset == NGX_MAX_OFF_T_VALUE)
1135     {
1136         return NGX_OK;
1137     }
1138 
1139     if (u->conf->cache_max_range_offset == 0) {
1140         return NGX_DECLINED;
1141     }
1142 
1143     if (h->value.len < 7
1144         || ngx_strncasecmp(h->value.data, (u_char *) "bytes=", 6) != 0)
1145     {
1146         return NGX_OK;
1147     }
1148 
1149     p = h->value.data + 6;
1150 
1151     while (*p == ' ') { p++; }
1152 
1153     if (*p == '-') {
1154         return NGX_DECLINED;
1155     }
1156 
1157     start = p;
1158 
1159     while (*p >= '0' && *p <= '9') { p++; }
1160 
1161     offset = ngx_atoof(start, p - start);
1162 
1163     if (offset >= u->conf->cache_max_range_offset) {
1164         return NGX_DECLINED;
1165     }
1166 
1167     return NGX_OK;
1168 }
1169 
1170 #endif
1171 
1172 
1173 static void
1174 ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
1175 {
1176     ngx_uint_t                     run_posted;
1177     ngx_connection_t              *c;
1178     ngx_http_request_t            *r;
1179     ngx_http_upstream_t           *u;
1180     ngx_http_upstream_resolved_t  *ur;
1181 
1182     run_posted = ctx->async;
1183 
1184     r = ctx->data;
1185     c = r->connection;
1186 
1187     u = r->upstream;
1188     ur = u->resolved;
1189 
1190     ngx_http_set_log_request(c->log, r);
1191 
1192     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1193                    "http upstream resolve: \"%V?%V\"", &r->uri, &r->args);
1194 
1195     if (ctx->state) {
1196         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1197                       "%V could not be resolved (%i: %s)",
1198                       &ctx->name, ctx->state,
1199                       ngx_resolver_strerror(ctx->state));
1200 
1201         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
1202         goto failed;
1203     }
1204 
1205     ur->naddrs = ctx->naddrs;
1206     ur->addrs = ctx->addrs;
1207 
1208 #if (NGX_DEBUG)
1209     {
1210     u_char      text[NGX_SOCKADDR_STRLEN];
1211     ngx_str_t   addr;
1212     ngx_uint_t  i;
1213 
1214     addr.data = text;
1215 
1216     for (i = 0; i < ctx->naddrs; i++) {
1217         addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
1218                                  text, NGX_SOCKADDR_STRLEN, 0);
1219 
1220         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1221                        "name was resolved to %V", &addr);
1222     }
1223     }
1224 #endif
1225 
1226     if (ngx_http_upstream_create_round_robin_peer(r, ur) != NGX_OK) {
1227         ngx_http_upstream_finalize_request(r, u,
1228                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1229         goto failed;
1230     }
1231 
1232     ngx_resolve_name_done(ctx);
1233     ur->ctx = NULL;
1234 
1235     u->peer.start_time = ngx_current_msec;
1236 
1237     if (u->conf->next_upstream_tries
1238         && u->peer.tries > u->conf->next_upstream_tries)
1239     {
1240         u->peer.tries = u->conf->next_upstream_tries;
1241     }
1242 
1243     ngx_http_upstream_connect(r, u);
1244 
1245 failed:
1246 
1247     if (run_posted) {
1248         ngx_http_run_posted_requests(c);
1249     }
1250 }
1251 
1252 
1253 static void
1254 ngx_http_upstream_handler(ngx_event_t *ev)
1255 {
1256     ngx_connection_t     *c;
1257     ngx_http_request_t   *r;
1258     ngx_http_upstream_t  *u;
1259 
1260     c = ev->data;
1261     r = c->data;
1262 
1263     u = r->upstream;
1264     c = r->connection;
1265 
1266     ngx_http_set_log_request(c->log, r);
1267 
1268     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1269                    "http upstream request: \"%V?%V\"", &r->uri, &r->args);
1270 
1271     if (ev->delayed && ev->timedout) {
1272         ev->delayed = 0;
1273         ev->timedout = 0;
1274     }
1275 
1276     if (ev->write) {
1277         u->write_event_handler(r, u);
1278 
1279     } else {
1280         u->read_event_handler(r, u);
1281     }
1282 
1283     ngx_http_run_posted_requests(c);
1284 }
1285 
1286 
1287 static void
1288 ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r)
1289 {
1290     ngx_http_upstream_check_broken_connection(r, r->connection->read);
1291 }
1292 
1293 
1294 static void
1295 ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r)
1296 {
1297     ngx_http_upstream_check_broken_connection(r, r->connection->write);
1298 }
1299 
1300 
1301 static void
1302 ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
1303     ngx_event_t *ev)
1304 {
1305     int                  n;
1306     char                 buf[1];
1307     ngx_err_t            err;
1308     ngx_int_t            event;
1309     ngx_connection_t     *c;
1310     ngx_http_upstream_t  *u;
1311 
1312     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0,
1313                    "http upstream check client, write event:%d, \"%V\"",
1314                    ev->write, &r->uri);
1315 
1316     c = r->connection;
1317     u = r->upstream;
1318 
1319     if (c->error) {
1320         if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
1321 
1322             event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
1323 
1324             if (ngx_del_event(ev, event, 0) != NGX_OK) {
1325                 ngx_http_upstream_finalize_request(r, u,
1326                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1327                 return;
1328             }
1329         }
1330 
1331         if (!u->cacheable) {
1332             ngx_http_upstream_finalize_request(r, u,
1333                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
1334         }
1335 
1336         return;
1337     }
1338 
1339 #if (NGX_HTTP_V2)
1340     if (r->stream) {
1341         return;
1342     }
1343 #endif
1344 
1345 #if (NGX_HAVE_KQUEUE)
1346 
1347     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
1348 
1349         if (!ev->pending_eof) {
1350             return;
1351         }
1352 
1353         ev->eof = 1;
1354         c->error = 1;
1355 
1356         if (ev->kq_errno) {
1357             ev->error = 1;
1358         }
1359 
1360         if (!u->cacheable && u->peer.connection) {
1361             ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
1362                           "kevent() reported that client prematurely closed "
1363                           "connection, so upstream connection is closed too");
1364             ngx_http_upstream_finalize_request(r, u,
1365                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
1366             return;
1367         }
1368 
1369         ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
1370                       "kevent() reported that client prematurely closed "
1371                       "connection");
1372 
1373         if (u->peer.connection == NULL) {
1374             ngx_http_upstream_finalize_request(r, u,
1375                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
1376         }
1377 
1378         return;
1379     }
1380 
1381 #endif
1382 
1383 #if (NGX_HAVE_EPOLLRDHUP)
1384 
1385     if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) {
1386         socklen_t  len;
1387 
1388         if (!ev->pending_eof) {
1389             return;
1390         }
1391 
1392         ev->eof = 1;
1393         c->error = 1;
1394 
1395         err = 0;
1396         len = sizeof(ngx_err_t);
1397 
1398         /*
1399          * BSDs and Linux return 0 and set a pending error in err
1400          * Solaris returns -1 and sets errno
1401          */
1402 
1403         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
1404             == -1)
1405         {
1406             err = ngx_socket_errno;
1407         }
1408 
1409         if (err) {
1410             ev->error = 1;
1411         }
1412 
1413         if (!u->cacheable && u->peer.connection) {
1414             ngx_log_error(NGX_LOG_INFO, ev->log, err,
1415                         "epoll_wait() reported that client prematurely closed "
1416                         "connection, so upstream connection is closed too");
1417             ngx_http_upstream_finalize_request(r, u,
1418                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
1419             return;
1420         }
1421 
1422         ngx_log_error(NGX_LOG_INFO, ev->log, err,
1423                       "epoll_wait() reported that client prematurely closed "
1424                       "connection");
1425 
1426         if (u->peer.connection == NULL) {
1427             ngx_http_upstream_finalize_request(r, u,
1428                                                NGX_HTTP_CLIENT_CLOSED_REQUEST);
1429         }
1430 
1431         return;
1432     }
1433 
1434 #endif
1435 
1436     n = recv(c->fd, buf, 1, MSG_PEEK);
1437 
1438     err = ngx_socket_errno;
1439 
1440     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err,
1441                    "http upstream recv(): %d", n);
1442 
1443     if (ev->write && (n >= 0 || err == NGX_EAGAIN)) {
1444         return;
1445     }
1446 
1447     if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) {
1448 
1449         event = ev->write ? NGX_WRITE_EVENT : NGX_READ_EVENT;
1450 
1451         if (ngx_del_event(ev, event, 0) != NGX_OK) {
1452             ngx_http_upstream_finalize_request(r, u,
1453                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1454             return;
1455         }
1456     }
1457 
1458     if (n > 0) {
1459         return;
1460     }
1461 
1462     if (n == -1) {
1463         if (err == NGX_EAGAIN) {
1464             return;
1465         }
1466 
1467         ev->error = 1;
1468 
1469     } else { /* n == 0 */
1470         err = 0;
1471     }
1472 
1473     ev->eof = 1;
1474     c->error = 1;
1475 
1476     if (!u->cacheable && u->peer.connection) {
1477         ngx_log_error(NGX_LOG_INFO, ev->log, err,
1478                       "client prematurely closed connection, "
1479                       "so upstream connection is closed too");
1480         ngx_http_upstream_finalize_request(r, u,
1481                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
1482         return;
1483     }
1484 
1485     ngx_log_error(NGX_LOG_INFO, ev->log, err,
1486                   "client prematurely closed connection");
1487 
1488     if (u->peer.connection == NULL) {
1489         ngx_http_upstream_finalize_request(r, u,
1490                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
1491     }
1492 }
1493 
1494 
1495 static void
1496 ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
1497 {
1498     ngx_int_t          rc;
1499     ngx_connection_t  *c;
1500 
1501     r->connection->log->action = "connecting to upstream";
1502 
1503     if (u->state && u->state->response_time) {
1504         u->state->response_time = ngx_current_msec - u->state->response_time;
1505     }
1506 
1507     u->state = ngx_array_push(r->upstream_states);
1508     if (u->state == NULL) {
1509         ngx_http_upstream_finalize_request(r, u,
1510                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1511         return;
1512     }
1513 
1514     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
1515 
1516     u->state->response_time = ngx_current_msec;
1517     u->state->connect_time = (ngx_msec_t) -1;
1518     u->state->header_time = (ngx_msec_t) -1;
1519 
1520     rc = ngx_event_connect_peer(&u->peer);
1521 
1522     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1523                    "http upstream connect: %i", rc);
1524 
1525     if (rc == NGX_ERROR) {
1526         ngx_http_upstream_finalize_request(r, u,
1527                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1528         return;
1529     }
1530 
1531     u->state->peer = u->peer.name;
1532 
1533     if (rc == NGX_BUSY) {
1534         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
1535         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE);
1536         return;
1537     }
1538 
1539     if (rc == NGX_DECLINED) {
1540         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1541         return;
1542     }
1543 
1544     /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */
1545 
1546     c = u->peer.connection;
1547 
1548     c->data = r;
1549 
1550     c->write->handler = ngx_http_upstream_handler;
1551     c->read->handler = ngx_http_upstream_handler;
1552 
1553     u->write_event_handler = ngx_http_upstream_send_request_handler;
1554     u->read_event_handler = ngx_http_upstream_process_header;
1555 
1556     c->sendfile &= r->connection->sendfile;
1557     u->output.sendfile = c->sendfile;
1558 
1559     if (c->pool == NULL) {
1560 
1561         /* we need separate pool here to be able to cache SSL connections */
1562 
1563         c->pool = ngx_create_pool(128, r->connection->log);
1564         if (c->pool == NULL) {
1565             ngx_http_upstream_finalize_request(r, u,
1566                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1567             return;
1568         }
1569     }
1570 
1571     c->log = r->connection->log;
1572     c->pool->log = c->log;
1573     c->read->log = c->log;
1574     c->write->log = c->log;
1575 
1576     /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */
1577 
1578     u->writer.out = NULL;
1579     u->writer.last = &u->writer.out;
1580     u->writer.connection = c;
1581     u->writer.limit = 0;
1582 
1583     if (u->request_sent) {
1584         if (ngx_http_upstream_reinit(r, u) != NGX_OK) {
1585             ngx_http_upstream_finalize_request(r, u,
1586                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1587             return;
1588         }
1589     }
1590 
1591     if (r->request_body
1592         && r->request_body->buf
1593         && r->request_body->temp_file
1594         && r == r->main)
1595     {
1596         /*
1597          * the r->request_body->buf can be reused for one request only,
1598          * the subrequests should allocate their own temporary bufs
1599          */
1600 
1601         u->output.free = ngx_alloc_chain_link(r->pool);
1602         if (u->output.free == NULL) {
1603             ngx_http_upstream_finalize_request(r, u,
1604                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1605             return;
1606         }
1607 
1608         u->output.free->buf = r->request_body->buf;
1609         u->output.free->next = NULL;
1610         u->output.allocated = 1;
1611 
1612         r->request_body->buf->pos = r->request_body->buf->start;
1613         r->request_body->buf->last = r->request_body->buf->start;
1614         r->request_body->buf->tag = u->output.tag;
1615     }
1616 
1617     u->request_sent = 0;
1618     u->request_body_sent = 0;
1619     u->request_body_blocked = 0;
1620 
1621     if (rc == NGX_AGAIN) {
1622         ngx_add_timer(c->write, u->conf->connect_timeout);
1623         return;
1624     }
1625 
1626 #if (NGX_HTTP_SSL)
1627 
1628     if (u->ssl && c->ssl == NULL) {
1629         ngx_http_upstream_ssl_init_connection(r, u, c);
1630         return;
1631     }
1632 
1633 #endif
1634 
1635     ngx_http_upstream_send_request(r, u, 1);
1636 }
1637 
1638 
1639 #if (NGX_HTTP_SSL)
1640 
1641 static void
1642 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
1643     ngx_http_upstream_t *u, ngx_connection_t *c)
1644 {
1645     ngx_int_t                  rc;
1646     ngx_http_core_loc_conf_t  *clcf;
1647 
1648     if (ngx_http_upstream_test_connect(c) != NGX_OK) {
1649         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1650         return;
1651     }
1652 
1653     if (ngx_ssl_create_connection(u->conf->ssl, c,
1654                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
1655         != NGX_OK)
1656     {
1657         ngx_http_upstream_finalize_request(r, u,
1658                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
1659         return;
1660     }
1661 
1662     c->sendfile = 0;
1663     u->output.sendfile = 0;
1664 
1665     if (u->conf->ssl_server_name || u->conf->ssl_verify) {
1666         if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
1667             ngx_http_upstream_finalize_request(r, u,
1668                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1669             return;
1670         }
1671     }
1672 
1673     if (u->conf->ssl_session_reuse) {
1674         if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
1675             ngx_http_upstream_finalize_request(r, u,
1676                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1677             return;
1678         }
1679 
1680         /* abbreviated SSL handshake may interact badly with Nagle */
1681 
1682         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1683 
1684         if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
1685             ngx_http_upstream_finalize_request(r, u,
1686                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
1687             return;
1688         }
1689     }
1690 
1691     r->connection->log->action = "SSL handshaking to upstream";
1692 
1693     rc = ngx_ssl_handshake(c);
1694 
1695     if (rc == NGX_AGAIN) {
1696 
1697         if (!c->write->timer_set) {
1698             ngx_add_timer(c->write, u->conf->connect_timeout);
1699         }
1700 
1701         c->ssl->handler = ngx_http_upstream_ssl_handshake_handler;
1702         return;
1703     }
1704 
1705     ngx_http_upstream_ssl_handshake(r, u, c);
1706 }
1707 
1708 
1709 static void
1710 ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c)
1711 {
1712     ngx_http_request_t   *r;
1713     ngx_http_upstream_t  *u;
1714 
1715     r = c->data;
1716 
1717     u = r->upstream;
1718     c = r->connection;
1719 
1720     ngx_http_set_log_request(c->log, r);
1721 
1722     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1723                    "http upstream ssl handshake: \"%V?%V\"",
1724                    &r->uri, &r->args);
1725 
1726     ngx_http_upstream_ssl_handshake(r, u, u->peer.connection);
1727 
1728     ngx_http_run_posted_requests(c);
1729 }
1730 
1731 
1732 static void
1733 ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u,
1734     ngx_connection_t *c)
1735 {
1736     long  rc;
1737 
1738     if (c->ssl->handshaked) {
1739 
1740         if (u->conf->ssl_verify) {
1741             rc = SSL_get_verify_result(c->ssl->connection);
1742 
1743             if (rc != X509_V_OK) {
1744                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1745                               "upstream SSL certificate verify error: (%l:%s)",
1746                               rc, X509_verify_cert_error_string(rc));
1747                 goto failed;
1748             }
1749 
1750             if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) {
1751                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1752                               "upstream SSL certificate does not match \"%V\"",
1753                               &u->ssl_name);
1754                 goto failed;
1755             }
1756         }
1757 
1758         if (u->conf->ssl_session_reuse) {
1759             u->peer.save_session(&u->peer, u->peer.data);
1760         }
1761 
1762         c->write->handler = ngx_http_upstream_handler;
1763         c->read->handler = ngx_http_upstream_handler;
1764 
1765         ngx_http_upstream_send_request(r, u, 1);
1766 
1767         return;
1768     }
1769 
1770     if (c->write->timedout) {
1771         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
1772         return;
1773     }
1774 
1775 failed:
1776 
1777     ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1778 }
1779 
1780 
1781 static ngx_int_t
1782 ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u,
1783     ngx_connection_t *c)
1784 {
1785     u_char     *p, *last;
1786     ngx_str_t   name;
1787 
1788     if (u->conf->ssl_name) {
1789         if (ngx_http_complex_value(r, u->conf->ssl_name, &name) != NGX_OK) {
1790             return NGX_ERROR;
1791         }
1792 
1793     } else {
1794         name = u->ssl_name;
1795     }
1796 
1797     if (name.len == 0) {
1798         goto done;
1799     }
1800 
1801     /*
1802      * ssl name here may contain port, notably if derived from $proxy_host
1803      * or $http_host; we have to strip it
1804      */
1805 
1806     p = name.data;
1807     last = name.data + name.len;
1808 
1809     if (*p == '[') {
1810         p = ngx_strlchr(p, last, ']');
1811 
1812         if (p == NULL) {
1813             p = name.data;
1814         }
1815     }
1816 
1817     p = ngx_strlchr(p, last, ':');
1818 
1819     if (p != NULL) {
1820         name.len = p - name.data;
1821     }
1822 
1823     if (!u->conf->ssl_server_name) {
1824         goto done;
1825     }
1826 
1827 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1828 
1829     /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */
1830 
1831     if (name.len == 0 || *name.data == '[') {
1832         goto done;
1833     }
1834 
1835     if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) {
1836         goto done;
1837     }
1838 
1839     /*
1840      * SSL_set_tlsext_host_name() needs a null-terminated string,
1841      * hence we explicitly null-terminate name here
1842      */
1843 
1844     p = ngx_pnalloc(r->pool, name.len + 1);
1845     if (p == NULL) {
1846         return NGX_ERROR;
1847     }
1848 
1849     (void) ngx_cpystrn(p, name.data, name.len + 1);
1850 
1851     name.data = p;
1852 
1853     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1854                    "upstream SSL server name: \"%s\"", name.data);
1855 
1856     if (SSL_set_tlsext_host_name(c->ssl->connection,
1857                                  (char *) name.data)
1858         == 0)
1859     {
1860         ngx_ssl_error(NGX_LOG_ERR, r->connection->log, 0,
1861                       "SSL_set_tlsext_host_name(\"%s\") failed", name.data);
1862         return NGX_ERROR;
1863     }
1864 
1865 #endif
1866 
1867 done:
1868 
1869     u->ssl_name = name;
1870 
1871     return NGX_OK;
1872 }
1873 
1874 #endif
1875 
1876 
1877 static ngx_int_t
1878 ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
1879 {
1880     off_t         file_pos;
1881     ngx_chain_t  *cl;
1882 
1883     if (u->reinit_request(r) != NGX_OK) {
1884         return NGX_ERROR;
1885     }
1886 
1887     u->keepalive = 0;
1888     u->upgrade = 0;
1889 
1890     ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
1891     u->headers_in.content_length_n = -1;
1892     u->headers_in.last_modified_time = -1;
1893 
1894     if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
1895                       sizeof(ngx_table_elt_t))
1896         != NGX_OK)
1897     {
1898         return NGX_ERROR;
1899     }
1900 
1901     if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
1902                       sizeof(ngx_table_elt_t))
1903         != NGX_OK)
1904     {
1905         return NGX_ERROR;
1906     }
1907 
1908     /* reinit the request chain */
1909 
1910     file_pos = 0;
1911 
1912     for (cl = u->request_bufs; cl; cl = cl->next) {
1913         cl->buf->pos = cl->buf->start;
1914 
1915         /* there is at most one file */
1916 
1917         if (cl->buf->in_file) {
1918             cl->buf->file_pos = file_pos;
1919             file_pos = cl->buf->file_last;
1920         }
1921     }
1922 
1923     /* reinit the subrequest's ngx_output_chain() context */
1924 
1925     if (r->request_body && r->request_body->temp_file
1926         && r != r->main && u->output.buf)
1927     {
1928         u->output.free = ngx_alloc_chain_link(r->pool);
1929         if (u->output.free == NULL) {
1930             return NGX_ERROR;
1931         }
1932 
1933         u->output.free->buf = u->output.buf;
1934         u->output.free->next = NULL;
1935 
1936         u->output.buf->pos = u->output.buf->start;
1937         u->output.buf->last = u->output.buf->start;
1938     }
1939 
1940     u->output.buf = NULL;
1941     u->output.in = NULL;
1942     u->output.busy = NULL;
1943 
1944     /* reinit u->buffer */
1945 
1946     u->buffer.pos = u->buffer.start;
1947 
1948 #if (NGX_HTTP_CACHE)
1949 
1950     if (r->cache) {
1951         u->buffer.pos += r->cache->header_start;
1952     }
1953 
1954 #endif
1955 
1956     u->buffer.last = u->buffer.pos;
1957 
1958     return NGX_OK;
1959 }
1960 
1961 
1962 static void
1963 ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
1964     ngx_uint_t do_write)
1965 {
1966     ngx_int_t          rc;
1967     ngx_connection_t  *c;
1968 
1969     c = u->peer.connection;
1970 
1971     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1972                    "http upstream send request");
1973 
1974     if (u->state->connect_time == (ngx_msec_t) -1) {
1975         u->state->connect_time = ngx_current_msec - u->state->response_time;
1976     }
1977 
1978     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
1979         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1980         return;
1981     }
1982 
1983     c->log->action = "sending request to upstream";
1984 
1985     rc = ngx_http_upstream_send_request_body(r, u, do_write);
1986 
1987     if (rc == NGX_ERROR) {
1988         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
1989         return;
1990     }
1991 
1992     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
1993         ngx_http_upstream_finalize_request(r, u, rc);
1994         return;
1995     }
1996 
1997     if (rc == NGX_AGAIN) {
1998         if (!c->write->ready || u->request_body_blocked) {
1999             ngx_add_timer(c->write, u->conf->send_timeout);
2000 
2001         } else if (c->write->timer_set) {
2002             ngx_del_timer(c->write);
2003         }
2004 
2005         if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) {
2006             ngx_http_upstream_finalize_request(r, u,
2007                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2008             return;
2009         }
2010 
2011         return;
2012     }
2013 
2014     /* rc == NGX_OK */
2015 
2016     if (c->write->timer_set) {
2017         ngx_del_timer(c->write);
2018     }
2019 
2020     if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
2021         if (ngx_tcp_push(c->fd) == -1) {
2022             ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
2023                           ngx_tcp_push_n " failed");
2024             ngx_http_upstream_finalize_request(r, u,
2025                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2026             return;
2027         }
2028 
2029         c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
2030     }
2031 
2032     if (!u->conf->preserve_output) {
2033         u->write_event_handler = ngx_http_upstream_dummy_handler;
2034     }
2035 
2036     if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
2037         ngx_http_upstream_finalize_request(r, u,
2038                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
2039         return;
2040     }
2041 
2042     if (!u->request_body_sent) {
2043         u->request_body_sent = 1;
2044 
2045         if (u->header_sent) {
2046             return;
2047         }
2048 
2049         ngx_add_timer(c->read, u->conf->read_timeout);
2050 
2051         if (c->read->ready) {
2052             ngx_http_upstream_process_header(r, u);
2053             return;
2054         }
2055     }
2056 }
2057 
2058 
2059 static ngx_int_t
2060 ngx_http_upstream_send_request_body(ngx_http_request_t *r,
2061     ngx_http_upstream_t *u, ngx_uint_t do_write)
2062 {
2063     ngx_int_t                  rc;
2064     ngx_chain_t               *out, *cl, *ln;
2065     ngx_connection_t          *c;
2066     ngx_http_core_loc_conf_t  *clcf;
2067 
2068     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2069                    "http upstream send request body");
2070 
2071     if (!r->request_body_no_buffering) {
2072 
2073         /* buffered request body */
2074 
2075         if (!u->request_sent) {
2076             u->request_sent = 1;
2077             out = u->request_bufs;
2078 
2079         } else {
2080             out = NULL;
2081         }
2082 
2083         rc = ngx_output_chain(&u->output, out);
2084 
2085         if (rc == NGX_AGAIN) {
2086             u->request_body_blocked = 1;
2087 
2088         } else {
2089             u->request_body_blocked = 0;
2090         }
2091 
2092         return rc;
2093     }
2094 
2095     if (!u->request_sent) {
2096         u->request_sent = 1;
2097         out = u->request_bufs;
2098 
2099         if (r->request_body->bufs) {
2100             for (cl = out; cl->next; cl = out->next) { /* void */ }
2101             cl->next = r->request_body->bufs;
2102             r->request_body->bufs = NULL;
2103         }
2104 
2105         c = u->peer.connection;
2106         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2107 
2108         if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
2109             return NGX_ERROR;
2110         }
2111 
2112         r->read_event_handler = ngx_http_upstream_read_request_handler;
2113 
2114     } else {
2115         out = NULL;
2116     }
2117 
2118     for ( ;; ) {
2119 
2120         if (do_write) {
2121             rc = ngx_output_chain(&u->output, out);
2122 
2123             if (rc == NGX_ERROR) {
2124                 return NGX_ERROR;
2125             }
2126 
2127             while (out) {
2128                 ln = out;
2129                 out = out->next;
2130                 ngx_free_chain(r->pool, ln);
2131             }
2132 
2133             if (rc == NGX_AGAIN) {
2134                 u->request_body_blocked = 1;
2135 
2136             } else {
2137                 u->request_body_blocked = 0;
2138             }
2139 
2140             if (rc == NGX_OK && !r->reading_body) {
2141                 break;
2142             }
2143         }
2144 
2145         if (r->reading_body) {
2146             /* read client request body */
2147 
2148             rc = ngx_http_read_unbuffered_request_body(r);
2149 
2150             if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
2151                 return rc;
2152             }
2153 
2154             out = r->request_body->bufs;
2155             r->request_body->bufs = NULL;
2156         }
2157 
2158         /* stop if there is nothing to send */
2159 
2160         if (out == NULL) {
2161             rc = NGX_AGAIN;
2162             break;
2163         }
2164 
2165         do_write = 1;
2166     }
2167 
2168     if (!r->reading_body) {
2169         if (!u->store && !r->post_action && !u->conf->ignore_client_abort) {
2170             r->read_event_handler =
2171                                   ngx_http_upstream_rd_check_broken_connection;
2172         }
2173     }
2174 
2175     return rc;
2176 }
2177 
2178 
2179 static void
2180 ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
2181     ngx_http_upstream_t *u)
2182 {
2183     ngx_connection_t  *c;
2184 
2185     c = u->peer.connection;
2186 
2187     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2188                    "http upstream send request handler");
2189 
2190     if (c->write->timedout) {
2191         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
2192         return;
2193     }
2194 
2195 #if (NGX_HTTP_SSL)
2196 
2197     if (u->ssl && c->ssl == NULL) {
2198         ngx_http_upstream_ssl_init_connection(r, u, c);
2199         return;
2200     }
2201 
2202 #endif
2203 
2204     if (u->header_sent && !u->conf->preserve_output) {
2205         u->write_event_handler = ngx_http_upstream_dummy_handler;
2206 
2207         (void) ngx_handle_write_event(c->write, 0);
2208 
2209         return;
2210     }
2211 
2212     ngx_http_upstream_send_request(r, u, 1);
2213 }
2214 
2215 
2216 static void
2217 ngx_http_upstream_read_request_handler(ngx_http_request_t *r)
2218 {
2219     ngx_connection_t     *c;
2220     ngx_http_upstream_t  *u;
2221 
2222     c = r->connection;
2223     u = r->upstream;
2224 
2225     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2226                    "http upstream read request handler");
2227 
2228     if (c->read->timedout) {
2229         c->timedout = 1;
2230         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
2231         return;
2232     }
2233 
2234     ngx_http_upstream_send_request(r, u, 0);
2235 }
2236 
2237 
2238 static void
2239 ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
2240 {
2241     ssize_t            n;
2242     ngx_int_t          rc;
2243     ngx_connection_t  *c;
2244 
2245     c = u->peer.connection;
2246 
2247     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
2248                    "http upstream process header");
2249 
2250     c->log->action = "reading response header from upstream";
2251 
2252     if (c->read->timedout) {
2253         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT);
2254         return;
2255     }
2256 
2257     if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) {
2258         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
2259         return;
2260     }
2261 
2262     if (u->buffer.start == NULL) {
2263         u->buffer.start = ngx_palloc(r->pool, u->conf->buffer_size);
2264         if (u->buffer.start == NULL) {
2265             ngx_http_upstream_finalize_request(r, u,
2266                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2267             return;
2268         }
2269 
2270         u->buffer.pos = u->buffer.start;
2271         u->buffer.last = u->buffer.start;
2272         u->buffer.end = u->buffer.start + u->conf->buffer_size;
2273         u->buffer.temporary = 1;
2274 
2275         u->buffer.tag = u->output.tag;
2276 
2277         if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
2278                           sizeof(ngx_table_elt_t))
2279             != NGX_OK)
2280         {
2281             ngx_http_upstream_finalize_request(r, u,
2282                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2283             return;
2284         }
2285 
2286         if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
2287                           sizeof(ngx_table_elt_t))
2288             != NGX_OK)
2289         {
2290             ngx_http_upstream_finalize_request(r, u,
2291                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2292             return;
2293         }
2294 
2295 #if (NGX_HTTP_CACHE)
2296 
2297         if (r->cache) {
2298             u->buffer.pos += r->cache->header_start;
2299             u->buffer.last = u->buffer.pos;
2300         }
2301 #endif
2302     }
2303 
2304     for ( ;; ) {
2305 
2306         n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
2307 
2308         if (n == NGX_AGAIN) {
2309 #if 0
2310             ngx_add_timer(rev, u->read_timeout);
2311 #endif
2312 
2313             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
2314                 ngx_http_upstream_finalize_request(r, u,
2315                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2316                 return;
2317             }
2318 
2319             return;
2320         }
2321 
2322         if (n == 0) {
2323             ngx_log_error(NGX_LOG_ERR, c->log, 0,
2324                           "upstream prematurely closed connection");
2325         }
2326 
2327         if (n == NGX_ERROR || n == 0) {
2328             ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
2329             return;
2330         }
2331 
2332         u->state->bytes_received += n;
2333 
2334         u->buffer.last += n;
2335 
2336 #if 0
2337         u->valid_header_in = 0;
2338 
2339         u->peer.cached = 0;
2340 #endif
2341 
2342         rc = u->process_header(r);
2343 
2344         if (rc == NGX_AGAIN) {
2345 
2346             if (u->buffer.last == u->buffer.end) {
2347                 ngx_log_error(NGX_LOG_ERR, c->log, 0,
2348                               "upstream sent too big header");
2349 
2350                 ngx_http_upstream_next(r, u,
2351                                        NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
2352                 return;
2353             }
2354 
2355             continue;
2356         }
2357 
2358         break;
2359     }
2360 
2361     if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
2362         ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
2363         return;
2364     }
2365 
2366     if (rc == NGX_ERROR) {
2367         ngx_http_upstream_finalize_request(r, u,
2368                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
2369         return;
2370     }
2371 
2372     /* rc == NGX_OK */
2373 
2374     u->state->header_time = ngx_current_msec - u->state->response_time;
2375 
2376     if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) {
2377 
2378         if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
2379             return;
2380         }
2381 
2382         if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
2383             return;
2384         }
2385     }
2386 
2387     if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
2388         return;
2389     }
2390 
2391     ngx_http_upstream_send_response(r, u);
2392 }
2393 
2394 
2395 static ngx_int_t
2396 ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
2397 {
2398     ngx_msec_t                 timeout;
2399     ngx_uint_t                 status, mask;
2400     ngx_http_upstream_next_t  *un;
2401 
2402     status = u->headers_in.status_n;
2403 
2404     for (un = ngx_http_upstream_next_errors; un->status; un++) {
2405 
2406         if (status != un->status) {
2407             continue;
2408         }
2409 
2410         timeout = u->conf->next_upstream_timeout;
2411 
2412         if (u->request_sent
2413             && (r->method & (NGX_HTTP_POST|NGX_HTTP_LOCK|NGX_HTTP_PATCH)))
2414         {
2415             mask = un->mask | NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT;
2416 
2417         } else {
2418             mask = un->mask;
2419         }
2420 
2421         if (u->peer.tries > 1
2422             && ((u->conf->next_upstream & mask) == mask)
2423             && !(u->request_sent && r->request_body_no_buffering)
2424             && !(timeout && ngx_current_msec - u->peer.start_time >= timeout))
2425         {
2426             ngx_http_upstream_next(r, u, un->mask);
2427             return NGX_OK;
2428         }
2429 
2430 #if (NGX_HTTP_CACHE)
2431 
2432         if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
2433             && ((u->conf->cache_use_stale & un->mask) || r->cache->stale_error))
2434         {
2435             ngx_int_t  rc;
2436 
2437             rc = u->reinit_request(r);
2438 
2439             if (rc != NGX_OK) {
2440                 ngx_http_upstream_finalize_request(r, u, rc);
2441                 return NGX_OK;
2442             }
2443 
2444             u->cache_status = NGX_HTTP_CACHE_STALE;
2445             rc = ngx_http_upstream_cache_send(r, u);
2446 
2447             if (rc == NGX_DONE) {
2448                 return NGX_OK;
2449             }
2450 
2451             if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
2452                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
2453             }
2454 
2455             ngx_http_upstream_finalize_request(r, u, rc);
2456             return NGX_OK;
2457         }
2458 
2459 #endif
2460     }
2461 
2462 #if (NGX_HTTP_CACHE)
2463 
2464     if (status == NGX_HTTP_NOT_MODIFIED
2465         && u->cache_status == NGX_HTTP_CACHE_EXPIRED
2466         && u->conf->cache_revalidate)
2467     {
2468         time_t     now, valid, updating, error;
2469         ngx_int_t  rc;
2470 
2471         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2472                        "http upstream not modified");
2473 
2474         now = ngx_time();
2475 
2476         valid = r->cache->valid_sec;
2477         updating = r->cache->updating_sec;
2478         error = r->cache->error_sec;
2479 
2480         rc = u->reinit_request(r);
2481 
2482         if (rc != NGX_OK) {
2483             ngx_http_upstream_finalize_request(r, u, rc);
2484             return NGX_OK;
2485         }
2486 
2487         u->cache_status = NGX_HTTP_CACHE_REVALIDATED;
2488         rc = ngx_http_upstream_cache_send(r, u);
2489 
2490         if (rc == NGX_DONE) {
2491             return NGX_OK;
2492         }
2493 
2494         if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
2495             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
2496         }
2497 
2498         if (valid == 0) {
2499             valid = r->cache->valid_sec;
2500             updating = r->cache->updating_sec;
2501             error = r->cache->error_sec;
2502         }
2503 
2504         if (valid == 0) {
2505             valid = ngx_http_file_cache_valid(u->conf->cache_valid,
2506                                               u->headers_in.status_n);
2507             if (valid) {
2508                 valid = now + valid;
2509             }
2510         }
2511 
2512         if (valid) {
2513             r->cache->valid_sec = valid;
2514             r->cache->updating_sec = updating;
2515             r->cache->error_sec = error;
2516 
2517             r->cache->date = now;
2518 
2519             ngx_http_file_cache_update_header(r);
2520         }
2521 
2522         ngx_http_upstream_finalize_request(r, u, rc);
2523         return NGX_OK;
2524     }
2525 
2526 #endif
2527 
2528     return NGX_DECLINED;
2529 }
2530 
2531 
2532 static ngx_int_t
2533 ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
2534     ngx_http_upstream_t *u)
2535 {
2536     ngx_int_t                  status;
2537     ngx_uint_t                 i;
2538     ngx_table_elt_t           *h;
2539     ngx_http_err_page_t       *err_page;
2540     ngx_http_core_loc_conf_t  *clcf;
2541 
2542     status = u->headers_in.status_n;
2543 
2544     if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
2545         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
2546         return NGX_OK;
2547     }
2548 
2549     if (!u->conf->intercept_errors) {
2550         return NGX_DECLINED;
2551     }
2552 
2553     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2554 
2555     if (clcf->error_pages == NULL) {
2556         return NGX_DECLINED;
2557     }
2558 
2559     err_page = clcf->error_pages->elts;
2560     for (i = 0; i < clcf->error_pages->nelts; i++) {
2561 
2562         if (err_page[i].status == status) {
2563 
2564             if (status == NGX_HTTP_UNAUTHORIZED
2565                 && u->headers_in.www_authenticate)
2566             {
2567                 h = ngx_list_push(&r->headers_out.headers);
2568 
2569                 if (h == NULL) {
2570                     ngx_http_upstream_finalize_request(r, u,
2571                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2572                     return NGX_OK;
2573                 }
2574 
2575                 *h = *u->headers_in.www_authenticate;
2576 
2577                 r->headers_out.www_authenticate = h;
2578             }
2579 
2580 #if (NGX_HTTP_CACHE)
2581 
2582             if (r->cache) {
2583 
2584                 if (u->cacheable) {
2585                     time_t  valid;
2586 
2587                     valid = r->cache->valid_sec;
2588 
2589                     if (valid == 0) {
2590                         valid = ngx_http_file_cache_valid(u->conf->cache_valid,
2591                                                           status);
2592                         if (valid) {
2593                             r->cache->valid_sec = ngx_time() + valid;
2594                         }
2595                     }
2596 
2597                     if (valid) {
2598                         r->cache->error = status;
2599                     }
2600                 }
2601 
2602                 ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
2603             }
2604 #endif
2605             ngx_http_upstream_finalize_request(r, u, status);
2606 
2607             return NGX_OK;
2608         }
2609     }
2610 
2611     return NGX_DECLINED;
2612 }
2613 
2614 
2615 static ngx_int_t
2616 ngx_http_upstream_test_connect(ngx_connection_t *c)
2617 {
2618     int        err;
2619     socklen_t  len;
2620 
2621 #if (NGX_HAVE_KQUEUE)
2622 
2623     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT)  {
2624         if (c->write->pending_eof || c->read->pending_eof) {
2625             if (c->write->pending_eof) {
2626                 err = c->write->kq_errno;
2627 
2628             } else {
2629                 err = c->read->kq_errno;
2630             }
2631 
2632             c->log->action = "connecting to upstream";
2633             (void) ngx_connection_error(c, err,
2634                                     "kevent() reported that connect() failed");
2635             return NGX_ERROR;
2636         }
2637 
2638     } else
2639 #endif
2640     {
2641         err = 0;
2642         len = sizeof(int);
2643 
2644         /*
2645          * BSDs and Linux return 0 and set a pending error in err
2646          * Solaris returns -1 and sets errno
2647          */
2648 
2649         if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len)
2650             == -1)
2651         {
2652             err = ngx_socket_errno;
2653         }
2654 
2655         if (err) {
2656             c->log->action = "connecting to upstream";
2657             (void) ngx_connection_error(c, err, "connect() failed");
2658             return NGX_ERROR;
2659         }
2660     }
2661 
2662     return NGX_OK;
2663 }
2664 
2665 
2666 static ngx_int_t
2667 ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
2668 {
2669     ngx_str_t                       uri, args;
2670     ngx_uint_t                      i, flags;
2671     ngx_list_part_t                *part;
2672     ngx_table_elt_t                *h;
2673     ngx_http_upstream_header_t     *hh;
2674     ngx_http_upstream_main_conf_t  *umcf;
2675 
2676     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
2677 
2678     if (u->headers_in.x_accel_redirect
2679         && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
2680     {
2681         ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
2682 
2683         part = &u->headers_in.headers.part;
2684         h = part->elts;
2685 
2686         for (i = 0; /* void */; i++) {
2687 
2688             if (i >= part->nelts) {
2689                 if (part->next == NULL) {
2690                     break;
2691                 }
2692 
2693                 part = part->next;
2694                 h = part->elts;
2695                 i = 0;
2696             }
2697 
2698             hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2699                                h[i].lowcase_key, h[i].key.len);
2700 
2701             if (hh && hh->redirect) {
2702                 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
2703                     ngx_http_finalize_request(r,
2704                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
2705                     return NGX_DONE;
2706                 }
2707             }
2708         }
2709 
2710         uri = u->headers_in.x_accel_redirect->value;
2711 
2712         if (uri.data[0] == '@') {
2713             ngx_http_named_location(r, &uri);
2714 
2715         } else {
2716             ngx_str_null(&args);
2717             flags = NGX_HTTP_LOG_UNSAFE;
2718 
2719             if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
2720                 ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
2721                 return NGX_DONE;
2722             }
2723 
2724             if (r->method != NGX_HTTP_HEAD) {
2725                 r->method = NGX_HTTP_GET;
2726                 r->method_name = ngx_http_core_get_method;
2727             }
2728 
2729             ngx_http_internal_redirect(r, &uri, &args);
2730         }
2731 
2732         ngx_http_finalize_request(r, NGX_DONE);
2733         return NGX_DONE;
2734     }
2735 
2736     part = &u->headers_in.headers.part;
2737     h = part->elts;
2738 
2739     for (i = 0; /* void */; i++) {
2740 
2741         if (i >= part->nelts) {
2742             if (part->next == NULL) {
2743                 break;
2744             }
2745 
2746             part = part->next;
2747             h = part->elts;
2748             i = 0;
2749         }
2750 
2751         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
2752                           h[i].lowcase_key, h[i].key.len))
2753         {
2754             continue;
2755         }
2756 
2757         hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2758                            h[i].lowcase_key, h[i].key.len);
2759 
2760         if (hh) {
2761             if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
2762                 ngx_http_upstream_finalize_request(r, u,
2763                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2764                 return NGX_DONE;
2765             }
2766 
2767             continue;
2768         }
2769 
2770         if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
2771             ngx_http_upstream_finalize_request(r, u,
2772                                                NGX_HTTP_INTERNAL_SERVER_ERROR);
2773             return NGX_DONE;
2774         }
2775     }
2776 
2777     if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
2778         r->headers_out.server->hash = 0;
2779     }
2780 
2781     if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
2782         r->headers_out.date->hash = 0;
2783     }
2784 
2785     r->headers_out.status = u->headers_in.status_n;
2786     r->headers_out.status_line = u->headers_in.status_line;
2787 
2788     r->headers_out.content_length_n = u->headers_in.content_length_n;
2789 
2790     r->disable_not_modified = !u->cacheable;
2791 
2792     if (u->conf->force_ranges) {
2793         r->allow_ranges = 1;
2794         r->single_range = 1;
2795 
2796 #if (NGX_HTTP_CACHE)
2797         if (r->cached) {
2798             r->single_range = 0;
2799         }
2800 #endif
2801     }
2802 
2803     u->length = -1;
2804 
2805     return NGX_OK;
2806 }
2807 
2808 
2809 static ngx_int_t
2810 ngx_http_upstream_process_trailers(ngx_http_request_t *r,
2811     ngx_http_upstream_t *u)
2812 {
2813     ngx_uint_t        i;
2814     ngx_list_part_t  *part;
2815     ngx_table_elt_t  *h, *ho;
2816 
2817     if (!u->conf->pass_trailers) {
2818         return NGX_OK;
2819     }
2820 
2821     part = &u->headers_in.trailers.part;
2822     h = part->elts;
2823 
2824     for (i = 0; /* void */; i++) {
2825 
2826         if (i >= part->nelts) {
2827             if (part->next == NULL) {
2828                 break;
2829             }
2830 
2831             part = part->next;
2832             h = part->elts;
2833             i = 0;
2834         }
2835 
2836         if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
2837                           h[i].lowcase_key, h[i].key.len))
2838         {
2839             continue;
2840         }
2841 
2842         ho = ngx_list_push(&r->headers_out.trailers);
2843         if (ho == NULL) {
2844             return NGX_ERROR;
2845         }
2846 
2847         *ho = h[i];
2848     }
2849 
2850     return NGX_OK;
2851 }
2852 
2853 
2854 static void
2855 ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
2856 {
2857     ssize_t                    n;
2858     ngx_int_t                  rc;
2859     ngx_event_pipe_t          *p;
2860     ngx_connection_t          *c;
2861     ngx_http_core_loc_conf_t  *clcf;
2862 
2863     rc = ngx_http_send_header(r);
2864 
2865     if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) {
2866         ngx_http_upstream_finalize_request(r, u, rc);
2867         return;
2868     }
2869 
2870     u->header_sent = 1;
2871 
2872     if (u->upgrade) {
2873 
2874 #if (NGX_HTTP_CACHE)
2875 
2876         if (r->cache) {
2877             ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
2878         }
2879 
2880 #endif
2881 
2882         ngx_http_upstream_upgrade(r, u);
2883         return;
2884     }
2885 
2886     c = r->connection;
2887 
2888     if (r->header_only) {
2889 
2890         if (!u->buffering) {
2891             ngx_http_upstream_finalize_request(r, u, rc);
2892             return;
2893         }
2894 
2895         if (!u->cacheable && !u->store) {
2896             ngx_http_upstream_finalize_request(r, u, rc);
2897             return;
2898         }
2899 
2900         u->pipe->downstream_error = 1;
2901     }
2902 
2903     if (r->request_body && r->request_body->temp_file
2904         && r == r->main && !r->preserve_body)
2905     {
2906         ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
2907         r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
2908     }
2909 
2910     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
2911 
2912     if (!u->buffering) {
2913 
2914 #if (NGX_HTTP_CACHE)
2915 
2916         if (r->cache) {
2917             ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
2918         }
2919 
2920 #endif
2921 
2922         if (u->input_filter == NULL) {
2923             u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
2924             u->input_filter = ngx_http_upstream_non_buffered_filter;
2925             u->input_filter_ctx = r;
2926         }
2927 
2928         u->read_event_handler = ngx_http_upstream_process_non_buffered_upstream;
2929         r->write_event_handler =
2930                              ngx_http_upstream_process_non_buffered_downstream;
2931 
2932         r->limit_rate = 0;
2933 
2934         if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
2935             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2936             return;
2937         }
2938 
2939         if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) {
2940             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2941             return;
2942         }
2943 
2944         n = u->buffer.last - u->buffer.pos;
2945 
2946         if (n) {
2947             u->buffer.last = u->buffer.pos;
2948 
2949             u->state->response_length += n;
2950 
2951             if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
2952                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2953                 return;
2954             }
2955 
2956             ngx_http_upstream_process_non_buffered_downstream(r);
2957 
2958         } else {
2959             u->buffer.pos = u->buffer.start;
2960             u->buffer.last = u->buffer.start;
2961 
2962             if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
2963                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2964                 return;
2965             }
2966 
2967             if (u->peer.connection->read->ready || u->length == 0) {
2968                 ngx_http_upstream_process_non_buffered_upstream(r, u);
2969             }
2970         }
2971 
2972         return;
2973     }
2974 
2975     /* TODO: preallocate event_pipe bufs, look "Content-Length" */
2976 
2977 #if (NGX_HTTP_CACHE)
2978 
2979     if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
2980         ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
2981         r->cache->file.fd = NGX_INVALID_FILE;
2982     }
2983 
2984     switch (ngx_http_test_predicates(r, u->conf->no_cache)) {
2985 
2986     case NGX_ERROR:
2987         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
2988         return;
2989 
2990     case NGX_DECLINED:
2991         u->cacheable = 0;
2992         break;
2993 
2994     default: /* NGX_OK */
2995 
2996         if (u->cache_status == NGX_HTTP_CACHE_BYPASS) {
2997 
2998             /* create cache if previously bypassed */
2999 
3000             if (ngx_http_file_cache_create(r) != NGX_OK) {
3001                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3002                 return;
3003             }
3004         }
3005 
3006         break;
3007     }
3008 
3009     if (u->cacheable) {
3010         time_t  now, valid;
3011 
3012         now = ngx_time();
3013 
3014         valid = r->cache->valid_sec;
3015 
3016         if (valid == 0) {
3017             valid = ngx_http_file_cache_valid(u->conf->cache_valid,
3018                                               u->headers_in.status_n);
3019             if (valid) {
3020                 r->cache->valid_sec = now + valid;
3021             }
3022         }
3023 
3024         if (valid) {
3025             r->cache->date = now;
3026             r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
3027 
3028             if (u->headers_in.status_n == NGX_HTTP_OK
3029                 || u->headers_in.status_n == NGX_HTTP_PARTIAL_CONTENT)
3030             {
3031                 r->cache->last_modified = u->headers_in.last_modified_time;
3032 
3033                 if (u->headers_in.etag) {
3034                     r->cache->etag = u->headers_in.etag->value;
3035 
3036                 } else {
3037                     ngx_str_null(&r->cache->etag);
3038                 }
3039 
3040             } else {
3041                 r->cache->last_modified = -1;
3042                 ngx_str_null(&r->cache->etag);
3043             }
3044 
3045             if (ngx_http_file_cache_set_header(r, u->buffer.start) != NGX_OK) {
3046                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3047                 return;
3048             }
3049 
3050         } else {
3051             u->cacheable = 0;
3052         }
3053     }
3054 
3055     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
3056                    "http cacheable: %d", u->cacheable);
3057 
3058     if (u->cacheable == 0 && r->cache) {
3059         ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
3060     }
3061 
3062     if (r->header_only && !u->cacheable && !u->store) {
3063         ngx_http_upstream_finalize_request(r, u, 0);
3064         return;
3065     }
3066 
3067 #endif
3068 
3069     p = u->pipe;
3070 
3071     p->output_filter = ngx_http_upstream_output_filter;
3072     p->output_ctx = r;
3073     p->tag = u->output.tag;
3074     p->bufs = u->conf->bufs;
3075     p->busy_size = u->conf->busy_buffers_size;
3076     p->upstream = u->peer.connection;
3077     p->downstream = c;
3078     p->pool = r->pool;
3079     p->log = c->log;
3080     p->limit_rate = u->conf->limit_rate;
3081     p->start_sec = ngx_time();
3082 
3083     p->cacheable = u->cacheable || u->store;
3084 
3085     p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
3086     if (p->temp_file == NULL) {
3087         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3088         return;
3089     }
3090 
3091     p->temp_file->file.fd = NGX_INVALID_FILE;
3092     p->temp_file->file.log = c->log;
3093     p->temp_file->path = u->conf->temp_path;
3094     p->temp_file->pool = r->pool;
3095 
3096     if (p->cacheable) {
3097         p->temp_file->persistent = 1;
3098 
3099 #if (NGX_HTTP_CACHE)
3100         if (r->cache && !r->cache->file_cache->use_temp_path) {
3101             p->temp_file->path = r->cache->file_cache->path;
3102             p->temp_file->file.name = r->cache->file.name;
3103         }
3104 #endif
3105 
3106     } else {
3107         p->temp_file->log_level = NGX_LOG_WARN;
3108         p->temp_file->warn = "an upstream response is buffered "
3109                              "to a temporary file";
3110     }
3111 
3112     p->max_temp_file_size = u->conf->max_temp_file_size;
3113     p->temp_file_write_size = u->conf->temp_file_write_size;
3114 
3115 #if (NGX_THREADS)
3116     if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_write) {
3117         p->thread_handler = ngx_http_upstream_thread_handler;
3118         p->thread_ctx = r;
3119     }
3120 #endif
3121 
3122     p->preread_bufs = ngx_alloc_chain_link(r->pool);
3123     if (p->preread_bufs == NULL) {
3124         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3125         return;
3126     }
3127 
3128     p->preread_bufs->buf = &u->buffer;
3129     p->preread_bufs->next = NULL;
3130     u->buffer.recycled = 1;
3131 
3132     p->preread_size = u->buffer.last - u->buffer.pos;
3133 
3134     if (u->cacheable) {
3135 
3136         p->buf_to_file = ngx_calloc_buf(r->pool);
3137         if (p->buf_to_file == NULL) {
3138             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3139             return;
3140         }
3141 
3142         p->buf_to_file->start = u->buffer.start;
3143         p->buf_to_file->pos = u->buffer.start;
3144         p->buf_to_file->last = u->buffer.pos;
3145         p->buf_to_file->temporary = 1;
3146     }
3147 
3148     if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
3149         /* the posted aio operation may corrupt a shadow buffer */
3150         p->single_buf = 1;
3151     }
3152 
3153     /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */
3154     p->free_bufs = 1;
3155 
3156     /*
3157      * event_pipe would do u->buffer.last += p->preread_size
3158      * as though these bytes were read
3159      */
3160     u->buffer.last = u->buffer.pos;
3161 
3162     if (u->conf->cyclic_temp_file) {
3163 
3164         /*
3165          * we need to disable the use of sendfile() if we use cyclic temp file
3166          * because the writing a new data may interfere with sendfile()
3167          * that uses the same kernel file pages (at least on FreeBSD)
3168          */
3169 
3170         p->cyclic_temp_file = 1;
3171         c->sendfile = 0;
3172 
3173     } else {
3174         p->cyclic_temp_file = 0;
3175     }
3176 
3177     p->read_timeout = u->conf->read_timeout;
3178     p->send_timeout = clcf->send_timeout;
3179     p->send_lowat = clcf->send_lowat;
3180 
3181     p->length = -1;
3182 
3183     if (u->input_filter_init
3184         && u->input_filter_init(p->input_ctx) != NGX_OK)
3185     {
3186         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3187         return;
3188     }
3189 
3190     u->read_event_handler = ngx_http_upstream_process_upstream;
3191     r->write_event_handler = ngx_http_upstream_process_downstream;
3192 
3193     ngx_http_upstream_process_upstream(r, u);
3194 }
3195 
3196 
3197 static void
3198 ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u)
3199 {
3200     ngx_connection_t          *c;
3201     ngx_http_core_loc_conf_t  *clcf;
3202 
3203     c = r->connection;
3204     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3205 
3206     /* TODO: prevent upgrade if not requested or not possible */
3207 
3208     if (r != r->main) {
3209         ngx_log_error(NGX_LOG_ERR, c->log, 0,
3210                       "connection upgrade in subrequest");
3211         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3212         return;
3213     }
3214 
3215     r->keepalive = 0;
3216     c->log->action = "proxying upgraded connection";
3217 
3218     u->read_event_handler = ngx_http_upstream_upgraded_read_upstream;
3219     u->write_event_handler = ngx_http_upstream_upgraded_write_upstream;
3220     r->read_event_handler = ngx_http_upstream_upgraded_read_downstream;
3221     r->write_event_handler = ngx_http_upstream_upgraded_write_downstream;
3222 
3223     if (clcf->tcp_nodelay) {
3224 
3225         if (ngx_tcp_nodelay(c) != NGX_OK) {
3226             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3227             return;
3228         }
3229 
3230         if (ngx_tcp_nodelay(u->peer.connection) != NGX_OK) {
3231             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3232             return;
3233         }
3234     }
3235 
3236     if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) {
3237         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3238         return;
3239     }
3240 
3241     if (u->peer.connection->read->ready
3242         || u->buffer.pos != u->buffer.last)
3243     {
3244         ngx_post_event(c->read, &ngx_posted_events);
3245         ngx_http_upstream_process_upgraded(r, 1, 1);
3246         return;
3247     }
3248 
3249     ngx_http_upstream_process_upgraded(r, 0, 1);
3250 }
3251 
3252 
3253 static void
3254 ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r)
3255 {
3256     ngx_http_upstream_process_upgraded(r, 0, 0);
3257 }
3258 
3259 
3260 static void
3261 ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r)
3262 {
3263     ngx_http_upstream_process_upgraded(r, 1, 1);
3264 }
3265 
3266 
3267 static void
3268 ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r,
3269     ngx_http_upstream_t *u)
3270 {
3271     ngx_http_upstream_process_upgraded(r, 1, 0);
3272 }
3273 
3274 
3275 static void
3276 ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r,
3277     ngx_http_upstream_t *u)
3278 {
3279     ngx_http_upstream_process_upgraded(r, 0, 1);
3280 }
3281 
3282 
3283 static void
3284 ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
3285     ngx_uint_t from_upstream, ngx_uint_t do_write)
3286 {
3287     size_t                     size;
3288     ssize_t                    n;
3289     ngx_buf_t                 *b;
3290     ngx_connection_t          *c, *downstream, *upstream, *dst, *src;
3291     ngx_http_upstream_t       *u;
3292     ngx_http_core_loc_conf_t  *clcf;
3293 
3294     c = r->connection;
3295     u = r->upstream;
3296 
3297     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
3298                    "http upstream process upgraded, fu:%ui", from_upstream);
3299 
3300     downstream = c;
3301     upstream = u->peer.connection;
3302 
3303     if (downstream->write->timedout) {
3304         c->timedout = 1;
3305         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
3306         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
3307         return;
3308     }
3309 
3310     if (upstream->read->timedout || upstream->write->timedout) {
3311         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
3312         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
3313         return;
3314     }
3315 
3316     if (from_upstream) {
3317         src = upstream;
3318         dst = downstream;
3319         b = &u->buffer;
3320 
3321     } else {
3322         src = downstream;
3323         dst = upstream;
3324         b = &u->from_client;
3325 
3326         if (r->header_in->last > r->header_in->pos) {
3327             b = r->header_in;
3328             b->end = b->last;
3329             do_write = 1;
3330         }
3331 
3332         if (b->start == NULL) {
3333             b->start = ngx_palloc(r->pool, u->conf->buffer_size);
3334             if (b->start == NULL) {
3335                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3336                 return;
3337             }
3338 
3339             b->pos = b->start;
3340             b->last = b->start;
3341             b->end = b->start + u->conf->buffer_size;
3342             b->temporary = 1;
3343             b->tag = u->output.tag;
3344         }
3345     }
3346 
3347     for ( ;; ) {
3348 
3349         if (do_write) {
3350 
3351             size = b->last - b->pos;
3352 
3353             if (size && dst->write->ready) {
3354 
3355                 n = dst->send(dst, b->pos, size);
3356 
3357                 if (n == NGX_ERROR) {
3358                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3359                     return;
3360                 }
3361 
3362                 if (n > 0) {
3363                     b->pos += n;
3364 
3365                     if (b->pos == b->last) {
3366                         b->pos = b->start;
3367                         b->last = b->start;
3368                     }
3369                 }
3370             }
3371         }
3372 
3373         size = b->end - b->last;
3374 
3375         if (size && src->read->ready) {
3376 
3377             n = src->recv(src, b->last, size);
3378 
3379             if (n == NGX_AGAIN || n == 0) {
3380                 break;
3381             }
3382 
3383             if (n > 0) {
3384                 do_write = 1;
3385                 b->last += n;
3386 
3387                 if (from_upstream) {
3388                     u->state->bytes_received += n;
3389                 }
3390 
3391                 continue;
3392             }
3393 
3394             if (n == NGX_ERROR) {
3395                 src->read->eof = 1;
3396             }
3397         }
3398 
3399         break;
3400     }
3401 
3402     if ((upstream->read->eof && u->buffer.pos == u->buffer.last)
3403         || (downstream->read->eof && u->from_client.pos == u->from_client.last)
3404         || (downstream->read->eof && upstream->read->eof))
3405     {
3406         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3407                        "http upstream upgraded done");
3408         ngx_http_upstream_finalize_request(r, u, 0);
3409         return;
3410     }
3411 
3412     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3413 
3414     if (ngx_handle_write_event(upstream->write, u->conf->send_lowat)
3415         != NGX_OK)
3416     {
3417         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3418         return;
3419     }
3420 
3421     if (upstream->write->active && !upstream->write->ready) {
3422         ngx_add_timer(upstream->write, u->conf->send_timeout);
3423 
3424     } else if (upstream->write->timer_set) {
3425         ngx_del_timer(upstream->write);
3426     }
3427 
3428     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
3429         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3430         return;
3431     }
3432 
3433     if (upstream->read->active && !upstream->read->ready) {
3434         ngx_add_timer(upstream->read, u->conf->read_timeout);
3435 
3436     } else if (upstream->read->timer_set) {
3437         ngx_del_timer(upstream->read);
3438     }
3439 
3440     if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
3441         != NGX_OK)
3442     {
3443         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3444         return;
3445     }
3446 
3447     if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) {
3448         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3449         return;
3450     }
3451 
3452     if (downstream->write->active && !downstream->write->ready) {
3453         ngx_add_timer(downstream->write, clcf->send_timeout);
3454 
3455     } else if (downstream->write->timer_set) {
3456         ngx_del_timer(downstream->write);
3457     }
3458 }
3459 
3460 
3461 static void
3462 ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r)
3463 {
3464     ngx_event_t          *wev;
3465     ngx_connection_t     *c;
3466     ngx_http_upstream_t  *u;
3467 
3468     c = r->connection;
3469     u = r->upstream;
3470     wev = c->write;
3471 
3472     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3473                    "http upstream process non buffered downstream");
3474 
3475     c->log->action = "sending to client";
3476 
3477     if (wev->timedout) {
3478         c->timedout = 1;
3479         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
3480         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT);
3481         return;
3482     }
3483 
3484     ngx_http_upstream_process_non_buffered_request(r, 1);
3485 }
3486 
3487 
3488 static void
3489 ngx_http_upstream_process_non_buffered_upstream(ngx_http_request_t *r,
3490     ngx_http_upstream_t *u)
3491 {
3492     ngx_connection_t  *c;
3493 
3494     c = u->peer.connection;
3495 
3496     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3497                    "http upstream process non buffered upstream");
3498 
3499     c->log->action = "reading upstream";
3500 
3501     if (c->read->timedout) {
3502         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
3503         ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
3504         return;
3505     }
3506 
3507     ngx_http_upstream_process_non_buffered_request(r, 0);
3508 }
3509 
3510 
3511 static void
3512 ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
3513     ngx_uint_t do_write)
3514 {
3515     size_t                     size;
3516     ssize_t                    n;
3517     ngx_buf_t                 *b;
3518     ngx_int_t                  rc;
3519     ngx_connection_t          *downstream, *upstream;
3520     ngx_http_upstream_t       *u;
3521     ngx_http_core_loc_conf_t  *clcf;
3522 
3523     u = r->upstream;
3524     downstream = r->connection;
3525     upstream = u->peer.connection;
3526 
3527     b = &u->buffer;
3528 
3529     do_write = do_write || u->length == 0;
3530 
3531     for ( ;; ) {
3532 
3533         if (do_write) {
3534 
3535             if (u->out_bufs || u->busy_bufs || downstream->buffered) {
3536                 rc = ngx_http_output_filter(r, u->out_bufs);
3537 
3538                 if (rc == NGX_ERROR) {
3539                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3540                     return;
3541                 }
3542 
3543                 ngx_chain_update_chains(r->pool, &u->free_bufs, &u->busy_bufs,
3544                                         &u->out_bufs, u->output.tag);
3545             }
3546 
3547             if (u->busy_bufs == NULL) {
3548 
3549                 if (u->length == 0
3550                     || (upstream->read->eof && u->length == -1))
3551                 {
3552                     ngx_http_upstream_finalize_request(r, u, 0);
3553                     return;
3554                 }
3555 
3556                 if (upstream->read->eof) {
3557                     ngx_log_error(NGX_LOG_ERR, upstream->log, 0,
3558                                   "upstream prematurely closed connection");
3559 
3560                     ngx_http_upstream_finalize_request(r, u,
3561                                                        NGX_HTTP_BAD_GATEWAY);
3562                     return;
3563                 }
3564 
3565                 if (upstream->read->error) {
3566                     ngx_http_upstream_finalize_request(r, u,
3567                                                        NGX_HTTP_BAD_GATEWAY);
3568                     return;
3569                 }
3570 
3571                 b->pos = b->start;
3572                 b->last = b->start;
3573             }
3574         }
3575 
3576         size = b->end - b->last;
3577 
3578         if (size && upstream->read->ready) {
3579 
3580             n = upstream->recv(upstream, b->last, size);
3581 
3582             if (n == NGX_AGAIN) {
3583                 break;
3584             }
3585 
3586             if (n > 0) {
3587                 u->state->bytes_received += n;
3588                 u->state->response_length += n;
3589 
3590                 if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
3591                     ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3592                     return;
3593                 }
3594             }
3595 
3596             do_write = 1;
3597 
3598             continue;
3599         }
3600 
3601         break;
3602     }
3603 
3604     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3605 
3606     if (downstream->data == r) {
3607         if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
3608             != NGX_OK)
3609         {
3610             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3611             return;
3612         }
3613     }
3614 
3615     if (downstream->write->active && !downstream->write->ready) {
3616         ngx_add_timer(downstream->write, clcf->send_timeout);
3617 
3618     } else if (downstream->write->timer_set) {
3619         ngx_del_timer(downstream->write);
3620     }
3621 
3622     if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) {
3623         ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3624         return;
3625     }
3626 
3627     if (upstream->read->active && !upstream->read->ready) {
3628         ngx_add_timer(upstream->read, u->conf->read_timeout);
3629 
3630     } else if (upstream->read->timer_set) {
3631         ngx_del_timer(upstream->read);
3632     }
3633 }
3634 
3635 
3636 static ngx_int_t
3637 ngx_http_upstream_non_buffered_filter_init(void *data)
3638 {
3639     return NGX_OK;
3640 }
3641 
3642 
3643 static ngx_int_t
3644 ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
3645 {
3646     ngx_http_request_t  *r = data;
3647 
3648     ngx_buf_t            *b;
3649     ngx_chain_t          *cl, **ll;
3650     ngx_http_upstream_t  *u;
3651 
3652     u = r->upstream;
3653 
3654     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
3655         ll = &cl->next;
3656     }
3657 
3658     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
3659     if (cl == NULL) {
3660         return NGX_ERROR;
3661     }
3662 
3663     *ll = cl;
3664 
3665     cl->buf->flush = 1;
3666     cl->buf->memory = 1;
3667 
3668     b = &u->buffer;
3669 
3670     cl->buf->pos = b->last;
3671     b->last += bytes;
3672     cl->buf->last = b->last;
3673     cl->buf->tag = u->output.tag;
3674 
3675     if (u->length == -1) {
3676         return NGX_OK;
3677     }
3678 
3679     u->length -= bytes;
3680 
3681     return NGX_OK;
3682 }
3683 
3684 
3685 #if (NGX_THREADS)
3686 
3687 static ngx_int_t
3688 ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file)
3689 {
3690     ngx_str_t                  name;
3691     ngx_event_pipe_t          *p;
3692     ngx_thread_pool_t         *tp;
3693     ngx_http_request_t        *r;
3694     ngx_http_core_loc_conf_t  *clcf;
3695 
3696     r = file->thread_ctx;
3697     p = r->upstream->pipe;
3698 
3699     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3700     tp = clcf->thread_pool;
3701 
3702     if (tp == NULL) {
3703         if (ngx_http_complex_value(r, clcf->thread_pool_value, &name)
3704             != NGX_OK)
3705         {
3706             return NGX_ERROR;
3707         }
3708 
3709         tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name);
3710 
3711         if (tp == NULL) {
3712             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3713                           "thread pool \"%V\" not found", &name);
3714             return NGX_ERROR;
3715         }
3716     }
3717 
3718     task->event.data = r;
3719     task->event.handler = ngx_http_upstream_thread_event_handler;
3720 
3721     if (ngx_thread_task_post(tp, task) != NGX_OK) {
3722         return NGX_ERROR;
3723     }
3724 
3725     r->main->blocked++;
3726     r->aio = 1;
3727     p->aio = 1;
3728 
3729     return NGX_OK;
3730 }
3731 
3732 
3733 static void
3734 ngx_http_upstream_thread_event_handler(ngx_event_t *ev)
3735 {
3736     ngx_connection_t    *c;
3737     ngx_http_request_t  *r;
3738 
3739     r = ev->data;
3740     c = r->connection;
3741 
3742     ngx_http_set_log_request(c->log, r);
3743 
3744     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
3745                    "http upstream thread: \"%V?%V\"", &r->uri, &r->args);
3746 
3747     r->main->blocked--;
3748     r->aio = 0;
3749 
3750     if (r->done) {
3751         /*
3752          * trigger connection event handler if the subrequest was
3753          * already finalized; this can happen if the handler is used
3754          * for sendfile() in threads
3755          */
3756 
3757         c->write->handler(c->write);
3758 
3759     } else {
3760         r->write_event_handler(r);
3761         ngx_http_run_posted_requests(c);
3762     }
3763 }
3764 
3765 #endif
3766 
3767 
3768 static ngx_int_t
3769 ngx_http_upstream_output_filter(void *data, ngx_chain_t *chain)
3770 {
3771     ngx_int_t            rc;
3772     ngx_event_pipe_t    *p;
3773     ngx_http_request_t  *r;
3774 
3775     r = data;
3776     p = r->upstream->pipe;
3777 
3778     rc = ngx_http_output_filter(r, chain);
3779 
3780     p->aio = r->aio;
3781 
3782     return rc;
3783 }
3784 
3785 
3786 static void
3787 ngx_http_upstream_process_downstream(ngx_http_request_t *r)
3788 {
3789     ngx_event_t          *wev;
3790     ngx_connection_t     *c;
3791     ngx_event_pipe_t     *p;
3792     ngx_http_upstream_t  *u;
3793 
3794     c = r->connection;
3795     u = r->upstream;
3796     p = u->pipe;
3797     wev = c->write;
3798 
3799     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3800                    "http upstream process downstream");
3801 
3802     c->log->action = "sending to client";
3803 
3804 #if (NGX_THREADS)
3805     p->aio = r->aio;
3806 #endif
3807 
3808     if (wev->timedout) {
3809 
3810         p->downstream_error = 1;
3811         c->timedout = 1;
3812         ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out");
3813 
3814     } else {
3815 
3816         if (wev->delayed) {
3817 
3818             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3819                            "http downstream delayed");
3820 
3821             if (ngx_handle_write_event(wev, p->send_lowat) != NGX_OK) {
3822                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3823             }
3824 
3825             return;
3826         }
3827 
3828         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
3829             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3830             return;
3831         }
3832     }
3833 
3834     ngx_http_upstream_process_request(r, u);
3835 }
3836 
3837 
3838 static void
3839 ngx_http_upstream_process_upstream(ngx_http_request_t *r,
3840     ngx_http_upstream_t *u)
3841 {
3842     ngx_event_t       *rev;
3843     ngx_event_pipe_t  *p;
3844     ngx_connection_t  *c;
3845 
3846     c = u->peer.connection;
3847     p = u->pipe;
3848     rev = c->read;
3849 
3850     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3851                    "http upstream process upstream");
3852 
3853     c->log->action = "reading upstream";
3854 
3855     if (rev->timedout) {
3856 
3857         p->upstream_error = 1;
3858         ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
3859 
3860     } else {
3861 
3862         if (rev->delayed) {
3863 
3864             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
3865                            "http upstream delayed");
3866 
3867             if (ngx_handle_read_event(rev, 0) != NGX_OK) {
3868                 ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3869             }
3870 
3871             return;
3872         }
3873 
3874         if (ngx_event_pipe(p, 0) == NGX_ABORT) {
3875             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3876             return;
3877         }
3878     }
3879 
3880     ngx_http_upstream_process_request(r, u);
3881 }
3882 
3883 
3884 static void
3885 ngx_http_upstream_process_request(ngx_http_request_t *r,
3886     ngx_http_upstream_t *u)
3887 {
3888     ngx_temp_file_t   *tf;
3889     ngx_event_pipe_t  *p;
3890 
3891     p = u->pipe;
3892 
3893 #if (NGX_THREADS)
3894 
3895     if (p->writing && !p->aio) {
3896 
3897         /*
3898          * make sure to call ngx_event_pipe()
3899          * if there is an incomplete aio write
3900          */
3901 
3902         if (ngx_event_pipe(p, 1) == NGX_ABORT) {
3903             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3904             return;
3905         }
3906     }
3907 
3908     if (p->writing) {
3909         return;
3910     }
3911 
3912 #endif
3913 
3914     if (u->peer.connection) {
3915 
3916         if (u->store) {
3917 
3918             if (p->upstream_eof || p->upstream_done) {
3919 
3920                 tf = p->temp_file;
3921 
3922                 if (u->headers_in.status_n == NGX_HTTP_OK
3923                     && (p->upstream_done || p->length == -1)
3924                     && (u->headers_in.content_length_n == -1
3925                         || u->headers_in.content_length_n == tf->offset))
3926                 {
3927                     ngx_http_upstream_store(r, u);
3928                 }
3929             }
3930         }
3931 
3932 #if (NGX_HTTP_CACHE)
3933 
3934         if (u->cacheable) {
3935 
3936             if (p->upstream_done) {
3937                 ngx_http_file_cache_update(r, p->temp_file);
3938 
3939             } else if (p->upstream_eof) {
3940 
3941                 tf = p->temp_file;
3942 
3943                 if (p->length == -1
3944                     && (u->headers_in.content_length_n == -1
3945                         || u->headers_in.content_length_n
3946                            == tf->offset - (off_t) r->cache->body_start))
3947                 {
3948                     ngx_http_file_cache_update(r, tf);
3949 
3950                 } else {
3951                     ngx_http_file_cache_free(r->cache, tf);
3952                 }
3953 
3954             } else if (p->upstream_error) {
3955                 ngx_http_file_cache_free(r->cache, p->temp_file);
3956             }
3957         }
3958 
3959 #endif
3960 
3961         if (p->upstream_done || p->upstream_eof || p->upstream_error) {
3962             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3963                            "http upstream exit: %p", p->out);
3964 
3965             if (p->upstream_done
3966                 || (p->upstream_eof && p->length == -1))
3967             {
3968                 ngx_http_upstream_finalize_request(r, u, 0);
3969                 return;
3970             }
3971 
3972             if (p->upstream_eof) {
3973                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3974                               "upstream prematurely closed connection");
3975             }
3976 
3977             ngx_http_upstream_finalize_request(r, u, NGX_HTTP_BAD_GATEWAY);
3978             return;
3979         }
3980     }
3981 
3982     if (p->downstream_error) {
3983         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3984                        "http upstream downstream error");
3985 
3986         if (!u->cacheable && !u->store && u->peer.connection) {
3987             ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
3988         }
3989     }
3990 }
3991 
3992 
3993 static void
3994 ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
3995 {
3996     size_t                  root;
3997     time_t                  lm;
3998     ngx_str_t               path;
3999     ngx_temp_file_t        *tf;
4000     ngx_ext_rename_file_t   ext;
4001 
4002     tf = u->pipe->temp_file;
4003 
4004     if (tf->file.fd == NGX_INVALID_FILE) {
4005 
4006         /* create file for empty 200 response */
4007 
4008         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
4009         if (tf == NULL) {
4010             return;
4011         }
4012 
4013         tf->file.fd = NGX_INVALID_FILE;
4014         tf->file.log = r->connection->log;
4015         tf->path = u->conf->temp_path;
4016         tf->pool = r->pool;
4017         tf->persistent = 1;
4018 
4019         if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
4020                                  tf->persistent, tf->clean, tf->access)
4021             != NGX_OK)
4022         {
4023             return;
4024         }
4025 
4026         u->pipe->temp_file = tf;
4027     }
4028 
4029     ext.access = u->conf->store_access;
4030     ext.path_access = u->conf->store_access;
4031     ext.time = -1;
4032     ext.create_path = 1;
4033     ext.delete_file = 1;
4034     ext.log = r->connection->log;
4035 
4036     if (u->headers_in.last_modified) {
4037 
4038         lm = ngx_parse_http_time(u->headers_in.last_modified->value.data,
4039                                  u->headers_in.last_modified->value.len);
4040 
4041         if (lm != NGX_ERROR) {
4042             ext.time = lm;
4043             ext.fd = tf->file.fd;
4044         }
4045     }
4046 
4047     if (u->conf->store_lengths == NULL) {
4048 
4049         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
4050             return;
4051         }
4052 
4053     } else {
4054         if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0,
4055                                 u->conf->store_values->elts)
4056             == NULL)
4057         {
4058             return;
4059         }
4060     }
4061 
4062     path.len--;
4063 
4064     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4065                    "upstream stores \"%s\" to \"%s\"",
4066                    tf->file.name.data, path.data);
4067 
4068     (void) ngx_ext_rename_file(&tf->file.name, &path, &ext);
4069 
4070     u->store = 0;
4071 }
4072 
4073 
4074 static void
4075 ngx_http_upstream_dummy_handler(ngx_http_request_t *r, ngx_http_upstream_t *u)
4076 {
4077     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4078                    "http upstream dummy handler");
4079 }
4080 
4081 
4082 static void
4083 ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
4084     ngx_uint_t ft_type)
4085 {
4086     ngx_msec_t  timeout;
4087     ngx_uint_t  status, state;
4088 
4089     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4090                    "http next upstream, %xi", ft_type);
4091 
4092     if (u->peer.sockaddr) {
4093 
4094         if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403
4095             || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404)
4096         {
4097             state = NGX_PEER_NEXT;
4098 
4099         } else {
4100             state = NGX_PEER_FAILED;
4101         }
4102 
4103         u->peer.free(&u->peer, u->peer.data, state);
4104         u->peer.sockaddr = NULL;
4105     }
4106 
4107     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
4108         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
4109                       "upstream timed out");
4110     }
4111 
4112     if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) {
4113         /* TODO: inform balancer instead */
4114         u->peer.tries++;
4115     }
4116 
4117     switch (ft_type) {
4118 
4119     case NGX_HTTP_UPSTREAM_FT_TIMEOUT:
4120     case NGX_HTTP_UPSTREAM_FT_HTTP_504:
4121         status = NGX_HTTP_GATEWAY_TIME_OUT;
4122         break;
4123 
4124     case NGX_HTTP_UPSTREAM_FT_HTTP_500:
4125         status = NGX_HTTP_INTERNAL_SERVER_ERROR;
4126         break;
4127 
4128     case NGX_HTTP_UPSTREAM_FT_HTTP_503:
4129         status = NGX_HTTP_SERVICE_UNAVAILABLE;
4130         break;
4131 
4132     case NGX_HTTP_UPSTREAM_FT_HTTP_403:
4133         status = NGX_HTTP_FORBIDDEN;
4134         break;
4135 
4136     case NGX_HTTP_UPSTREAM_FT_HTTP_404:
4137         status = NGX_HTTP_NOT_FOUND;
4138         break;
4139 
4140     case NGX_HTTP_UPSTREAM_FT_HTTP_429:
4141         status = NGX_HTTP_TOO_MANY_REQUESTS;
4142         break;
4143 
4144     /*
4145      * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING
4146      * never reach here
4147      */
4148 
4149     default:
4150         status = NGX_HTTP_BAD_GATEWAY;
4151     }
4152 
4153     if (r->connection->error) {
4154         ngx_http_upstream_finalize_request(r, u,
4155                                            NGX_HTTP_CLIENT_CLOSED_REQUEST);
4156         return;
4157     }
4158 
4159     u->state->status = status;
4160 
4161     timeout = u->conf->next_upstream_timeout;
4162 
4163     if (u->request_sent
4164         && (r->method & (NGX_HTTP_POST|NGX_HTTP_LOCK|NGX_HTTP_PATCH)))
4165     {
4166         ft_type |= NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT;
4167     }
4168 
4169     if (u->peer.tries == 0
4170         || ((u->conf->next_upstream & ft_type) != ft_type)
4171         || (u->request_sent && r->request_body_no_buffering)
4172         || (timeout && ngx_current_msec - u->peer.start_time >= timeout))
4173     {
4174 #if (NGX_HTTP_CACHE)
4175 
4176         if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
4177             && ((u->conf->cache_use_stale & ft_type) || r->cache->stale_error))
4178         {
4179             ngx_int_t  rc;
4180 
4181             rc = u->reinit_request(r);
4182 
4183             if (rc != NGX_OK) {
4184                 ngx_http_upstream_finalize_request(r, u, rc);
4185                 return;
4186             }
4187 
4188             u->cache_status = NGX_HTTP_CACHE_STALE;
4189             rc = ngx_http_upstream_cache_send(r, u);
4190 
4191             if (rc == NGX_DONE) {
4192                 return;
4193             }
4194 
4195             if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
4196                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
4197             }
4198 
4199             ngx_http_upstream_finalize_request(r, u, rc);
4200             return;
4201         }
4202 #endif
4203 
4204         ngx_http_upstream_finalize_request(r, u, status);
4205         return;
4206     }
4207 
4208     if (u->peer.connection) {
4209         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4210                        "close http upstream connection: %d",
4211                        u->peer.connection->fd);
4212 #if (NGX_HTTP_SSL)
4213 
4214         if (u->peer.connection->ssl) {
4215             u->peer.connection->ssl->no_wait_shutdown = 1;
4216             u->peer.connection->ssl->no_send_shutdown = 1;
4217 
4218             (void) ngx_ssl_shutdown(u->peer.connection);
4219         }
4220 #endif
4221 
4222         if (u->peer.connection->pool) {
4223             ngx_destroy_pool(u->peer.connection->pool);
4224         }
4225 
4226         ngx_close_connection(u->peer.connection);
4227         u->peer.connection = NULL;
4228     }
4229 
4230     ngx_http_upstream_connect(r, u);
4231 }
4232 
4233 
4234 static void
4235 ngx_http_upstream_cleanup(void *data)
4236 {
4237     ngx_http_request_t *r = data;
4238 
4239     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4240                    "cleanup http upstream request: \"%V\"", &r->uri);
4241 
4242     ngx_http_upstream_finalize_request(r, r->upstream, NGX_DONE);
4243 }
4244 
4245 
4246 static void
4247 ngx_http_upstream_finalize_request(ngx_http_request_t *r,
4248     ngx_http_upstream_t *u, ngx_int_t rc)
4249 {
4250     ngx_uint_t  flush;
4251 
4252     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4253                    "finalize http upstream request: %i", rc);
4254 
4255     if (u->cleanup == NULL) {
4256         /* the request was already finalized */
4257         ngx_http_finalize_request(r, NGX_DONE);
4258         return;
4259     }
4260 
4261     *u->cleanup = NULL;
4262     u->cleanup = NULL;
4263 
4264     if (u->resolved && u->resolved->ctx) {
4265         ngx_resolve_name_done(u->resolved->ctx);
4266         u->resolved->ctx = NULL;
4267     }
4268 
4269     if (u->state && u->state->response_time) {
4270         u->state->response_time = ngx_current_msec - u->state->response_time;
4271 
4272         if (u->pipe && u->pipe->read_length) {
4273             u->state->bytes_received += u->pipe->read_length
4274                                         - u->pipe->preread_size;
4275             u->state->response_length = u->pipe->read_length;
4276         }
4277     }
4278 
4279     u->finalize_request(r, rc);
4280 
4281     if (u->peer.free && u->peer.sockaddr) {
4282         u->peer.free(&u->peer, u->peer.data, 0);
4283         u->peer.sockaddr = NULL;
4284     }
4285 
4286     if (u->peer.connection) {
4287 
4288 #if (NGX_HTTP_SSL)
4289 
4290         /* TODO: do not shutdown persistent connection */
4291 
4292         if (u->peer.connection->ssl) {
4293 
4294             /*
4295              * We send the "close notify" shutdown alert to the upstream only
4296              * and do not wait its "close notify" shutdown alert.
4297              * It is acceptable according to the TLS standard.
4298              */
4299 
4300             u->peer.connection->ssl->no_wait_shutdown = 1;
4301 
4302             (void) ngx_ssl_shutdown(u->peer.connection);
4303         }
4304 #endif
4305 
4306         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4307                        "close http upstream connection: %d",
4308                        u->peer.connection->fd);
4309 
4310         if (u->peer.connection->pool) {
4311             ngx_destroy_pool(u->peer.connection->pool);
4312         }
4313 
4314         ngx_close_connection(u->peer.connection);
4315     }
4316 
4317     u->peer.connection = NULL;
4318 
4319     if (u->pipe && u->pipe->temp_file) {
4320         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
4321                        "http upstream temp fd: %d",
4322                        u->pipe->temp_file->file.fd);
4323     }
4324 
4325     if (u->store && u->pipe && u->pipe->temp_file
4326         && u->pipe->temp_file->file.fd != NGX_INVALID_FILE)
4327     {
4328         if (ngx_delete_file(u->pipe->temp_file->file.name.data)
4329             == NGX_FILE_ERROR)
4330         {
4331             ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
4332                           ngx_delete_file_n " \"%s\" failed",
4333                           u->pipe->temp_file->file.name.data);
4334         }
4335     }
4336 
4337 #if (NGX_HTTP_CACHE)
4338 
4339     if (r->cache) {
4340 
4341         if (u->cacheable) {
4342 
4343             if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
4344                 time_t  valid;
4345 
4346                 valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
4347 
4348                 if (valid) {
4349                     r->cache->valid_sec = ngx_time() + valid;
4350                     r->cache->error = rc;
4351                 }
4352             }
4353         }
4354 
4355         ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
4356     }
4357 
4358 #endif
4359 
4360     r->read_event_handler = ngx_http_block_reading;
4361 
4362     if (rc == NGX_DECLINED) {
4363         return;
4364     }
4365 
4366     r->connection->log->action = "sending to client";
4367 
4368     if (!u->header_sent
4369         || rc == NGX_HTTP_REQUEST_TIME_OUT
4370         || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST)
4371     {
4372         ngx_http_finalize_request(r, rc);
4373         return;
4374     }
4375 
4376     flush = 0;
4377 
4378     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
4379         rc = NGX_ERROR;
4380         flush = 1;
4381     }
4382 
4383     if (r->header_only
4384         || (u->pipe && u->pipe->downstream_error))
4385     {
4386         ngx_http_finalize_request(r, rc);
4387         return;
4388     }
4389 
4390     if (rc == 0) {
4391 
4392         if (ngx_http_upstream_process_trailers(r, u) != NGX_OK) {
4393             ngx_http_finalize_request(r, NGX_ERROR);
4394             return;
4395         }
4396 
4397         rc = ngx_http_send_special(r, NGX_HTTP_LAST);
4398 
4399     } else if (flush) {
4400         r->keepalive = 0;
4401         rc = ngx_http_send_special(r, NGX_HTTP_FLUSH);
4402     }
4403 
4404     ngx_http_finalize_request(r, rc);
4405 }
4406 
4407 
4408 static ngx_int_t
4409 ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
4410     ngx_uint_t offset)
4411 {
4412     ngx_table_elt_t  **ph;
4413 
4414     ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
4415 
4416     if (*ph == NULL) {
4417         *ph = h;
4418     }
4419 
4420     return NGX_OK;
4421 }
4422 
4423 
4424 static ngx_int_t
4425 ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
4426     ngx_uint_t offset)
4427 {
4428     return NGX_OK;
4429 }
4430 
4431 
4432 static ngx_int_t
4433 ngx_http_upstream_process_content_length(ngx_http_request_t *r,
4434     ngx_table_elt_t *h, ngx_uint_t offset)
4435 {
4436     ngx_http_upstream_t  *u;
4437 
4438     u = r->upstream;
4439 
4440     u->headers_in.content_length = h;
4441     u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
4442 
4443     return NGX_OK;
4444 }
4445 
4446 
4447 static ngx_int_t
4448 ngx_http_upstream_process_last_modified(ngx_http_request_t *r,
4449     ngx_table_elt_t *h, ngx_uint_t offset)
4450 {
4451     ngx_http_upstream_t  *u;
4452 
4453     u = r->upstream;
4454 
4455     u->headers_in.last_modified = h;
4456     u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data,
4457                                                            h->value.len);
4458 
4459     return NGX_OK;
4460 }
4461 
4462 
4463 static ngx_int_t
4464 ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
4465     ngx_uint_t offset)
4466 {
4467     ngx_array_t           *pa;
4468     ngx_table_elt_t      **ph;
4469     ngx_http_upstream_t   *u;
4470 
4471     u = r->upstream;
4472     pa = &u->headers_in.cookies;
4473 
4474     if (pa->elts == NULL) {
4475         if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
4476         {
4477             return NGX_ERROR;
4478         }
4479     }
4480 
4481     ph = ngx_array_push(pa);
4482     if (ph == NULL) {
4483         return NGX_ERROR;
4484     }
4485 
4486     *ph = h;
4487 
4488 #if (NGX_HTTP_CACHE)
4489     if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
4490         u->cacheable = 0;
4491     }
4492 #endif
4493 
4494     return NGX_OK;
4495 }
4496 
4497 
4498 static ngx_int_t
4499 ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
4500     ngx_table_elt_t *h, ngx_uint_t offset)
4501 {
4502     ngx_array_t          *pa;
4503     ngx_table_elt_t     **ph;
4504     ngx_http_upstream_t  *u;
4505 
4506     u = r->upstream;
4507     pa = &u->headers_in.cache_control;
4508 
4509     if (pa->elts == NULL) {
4510         if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
4511         {
4512             return NGX_ERROR;
4513         }
4514     }
4515 
4516     ph = ngx_array_push(pa);
4517     if (ph == NULL) {
4518         return NGX_ERROR;
4519     }
4520 
4521     *ph = h;
4522 
4523 #if (NGX_HTTP_CACHE)
4524     {
4525     u_char     *p, *start, *last;
4526     ngx_int_t   n;
4527 
4528     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) {
4529         return NGX_OK;
4530     }
4531 
4532     if (r->cache == NULL) {
4533         return NGX_OK;
4534     }
4535 
4536     if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
4537         return NGX_OK;
4538     }
4539 
4540     start = h->value.data;
4541     last = start + h->value.len;
4542 
4543     if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
4544         || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
4545         || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
4546     {
4547         u->cacheable = 0;
4548         return NGX_OK;
4549     }
4550 
4551     p = ngx_strlcasestrn(start, last, (u_char *) "s-maxage=", 9 - 1);
4552     offset = 9;
4553 
4554     if (p == NULL) {
4555         p = ngx_strlcasestrn(start, last, (u_char *) "max-age=", 8 - 1);
4556         offset = 8;
4557     }
4558 
4559     if (p) {
4560         n = 0;
4561 
4562         for (p += offset; p < last; p++) {
4563             if (*p == ',' || *p == ';' || *p == ' ') {
4564                 break;
4565             }
4566 
4567             if (*p >= '0' && *p <= '9') {
4568                 n = n * 10 + (*p - '0');
4569                 continue;
4570             }
4571 
4572             u->cacheable = 0;
4573             return NGX_OK;
4574         }
4575 
4576         if (n == 0) {
4577             u->cacheable = 0;
4578             return NGX_OK;
4579         }
4580 
4581         r->cache->valid_sec = ngx_time() + n;
4582     }
4583 
4584     p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
4585                          23 - 1);
4586 
4587     if (p) {
4588         n = 0;
4589 
4590         for (p += 23; p < last; p++) {
4591             if (*p == ',' || *p == ';' || *p == ' ') {
4592                 break;
4593             }
4594 
4595             if (*p >= '0' && *p <= '9') {
4596                 n = n * 10 + (*p - '0');
4597                 continue;
4598             }
4599 
4600             u->cacheable = 0;
4601             return NGX_OK;
4602         }
4603 
4604         r->cache->updating_sec = n;
4605         r->cache->error_sec = n;
4606     }
4607 
4608     p = ngx_strlcasestrn(start, last, (u_char *) "stale-if-error=", 15 - 1);
4609 
4610     if (p) {
4611         n = 0;
4612 
4613         for (p += 15; p < last; p++) {
4614             if (*p == ',' || *p == ';' || *p == ' ') {
4615                 break;
4616             }
4617 
4618             if (*p >= '0' && *p <= '9') {
4619                 n = n * 10 + (*p - '0');
4620                 continue;
4621             }
4622 
4623             u->cacheable = 0;
4624             return NGX_OK;
4625         }
4626 
4627         r->cache->error_sec = n;
4628     }
4629     }
4630 #endif
4631 
4632     return NGX_OK;
4633 }
4634 
4635 
4636 static ngx_int_t
4637 ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h,
4638     ngx_uint_t offset)
4639 {
4640     ngx_http_upstream_t  *u;
4641 
4642     u = r->upstream;
4643     u->headers_in.expires = h;
4644 
4645 #if (NGX_HTTP_CACHE)
4646     {
4647     time_t  expires;
4648 
4649     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) {
4650         return NGX_OK;
4651     }
4652 
4653     if (r->cache == NULL) {
4654         return NGX_OK;
4655     }
4656 
4657     if (r->cache->valid_sec != 0) {
4658         return NGX_OK;
4659     }
4660 
4661     expires = ngx_parse_http_time(h->value.data, h->value.len);
4662 
4663     if (expires == NGX_ERROR || expires < ngx_time()) {
4664         u->cacheable = 0;
4665         return NGX_OK;
4666     }
4667 
4668     r->cache->valid_sec = expires;
4669     }
4670 #endif
4671 
4672     return NGX_OK;
4673 }
4674 
4675 
4676 static ngx_int_t
4677 ngx_http_upstream_process_accel_expires(ngx_http_request_t *r,
4678     ngx_table_elt_t *h, ngx_uint_t offset)
4679 {
4680     ngx_http_upstream_t  *u;
4681 
4682     u = r->upstream;
4683     u->headers_in.x_accel_expires = h;
4684 
4685 #if (NGX_HTTP_CACHE)
4686     {
4687     u_char     *p;
4688     size_t      len;
4689     ngx_int_t   n;
4690 
4691     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) {
4692         return NGX_OK;
4693     }
4694 
4695     if (r->cache == NULL) {
4696         return NGX_OK;
4697     }
4698 
4699     len = h->value.len;
4700     p = h->value.data;
4701 
4702     if (p[0] != '@') {
4703         n = ngx_atoi(p, len);
4704 
4705         switch (n) {
4706         case 0:
4707             u->cacheable = 0;
4708             /* fall through */
4709 
4710         case NGX_ERROR:
4711             return NGX_OK;
4712 
4713         default:
4714             r->cache->valid_sec = ngx_time() + n;
4715             return NGX_OK;
4716         }
4717     }
4718 
4719     p++;
4720     len--;
4721 
4722     n = ngx_atoi(p, len);
4723 
4724     if (n != NGX_ERROR) {
4725         r->cache->valid_sec = n;
4726     }
4727     }
4728 #endif
4729 
4730     return NGX_OK;
4731 }
4732 
4733 
4734 static ngx_int_t
4735 ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
4736     ngx_uint_t offset)
4737 {
4738     ngx_int_t             n;
4739     ngx_http_upstream_t  *u;
4740 
4741     u = r->upstream;
4742     u->headers_in.x_accel_limit_rate = h;
4743 
4744     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
4745         return NGX_OK;
4746     }
4747 
4748     n = ngx_atoi(h->value.data, h->value.len);
4749 
4750     if (n != NGX_ERROR) {
4751         r->limit_rate = (size_t) n;
4752     }
4753 
4754     return NGX_OK;
4755 }
4756 
4757 
4758 static ngx_int_t
4759 ngx_http_upstream_process_buffering(ngx_http_request_t *r, ngx_table_elt_t *h,
4760     ngx_uint_t offset)
4761 {
4762     u_char                c0, c1, c2;
4763     ngx_http_upstream_t  *u;
4764 
4765     u = r->upstream;
4766 
4767     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_BUFFERING) {
4768         return NGX_OK;
4769     }
4770 
4771     if (u->conf->change_buffering) {
4772 
4773         if (h->value.len == 2) {
4774             c0 = ngx_tolower(h->value.data[0]);
4775             c1 = ngx_tolower(h->value.data[1]);
4776 
4777             if (c0 == 'n' && c1 == 'o') {
4778                 u->buffering = 0;
4779             }
4780 
4781         } else if (h->value.len == 3) {
4782             c0 = ngx_tolower(h->value.data[0]);
4783             c1 = ngx_tolower(h->value.data[1]);
4784             c2 = ngx_tolower(h->value.data[2]);
4785 
4786             if (c0 == 'y' && c1 == 'e' && c2 == 's') {
4787                 u->buffering = 1;
4788             }
4789         }
4790     }
4791 
4792     return NGX_OK;
4793 }
4794 
4795 
4796 static ngx_int_t
4797 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
4798     ngx_uint_t offset)
4799 {
4800     if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
4801         return NGX_OK;
4802     }
4803 
4804     r->headers_out.override_charset = &h->value;
4805 
4806     return NGX_OK;
4807 }
4808 
4809 
4810 static ngx_int_t
4811 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
4812     ngx_uint_t offset)
4813 {
4814     r->upstream->headers_in.connection = h;
4815 
4816     if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
4817                          (u_char *) "close", 5 - 1)
4818         != NULL)
4819     {
4820         r->upstream->headers_in.connection_close = 1;
4821     }
4822 
4823     return NGX_OK;
4824 }
4825 
4826 
4827 static ngx_int_t
4828 ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
4829     ngx_table_elt_t *h, ngx_uint_t offset)
4830 {
4831     r->upstream->headers_in.transfer_encoding = h;
4832 
4833     if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
4834                          (u_char *) "chunked", 7 - 1)
4835         != NULL)
4836     {
4837         r->upstream->headers_in.chunked = 1;
4838     }
4839 
4840     return NGX_OK;
4841 }
4842 
4843 
4844 static ngx_int_t
4845 ngx_http_upstream_process_vary(ngx_http_request_t *r,
4846     ngx_table_elt_t *h, ngx_uint_t offset)
4847 {
4848     ngx_http_upstream_t  *u;
4849 
4850     u = r->upstream;
4851     u->headers_in.vary = h;
4852 
4853 #if (NGX_HTTP_CACHE)
4854 
4855     if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
4856         return NGX_OK;
4857     }
4858 
4859     if (r->cache == NULL) {
4860         return NGX_OK;
4861     }
4862 
4863     if (h->value.len > NGX_HTTP_CACHE_VARY_LEN
4864         || (h->value.len == 1 && h->value.data[0] == '*'))
4865     {
4866         u->cacheable = 0;
4867     }
4868 
4869     r->cache->vary = h->value;
4870 
4871 #endif
4872 
4873     return NGX_OK;
4874 }
4875 
4876 
4877 static ngx_int_t
4878 ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
4879     ngx_uint_t offset)
4880 {
4881     ngx_table_elt_t  *ho, **ph;
4882 
4883     ho = ngx_list_push(&r->headers_out.headers);
4884     if (ho == NULL) {
4885         return NGX_ERROR;
4886     }
4887 
4888     *ho = *h;
4889 
4890     if (offset) {
4891         ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
4892         *ph = ho;
4893     }
4894 
4895     return NGX_OK;
4896 }
4897 
4898 
4899 static ngx_int_t
4900 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
4901     ngx_table_elt_t *h, ngx_uint_t offset)
4902 {
4903     ngx_array_t      *pa;
4904     ngx_table_elt_t  *ho, **ph;
4905 
4906     pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
4907 
4908     if (pa->elts == NULL) {
4909         if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
4910         {
4911             return NGX_ERROR;
4912         }
4913     }
4914 
4915     ho = ngx_list_push(&r->headers_out.headers);
4916     if (ho == NULL) {
4917         return NGX_ERROR;
4918     }
4919 
4920     *ho = *h;
4921 
4922     ph = ngx_array_push(pa);
4923     if (ph == NULL) {
4924         return NGX_ERROR;
4925     }
4926 
4927     *ph = ho;
4928 
4929     return NGX_OK;
4930 }
4931 
4932 
4933 static ngx_int_t
4934 ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
4935     ngx_uint_t offset)
4936 {
4937     u_char  *p, *last;
4938 
4939     r->headers_out.content_type_len = h->value.len;
4940     r->headers_out.content_type = h->value;
4941     r->headers_out.content_type_lowcase = NULL;
4942 
4943     for (p = h->value.data; *p; p++) {
4944 
4945         if (*p != ';') {
4946             continue;
4947         }
4948 
4949         last = p;
4950 
4951         while (*++p == ' ') { /* void */ }
4952 
4953         if (*p == '\0') {
4954             return NGX_OK;
4955         }
4956 
4957         if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) {
4958             continue;
4959         }
4960 
4961         p += 8;
4962 
4963         r->headers_out.content_type_len = last - h->value.data;
4964 
4965         if (*p == '"') {
4966             p++;
4967         }
4968 
4969         last = h->value.data + h->value.len;
4970 
4971         if (*(last - 1) == '"') {
4972             last--;
4973         }
4974 
4975         r->headers_out.charset.len = last - p;
4976         r->headers_out.charset.data = p;
4977 
4978         return NGX_OK;
4979     }
4980 
4981     return NGX_OK;
4982 }
4983 
4984 
4985 static ngx_int_t
4986 ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
4987     ngx_uint_t offset)
4988 {
4989     ngx_table_elt_t  *ho;
4990 
4991     ho = ngx_list_push(&r->headers_out.headers);
4992     if (ho == NULL) {
4993         return NGX_ERROR;
4994     }
4995 
4996     *ho = *h;
4997 
4998     r->headers_out.last_modified = ho;
4999     r->headers_out.last_modified_time =
5000                                     r->upstream->headers_in.last_modified_time;
5001 
5002     return NGX_OK;
5003 }
5004 
5005 
5006 static ngx_int_t
5007 ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
5008     ngx_uint_t offset)
5009 {
5010     ngx_int_t         rc;
5011     ngx_table_elt_t  *ho;
5012 
5013     ho = ngx_list_push(&r->headers_out.headers);
5014     if (ho == NULL) {
5015         return NGX_ERROR;
5016     }
5017 
5018     *ho = *h;
5019 
5020     if (r->upstream->rewrite_redirect) {
5021         rc = r->upstream->rewrite_redirect(r, ho, 0);
5022 
5023         if (rc == NGX_DECLINED) {
5024             return NGX_OK;
5025         }
5026 
5027         if (rc == NGX_OK) {
5028             r->headers_out.location = ho;
5029 
5030             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
5031                            "rewritten location: \"%V\"", &ho->value);
5032         }
5033 
5034         return rc;
5035     }
5036 
5037     if (ho->value.data[0] != '/') {
5038         r->headers_out.location = ho;
5039     }
5040 
5041     /*
5042      * we do not set r->headers_out.location here to avoid handling
5043      * relative redirects in ngx_http_header_filter()
5044      */
5045 
5046     return NGX_OK;
5047 }
5048 
5049 
5050 static ngx_int_t
5051 ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
5052     ngx_uint_t offset)
5053 {
5054     u_char           *p;
5055     ngx_int_t         rc;
5056     ngx_table_elt_t  *ho;
5057 
5058     ho = ngx_list_push(&r->headers_out.headers);
5059     if (ho == NULL) {
5060         return NGX_ERROR;
5061     }
5062 
5063     *ho = *h;
5064 
5065     if (r->upstream->rewrite_redirect) {
5066 
5067         p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
5068 
5069         if (p) {
5070             rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data);
5071 
5072         } else {
5073             return NGX_OK;
5074         }
5075 
5076         if (rc == NGX_DECLINED) {
5077             return NGX_OK;
5078         }
5079 
5080         if (rc == NGX_OK) {
5081             r->headers_out.refresh = ho;
5082 
5083             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
5084                            "rewritten refresh: \"%V\"", &ho->value);
5085         }
5086 
5087         return rc;
5088     }
5089 
5090     r->headers_out.refresh = ho;
5091 
5092     return NGX_OK;
5093 }
5094 
5095 
5096 static ngx_int_t
5097 ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
5098     ngx_uint_t offset)
5099 {
5100     ngx_int_t         rc;
5101     ngx_table_elt_t  *ho;
5102 
5103     ho = ngx_list_push(&r->headers_out.headers);
5104     if (ho == NULL) {
5105         return NGX_ERROR;
5106     }
5107 
5108     *ho = *h;
5109 
5110     if (r->upstream->rewrite_cookie) {
5111         rc = r->upstream->rewrite_cookie(r, ho);
5112 
5113         if (rc == NGX_DECLINED) {
5114             return NGX_OK;
5115         }
5116 
5117 #if (NGX_DEBUG)
5118         if (rc == NGX_OK) {
5119             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
5120                            "rewritten cookie: \"%V\"", &ho->value);
5121         }
5122 #endif
5123 
5124         return rc;
5125     }
5126 
5127     return NGX_OK;
5128 }
5129 
5130 
5131 static ngx_int_t
5132 ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
5133     ngx_table_elt_t *h, ngx_uint_t offset)
5134 {
5135     ngx_table_elt_t  *ho;
5136 
5137     if (r->upstream->conf->force_ranges) {
5138         return NGX_OK;
5139     }
5140 
5141 #if (NGX_HTTP_CACHE)
5142 
5143     if (r->cached) {
5144         r->allow_ranges = 1;
5145         return NGX_OK;
5146     }
5147 
5148     if (r->upstream->cacheable) {
5149         r->allow_ranges = 1;
5150         r->single_range = 1;
5151         return NGX_OK;
5152     }
5153 
5154 #endif
5155 
5156     ho = ngx_list_push(&r->headers_out.headers);
5157     if (ho == NULL) {
5158         return NGX_ERROR;
5159     }
5160 
5161     *ho = *h;
5162 
5163     r->headers_out.accept_ranges = ho;
5164 
5165     return NGX_OK;
5166 }
5167 
5168 
5169 #if (NGX_HTTP_GZIP)
5170 
5171 static ngx_int_t
5172 ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
5173     ngx_table_elt_t *h, ngx_uint_t offset)
5174 {
5175     ngx_table_elt_t  *ho;
5176 
5177     ho = ngx_list_push(&r->headers_out.headers);
5178     if (ho == NULL) {
5179         return NGX_ERROR;
5180     }
5181 
5182     *ho = *h;
5183 
5184     r->headers_out.content_encoding = ho;
5185 
5186     return NGX_OK;
5187 }
5188 
5189 #endif
5190 
5191 
5192 static ngx_int_t
5193 ngx_http_upstream_add_variables(ngx_conf_t *cf)
5194 {
5195     ngx_http_variable_t  *var, *v;
5196 
5197     for (v = ngx_http_upstream_vars; v->name.len; v++) {
5198         var = ngx_http_add_variable(cf, &v->name, v->flags);
5199         if (var == NULL) {
5200             return NGX_ERROR;
5201         }
5202 
5203         var->get_handler = v->get_handler;
5204         var->data = v->data;
5205     }
5206 
5207     return NGX_OK;
5208 }
5209 
5210 
5211 static ngx_int_t
5212 ngx_http_upstream_addr_variable(ngx_http_request_t *r,
5213     ngx_http_variable_value_t *v, uintptr_t data)
5214 {
5215     u_char                     *p;
5216     size_t                      len;
5217     ngx_uint_t                  i;
5218     ngx_http_upstream_state_t  *state;
5219 
5220     v->valid = 1;
5221     v->no_cacheable = 0;
5222     v->not_found = 0;
5223 
5224     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
5225         v->not_found = 1;
5226         return NGX_OK;
5227     }
5228 
5229     len = 0;
5230     state = r->upstream_states->elts;
5231 
5232     for (i = 0; i < r->upstream_states->nelts; i++) {
5233         if (state[i].peer) {
5234             len += state[i].peer->len + 2;
5235 
5236         } else {
5237             len += 3;
5238         }
5239     }
5240 
5241     p = ngx_pnalloc(r->pool, len);
5242     if (p == NULL) {
5243         return NGX_ERROR;
5244     }
5245 
5246     v->data = p;
5247 
5248     i = 0;
5249 
5250     for ( ;; ) {
5251         if (state[i].peer) {
5252             p = ngx_cpymem(p, state[i].peer->data, state[i].peer->len);
5253         }
5254 
5255         if (++i == r->upstream_states->nelts) {
5256             break;
5257         }
5258 
5259         if (state[i].peer) {
5260             *p++ = ',';
5261             *p++ = ' ';
5262 
5263         } else {
5264             *p++ = ' ';
5265             *p++ = ':';
5266             *p++ = ' ';
5267 
5268             if (++i == r->upstream_states->nelts) {
5269                 break;
5270             }
5271 
5272             continue;
5273         }
5274     }
5275 
5276     v->len = p - v->data;
5277 
5278     return NGX_OK;
5279 }
5280 
5281 
5282 static ngx_int_t
5283 ngx_http_upstream_status_variable(ngx_http_request_t *r,
5284     ngx_http_variable_value_t *v, uintptr_t data)
5285 {
5286     u_char                     *p;
5287     size_t                      len;
5288     ngx_uint_t                  i;
5289     ngx_http_upstream_state_t  *state;
5290 
5291     v->valid = 1;
5292     v->no_cacheable = 0;
5293     v->not_found = 0;
5294 
5295     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
5296         v->not_found = 1;
5297         return NGX_OK;
5298     }
5299 
5300     len = r->upstream_states->nelts * (3 + 2);
5301 
5302     p = ngx_pnalloc(r->pool, len);
5303     if (p == NULL) {
5304         return NGX_ERROR;
5305     }
5306 
5307     v->data = p;
5308 
5309     i = 0;
5310     state = r->upstream_states->elts;
5311 
5312     for ( ;; ) {
5313         if (state[i].status) {
5314             p = ngx_sprintf(p, "%ui", state[i].status);
5315 
5316         } else {
5317             *p++ = '-';
5318         }
5319 
5320         if (++i == r->upstream_states->nelts) {
5321             break;
5322         }
5323 
5324         if (state[i].peer) {
5325             *p++ = ',';
5326             *p++ = ' ';
5327 
5328         } else {
5329             *p++ = ' ';
5330             *p++ = ':';
5331             *p++ = ' ';
5332 
5333             if (++i == r->upstream_states->nelts) {
5334                 break;
5335             }
5336 
5337             continue;
5338         }
5339     }
5340 
5341     v->len = p - v->data;
5342 
5343     return NGX_OK;
5344 }
5345 
5346 
5347 static ngx_int_t
5348 ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
5349     ngx_http_variable_value_t *v, uintptr_t data)
5350 {
5351     u_char                     *p;
5352     size_t                      len;
5353     ngx_uint_t                  i;
5354     ngx_msec_int_t              ms;
5355     ngx_http_upstream_state_t  *state;
5356 
5357     v->valid = 1;
5358     v->no_cacheable = 0;
5359     v->not_found = 0;
5360 
5361     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
5362         v->not_found = 1;
5363         return NGX_OK;
5364     }
5365 
5366     len = r->upstream_states->nelts * (NGX_TIME_T_LEN + 4 + 2);
5367 
5368     p = ngx_pnalloc(r->pool, len);
5369     if (p == NULL) {
5370         return NGX_ERROR;
5371     }
5372 
5373     v->data = p;
5374 
5375     i = 0;
5376     state = r->upstream_states->elts;
5377 
5378     for ( ;; ) {
5379         if (state[i].status) {
5380 
5381             if (data == 1 && state[i].header_time != (ngx_msec_t) -1) {
5382                 ms = state[i].header_time;
5383 
5384             } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) {
5385                 ms = state[i].connect_time;
5386 
5387             } else {
5388                 ms = state[i].response_time;
5389             }
5390 
5391             ms = ngx_max(ms, 0);
5392             p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000);
5393 
5394         } else {
5395             *p++ = '-';
5396         }
5397 
5398         if (++i == r->upstream_states->nelts) {
5399             break;
5400         }
5401 
5402         if (state[i].peer) {
5403             *p++ = ',';
5404             *p++ = ' ';
5405 
5406         } else {
5407             *p++ = ' ';
5408             *p++ = ':';
5409             *p++ = ' ';
5410 
5411             if (++i == r->upstream_states->nelts) {
5412                 break;
5413             }
5414 
5415             continue;
5416         }
5417     }
5418 
5419     v->len = p - v->data;
5420 
5421     return NGX_OK;
5422 }
5423 
5424 
5425 static ngx_int_t
5426 ngx_http_upstream_response_length_variable(ngx_http_request_t *r,
5427     ngx_http_variable_value_t *v, uintptr_t data)
5428 {
5429     u_char                     *p;
5430     size_t                      len;
5431     ngx_uint_t                  i;
5432     ngx_http_upstream_state_t  *state;
5433 
5434     v->valid = 1;
5435     v->no_cacheable = 0;
5436     v->not_found = 0;
5437 
5438     if (r->upstream_states == NULL || r->upstream_states->nelts == 0) {
5439         v->not_found = 1;
5440         return NGX_OK;
5441     }
5442 
5443     len = r->upstream_states->nelts * (NGX_OFF_T_LEN + 2);
5444 
5445     p = ngx_pnalloc(r->pool, len);
5446     if (p == NULL) {
5447         return NGX_ERROR;
5448     }
5449 
5450     v->data = p;
5451 
5452     i = 0;
5453     state = r->upstream_states->elts;
5454 
5455     for ( ;; ) {
5456 
5457         if (data == 1) {
5458             p = ngx_sprintf(p, "%O", state[i].bytes_received);
5459 
5460         } else {
5461             p = ngx_sprintf(p, "%O", state[i].response_length);
5462         }
5463 
5464         if (++i == r->upstream_states->nelts) {
5465             break;
5466         }
5467 
5468         if (state[i].peer) {
5469             *p++ = ',';
5470             *p++ = ' ';
5471 
5472         } else {
5473             *p++ = ' ';
5474             *p++ = ':';
5475             *p++ = ' ';
5476 
5477             if (++i == r->upstream_states->nelts) {
5478                 break;
5479             }
5480 
5481             continue;
5482         }
5483     }
5484 
5485     v->len = p - v->data;
5486 
5487     return NGX_OK;
5488 }
5489 
5490 
5491 static ngx_int_t
5492 ngx_http_upstream_header_variable(ngx_http_request_t *r,
5493     ngx_http_variable_value_t *v, uintptr_t data)
5494 {
5495     if (r->upstream == NULL) {
5496         v->not_found = 1;
5497         return NGX_OK;
5498     }
5499 
5500     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
5501                                          &r->upstream->headers_in.headers.part,
5502                                          sizeof("upstream_http_") - 1);
5503 }
5504 
5505 
5506 static ngx_int_t
5507 ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
5508     ngx_http_variable_value_t *v, uintptr_t data)
5509 {
5510     if (r->upstream == NULL) {
5511         v->not_found = 1;
5512         return NGX_OK;
5513     }
5514 
5515     return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
5516                                         &r->upstream->headers_in.trailers.part,
5517                                         sizeof("upstream_trailer_") - 1);
5518 }
5519 
5520 
5521 static ngx_int_t
5522 ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
5523     ngx_http_variable_value_t *v, uintptr_t data)
5524 {
5525     ngx_str_t  *name = (ngx_str_t *) data;
5526 
5527     ngx_str_t   cookie, s;
5528 
5529     if (r->upstream == NULL) {
5530         v->not_found = 1;
5531         return NGX_OK;
5532     }
5533 
5534     s.len = name->len - (sizeof("upstream_cookie_") - 1);
5535     s.data = name->data + sizeof("upstream_cookie_") - 1;
5536 
5537     if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies,
5538                                         &s, &cookie)
5539         == NGX_DECLINED)
5540     {
5541         v->not_found = 1;
5542         return NGX_OK;
5543     }
5544 
5545     v->len = cookie.len;
5546     v->valid = 1;
5547     v->no_cacheable = 0;
5548     v->not_found = 0;
5549     v->data = cookie.data;
5550 
5551     return NGX_OK;
5552 }
5553 
5554 
5555 #if (NGX_HTTP_CACHE)
5556 
5557 static ngx_int_t
5558 ngx_http_upstream_cache_status(ngx_http_request_t *r,
5559     ngx_http_variable_value_t *v, uintptr_t data)
5560 {
5561     ngx_uint_t  n;
5562 
5563     if (r->upstream == NULL || r->upstream->cache_status == 0) {
5564         v->not_found = 1;
5565         return NGX_OK;
5566     }
5567 
5568     n = r->upstream->cache_status - 1;
5569 
5570     v->valid = 1;
5571     v->no_cacheable = 0;
5572     v->not_found = 0;
5573     v->len = ngx_http_cache_status[n].len;
5574     v->data = ngx_http_cache_status[n].data;
5575 
5576     return NGX_OK;
5577 }
5578 
5579 
5580 static ngx_int_t
5581 ngx_http_upstream_cache_last_modified(ngx_http_request_t *r,
5582     ngx_http_variable_value_t *v, uintptr_t data)
5583 {
5584     u_char  *p;
5585 
5586     if (r->upstream == NULL
5587         || !r->upstream->conf->cache_revalidate
5588         || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
5589         || r->cache->last_modified == -1)
5590     {
5591         v->not_found = 1;
5592         return NGX_OK;
5593     }
5594 
5595     p = ngx_pnalloc(r->pool, sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1);
5596     if (p == NULL) {
5597         return NGX_ERROR;
5598     }
5599 
5600     v->len = ngx_http_time(p, r->cache->last_modified) - p;
5601     v->valid = 1;
5602     v->no_cacheable = 0;
5603     v->not_found = 0;
5604     v->data = p;
5605 
5606     return NGX_OK;
5607 }
5608 
5609 
5610 static ngx_int_t
5611 ngx_http_upstream_cache_etag(ngx_http_request_t *r,
5612     ngx_http_variable_value_t *v, uintptr_t data)
5613 {
5614     if (r->upstream == NULL
5615         || !r->upstream->conf->cache_revalidate
5616         || r->upstream->cache_status != NGX_HTTP_CACHE_EXPIRED
5617         || r->cache->etag.len == 0)
5618     {
5619         v->not_found = 1;
5620         return NGX_OK;
5621     }
5622 
5623     v->valid = 1;
5624     v->no_cacheable = 0;
5625     v->not_found = 0;
5626     v->len = r->cache->etag.len;
5627     v->data = r->cache->etag.data;
5628 
5629     return NGX_OK;
5630 }
5631 
5632 #endif
5633 
5634 
5635 static char *
5636 ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
5637 {
5638     char                          *rv;
5639     void                          *mconf;
5640     ngx_str_t                     *value;
5641     ngx_url_t                      u;
5642     ngx_uint_t                     m;
5643     ngx_conf_t                     pcf;
5644     ngx_http_module_t             *module;
5645     ngx_http_conf_ctx_t           *ctx, *http_ctx;
5646     ngx_http_upstream_srv_conf_t  *uscf;
5647 
5648     ngx_memzero(&u, sizeof(ngx_url_t));
5649 
5650     value = cf->args->elts;
5651     u.host = value[1];
5652     u.no_resolve = 1;
5653     u.no_port = 1;
5654 
5655     uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
5656                                          |NGX_HTTP_UPSTREAM_WEIGHT
5657                                          |NGX_HTTP_UPSTREAM_MAX_CONNS
5658                                          |NGX_HTTP_UPSTREAM_MAX_FAILS
5659                                          |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
5660                                          |NGX_HTTP_UPSTREAM_DOWN
5661                                          |NGX_HTTP_UPSTREAM_BACKUP);
5662     if (uscf == NULL) {
5663         return NGX_CONF_ERROR;
5664     }
5665 
5666 
5667     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
5668     if (ctx == NULL) {
5669         return NGX_CONF_ERROR;
5670     }
5671 
5672     http_ctx = cf->ctx;
5673     ctx->main_conf = http_ctx->main_conf;
5674 
5675     /* the upstream{}'s srv_conf */
5676 
5677     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
5678     if (ctx->srv_conf == NULL) {
5679         return NGX_CONF_ERROR;
5680     }
5681 
5682     ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
5683 
5684     uscf->srv_conf = ctx->srv_conf;
5685 
5686 
5687     /* the upstream{}'s loc_conf */
5688 
5689     ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
5690     if (ctx->loc_conf == NULL) {
5691         return NGX_CONF_ERROR;
5692     }
5693 
5694     for (m = 0; cf->cycle->modules[m]; m++) {
5695         if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
5696             continue;
5697         }
5698 
5699         module = cf->cycle->modules[m]->ctx;
5700 
5701         if (module->create_srv_conf) {
5702             mconf = module->create_srv_conf(cf);
5703             if (mconf == NULL) {
5704                 return NGX_CONF_ERROR;
5705             }
5706 
5707             ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
5708         }
5709 
5710         if (module->create_loc_conf) {
5711             mconf = module->create_loc_conf(cf);
5712             if (mconf == NULL) {
5713                 return NGX_CONF_ERROR;
5714             }
5715 
5716             ctx->loc_conf[cf->cycle->modules[m]->ctx_index] = mconf;
5717         }
5718     }
5719 
5720     uscf->servers = ngx_array_create(cf->pool, 4,
5721                                      sizeof(ngx_http_upstream_server_t));
5722     if (uscf->servers == NULL) {
5723         return NGX_CONF_ERROR;
5724     }
5725 
5726 
5727     /* parse inside upstream{} */
5728 
5729     pcf = *cf;
5730     cf->ctx = ctx;
5731     cf->cmd_type = NGX_HTTP_UPS_CONF;
5732 
5733     rv = ngx_conf_parse(cf, NULL);
5734 
5735     *cf = pcf;
5736 
5737     if (rv != NGX_CONF_OK) {
5738         return rv;
5739     }
5740 
5741     if (uscf->servers->nelts == 0) {
5742         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5743                            "no servers are inside upstream");
5744         return NGX_CONF_ERROR;
5745     }
5746 
5747     return rv;
5748 }
5749 
5750 
5751 static char *
5752 ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
5753 {
5754     ngx_http_upstream_srv_conf_t  *uscf = conf;
5755 
5756     time_t                       fail_timeout;
5757     ngx_str_t                   *value, s;
5758     ngx_url_t                    u;
5759     ngx_int_t                    weight, max_conns, max_fails;
5760     ngx_uint_t                   i;
5761     ngx_http_upstream_server_t  *us;
5762 
5763     us = ngx_array_push(uscf->servers);
5764     if (us == NULL) {
5765         return NGX_CONF_ERROR;
5766     }
5767 
5768     ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
5769 
5770     value = cf->args->elts;
5771 
5772     weight = 1;
5773     max_conns = 0;
5774     max_fails = 1;
5775     fail_timeout = 10;
5776 
5777     for (i = 2; i < cf->args->nelts; i++) {
5778 
5779         if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
5780 
5781             if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
5782                 goto not_supported;
5783             }
5784 
5785             weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
5786 
5787             if (weight == NGX_ERROR || weight == 0) {
5788                 goto invalid;
5789             }
5790 
5791             continue;
5792         }
5793 
5794         if (ngx_strncmp(value[i].data, "max_conns=", 10) == 0) {
5795 
5796             if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_CONNS)) {
5797                 goto not_supported;
5798             }
5799 
5800             max_conns = ngx_atoi(&value[i].data[10], value[i].len - 10);
5801 
5802             if (max_conns == NGX_ERROR) {
5803                 goto invalid;
5804             }
5805 
5806             continue;
5807         }
5808 
5809         if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
5810 
5811             if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
5812                 goto not_supported;
5813             }
5814 
5815             max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
5816 
5817             if (max_fails == NGX_ERROR) {
5818                 goto invalid;
5819             }
5820 
5821             continue;
5822         }
5823 
5824         if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
5825 
5826             if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
5827                 goto not_supported;
5828             }
5829 
5830             s.len = value[i].len - 13;
5831             s.data = &value[i].data[13];
5832 
5833             fail_timeout = ngx_parse_time(&s, 1);
5834 
5835             if (fail_timeout == (time_t) NGX_ERROR) {
5836                 goto invalid;
5837             }
5838 
5839             continue;
5840         }
5841 
5842         if (ngx_strcmp(value[i].data, "backup") == 0) {
5843 
5844             if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
5845                 goto not_supported;
5846             }
5847 
5848             us->backup = 1;
5849 
5850             continue;
5851         }
5852 
5853         if (ngx_strcmp(value[i].data, "down") == 0) {
5854 
5855             if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
5856                 goto not_supported;
5857             }
5858 
5859             us->down = 1;
5860 
5861             continue;
5862         }
5863 
5864         goto invalid;
5865     }
5866 
5867     ngx_memzero(&u, sizeof(ngx_url_t));
5868 
5869     u.url = value[1];
5870     u.default_port = 80;
5871 
5872     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
5873         if (u.err) {
5874             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5875                                "%s in upstream \"%V\"", u.err, &u.url);
5876         }
5877 
5878         return NGX_CONF_ERROR;
5879     }
5880 
5881     us->name = u.url;
5882     us->addrs = u.addrs;
5883     us->naddrs = u.naddrs;
5884     us->weight = weight;
5885     us->max_conns = max_conns;
5886     us->max_fails = max_fails;
5887     us->fail_timeout = fail_timeout;
5888 
5889     return NGX_CONF_OK;
5890 
5891 invalid:
5892 
5893     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5894                        "invalid parameter \"%V\"", &value[i]);
5895 
5896     return NGX_CONF_ERROR;
5897 
5898 not_supported:
5899 
5900     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5901                        "balancing method does not support parameter \"%V\"",
5902                        &value[i]);
5903 
5904     return NGX_CONF_ERROR;
5905 }
5906 
5907 
5908 ngx_http_upstream_srv_conf_t *
5909 ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
5910 {
5911     ngx_uint_t                      i;
5912     ngx_http_upstream_server_t     *us;
5913     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
5914     ngx_http_upstream_main_conf_t  *umcf;
5915 
5916     if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
5917 
5918         if (ngx_parse_url(cf->pool, u) != NGX_OK) {
5919             if (u->err) {
5920                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5921                                    "%s in upstream \"%V\"", u->err, &u->url);
5922             }
5923 
5924             return NULL;
5925         }
5926     }
5927 
5928     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
5929 
5930     uscfp = umcf->upstreams.elts;
5931 
5932     for (i = 0; i < umcf->upstreams.nelts; i++) {
5933 
5934         if (uscfp[i]->host.len != u->host.len
5935             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
5936                != 0)
5937         {
5938             continue;
5939         }
5940 
5941         if ((flags & NGX_HTTP_UPSTREAM_CREATE)
5942              && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
5943         {
5944             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5945                                "duplicate upstream \"%V\"", &u->host);
5946             return NULL;
5947         }
5948 
5949         if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && !u->no_port) {
5950             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
5951                                "upstream \"%V\" may not have port %d",
5952                                &u->host, u->port);
5953             return NULL;
5954         }
5955 
5956         if ((flags & NGX_HTTP_UPSTREAM_CREATE) && !uscfp[i]->no_port) {
5957             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
5958                           "upstream \"%V\" may not have port %d in %s:%ui",
5959                           &u->host, uscfp[i]->port,
5960                           uscfp[i]->file_name, uscfp[i]->line);
5961             return NULL;
5962         }
5963 
5964         if (uscfp[i]->port && u->port
5965             && uscfp[i]->port != u->port)
5966         {
5967             continue;
5968         }
5969 
5970         if (flags & NGX_HTTP_UPSTREAM_CREATE) {
5971             uscfp[i]->flags = flags;
5972             uscfp[i]->port = 0;
5973         }
5974 
5975         return uscfp[i];
5976     }
5977 
5978     uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
5979     if (uscf == NULL) {
5980         return NULL;
5981     }
5982 
5983     uscf->flags = flags;
5984     uscf->host = u->host;
5985     uscf->file_name = cf->conf_file->file.name.data;
5986     uscf->line = cf->conf_file->line;
5987     uscf->port = u->port;
5988     uscf->no_port = u->no_port;
5989 
5990     if (u->naddrs == 1 && (u->port || u->family == AF_UNIX)) {
5991         uscf->servers = ngx_array_create(cf->pool, 1,
5992                                          sizeof(ngx_http_upstream_server_t));
5993         if (uscf->servers == NULL) {
5994             return NULL;
5995         }
5996 
5997         us = ngx_array_push(uscf->servers);
5998         if (us == NULL) {
5999             return NULL;
6000         }
6001 
6002         ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
6003 
6004         us->addrs = u->addrs;
6005         us->naddrs = 1;
6006     }
6007 
6008     uscfp = ngx_array_push(&umcf->upstreams);
6009     if (uscfp == NULL) {
6010         return NULL;
6011     }
6012 
6013     *uscfp = uscf;
6014 
6015     return uscf;
6016 }
6017 
6018 
6019 char *
6020 ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
6021     void *conf)
6022 {
6023     char  *p = conf;
6024 
6025     ngx_int_t                           rc;
6026     ngx_str_t                          *value;
6027     ngx_http_complex_value_t            cv;
6028     ngx_http_upstream_local_t         **plocal, *local;
6029     ngx_http_compile_complex_value_t    ccv;
6030 
6031     plocal = (ngx_http_upstream_local_t **) (p + cmd->offset);
6032 
6033     if (*plocal != NGX_CONF_UNSET_PTR) {
6034         return "is duplicate";
6035     }
6036 
6037     value = cf->args->elts;
6038 
6039     if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "off") == 0) {
6040         *plocal = NULL;
6041         return NGX_CONF_OK;
6042     }
6043 
6044     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
6045 
6046     ccv.cf = cf;
6047     ccv.value = &value[1];
6048     ccv.complex_value = &cv;
6049 
6050     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
6051         return NGX_CONF_ERROR;
6052     }
6053 
6054     local = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_local_t));
6055     if (local == NULL) {
6056         return NGX_CONF_ERROR;
6057     }
6058 
6059     *plocal = local;
6060 
6061     if (cv.lengths) {
6062         local->value = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
6063         if (local->value == NULL) {
6064             return NGX_CONF_ERROR;
6065         }
6066 
6067         *local->value = cv;
6068 
6069     } else {
6070         local->addr = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
6071         if (local->addr == NULL) {
6072             return NGX_CONF_ERROR;
6073         }
6074 
6075         rc = ngx_parse_addr_port(cf->pool, local->addr, value[1].data,
6076                                  value[1].len);
6077 
6078         switch (rc) {
6079         case NGX_OK:
6080             local->addr->name = value[1];
6081             break;
6082 
6083         case NGX_DECLINED:
6084             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
6085                                "invalid address \"%V\"", &value[1]);
6086             /* fall through */
6087 
6088         default:
6089             return NGX_CONF_ERROR;
6090         }
6091     }
6092 
6093     if (cf->args->nelts > 2) {
6094         if (ngx_strcmp(value[2].data, "transparent") == 0) {
6095 #if (NGX_HAVE_TRANSPARENT_PROXY)
6096             ngx_core_conf_t  *ccf;
6097 
6098             ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
6099                                                    ngx_core_module);
6100 
6101             ccf->transparent = 1;
6102             local->transparent = 1;
6103 #else
6104             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
6105                                "transparent proxying is not supported "
6106                                "on this platform, ignored");
6107 #endif
6108         } else {
6109             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
6110                                "invalid parameter \"%V\"", &value[2]);
6111             return NGX_CONF_ERROR;
6112         }
6113     }
6114 
6115     return NGX_CONF_OK;
6116 }
6117 
6118 
6119 static ngx_int_t
6120 ngx_http_upstream_set_local(ngx_http_request_t *r, ngx_http_upstream_t *u,
6121     ngx_http_upstream_local_t *local)
6122 {
6123     ngx_int_t    rc;
6124     ngx_str_t    val;
6125     ngx_addr_t  *addr;
6126 
6127     if (local == NULL) {
6128         u->peer.local = NULL;
6129         return NGX_OK;
6130     }
6131 
6132 #if (NGX_HAVE_TRANSPARENT_PROXY)
6133     u->peer.transparent = local->transparent;
6134 #endif
6135 
6136     if (local->value == NULL) {
6137         u->peer.local = local->addr;
6138         return NGX_OK;
6139     }
6140 
6141     if (ngx_http_complex_value(r, local->value, &val) != NGX_OK) {
6142         return NGX_ERROR;
6143     }
6144 
6145     if (val.len == 0) {
6146         return NGX_OK;
6147     }
6148 
6149     addr = ngx_palloc(r->pool, sizeof(ngx_addr_t));
6150     if (addr == NULL) {
6151         return NGX_ERROR;
6152     }
6153 
6154     rc = ngx_parse_addr_port(r->pool, addr, val.data, val.len);
6155     if (rc == NGX_ERROR) {
6156         return NGX_ERROR;
6157     }
6158 
6159     if (rc != NGX_OK) {
6160         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
6161                       "invalid local address \"%V\"", &val);
6162         return NGX_OK;
6163     }
6164 
6165     addr->name = val;
6166     u->peer.local = addr;
6167 
6168     return NGX_OK;
6169 }
6170 
6171 
6172 char *
6173 ngx_http_upstream_param_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
6174     void *conf)
6175 {
6176     char  *p = conf;
6177 
6178     ngx_str_t                   *value;
6179     ngx_array_t                **a;
6180     ngx_http_upstream_param_t   *param;
6181 
6182     a = (ngx_array_t **) (p + cmd->offset);
6183 
6184     if (*a == NULL) {
6185         *a = ngx_array_create(cf->pool, 4, sizeof(ngx_http_upstream_param_t));
6186         if (*a == NULL) {
6187             return NGX_CONF_ERROR;
6188         }
6189     }
6190 
6191     param = ngx_array_push(*a);
6192     if (param == NULL) {
6193         return NGX_CONF_ERROR;
6194     }
6195 
6196     value = cf->args->elts;
6197 
6198     param->key = value[1];
6199     param->value = value[2];
6200     param->skip_empty = 0;
6201 
6202     if (cf->args->nelts == 4) {
6203         if (ngx_strcmp(value[3].data, "if_not_empty") != 0) {
6204             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
6205                                "invalid parameter \"%V\"", &value[3]);
6206             return NGX_CONF_ERROR;
6207         }
6208 
6209         param->skip_empty = 1;
6210     }
6211 
6212     return NGX_CONF_OK;
6213 }
6214 
6215 
6216 ngx_int_t
6217 ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf,
6218     ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev,
6219     ngx_str_t *default_hide_headers, ngx_hash_init_t *hash)
6220 {
6221     ngx_str_t       *h;
6222     ngx_uint_t       i, j;
6223     ngx_array_t      hide_headers;
6224     ngx_hash_key_t  *hk;
6225 
6226     if (conf->hide_headers == NGX_CONF_UNSET_PTR
6227         && conf->pass_headers == NGX_CONF_UNSET_PTR)
6228     {
6229         conf->hide_headers = prev->hide_headers;
6230         conf->pass_headers = prev->pass_headers;
6231 
6232         conf->hide_headers_hash = prev->hide_headers_hash;
6233 
6234         if (conf->hide_headers_hash.buckets) {
6235             return NGX_OK;
6236         }
6237 
6238     } else {
6239         if (conf->hide_headers == NGX_CONF_UNSET_PTR) {
6240             conf->hide_headers = prev->hide_headers;
6241         }
6242 
6243         if (conf->pass_headers == NGX_CONF_UNSET_PTR) {
6244             conf->pass_headers = prev->pass_headers;
6245         }
6246     }
6247 
6248     if (ngx_array_init(&hide_headers, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
6249         != NGX_OK)
6250     {
6251         return NGX_ERROR;
6252     }
6253 
6254     for (h = default_hide_headers; h->len; h++) {
6255         hk = ngx_array_push(&hide_headers);
6256         if (hk == NULL) {
6257             return NGX_ERROR;
6258         }
6259 
6260         hk->key = *h;
6261         hk->key_hash = ngx_hash_key_lc(h->data, h->len);
6262         hk->value = (void *) 1;
6263     }
6264 
6265     if (conf->hide_headers != NGX_CONF_UNSET_PTR) {
6266 
6267         h = conf->hide_headers->elts;
6268 
6269         for (i = 0; i < conf->hide_headers->nelts; i++) {
6270 
6271             hk = hide_headers.elts;
6272 
6273             for (j = 0; j < hide_headers.nelts; j++) {
6274                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
6275                     goto exist;
6276                 }
6277             }
6278 
6279             hk = ngx_array_push(&hide_headers);
6280             if (hk == NULL) {
6281                 return NGX_ERROR;
6282             }
6283 
6284             hk->key = h[i];
6285             hk->key_hash = ngx_hash_key_lc(h[i].data, h[i].len);
6286             hk->value = (void *) 1;
6287 
6288         exist:
6289 
6290             continue;
6291         }
6292     }
6293 
6294     if (conf->pass_headers != NGX_CONF_UNSET_PTR) {
6295 
6296         h = conf->pass_headers->elts;
6297         hk = hide_headers.elts;
6298 
6299         for (i = 0; i < conf->pass_headers->nelts; i++) {
6300             for (j = 0; j < hide_headers.nelts; j++) {
6301 
6302                 if (hk[j].key.data == NULL) {
6303                     continue;
6304                 }
6305 
6306                 if (ngx_strcasecmp(h[i].data, hk[j].key.data) == 0) {
6307                     hk[j].key.data = NULL;
6308                     break;
6309                 }
6310             }
6311         }
6312     }
6313 
6314     hash->hash = &conf->hide_headers_hash;
6315     hash->key = ngx_hash_key_lc;
6316     hash->pool = cf->pool;
6317     hash->temp_pool = NULL;
6318 
6319     if (ngx_hash_init(hash, hide_headers.elts, hide_headers.nelts) != NGX_OK) {
6320         return NGX_ERROR;
6321     }
6322 
6323     /*
6324      * special handling to preserve conf->hide_headers_hash
6325      * in the "http" section to inherit it to all servers
6326      */
6327 
6328     if (prev->hide_headers_hash.buckets == NULL
6329         && conf->hide_headers == prev->hide_headers
6330         && conf->pass_headers == prev->pass_headers)
6331     {
6332         prev->hide_headers_hash = conf->hide_headers_hash;
6333     }
6334 
6335     return NGX_OK;
6336 }
6337 
6338 
6339 static void *
6340 ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
6341 {
6342     ngx_http_upstream_main_conf_t  *umcf;
6343 
6344     umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t));
6345     if (umcf == NULL) {
6346         return NULL;
6347     }
6348 
6349     if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
6350                        sizeof(ngx_http_upstream_srv_conf_t *))
6351         != NGX_OK)
6352     {
6353         return NULL;
6354     }
6355 
6356     return umcf;
6357 }
6358 
6359 
6360 static char *
6361 ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
6362 {
6363     ngx_http_upstream_main_conf_t  *umcf = conf;
6364 
6365     ngx_uint_t                      i;
6366     ngx_array_t                     headers_in;
6367     ngx_hash_key_t                 *hk;
6368     ngx_hash_init_t                 hash;
6369     ngx_http_upstream_init_pt       init;
6370     ngx_http_upstream_header_t     *header;
6371     ngx_http_upstream_srv_conf_t  **uscfp;
6372 
6373     uscfp = umcf->upstreams.elts;
6374 
6375     for (i = 0; i < umcf->upstreams.nelts; i++) {
6376 
6377         init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
6378                                             ngx_http_upstream_init_round_robin;
6379 
6380         if (init(cf, uscfp[i]) != NGX_OK) {
6381             return NGX_CONF_ERROR;
6382         }
6383     }
6384 
6385 
6386     /* upstream_headers_in_hash */
6387 
6388     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
6389         != NGX_OK)
6390     {
6391         return NGX_CONF_ERROR;
6392     }
6393 
6394     for (header = ngx_http_upstream_headers_in; header->name.len; header++) {
6395         hk = ngx_array_push(&headers_in);
6396         if (hk == NULL) {
6397             return NGX_CONF_ERROR;
6398         }
6399 
6400         hk->key = header->name;
6401         hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len);
6402         hk->value = header;
6403     }
6404 
6405     hash.hash = &umcf->headers_in_hash;
6406     hash.key = ngx_hash_key_lc;
6407     hash.max_size = 512;
6408     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
6409     hash.name = "upstream_headers_in_hash";
6410     hash.pool = cf->pool;
6411     hash.temp_pool = NULL;
6412 
6413     if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) {
6414         return NGX_CONF_ERROR;
6415     }
6416 
6417     return NGX_CONF_OK;
6418 }