Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

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