Back to home page

Nginx displayed by LXR

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

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