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 typedef struct {
0014     ngx_array_t                    caches;  /* ngx_http_file_cache_t * */
0015 } ngx_http_proxy_main_conf_t;
0016 
0017 
0018 typedef struct ngx_http_proxy_rewrite_s  ngx_http_proxy_rewrite_t;
0019 
0020 typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
0021     ngx_table_elt_t *h, size_t prefix, size_t len,
0022     ngx_http_proxy_rewrite_t *pr);
0023 
0024 struct ngx_http_proxy_rewrite_s {
0025     ngx_http_proxy_rewrite_pt      handler;
0026 
0027     union {
0028         ngx_http_complex_value_t   complex;
0029 #if (NGX_PCRE)
0030         ngx_http_regex_t          *regex;
0031 #endif
0032     } pattern;
0033 
0034     ngx_http_complex_value_t       replacement;
0035 };
0036 
0037 
0038 typedef struct {
0039     ngx_str_t                      key_start;
0040     ngx_str_t                      schema;
0041     ngx_str_t                      host_header;
0042     ngx_str_t                      port;
0043     ngx_str_t                      uri;
0044 } ngx_http_proxy_vars_t;
0045 
0046 
0047 typedef struct {
0048     ngx_array_t                   *flushes;
0049     ngx_array_t                   *lengths;
0050     ngx_array_t                   *values;
0051     ngx_hash_t                     hash;
0052 } ngx_http_proxy_headers_t;
0053 
0054 
0055 typedef struct {
0056     ngx_http_upstream_conf_t       upstream;
0057 
0058     ngx_array_t                   *body_flushes;
0059     ngx_array_t                   *body_lengths;
0060     ngx_array_t                   *body_values;
0061     ngx_str_t                      body_source;
0062 
0063     ngx_http_proxy_headers_t       headers;
0064 #if (NGX_HTTP_CACHE)
0065     ngx_http_proxy_headers_t       headers_cache;
0066 #endif
0067     ngx_array_t                   *headers_source;
0068 
0069     ngx_array_t                   *proxy_lengths;
0070     ngx_array_t                   *proxy_values;
0071 
0072     ngx_array_t                   *redirects;
0073     ngx_array_t                   *cookie_domains;
0074     ngx_array_t                   *cookie_paths;
0075 
0076     ngx_http_complex_value_t      *method;
0077     ngx_str_t                      location;
0078     ngx_str_t                      url;
0079 
0080 #if (NGX_HTTP_CACHE)
0081     ngx_http_complex_value_t       cache_key;
0082 #endif
0083 
0084     ngx_http_proxy_vars_t          vars;
0085 
0086     ngx_flag_t                     redirect;
0087 
0088     ngx_uint_t                     http_version;
0089 
0090     ngx_uint_t                     headers_hash_max_size;
0091     ngx_uint_t                     headers_hash_bucket_size;
0092 
0093 #if (NGX_HTTP_SSL)
0094     ngx_uint_t                     ssl;
0095     ngx_uint_t                     ssl_protocols;
0096     ngx_str_t                      ssl_ciphers;
0097     ngx_uint_t                     ssl_verify_depth;
0098     ngx_str_t                      ssl_trusted_certificate;
0099     ngx_str_t                      ssl_crl;
0100     ngx_str_t                      ssl_certificate;
0101     ngx_str_t                      ssl_certificate_key;
0102     ngx_array_t                   *ssl_passwords;
0103 #endif
0104 } ngx_http_proxy_loc_conf_t;
0105 
0106 
0107 typedef struct {
0108     ngx_http_status_t              status;
0109     ngx_http_chunked_t             chunked;
0110     ngx_http_proxy_vars_t          vars;
0111     off_t                          internal_body_length;
0112 
0113     ngx_chain_t                   *free;
0114     ngx_chain_t                   *busy;
0115 
0116     unsigned                       head:1;
0117     unsigned                       internal_chunked:1;
0118     unsigned                       header_sent:1;
0119 } ngx_http_proxy_ctx_t;
0120 
0121 
0122 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
0123     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
0124 #if (NGX_HTTP_CACHE)
0125 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
0126 #endif
0127 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
0128 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
0129 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
0130 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
0131 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
0132 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
0133 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
0134     ngx_buf_t *buf);
0135 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
0136     ngx_buf_t *buf);
0137 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
0138     ssize_t bytes);
0139 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
0140     ssize_t bytes);
0141 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
0142 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
0143     ngx_int_t rc);
0144 
0145 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
0146     ngx_http_variable_value_t *v, uintptr_t data);
0147 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
0148     ngx_http_variable_value_t *v, uintptr_t data);
0149 static ngx_int_t
0150     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
0151     ngx_http_variable_value_t *v, uintptr_t data);
0152 static ngx_int_t
0153     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
0154     ngx_http_variable_value_t *v, uintptr_t data);
0155 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
0156     ngx_http_variable_value_t *v, uintptr_t data);
0157 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
0158     ngx_table_elt_t *h, size_t prefix);
0159 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
0160     ngx_table_elt_t *h);
0161 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
0162     ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
0163 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
0164     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
0165 
0166 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
0167 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
0168 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
0169 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
0170     void *parent, void *child);
0171 static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
0172     ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
0173     ngx_keyval_t *default_headers);
0174 
0175 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
0176     void *conf);
0177 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
0178     void *conf);
0179 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
0180     void *conf);
0181 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
0182     void *conf);
0183 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
0184     void *conf);
0185 #if (NGX_HTTP_CACHE)
0186 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0187     void *conf);
0188 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
0189     void *conf);
0190 #endif
0191 #if (NGX_HTTP_SSL)
0192 static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
0193     ngx_command_t *cmd, void *conf);
0194 #endif
0195 
0196 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
0197 
0198 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
0199     ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
0200 
0201 #if (NGX_HTTP_SSL)
0202 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
0203     ngx_http_proxy_loc_conf_t *plcf);
0204 #endif
0205 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
0206 
0207 
0208 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
0209     { ngx_http_proxy_lowat_check };
0210 
0211 
0212 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
0213     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
0214     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
0215     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
0216     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
0217     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
0218     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
0219     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
0220     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
0221     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
0222     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0223     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
0224     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
0225     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
0226     { ngx_null_string, 0 }
0227 };
0228 
0229 
0230 #if (NGX_HTTP_SSL)
0231 
0232 static ngx_conf_bitmask_t  ngx_http_proxy_ssl_protocols[] = {
0233     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
0234     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
0235     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
0236     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
0237     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
0238     { ngx_null_string, 0 }
0239 };
0240 
0241 #endif
0242 
0243 
0244 static ngx_conf_enum_t  ngx_http_proxy_http_version[] = {
0245     { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
0246     { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
0247     { ngx_null_string, 0 }
0248 };
0249 
0250 
0251 ngx_module_t  ngx_http_proxy_module;
0252 
0253 
0254 static ngx_command_t  ngx_http_proxy_commands[] = {
0255 
0256     { ngx_string("proxy_pass"),
0257       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
0258       ngx_http_proxy_pass,
0259       NGX_HTTP_LOC_CONF_OFFSET,
0260       0,
0261       NULL },
0262 
0263     { ngx_string("proxy_redirect"),
0264       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0265       ngx_http_proxy_redirect,
0266       NGX_HTTP_LOC_CONF_OFFSET,
0267       0,
0268       NULL },
0269 
0270     { ngx_string("proxy_cookie_domain"),
0271       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0272       ngx_http_proxy_cookie_domain,
0273       NGX_HTTP_LOC_CONF_OFFSET,
0274       0,
0275       NULL },
0276 
0277     { ngx_string("proxy_cookie_path"),
0278       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0279       ngx_http_proxy_cookie_path,
0280       NGX_HTTP_LOC_CONF_OFFSET,
0281       0,
0282       NULL },
0283 
0284     { ngx_string("proxy_store"),
0285       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0286       ngx_http_proxy_store,
0287       NGX_HTTP_LOC_CONF_OFFSET,
0288       0,
0289       NULL },
0290 
0291     { ngx_string("proxy_store_access"),
0292       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
0293       ngx_conf_set_access_slot,
0294       NGX_HTTP_LOC_CONF_OFFSET,
0295       offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
0296       NULL },
0297 
0298     { ngx_string("proxy_buffering"),
0299       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0300       ngx_conf_set_flag_slot,
0301       NGX_HTTP_LOC_CONF_OFFSET,
0302       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
0303       NULL },
0304 
0305     { ngx_string("proxy_request_buffering"),
0306       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0307       ngx_conf_set_flag_slot,
0308       NGX_HTTP_LOC_CONF_OFFSET,
0309       offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering),
0310       NULL },
0311 
0312     { ngx_string("proxy_ignore_client_abort"),
0313       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0314       ngx_conf_set_flag_slot,
0315       NGX_HTTP_LOC_CONF_OFFSET,
0316       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
0317       NULL },
0318 
0319     { ngx_string("proxy_bind"),
0320       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0321       ngx_http_upstream_bind_set_slot,
0322       NGX_HTTP_LOC_CONF_OFFSET,
0323       offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
0324       NULL },
0325 
0326     { ngx_string("proxy_connect_timeout"),
0327       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0328       ngx_conf_set_msec_slot,
0329       NGX_HTTP_LOC_CONF_OFFSET,
0330       offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
0331       NULL },
0332 
0333     { ngx_string("proxy_send_timeout"),
0334       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0335       ngx_conf_set_msec_slot,
0336       NGX_HTTP_LOC_CONF_OFFSET,
0337       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
0338       NULL },
0339 
0340     { ngx_string("proxy_send_lowat"),
0341       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0342       ngx_conf_set_size_slot,
0343       NGX_HTTP_LOC_CONF_OFFSET,
0344       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
0345       &ngx_http_proxy_lowat_post },
0346 
0347     { ngx_string("proxy_intercept_errors"),
0348       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0349       ngx_conf_set_flag_slot,
0350       NGX_HTTP_LOC_CONF_OFFSET,
0351       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
0352       NULL },
0353 
0354     { ngx_string("proxy_set_header"),
0355       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0356       ngx_conf_set_keyval_slot,
0357       NGX_HTTP_LOC_CONF_OFFSET,
0358       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
0359       NULL },
0360 
0361     { ngx_string("proxy_headers_hash_max_size"),
0362       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0363       ngx_conf_set_num_slot,
0364       NGX_HTTP_LOC_CONF_OFFSET,
0365       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
0366       NULL },
0367 
0368     { ngx_string("proxy_headers_hash_bucket_size"),
0369       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0370       ngx_conf_set_num_slot,
0371       NGX_HTTP_LOC_CONF_OFFSET,
0372       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
0373       NULL },
0374 
0375     { ngx_string("proxy_set_body"),
0376       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0377       ngx_conf_set_str_slot,
0378       NGX_HTTP_LOC_CONF_OFFSET,
0379       offsetof(ngx_http_proxy_loc_conf_t, body_source),
0380       NULL },
0381 
0382     { ngx_string("proxy_method"),
0383       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0384       ngx_http_set_complex_value_slot,
0385       NGX_HTTP_LOC_CONF_OFFSET,
0386       offsetof(ngx_http_proxy_loc_conf_t, method),
0387       NULL },
0388 
0389     { ngx_string("proxy_pass_request_headers"),
0390       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0391       ngx_conf_set_flag_slot,
0392       NGX_HTTP_LOC_CONF_OFFSET,
0393       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
0394       NULL },
0395 
0396     { ngx_string("proxy_pass_request_body"),
0397       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0398       ngx_conf_set_flag_slot,
0399       NGX_HTTP_LOC_CONF_OFFSET,
0400       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
0401       NULL },
0402 
0403     { ngx_string("proxy_buffer_size"),
0404       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0405       ngx_conf_set_size_slot,
0406       NGX_HTTP_LOC_CONF_OFFSET,
0407       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
0408       NULL },
0409 
0410     { ngx_string("proxy_read_timeout"),
0411       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0412       ngx_conf_set_msec_slot,
0413       NGX_HTTP_LOC_CONF_OFFSET,
0414       offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
0415       NULL },
0416 
0417     { ngx_string("proxy_buffers"),
0418       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0419       ngx_conf_set_bufs_slot,
0420       NGX_HTTP_LOC_CONF_OFFSET,
0421       offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
0422       NULL },
0423 
0424     { ngx_string("proxy_busy_buffers_size"),
0425       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0426       ngx_conf_set_size_slot,
0427       NGX_HTTP_LOC_CONF_OFFSET,
0428       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
0429       NULL },
0430 
0431     { ngx_string("proxy_force_ranges"),
0432       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0433       ngx_conf_set_flag_slot,
0434       NGX_HTTP_LOC_CONF_OFFSET,
0435       offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
0436       NULL },
0437 
0438     { ngx_string("proxy_limit_rate"),
0439       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0440       ngx_conf_set_size_slot,
0441       NGX_HTTP_LOC_CONF_OFFSET,
0442       offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
0443       NULL },
0444 
0445 #if (NGX_HTTP_CACHE)
0446 
0447     { ngx_string("proxy_cache"),
0448       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0449       ngx_http_proxy_cache,
0450       NGX_HTTP_LOC_CONF_OFFSET,
0451       0,
0452       NULL },
0453 
0454     { ngx_string("proxy_cache_key"),
0455       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0456       ngx_http_proxy_cache_key,
0457       NGX_HTTP_LOC_CONF_OFFSET,
0458       0,
0459       NULL },
0460 
0461     { ngx_string("proxy_cache_path"),
0462       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
0463       ngx_http_file_cache_set_slot,
0464       NGX_HTTP_MAIN_CONF_OFFSET,
0465       offsetof(ngx_http_proxy_main_conf_t, caches),
0466       &ngx_http_proxy_module },
0467 
0468     { ngx_string("proxy_cache_bypass"),
0469       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0470       ngx_http_set_predicate_slot,
0471       NGX_HTTP_LOC_CONF_OFFSET,
0472       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
0473       NULL },
0474 
0475     { ngx_string("proxy_no_cache"),
0476       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0477       ngx_http_set_predicate_slot,
0478       NGX_HTTP_LOC_CONF_OFFSET,
0479       offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
0480       NULL },
0481 
0482     { ngx_string("proxy_cache_valid"),
0483       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0484       ngx_http_file_cache_valid_set_slot,
0485       NGX_HTTP_LOC_CONF_OFFSET,
0486       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
0487       NULL },
0488 
0489     { ngx_string("proxy_cache_min_uses"),
0490       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0491       ngx_conf_set_num_slot,
0492       NGX_HTTP_LOC_CONF_OFFSET,
0493       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
0494       NULL },
0495 
0496     { ngx_string("proxy_cache_max_range_offset"),
0497       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0498       ngx_conf_set_off_slot,
0499       NGX_HTTP_LOC_CONF_OFFSET,
0500       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset),
0501       NULL },
0502 
0503     { ngx_string("proxy_cache_use_stale"),
0504       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0505       ngx_conf_set_bitmask_slot,
0506       NGX_HTTP_LOC_CONF_OFFSET,
0507       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
0508       &ngx_http_proxy_next_upstream_masks },
0509 
0510     { ngx_string("proxy_cache_methods"),
0511       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0512       ngx_conf_set_bitmask_slot,
0513       NGX_HTTP_LOC_CONF_OFFSET,
0514       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
0515       &ngx_http_upstream_cache_method_mask },
0516 
0517     { ngx_string("proxy_cache_lock"),
0518       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0519       ngx_conf_set_flag_slot,
0520       NGX_HTTP_LOC_CONF_OFFSET,
0521       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
0522       NULL },
0523 
0524     { ngx_string("proxy_cache_lock_timeout"),
0525       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0526       ngx_conf_set_msec_slot,
0527       NGX_HTTP_LOC_CONF_OFFSET,
0528       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
0529       NULL },
0530 
0531     { ngx_string("proxy_cache_lock_age"),
0532       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0533       ngx_conf_set_msec_slot,
0534       NGX_HTTP_LOC_CONF_OFFSET,
0535       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age),
0536       NULL },
0537 
0538     { ngx_string("proxy_cache_revalidate"),
0539       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0540       ngx_conf_set_flag_slot,
0541       NGX_HTTP_LOC_CONF_OFFSET,
0542       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
0543       NULL },
0544 
0545     { ngx_string("proxy_cache_convert_head"),
0546       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0547       ngx_conf_set_flag_slot,
0548       NGX_HTTP_LOC_CONF_OFFSET,
0549       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_convert_head),
0550       NULL },
0551 
0552     { ngx_string("proxy_cache_background_update"),
0553       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0554       ngx_conf_set_flag_slot,
0555       NGX_HTTP_LOC_CONF_OFFSET,
0556       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_background_update),
0557       NULL },
0558 
0559 #endif
0560 
0561     { ngx_string("proxy_temp_path"),
0562       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
0563       ngx_conf_set_path_slot,
0564       NGX_HTTP_LOC_CONF_OFFSET,
0565       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
0566       NULL },
0567 
0568     { ngx_string("proxy_max_temp_file_size"),
0569       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0570       ngx_conf_set_size_slot,
0571       NGX_HTTP_LOC_CONF_OFFSET,
0572       offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
0573       NULL },
0574 
0575     { ngx_string("proxy_temp_file_write_size"),
0576       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0577       ngx_conf_set_size_slot,
0578       NGX_HTTP_LOC_CONF_OFFSET,
0579       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
0580       NULL },
0581 
0582     { ngx_string("proxy_next_upstream"),
0583       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0584       ngx_conf_set_bitmask_slot,
0585       NGX_HTTP_LOC_CONF_OFFSET,
0586       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
0587       &ngx_http_proxy_next_upstream_masks },
0588 
0589     { ngx_string("proxy_next_upstream_tries"),
0590       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0591       ngx_conf_set_num_slot,
0592       NGX_HTTP_LOC_CONF_OFFSET,
0593       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
0594       NULL },
0595 
0596     { ngx_string("proxy_next_upstream_timeout"),
0597       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0598       ngx_conf_set_msec_slot,
0599       NGX_HTTP_LOC_CONF_OFFSET,
0600       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
0601       NULL },
0602 
0603     { ngx_string("proxy_pass_header"),
0604       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0605       ngx_conf_set_str_array_slot,
0606       NGX_HTTP_LOC_CONF_OFFSET,
0607       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
0608       NULL },
0609 
0610     { ngx_string("proxy_hide_header"),
0611       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0612       ngx_conf_set_str_array_slot,
0613       NGX_HTTP_LOC_CONF_OFFSET,
0614       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
0615       NULL },
0616 
0617     { ngx_string("proxy_ignore_headers"),
0618       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0619       ngx_conf_set_bitmask_slot,
0620       NGX_HTTP_LOC_CONF_OFFSET,
0621       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
0622       &ngx_http_upstream_ignore_headers_masks },
0623 
0624     { ngx_string("proxy_http_version"),
0625       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0626       ngx_conf_set_enum_slot,
0627       NGX_HTTP_LOC_CONF_OFFSET,
0628       offsetof(ngx_http_proxy_loc_conf_t, http_version),
0629       &ngx_http_proxy_http_version },
0630 
0631 #if (NGX_HTTP_SSL)
0632 
0633     { ngx_string("proxy_ssl_session_reuse"),
0634       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0635       ngx_conf_set_flag_slot,
0636       NGX_HTTP_LOC_CONF_OFFSET,
0637       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
0638       NULL },
0639 
0640     { ngx_string("proxy_ssl_protocols"),
0641       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0642       ngx_conf_set_bitmask_slot,
0643       NGX_HTTP_LOC_CONF_OFFSET,
0644       offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
0645       &ngx_http_proxy_ssl_protocols },
0646 
0647     { ngx_string("proxy_ssl_ciphers"),
0648       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0649       ngx_conf_set_str_slot,
0650       NGX_HTTP_LOC_CONF_OFFSET,
0651       offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
0652       NULL },
0653 
0654     { ngx_string("proxy_ssl_name"),
0655       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0656       ngx_http_set_complex_value_slot,
0657       NGX_HTTP_LOC_CONF_OFFSET,
0658       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name),
0659       NULL },
0660 
0661     { ngx_string("proxy_ssl_server_name"),
0662       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0663       ngx_conf_set_flag_slot,
0664       NGX_HTTP_LOC_CONF_OFFSET,
0665       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
0666       NULL },
0667 
0668     { ngx_string("proxy_ssl_verify"),
0669       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0670       ngx_conf_set_flag_slot,
0671       NGX_HTTP_LOC_CONF_OFFSET,
0672       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
0673       NULL },
0674 
0675     { ngx_string("proxy_ssl_verify_depth"),
0676       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0677       ngx_conf_set_num_slot,
0678       NGX_HTTP_LOC_CONF_OFFSET,
0679       offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
0680       NULL },
0681 
0682     { ngx_string("proxy_ssl_trusted_certificate"),
0683       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0684       ngx_conf_set_str_slot,
0685       NGX_HTTP_LOC_CONF_OFFSET,
0686       offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
0687       NULL },
0688 
0689     { ngx_string("proxy_ssl_crl"),
0690       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0691       ngx_conf_set_str_slot,
0692       NGX_HTTP_LOC_CONF_OFFSET,
0693       offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
0694       NULL },
0695 
0696     { ngx_string("proxy_ssl_certificate"),
0697       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0698       ngx_conf_set_str_slot,
0699       NGX_HTTP_LOC_CONF_OFFSET,
0700       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
0701       NULL },
0702 
0703     { ngx_string("proxy_ssl_certificate_key"),
0704       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0705       ngx_conf_set_str_slot,
0706       NGX_HTTP_LOC_CONF_OFFSET,
0707       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
0708       NULL },
0709 
0710     { ngx_string("proxy_ssl_password_file"),
0711       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0712       ngx_http_proxy_ssl_password_file,
0713       NGX_HTTP_LOC_CONF_OFFSET,
0714       0,
0715       NULL },
0716 
0717 #endif
0718 
0719       ngx_null_command
0720 };
0721 
0722 
0723 static ngx_http_module_t  ngx_http_proxy_module_ctx = {
0724     ngx_http_proxy_add_variables,          /* preconfiguration */
0725     NULL,                                  /* postconfiguration */
0726 
0727     ngx_http_proxy_create_main_conf,       /* create main configuration */
0728     NULL,                                  /* init main configuration */
0729 
0730     NULL,                                  /* create server configuration */
0731     NULL,                                  /* merge server configuration */
0732 
0733     ngx_http_proxy_create_loc_conf,        /* create location configuration */
0734     ngx_http_proxy_merge_loc_conf          /* merge location configuration */
0735 };
0736 
0737 
0738 ngx_module_t  ngx_http_proxy_module = {
0739     NGX_MODULE_V1,
0740     &ngx_http_proxy_module_ctx,            /* module context */
0741     ngx_http_proxy_commands,               /* module directives */
0742     NGX_HTTP_MODULE,                       /* module type */
0743     NULL,                                  /* init master */
0744     NULL,                                  /* init module */
0745     NULL,                                  /* init process */
0746     NULL,                                  /* init thread */
0747     NULL,                                  /* exit thread */
0748     NULL,                                  /* exit process */
0749     NULL,                                  /* exit master */
0750     NGX_MODULE_V1_PADDING
0751 };
0752 
0753 
0754 static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
0755 static char  ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
0756 
0757 
0758 static ngx_keyval_t  ngx_http_proxy_headers[] = {
0759     { ngx_string("Host"), ngx_string("$proxy_host") },
0760     { ngx_string("Connection"), ngx_string("close") },
0761     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
0762     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
0763     { ngx_string("TE"), ngx_string("") },
0764     { ngx_string("Keep-Alive"), ngx_string("") },
0765     { ngx_string("Expect"), ngx_string("") },
0766     { ngx_string("Upgrade"), ngx_string("") },
0767     { ngx_null_string, ngx_null_string }
0768 };
0769 
0770 
0771 static ngx_str_t  ngx_http_proxy_hide_headers[] = {
0772     ngx_string("Date"),
0773     ngx_string("Server"),
0774     ngx_string("X-Pad"),
0775     ngx_string("X-Accel-Expires"),
0776     ngx_string("X-Accel-Redirect"),
0777     ngx_string("X-Accel-Limit-Rate"),
0778     ngx_string("X-Accel-Buffering"),
0779     ngx_string("X-Accel-Charset"),
0780     ngx_null_string
0781 };
0782 
0783 
0784 #if (NGX_HTTP_CACHE)
0785 
0786 static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
0787     { ngx_string("Host"), ngx_string("$proxy_host") },
0788     { ngx_string("Connection"), ngx_string("close") },
0789     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
0790     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
0791     { ngx_string("TE"), ngx_string("") },
0792     { ngx_string("Keep-Alive"), ngx_string("") },
0793     { ngx_string("Expect"), ngx_string("") },
0794     { ngx_string("Upgrade"), ngx_string("") },
0795     { ngx_string("If-Modified-Since"),
0796       ngx_string("$upstream_cache_last_modified") },
0797     { ngx_string("If-Unmodified-Since"), ngx_string("") },
0798     { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") },
0799     { ngx_string("If-Match"), ngx_string("") },
0800     { ngx_string("Range"), ngx_string("") },
0801     { ngx_string("If-Range"), ngx_string("") },
0802     { ngx_null_string, ngx_null_string }
0803 };
0804 
0805 #endif
0806 
0807 
0808 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
0809 
0810     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
0811       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0812 
0813     { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
0814       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0815 
0816     { ngx_string("proxy_add_x_forwarded_for"), NULL,
0817       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
0818 
0819 #if 0
0820     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
0821 #endif
0822 
0823     { ngx_string("proxy_internal_body_length"), NULL,
0824       ngx_http_proxy_internal_body_length_variable, 0,
0825       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0826 
0827     { ngx_string("proxy_internal_chunked"), NULL,
0828       ngx_http_proxy_internal_chunked_variable, 0,
0829       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0830 
0831     { ngx_null_string, NULL, NULL, 0, 0, 0 }
0832 };
0833 
0834 
0835 static ngx_path_init_t  ngx_http_proxy_temp_path = {
0836     ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
0837 };
0838 
0839 
0840 static ngx_int_t
0841 ngx_http_proxy_handler(ngx_http_request_t *r)
0842 {
0843     ngx_int_t                    rc;
0844     ngx_http_upstream_t         *u;
0845     ngx_http_proxy_ctx_t        *ctx;
0846     ngx_http_proxy_loc_conf_t   *plcf;
0847 #if (NGX_HTTP_CACHE)
0848     ngx_http_proxy_main_conf_t  *pmcf;
0849 #endif
0850 
0851     if (ngx_http_upstream_create(r) != NGX_OK) {
0852         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0853     }
0854 
0855     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
0856     if (ctx == NULL) {
0857         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0858     }
0859 
0860     ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
0861 
0862     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
0863 
0864     u = r->upstream;
0865 
0866     if (plcf->proxy_lengths == NULL) {
0867         ctx->vars = plcf->vars;
0868         u->schema = plcf->vars.schema;
0869 #if (NGX_HTTP_SSL)
0870         u->ssl = (plcf->upstream.ssl != NULL);
0871 #endif
0872 
0873     } else {
0874         if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
0875             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0876         }
0877     }
0878 
0879     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
0880 
0881     u->conf = &plcf->upstream;
0882 
0883 #if (NGX_HTTP_CACHE)
0884     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);
0885 
0886     u->caches = &pmcf->caches;
0887     u->create_key = ngx_http_proxy_create_key;
0888 #endif
0889 
0890     u->create_request = ngx_http_proxy_create_request;
0891     u->reinit_request = ngx_http_proxy_reinit_request;
0892     u->process_header = ngx_http_proxy_process_status_line;
0893     u->abort_request = ngx_http_proxy_abort_request;
0894     u->finalize_request = ngx_http_proxy_finalize_request;
0895     r->state = 0;
0896 
0897     if (plcf->redirects) {
0898         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
0899     }
0900 
0901     if (plcf->cookie_domains || plcf->cookie_paths) {
0902         u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
0903     }
0904 
0905     u->buffering = plcf->upstream.buffering;
0906 
0907     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
0908     if (u->pipe == NULL) {
0909         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0910     }
0911 
0912     u->pipe->input_filter = ngx_http_proxy_copy_filter;
0913     u->pipe->input_ctx = r;
0914 
0915     u->input_filter_init = ngx_http_proxy_input_filter_init;
0916     u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
0917     u->input_filter_ctx = r;
0918 
0919     u->accel = 1;
0920 
0921     if (!plcf->upstream.request_buffering
0922         && plcf->body_values == NULL && plcf->upstream.pass_request_body
0923         && (!r->headers_in.chunked
0924             || plcf->http_version == NGX_HTTP_VERSION_11))
0925     {
0926         r->request_body_no_buffering = 1;
0927     }
0928 
0929     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
0930 
0931     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0932         return rc;
0933     }
0934 
0935     return NGX_DONE;
0936 }
0937 
0938 
0939 static ngx_int_t
0940 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
0941     ngx_http_proxy_loc_conf_t *plcf)
0942 {
0943     u_char               *p;
0944     size_t                add;
0945     u_short               port;
0946     ngx_str_t             proxy;
0947     ngx_url_t             url;
0948     ngx_http_upstream_t  *u;
0949 
0950     if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
0951                             plcf->proxy_values->elts)
0952         == NULL)
0953     {
0954         return NGX_ERROR;
0955     }
0956 
0957     if (proxy.len > 7
0958         && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
0959     {
0960         add = 7;
0961         port = 80;
0962 
0963 #if (NGX_HTTP_SSL)
0964 
0965     } else if (proxy.len > 8
0966                && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
0967     {
0968         add = 8;
0969         port = 443;
0970         r->upstream->ssl = 1;
0971 
0972 #endif
0973 
0974     } else {
0975         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0976                       "invalid URL prefix in \"%V\"", &proxy);
0977         return NGX_ERROR;
0978     }
0979 
0980     u = r->upstream;
0981 
0982     u->schema.len = add;
0983     u->schema.data = proxy.data;
0984 
0985     ngx_memzero(&url, sizeof(ngx_url_t));
0986 
0987     url.url.len = proxy.len - add;
0988     url.url.data = proxy.data + add;
0989     url.default_port = port;
0990     url.uri_part = 1;
0991     url.no_resolve = 1;
0992 
0993     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
0994         if (url.err) {
0995             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0996                           "%s in upstream \"%V\"", url.err, &url.url);
0997         }
0998 
0999         return NGX_ERROR;
1000     }
1001 
1002     if (url.uri.len) {
1003         if (url.uri.data[0] == '?') {
1004             p = ngx_pnalloc(r->pool, url.uri.len + 1);
1005             if (p == NULL) {
1006                 return NGX_ERROR;
1007             }
1008 
1009             *p++ = '/';
1010             ngx_memcpy(p, url.uri.data, url.uri.len);
1011 
1012             url.uri.len++;
1013             url.uri.data = p - 1;
1014         }
1015     }
1016 
1017     ctx->vars.key_start = u->schema;
1018 
1019     ngx_http_proxy_set_vars(&url, &ctx->vars);
1020 
1021     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
1022     if (u->resolved == NULL) {
1023         return NGX_ERROR;
1024     }
1025 
1026     if (url.addrs) {
1027         u->resolved->sockaddr = url.addrs[0].sockaddr;
1028         u->resolved->socklen = url.addrs[0].socklen;
1029         u->resolved->name = url.addrs[0].name;
1030         u->resolved->naddrs = 1;
1031     }
1032 
1033     u->resolved->host = url.host;
1034     u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
1035     u->resolved->no_port = url.no_port;
1036 
1037     return NGX_OK;
1038 }
1039 
1040 
1041 #if (NGX_HTTP_CACHE)
1042 
1043 static ngx_int_t
1044 ngx_http_proxy_create_key(ngx_http_request_t *r)
1045 {
1046     size_t                      len, loc_len;
1047     u_char                     *p;
1048     uintptr_t                   escape;
1049     ngx_str_t                  *key;
1050     ngx_http_upstream_t        *u;
1051     ngx_http_proxy_ctx_t       *ctx;
1052     ngx_http_proxy_loc_conf_t  *plcf;
1053 
1054     u = r->upstream;
1055 
1056     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1057 
1058     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1059 
1060     key = ngx_array_push(&r->cache->keys);
1061     if (key == NULL) {
1062         return NGX_ERROR;
1063     }
1064 
1065     if (plcf->cache_key.value.data) {
1066 
1067         if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
1068             return NGX_ERROR;
1069         }
1070 
1071         return NGX_OK;
1072     }
1073 
1074     *key = ctx->vars.key_start;
1075 
1076     key = ngx_array_push(&r->cache->keys);
1077     if (key == NULL) {
1078         return NGX_ERROR;
1079     }
1080 
1081     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1082 
1083         *key = ctx->vars.uri;
1084         u->uri = ctx->vars.uri;
1085 
1086         return NGX_OK;
1087 
1088     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
1089     {
1090         *key = r->unparsed_uri;
1091         u->uri = r->unparsed_uri;
1092 
1093         return NGX_OK;
1094     }
1095 
1096     loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
1097 
1098     if (r->quoted_uri || r->internal) {
1099         escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1100                                     r->uri.len - loc_len, NGX_ESCAPE_URI);
1101     } else {
1102         escape = 0;
1103     }
1104 
1105     len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1106           + sizeof("?") - 1 + r->args.len;
1107 
1108     p = ngx_pnalloc(r->pool, len);
1109     if (p == NULL) {
1110         return NGX_ERROR;
1111     }
1112 
1113     key->data = p;
1114 
1115     if (r->valid_location) {
1116         p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
1117     }
1118 
1119     if (escape) {
1120         ngx_escape_uri(p, r->uri.data + loc_len,
1121                        r->uri.len - loc_len, NGX_ESCAPE_URI);
1122         p += r->uri.len - loc_len + escape;
1123 
1124     } else {
1125         p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
1126     }
1127 
1128     if (r->args.len > 0) {
1129         *p++ = '?';
1130         p = ngx_copy(p, r->args.data, r->args.len);
1131     }
1132 
1133     key->len = p - key->data;
1134     u->uri = *key;
1135 
1136     return NGX_OK;
1137 }
1138 
1139 #endif
1140 
1141 
1142 static ngx_int_t
1143 ngx_http_proxy_create_request(ngx_http_request_t *r)
1144 {
1145     size_t                        len, uri_len, loc_len, body_len;
1146     uintptr_t                     escape;
1147     ngx_buf_t                    *b;
1148     ngx_str_t                     method;
1149     ngx_uint_t                    i, unparsed_uri;
1150     ngx_chain_t                  *cl, *body;
1151     ngx_list_part_t              *part;
1152     ngx_table_elt_t              *header;
1153     ngx_http_upstream_t          *u;
1154     ngx_http_proxy_ctx_t         *ctx;
1155     ngx_http_script_code_pt       code;
1156     ngx_http_proxy_headers_t     *headers;
1157     ngx_http_script_engine_t      e, le;
1158     ngx_http_proxy_loc_conf_t    *plcf;
1159     ngx_http_script_len_code_pt   lcode;
1160 
1161     u = r->upstream;
1162 
1163     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1164 
1165 #if (NGX_HTTP_CACHE)
1166     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
1167 #else
1168     headers = &plcf->headers;
1169 #endif
1170 
1171     if (u->method.len) {
1172         /* HEAD was changed to GET to cache response */
1173         method = u->method;
1174 
1175     } else if (plcf->method) {
1176         if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
1177             return NGX_ERROR;
1178         }
1179 
1180     } else {
1181         method = r->method_name;
1182     }
1183 
1184     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1185 
1186     if (method.len == 4
1187         && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
1188     {
1189         ctx->head = 1;
1190     }
1191 
1192     len = method.len + 1 + sizeof(ngx_http_proxy_version) - 1
1193           + sizeof(CRLF) - 1;
1194 
1195     escape = 0;
1196     loc_len = 0;
1197     unparsed_uri = 0;
1198 
1199     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1200         uri_len = ctx->vars.uri.len;
1201 
1202     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
1203     {
1204         unparsed_uri = 1;
1205         uri_len = r->unparsed_uri.len;
1206 
1207     } else {
1208         loc_len = (r->valid_location && ctx->vars.uri.len) ?
1209                       plcf->location.len : 0;
1210 
1211         if (r->quoted_uri || r->space_in_uri || r->internal) {
1212             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1213                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
1214         }
1215 
1216         uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1217                   + sizeof("?") - 1 + r->args.len;
1218     }
1219 
1220     if (uri_len == 0) {
1221         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1222                       "zero length URI to proxy");
1223         return NGX_ERROR;
1224     }
1225 
1226     len += uri_len;
1227 
1228     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1229 
1230     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
1231     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);
1232 
1233     if (plcf->body_lengths) {
1234         le.ip = plcf->body_lengths->elts;
1235         le.request = r;
1236         le.flushed = 1;
1237         body_len = 0;
1238 
1239         while (*(uintptr_t *) le.ip) {
1240             lcode = *(ngx_http_script_len_code_pt *) le.ip;
1241             body_len += lcode(&le);
1242         }
1243 
1244         ctx->internal_body_length = body_len;
1245         len += body_len;
1246 
1247     } else if (r->headers_in.chunked && r->reading_body) {
1248         ctx->internal_body_length = -1;
1249         ctx->internal_chunked = 1;
1250 
1251     } else {
1252         ctx->internal_body_length = r->headers_in.content_length_n;
1253     }
1254 
1255     le.ip = headers->lengths->elts;
1256     le.request = r;
1257     le.flushed = 1;
1258 
1259     while (*(uintptr_t *) le.ip) {
1260         while (*(uintptr_t *) le.ip) {
1261             lcode = *(ngx_http_script_len_code_pt *) le.ip;
1262             len += lcode(&le);
1263         }
1264         le.ip += sizeof(uintptr_t);
1265     }
1266 
1267 
1268     if (plcf->upstream.pass_request_headers) {
1269         part = &r->headers_in.headers.part;
1270         header = part->elts;
1271 
1272         for (i = 0; /* void */; i++) {
1273 
1274             if (i >= part->nelts) {
1275                 if (part->next == NULL) {
1276                     break;
1277                 }
1278 
1279                 part = part->next;
1280                 header = part->elts;
1281                 i = 0;
1282             }
1283 
1284             if (ngx_hash_find(&headers->hash, header[i].hash,
1285                               header[i].lowcase_key, header[i].key.len))
1286             {
1287                 continue;
1288             }
1289 
1290             len += header[i].key.len + sizeof(": ") - 1
1291                 + header[i].value.len + sizeof(CRLF) - 1;
1292         }
1293     }
1294 
1295 
1296     b = ngx_create_temp_buf(r->pool, len);
1297     if (b == NULL) {
1298         return NGX_ERROR;
1299     }
1300 
1301     cl = ngx_alloc_chain_link(r->pool);
1302     if (cl == NULL) {
1303         return NGX_ERROR;
1304     }
1305 
1306     cl->buf = b;
1307 
1308 
1309     /* the request line */
1310 
1311     b->last = ngx_copy(b->last, method.data, method.len);
1312     *b->last++ = ' ';
1313 
1314     u->uri.data = b->last;
1315 
1316     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1317         b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1318 
1319     } else if (unparsed_uri) {
1320         b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1321 
1322     } else {
1323         if (r->valid_location) {
1324             b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1325         }
1326 
1327         if (escape) {
1328             ngx_escape_uri(b->last, r->uri.data + loc_len,
1329                            r->uri.len - loc_len, NGX_ESCAPE_URI);
1330             b->last += r->uri.len - loc_len + escape;
1331 
1332         } else {
1333             b->last = ngx_copy(b->last, r->uri.data + loc_len,
1334                                r->uri.len - loc_len);
1335         }
1336 
1337         if (r->args.len > 0) {
1338             *b->last++ = '?';
1339             b->last = ngx_copy(b->last, r->args.data, r->args.len);
1340         }
1341     }
1342 
1343     u->uri.len = b->last - u->uri.data;
1344 
1345     if (plcf->http_version == NGX_HTTP_VERSION_11) {
1346         b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1347                              sizeof(ngx_http_proxy_version_11) - 1);
1348 
1349     } else {
1350         b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1351                              sizeof(ngx_http_proxy_version) - 1);
1352     }
1353 
1354     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1355 
1356     e.ip = headers->values->elts;
1357     e.pos = b->last;
1358     e.request = r;
1359     e.flushed = 1;
1360 
1361     le.ip = headers->lengths->elts;
1362 
1363     while (*(uintptr_t *) le.ip) {
1364         lcode = *(ngx_http_script_len_code_pt *) le.ip;
1365 
1366         /* skip the header line name length */
1367         (void) lcode(&le);
1368 
1369         if (*(ngx_http_script_len_code_pt *) le.ip) {
1370 
1371             for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1372                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1373             }
1374 
1375             e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1376 
1377         } else {
1378             e.skip = 0;
1379         }
1380 
1381         le.ip += sizeof(uintptr_t);
1382 
1383         while (*(uintptr_t *) e.ip) {
1384             code = *(ngx_http_script_code_pt *) e.ip;
1385             code((ngx_http_script_engine_t *) &e);
1386         }
1387         e.ip += sizeof(uintptr_t);
1388     }
1389 
1390     b->last = e.pos;
1391 
1392 
1393     if (plcf->upstream.pass_request_headers) {
1394         part = &r->headers_in.headers.part;
1395         header = part->elts;
1396 
1397         for (i = 0; /* void */; i++) {
1398 
1399             if (i >= part->nelts) {
1400                 if (part->next == NULL) {
1401                     break;
1402                 }
1403 
1404                 part = part->next;
1405                 header = part->elts;
1406                 i = 0;
1407             }
1408 
1409             if (ngx_hash_find(&headers->hash, header[i].hash,
1410                               header[i].lowcase_key, header[i].key.len))
1411             {
1412                 continue;
1413             }
1414 
1415             b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1416 
1417             *b->last++ = ':'; *b->last++ = ' ';
1418 
1419             b->last = ngx_copy(b->last, header[i].value.data,
1420                                header[i].value.len);
1421 
1422             *b->last++ = CR; *b->last++ = LF;
1423 
1424             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1425                            "http proxy header: \"%V: %V\"",
1426                            &header[i].key, &header[i].value);
1427         }
1428     }
1429 
1430 
1431     /* add "\r\n" at the header end */
1432     *b->last++ = CR; *b->last++ = LF;
1433 
1434     if (plcf->body_values) {
1435         e.ip = plcf->body_values->elts;
1436         e.pos = b->last;
1437         e.skip = 0;
1438 
1439         while (*(uintptr_t *) e.ip) {
1440             code = *(ngx_http_script_code_pt *) e.ip;
1441             code((ngx_http_script_engine_t *) &e);
1442         }
1443 
1444         b->last = e.pos;
1445     }
1446 
1447     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1448                    "http proxy header:%N\"%*s\"",
1449                    (size_t) (b->last - b->pos), b->pos);
1450 
1451     if (r->request_body_no_buffering) {
1452 
1453         u->request_bufs = cl;
1454 
1455         if (ctx->internal_chunked) {
1456             u->output.output_filter = ngx_http_proxy_body_output_filter;
1457             u->output.filter_ctx = r;
1458         }
1459 
1460     } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
1461 
1462         body = u->request_bufs;
1463         u->request_bufs = cl;
1464 
1465         while (body) {
1466             b = ngx_alloc_buf(r->pool);
1467             if (b == NULL) {
1468                 return NGX_ERROR;
1469             }
1470 
1471             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1472 
1473             cl->next = ngx_alloc_chain_link(r->pool);
1474             if (cl->next == NULL) {
1475                 return NGX_ERROR;
1476             }
1477 
1478             cl = cl->next;
1479             cl->buf = b;
1480 
1481             body = body->next;
1482         }
1483 
1484     } else {
1485         u->request_bufs = cl;
1486     }
1487 
1488     b->flush = 1;
1489     cl->next = NULL;
1490 
1491     return NGX_OK;
1492 }
1493 
1494 
1495 static ngx_int_t
1496 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1497 {
1498     ngx_http_proxy_ctx_t  *ctx;
1499 
1500     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1501 
1502     if (ctx == NULL) {
1503         return NGX_OK;
1504     }
1505 
1506     ctx->status.code = 0;
1507     ctx->status.count = 0;
1508     ctx->status.start = NULL;
1509     ctx->status.end = NULL;
1510     ctx->chunked.state = 0;
1511 
1512     r->upstream->process_header = ngx_http_proxy_process_status_line;
1513     r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1514     r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1515     r->state = 0;
1516 
1517     return NGX_OK;
1518 }
1519 
1520 
1521 static ngx_int_t
1522 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
1523 {
1524     ngx_http_request_t  *r = data;
1525 
1526     off_t                  size;
1527     u_char                *chunk;
1528     ngx_int_t              rc;
1529     ngx_buf_t             *b;
1530     ngx_chain_t           *out, *cl, *tl, **ll, **fl;
1531     ngx_http_proxy_ctx_t  *ctx;
1532 
1533     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1534                    "proxy output filter");
1535 
1536     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1537 
1538     if (in == NULL) {
1539         out = in;
1540         goto out;
1541     }
1542 
1543     out = NULL;
1544     ll = &out;
1545 
1546     if (!ctx->header_sent) {
1547         /* first buffer contains headers, pass it unmodified */
1548 
1549         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1550                        "proxy output header");
1551 
1552         ctx->header_sent = 1;
1553 
1554         tl = ngx_alloc_chain_link(r->pool);
1555         if (tl == NULL) {
1556             return NGX_ERROR;
1557         }
1558 
1559         tl->buf = in->buf;
1560         *ll = tl;
1561         ll = &tl->next;
1562 
1563         in = in->next;
1564 
1565         if (in == NULL) {
1566             tl->next = NULL;
1567             goto out;
1568         }
1569     }
1570 
1571     size = 0;
1572     cl = in;
1573     fl = ll;
1574 
1575     for ( ;; ) {
1576         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1577                        "proxy output chunk: %O", ngx_buf_size(cl->buf));
1578 
1579         size += ngx_buf_size(cl->buf);
1580 
1581         if (cl->buf->flush
1582             || cl->buf->sync
1583             || ngx_buf_in_memory(cl->buf)
1584             || cl->buf->in_file)
1585         {
1586             tl = ngx_alloc_chain_link(r->pool);
1587             if (tl == NULL) {
1588                 return NGX_ERROR;
1589             }
1590 
1591             tl->buf = cl->buf;
1592             *ll = tl;
1593             ll = &tl->next;
1594         }
1595 
1596         if (cl->next == NULL) {
1597             break;
1598         }
1599 
1600         cl = cl->next;
1601     }
1602 
1603     if (size) {
1604         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1605         if (tl == NULL) {
1606             return NGX_ERROR;
1607         }
1608 
1609         b = tl->buf;
1610         chunk = b->start;
1611 
1612         if (chunk == NULL) {
1613             /* the "0000000000000000" is 64-bit hexadecimal string */
1614 
1615             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
1616             if (chunk == NULL) {
1617                 return NGX_ERROR;
1618             }
1619 
1620             b->start = chunk;
1621             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
1622         }
1623 
1624         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1625         b->memory = 0;
1626         b->temporary = 1;
1627         b->pos = chunk;
1628         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
1629 
1630         tl->next = *fl;
1631         *fl = tl;
1632     }
1633 
1634     if (cl->buf->last_buf) {
1635         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1636         if (tl == NULL) {
1637             return NGX_ERROR;
1638         }
1639 
1640         b = tl->buf;
1641 
1642         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1643         b->temporary = 0;
1644         b->memory = 1;
1645         b->last_buf = 1;
1646         b->pos = (u_char *) CRLF "0" CRLF CRLF;
1647         b->last = b->pos + 7;
1648 
1649         cl->buf->last_buf = 0;
1650 
1651         *ll = tl;
1652 
1653         if (size == 0) {
1654             b->pos += 2;
1655         }
1656 
1657     } else if (size > 0) {
1658         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1659         if (tl == NULL) {
1660             return NGX_ERROR;
1661         }
1662 
1663         b = tl->buf;
1664 
1665         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1666         b->temporary = 0;
1667         b->memory = 1;
1668         b->pos = (u_char *) CRLF;
1669         b->last = b->pos + 2;
1670 
1671         *ll = tl;
1672 
1673     } else {
1674         *ll = NULL;
1675     }
1676 
1677 out:
1678 
1679     rc = ngx_chain_writer(&r->upstream->writer, out);
1680 
1681     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1682                             (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
1683 
1684     return rc;
1685 }
1686 
1687 
1688 static ngx_int_t
1689 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1690 {
1691     size_t                 len;
1692     ngx_int_t              rc;
1693     ngx_http_upstream_t   *u;
1694     ngx_http_proxy_ctx_t  *ctx;
1695 
1696     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1697 
1698     if (ctx == NULL) {
1699         return NGX_ERROR;
1700     }
1701 
1702     u = r->upstream;
1703 
1704     rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1705 
1706     if (rc == NGX_AGAIN) {
1707         return rc;
1708     }
1709 
1710     if (rc == NGX_ERROR) {
1711 
1712 #if (NGX_HTTP_CACHE)
1713 
1714         if (r->cache) {
1715             r->http_version = NGX_HTTP_VERSION_9;
1716             return NGX_OK;
1717         }
1718 
1719 #endif
1720 
1721         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1722                       "upstream sent no valid HTTP/1.0 header");
1723 
1724 #if 0
1725         if (u->accel) {
1726             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1727         }
1728 #endif
1729 
1730         r->http_version = NGX_HTTP_VERSION_9;
1731         u->state->status = NGX_HTTP_OK;
1732         u->headers_in.connection_close = 1;
1733 
1734         return NGX_OK;
1735     }
1736 
1737     if (u->state && u->state->status == 0) {
1738         u->state->status = ctx->status.code;
1739     }
1740 
1741     u->headers_in.status_n = ctx->status.code;
1742 
1743     len = ctx->status.end - ctx->status.start;
1744     u->headers_in.status_line.len = len;
1745 
1746     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1747     if (u->headers_in.status_line.data == NULL) {
1748         return NGX_ERROR;
1749     }
1750 
1751     ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1752 
1753     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1754                    "http proxy status %ui \"%V\"",
1755                    u->headers_in.status_n, &u->headers_in.status_line);
1756 
1757     if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1758         u->headers_in.connection_close = 1;
1759     }
1760 
1761     u->process_header = ngx_http_proxy_process_header;
1762 
1763     return ngx_http_proxy_process_header(r);
1764 }
1765 
1766 
1767 static ngx_int_t
1768 ngx_http_proxy_process_header(ngx_http_request_t *r)
1769 {
1770     ngx_int_t                       rc;
1771     ngx_table_elt_t                *h;
1772     ngx_http_upstream_t            *u;
1773     ngx_http_proxy_ctx_t           *ctx;
1774     ngx_http_upstream_header_t     *hh;
1775     ngx_http_upstream_main_conf_t  *umcf;
1776 
1777     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1778 
1779     for ( ;; ) {
1780 
1781         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1782 
1783         if (rc == NGX_OK) {
1784 
1785             /* a header line has been parsed successfully */
1786 
1787             h = ngx_list_push(&r->upstream->headers_in.headers);
1788             if (h == NULL) {
1789                 return NGX_ERROR;
1790             }
1791 
1792             h->hash = r->header_hash;
1793 
1794             h->key.len = r->header_name_end - r->header_name_start;
1795             h->value.len = r->header_end - r->header_start;
1796 
1797             h->key.data = ngx_pnalloc(r->pool,
1798                                h->key.len + 1 + h->value.len + 1 + h->key.len);
1799             if (h->key.data == NULL) {
1800                 return NGX_ERROR;
1801             }
1802 
1803             h->value.data = h->key.data + h->key.len + 1;
1804             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1805 
1806             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1807             h->key.data[h->key.len] = '\0';
1808             ngx_memcpy(h->value.data, r->header_start, h->value.len);
1809             h->value.data[h->value.len] = '\0';
1810 
1811             if (h->key.len == r->lowcase_index) {
1812                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1813 
1814             } else {
1815                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1816             }
1817 
1818             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1819                                h->lowcase_key, h->key.len);
1820 
1821             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1822                 return NGX_ERROR;
1823             }
1824 
1825             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1826                            "http proxy header: \"%V: %V\"",
1827                            &h->key, &h->value);
1828 
1829             continue;
1830         }
1831 
1832         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1833 
1834             /* a whole header has been parsed successfully */
1835 
1836             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1837                            "http proxy header done");
1838 
1839             /*
1840              * if no "Server" and "Date" in header line,
1841              * then add the special empty headers
1842              */
1843 
1844             if (r->upstream->headers_in.server == NULL) {
1845                 h = ngx_list_push(&r->upstream->headers_in.headers);
1846                 if (h == NULL) {
1847                     return NGX_ERROR;
1848                 }
1849 
1850                 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1851                                     ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1852 
1853                 ngx_str_set(&h->key, "Server");
1854                 ngx_str_null(&h->value);
1855                 h->lowcase_key = (u_char *) "server";
1856             }
1857 
1858             if (r->upstream->headers_in.date == NULL) {
1859                 h = ngx_list_push(&r->upstream->headers_in.headers);
1860                 if (h == NULL) {
1861                     return NGX_ERROR;
1862                 }
1863 
1864                 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1865 
1866                 ngx_str_set(&h->key, "Date");
1867                 ngx_str_null(&h->value);
1868                 h->lowcase_key = (u_char *) "date";
1869             }
1870 
1871             /* clear content length if response is chunked */
1872 
1873             u = r->upstream;
1874 
1875             if (u->headers_in.chunked) {
1876                 u->headers_in.content_length_n = -1;
1877             }
1878 
1879             /*
1880              * set u->keepalive if response has no body; this allows to keep
1881              * connections alive in case of r->header_only or X-Accel-Redirect
1882              */
1883 
1884             ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1885 
1886             if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1887                 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1888                 || ctx->head
1889                 || (!u->headers_in.chunked
1890                     && u->headers_in.content_length_n == 0))
1891             {
1892                 u->keepalive = !u->headers_in.connection_close;
1893             }
1894 
1895             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1896                 u->keepalive = 0;
1897 
1898                 if (r->headers_in.upgrade) {
1899                     u->upgrade = 1;
1900                 }
1901             }
1902 
1903             return NGX_OK;
1904         }
1905 
1906         if (rc == NGX_AGAIN) {
1907             return NGX_AGAIN;
1908         }
1909 
1910         /* there was error while a header line parsing */
1911 
1912         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1913                       "upstream sent invalid header");
1914 
1915         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1916     }
1917 }
1918 
1919 
1920 static ngx_int_t
1921 ngx_http_proxy_input_filter_init(void *data)
1922 {
1923     ngx_http_request_t    *r = data;
1924     ngx_http_upstream_t   *u;
1925     ngx_http_proxy_ctx_t  *ctx;
1926 
1927     u = r->upstream;
1928     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1929 
1930     if (ctx == NULL) {
1931         return NGX_ERROR;
1932     }
1933 
1934     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1935                    "http proxy filter init s:%ui h:%d c:%d l:%O",
1936                    u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1937                    u->headers_in.content_length_n);
1938 
1939     /* as per RFC2616, 4.4 Message Length */
1940 
1941     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1942         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1943         || ctx->head)
1944     {
1945         /* 1xx, 204, and 304 and replies to HEAD requests */
1946         /* no 1xx since we don't send Expect and Upgrade */
1947 
1948         u->pipe->length = 0;
1949         u->length = 0;
1950         u->keepalive = !u->headers_in.connection_close;
1951 
1952     } else if (u->headers_in.chunked) {
1953         /* chunked */
1954 
1955         u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1956         u->pipe->length = 3; /* "0" LF LF */
1957 
1958         u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1959         u->length = 1;
1960 
1961     } else if (u->headers_in.content_length_n == 0) {
1962         /* empty body: special case as filter won't be called */
1963 
1964         u->pipe->length = 0;
1965         u->length = 0;
1966         u->keepalive = !u->headers_in.connection_close;
1967 
1968     } else {
1969         /* content length or connection close */
1970 
1971         u->pipe->length = u->headers_in.content_length_n;
1972         u->length = u->headers_in.content_length_n;
1973     }
1974 
1975     return NGX_OK;
1976 }
1977 
1978 
1979 static ngx_int_t
1980 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1981 {
1982     ngx_buf_t           *b;
1983     ngx_chain_t         *cl;
1984     ngx_http_request_t  *r;
1985 
1986     if (buf->pos == buf->last) {
1987         return NGX_OK;
1988     }
1989 
1990     cl = ngx_chain_get_free_buf(p->pool, &p->free);
1991     if (cl == NULL) {
1992         return NGX_ERROR;
1993     }
1994 
1995     b = cl->buf;
1996 
1997     ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1998     b->shadow = buf;
1999     b->tag = p->tag;
2000     b->last_shadow = 1;
2001     b->recycled = 1;
2002     buf->shadow = b;
2003 
2004     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
2005 
2006     if (p->in) {
2007         *p->last_in = cl;
2008     } else {
2009         p->in = cl;
2010     }
2011     p->last_in = &cl->next;
2012 
2013     if (p->length == -1) {
2014         return NGX_OK;
2015     }
2016 
2017     p->length -= b->last - b->pos;
2018 
2019     if (p->length == 0) {
2020         r = p->input_ctx;
2021         p->upstream_done = 1;
2022         r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2023 
2024     } else if (p->length < 0) {
2025         r = p->input_ctx;
2026         p->upstream_done = 1;
2027 
2028         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
2029                       "upstream sent more data than specified in "
2030                       "\"Content-Length\" header");
2031     }
2032 
2033     return NGX_OK;
2034 }
2035 
2036 
2037 static ngx_int_t
2038 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2039 {
2040     ngx_int_t              rc;
2041     ngx_buf_t             *b, **prev;
2042     ngx_chain_t           *cl;
2043     ngx_http_request_t    *r;
2044     ngx_http_proxy_ctx_t  *ctx;
2045 
2046     if (buf->pos == buf->last) {
2047         return NGX_OK;
2048     }
2049 
2050     r = p->input_ctx;
2051     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2052 
2053     if (ctx == NULL) {
2054         return NGX_ERROR;
2055     }
2056 
2057     b = NULL;
2058     prev = &buf->shadow;
2059 
2060     for ( ;; ) {
2061 
2062         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2063 
2064         if (rc == NGX_OK) {
2065 
2066             /* a chunk has been parsed successfully */
2067 
2068             cl = ngx_chain_get_free_buf(p->pool, &p->free);
2069             if (cl == NULL) {
2070                 return NGX_ERROR;
2071             }
2072 
2073             b = cl->buf;
2074 
2075             ngx_memzero(b, sizeof(ngx_buf_t));
2076 
2077             b->pos = buf->pos;
2078             b->start = buf->start;
2079             b->end = buf->end;
2080             b->tag = p->tag;
2081             b->temporary = 1;
2082             b->recycled = 1;
2083 
2084             *prev = b;
2085             prev = &b->shadow;
2086 
2087             if (p->in) {
2088                 *p->last_in = cl;
2089             } else {
2090                 p->in = cl;
2091             }
2092             p->last_in = &cl->next;
2093 
2094             /* STUB */ b->num = buf->num;
2095 
2096             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2097                            "input buf #%d %p", b->num, b->pos);
2098 
2099             if (buf->last - buf->pos >= ctx->chunked.size) {
2100 
2101                 buf->pos += (size_t) ctx->chunked.size;
2102                 b->last = buf->pos;
2103                 ctx->chunked.size = 0;
2104 
2105                 continue;
2106             }
2107 
2108             ctx->chunked.size -= buf->last - buf->pos;
2109             buf->pos = buf->last;
2110             b->last = buf->last;
2111 
2112             continue;
2113         }
2114 
2115         if (rc == NGX_DONE) {
2116 
2117             /* a whole response has been parsed successfully */
2118 
2119             p->upstream_done = 1;
2120             r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2121 
2122             break;
2123         }
2124 
2125         if (rc == NGX_AGAIN) {
2126 
2127             /* set p->length, minimal amount of data we want to see */
2128 
2129             p->length = ctx->chunked.length;
2130 
2131             break;
2132         }
2133 
2134         /* invalid response */
2135 
2136         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2137                       "upstream sent invalid chunked response");
2138 
2139         return NGX_ERROR;
2140     }
2141 
2142     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2143                    "http proxy chunked state %ui, length %O",
2144                    ctx->chunked.state, p->length);
2145 
2146     if (b) {
2147         b->shadow = buf;
2148         b->last_shadow = 1;
2149 
2150         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2151                        "input buf %p %z", b->pos, b->last - b->pos);
2152 
2153         return NGX_OK;
2154     }
2155 
2156     /* there is no data record in the buf, add it to free chain */
2157 
2158     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2159         return NGX_ERROR;
2160     }
2161 
2162     return NGX_OK;
2163 }
2164 
2165 
2166 static ngx_int_t
2167 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
2168 {
2169     ngx_http_request_t   *r = data;
2170 
2171     ngx_buf_t            *b;
2172     ngx_chain_t          *cl, **ll;
2173     ngx_http_upstream_t  *u;
2174 
2175     u = r->upstream;
2176 
2177     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2178         ll = &cl->next;
2179     }
2180 
2181     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2182     if (cl == NULL) {
2183         return NGX_ERROR;
2184     }
2185 
2186     *ll = cl;
2187 
2188     cl->buf->flush = 1;
2189     cl->buf->memory = 1;
2190 
2191     b = &u->buffer;
2192 
2193     cl->buf->pos = b->last;
2194     b->last += bytes;
2195     cl->buf->last = b->last;
2196     cl->buf->tag = u->output.tag;
2197 
2198     if (u->length == -1) {
2199         return NGX_OK;
2200     }
2201 
2202     u->length -= bytes;
2203 
2204     if (u->length == 0) {
2205         u->keepalive = !u->headers_in.connection_close;
2206     }
2207 
2208     return NGX_OK;
2209 }
2210 
2211 
2212 static ngx_int_t
2213 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
2214 {
2215     ngx_http_request_t   *r = data;
2216 
2217     ngx_int_t              rc;
2218     ngx_buf_t             *b, *buf;
2219     ngx_chain_t           *cl, **ll;
2220     ngx_http_upstream_t   *u;
2221     ngx_http_proxy_ctx_t  *ctx;
2222 
2223     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2224 
2225     if (ctx == NULL) {
2226         return NGX_ERROR;
2227     }
2228 
2229     u = r->upstream;
2230     buf = &u->buffer;
2231 
2232     buf->pos = buf->last;
2233     buf->last += bytes;
2234 
2235     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2236         ll = &cl->next;
2237     }
2238 
2239     for ( ;; ) {
2240 
2241         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2242 
2243         if (rc == NGX_OK) {
2244 
2245             /* a chunk has been parsed successfully */
2246 
2247             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2248             if (cl == NULL) {
2249                 return NGX_ERROR;
2250             }
2251 
2252             *ll = cl;
2253             ll = &cl->next;
2254 
2255             b = cl->buf;
2256 
2257             b->flush = 1;
2258             b->memory = 1;
2259 
2260             b->pos = buf->pos;
2261             b->tag = u->output.tag;
2262 
2263             if (buf->last - buf->pos >= ctx->chunked.size) {
2264                 buf->pos += (size_t) ctx->chunked.size;
2265                 b->last = buf->pos;
2266                 ctx->chunked.size = 0;
2267 
2268             } else {
2269                 ctx->chunked.size -= buf->last - buf->pos;
2270                 buf->pos = buf->last;
2271                 b->last = buf->last;
2272             }
2273 
2274             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2275                            "http proxy out buf %p %z",
2276                            b->pos, b->last - b->pos);
2277 
2278             continue;
2279         }
2280 
2281         if (rc == NGX_DONE) {
2282 
2283             /* a whole response has been parsed successfully */
2284 
2285             u->keepalive = !u->headers_in.connection_close;
2286             u->length = 0;
2287 
2288             break;
2289         }
2290 
2291         if (rc == NGX_AGAIN) {
2292             break;
2293         }
2294 
2295         /* invalid response */
2296 
2297         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2298                       "upstream sent invalid chunked response");
2299 
2300         return NGX_ERROR;
2301     }
2302 
2303     /* provide continuous buffer for subrequests in memory */
2304 
2305     if (r->subrequest_in_memory) {
2306 
2307         cl = u->out_bufs;
2308 
2309         if (cl) {
2310             buf->pos = cl->buf->pos;
2311         }
2312 
2313         buf->last = buf->pos;
2314 
2315         for (cl = u->out_bufs; cl; cl = cl->next) {
2316             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2317                            "http proxy in memory %p-%p %O",
2318                            cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2319 
2320             if (buf->last == cl->buf->pos) {
2321                 buf->last = cl->buf->last;
2322                 continue;
2323             }
2324 
2325             buf->last = ngx_movemem(buf->last, cl->buf->pos,
2326                                     cl->buf->last - cl->buf->pos);
2327 
2328             cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2329             cl->buf->last = buf->last;
2330         }
2331     }
2332 
2333     return NGX_OK;
2334 }
2335 
2336 
2337 static void
2338 ngx_http_proxy_abort_request(ngx_http_request_t *r)
2339 {
2340     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2341                    "abort http proxy request");
2342 
2343     return;
2344 }
2345 
2346 
2347 static void
2348 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2349 {
2350     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2351                    "finalize http proxy request");
2352 
2353     return;
2354 }
2355 
2356 
2357 static ngx_int_t
2358 ngx_http_proxy_host_variable(ngx_http_request_t *r,
2359     ngx_http_variable_value_t *v, uintptr_t data)
2360 {
2361     ngx_http_proxy_ctx_t  *ctx;
2362 
2363     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2364 
2365     if (ctx == NULL) {
2366         v->not_found = 1;
2367         return NGX_OK;
2368     }
2369 
2370     v->len = ctx->vars.host_header.len;
2371     v->valid = 1;
2372     v->no_cacheable = 0;
2373     v->not_found = 0;
2374     v->data = ctx->vars.host_header.data;
2375 
2376     return NGX_OK;
2377 }
2378 
2379 
2380 static ngx_int_t
2381 ngx_http_proxy_port_variable(ngx_http_request_t *r,
2382     ngx_http_variable_value_t *v, uintptr_t data)
2383 {
2384     ngx_http_proxy_ctx_t  *ctx;
2385 
2386     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2387 
2388     if (ctx == NULL) {
2389         v->not_found = 1;
2390         return NGX_OK;
2391     }
2392 
2393     v->len = ctx->vars.port.len;
2394     v->valid = 1;
2395     v->no_cacheable = 0;
2396     v->not_found = 0;
2397     v->data = ctx->vars.port.data;
2398 
2399     return NGX_OK;
2400 }
2401 
2402 
2403 static ngx_int_t
2404 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2405     ngx_http_variable_value_t *v, uintptr_t data)
2406 {
2407     size_t             len;
2408     u_char            *p;
2409     ngx_uint_t         i, n;
2410     ngx_table_elt_t  **h;
2411 
2412     v->valid = 1;
2413     v->no_cacheable = 0;
2414     v->not_found = 0;
2415 
2416     n = r->headers_in.x_forwarded_for.nelts;
2417     h = r->headers_in.x_forwarded_for.elts;
2418 
2419     len = 0;
2420 
2421     for (i = 0; i < n; i++) {
2422         len += h[i]->value.len + sizeof(", ") - 1;
2423     }
2424 
2425     if (len == 0) {
2426         v->len = r->connection->addr_text.len;
2427         v->data = r->connection->addr_text.data;
2428         return NGX_OK;
2429     }
2430 
2431     len += r->connection->addr_text.len;
2432 
2433     p = ngx_pnalloc(r->pool, len);
2434     if (p == NULL) {
2435         return NGX_ERROR;
2436     }
2437 
2438     v->len = len;
2439     v->data = p;
2440 
2441     for (i = 0; i < n; i++) {
2442         p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2443         *p++ = ','; *p++ = ' ';
2444     }
2445 
2446     ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2447 
2448     return NGX_OK;
2449 }
2450 
2451 
2452 static ngx_int_t
2453 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2454     ngx_http_variable_value_t *v, uintptr_t data)
2455 {
2456     ngx_http_proxy_ctx_t  *ctx;
2457 
2458     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2459 
2460     if (ctx == NULL || ctx->internal_body_length < 0) {
2461         v->not_found = 1;
2462         return NGX_OK;
2463     }
2464 
2465     v->valid = 1;
2466     v->no_cacheable = 0;
2467     v->not_found = 0;
2468 
2469     v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
2470 
2471     if (v->data == NULL) {
2472         return NGX_ERROR;
2473     }
2474 
2475     v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2476 
2477     return NGX_OK;
2478 }
2479 
2480 
2481 static ngx_int_t
2482 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
2483     ngx_http_variable_value_t *v, uintptr_t data)
2484 {
2485     ngx_http_proxy_ctx_t  *ctx;
2486 
2487     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2488 
2489     if (ctx == NULL || !ctx->internal_chunked) {
2490         v->not_found = 1;
2491         return NGX_OK;
2492     }
2493 
2494     v->valid = 1;
2495     v->no_cacheable = 0;
2496     v->not_found = 0;
2497 
2498     v->data = (u_char *) "chunked";
2499     v->len = sizeof("chunked") - 1;
2500 
2501     return NGX_OK;
2502 }
2503 
2504 
2505 static ngx_int_t
2506 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2507     size_t prefix)
2508 {
2509     size_t                      len;
2510     ngx_int_t                   rc;
2511     ngx_uint_t                  i;
2512     ngx_http_proxy_rewrite_t   *pr;
2513     ngx_http_proxy_loc_conf_t  *plcf;
2514 
2515     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2516 
2517     pr = plcf->redirects->elts;
2518 
2519     if (pr == NULL) {
2520         return NGX_DECLINED;
2521     }
2522 
2523     len = h->value.len - prefix;
2524 
2525     for (i = 0; i < plcf->redirects->nelts; i++) {
2526         rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2527 
2528         if (rc != NGX_DECLINED) {
2529             return rc;
2530         }
2531     }
2532 
2533     return NGX_DECLINED;
2534 }
2535 
2536 
2537 static ngx_int_t
2538 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2539 {
2540     size_t                      prefix;
2541     u_char                     *p;
2542     ngx_int_t                   rc, rv;
2543     ngx_http_proxy_loc_conf_t  *plcf;
2544 
2545     p = (u_char *) ngx_strchr(h->value.data, ';');
2546     if (p == NULL) {
2547         return NGX_DECLINED;
2548     }
2549 
2550     prefix = p + 1 - h->value.data;
2551 
2552     rv = NGX_DECLINED;
2553 
2554     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2555 
2556     if (plcf->cookie_domains) {
2557         p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2558 
2559         if (p) {
2560             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2561                                                      plcf->cookie_domains);
2562             if (rc == NGX_ERROR) {
2563                 return NGX_ERROR;
2564             }
2565 
2566             if (rc != NGX_DECLINED) {
2567                 rv = rc;
2568             }
2569         }
2570     }
2571 
2572     if (plcf->cookie_paths) {
2573         p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2574 
2575         if (p) {
2576             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2577                                                      plcf->cookie_paths);
2578             if (rc == NGX_ERROR) {
2579                 return NGX_ERROR;
2580             }
2581 
2582             if (rc != NGX_DECLINED) {
2583                 rv = rc;
2584             }
2585         }
2586     }
2587 
2588     return rv;
2589 }
2590 
2591 
2592 static ngx_int_t
2593 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2594     u_char *value, ngx_array_t *rewrites)
2595 {
2596     size_t                     len, prefix;
2597     u_char                    *p;
2598     ngx_int_t                  rc;
2599     ngx_uint_t                 i;
2600     ngx_http_proxy_rewrite_t  *pr;
2601 
2602     prefix = value - h->value.data;
2603 
2604     p = (u_char *) ngx_strchr(value, ';');
2605 
2606     len = p ? (size_t) (p - value) : (h->value.len - prefix);
2607 
2608     pr = rewrites->elts;
2609 
2610     for (i = 0; i < rewrites->nelts; i++) {
2611         rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2612 
2613         if (rc != NGX_DECLINED) {
2614             return rc;
2615         }
2616     }
2617 
2618     return NGX_DECLINED;
2619 }
2620 
2621 
2622 static ngx_int_t
2623 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2624     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2625 {
2626     ngx_str_t  pattern, replacement;
2627 
2628     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2629         return NGX_ERROR;
2630     }
2631 
2632     if (pattern.len > len
2633         || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2634                         pattern.len) != 0)
2635     {
2636         return NGX_DECLINED;
2637     }
2638 
2639     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2640         return NGX_ERROR;
2641     }
2642 
2643     return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2644 }
2645 
2646 
2647 #if (NGX_PCRE)
2648 
2649 static ngx_int_t
2650 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2651     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2652 {
2653     ngx_str_t  pattern, replacement;
2654 
2655     pattern.len = len;
2656     pattern.data = h->value.data + prefix;
2657 
2658     if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2659         return NGX_DECLINED;
2660     }
2661 
2662     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2663         return NGX_ERROR;
2664     }
2665 
2666     if (prefix == 0 && h->value.len == len) {
2667         h->value = replacement;
2668         return NGX_OK;
2669     }
2670 
2671     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2672 }
2673 
2674 #endif
2675 
2676 
2677 static ngx_int_t
2678 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2679     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2680 {
2681     u_char     *p;
2682     ngx_str_t   pattern, replacement;
2683 
2684     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2685         return NGX_ERROR;
2686     }
2687 
2688     p = h->value.data + prefix;
2689 
2690     if (p[0] == '.') {
2691         p++;
2692         prefix++;
2693         len--;
2694     }
2695 
2696     if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2697         return NGX_DECLINED;
2698     }
2699 
2700     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2701         return NGX_ERROR;
2702     }
2703 
2704     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2705 }
2706 
2707 
2708 static ngx_int_t
2709 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2710     size_t len, ngx_str_t *replacement)
2711 {
2712     u_char  *p, *data;
2713     size_t   new_len;
2714 
2715     new_len = replacement->len + h->value.len - len;
2716 
2717     if (replacement->len > len) {
2718 
2719         data = ngx_pnalloc(r->pool, new_len + 1);
2720         if (data == NULL) {
2721             return NGX_ERROR;
2722         }
2723 
2724         p = ngx_copy(data, h->value.data, prefix);
2725         p = ngx_copy(p, replacement->data, replacement->len);
2726 
2727         ngx_memcpy(p, h->value.data + prefix + len,
2728                    h->value.len - len - prefix + 1);
2729 
2730         h->value.data = data;
2731 
2732     } else {
2733         p = ngx_copy(h->value.data + prefix, replacement->data,
2734                      replacement->len);
2735 
2736         ngx_memmove(p, h->value.data + prefix + len,
2737                     h->value.len - len - prefix + 1);
2738     }
2739 
2740     h->value.len = new_len;
2741 
2742     return NGX_OK;
2743 }
2744 
2745 
2746 static ngx_int_t
2747 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2748 {
2749     ngx_http_variable_t  *var, *v;
2750 
2751     for (v = ngx_http_proxy_vars; v->name.len; v++) {
2752         var = ngx_http_add_variable(cf, &v->name, v->flags);
2753         if (var == NULL) {
2754             return NGX_ERROR;
2755         }
2756 
2757         var->get_handler = v->get_handler;
2758         var->data = v->data;
2759     }
2760 
2761     return NGX_OK;
2762 }
2763 
2764 
2765 static void *
2766 ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
2767 {
2768     ngx_http_proxy_main_conf_t  *conf;
2769 
2770     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
2771     if (conf == NULL) {
2772         return NULL;
2773     }
2774 
2775 #if (NGX_HTTP_CACHE)
2776     if (ngx_array_init(&conf->caches, cf->pool, 4,
2777                        sizeof(ngx_http_file_cache_t *))
2778         != NGX_OK)
2779     {
2780         return NULL;
2781     }
2782 #endif
2783 
2784     return conf;
2785 }
2786 
2787 
2788 static void *
2789 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2790 {
2791     ngx_http_proxy_loc_conf_t  *conf;
2792 
2793     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2794     if (conf == NULL) {
2795         return NULL;
2796     }
2797 
2798     /*
2799      * set by ngx_pcalloc():
2800      *
2801      *     conf->upstream.bufs.num = 0;
2802      *     conf->upstream.ignore_headers = 0;
2803      *     conf->upstream.next_upstream = 0;
2804      *     conf->upstream.cache_zone = NULL;
2805      *     conf->upstream.cache_use_stale = 0;
2806      *     conf->upstream.cache_methods = 0;
2807      *     conf->upstream.temp_path = NULL;
2808      *     conf->upstream.hide_headers_hash = { NULL, 0 };
2809      *     conf->upstream.uri = { 0, NULL };
2810      *     conf->upstream.location = NULL;
2811      *     conf->upstream.store_lengths = NULL;
2812      *     conf->upstream.store_values = NULL;
2813      *     conf->upstream.ssl_name = NULL;
2814      *
2815      *     conf->method = NULL;
2816      *     conf->headers_source = NULL;
2817      *     conf->headers.lengths = NULL;
2818      *     conf->headers.values = NULL;
2819      *     conf->headers.hash = { NULL, 0 };
2820      *     conf->headers_cache.lengths = NULL;
2821      *     conf->headers_cache.values = NULL;
2822      *     conf->headers_cache.hash = { NULL, 0 };
2823      *     conf->body_lengths = NULL;
2824      *     conf->body_values = NULL;
2825      *     conf->body_source = { 0, NULL };
2826      *     conf->redirects = NULL;
2827      *     conf->ssl = 0;
2828      *     conf->ssl_protocols = 0;
2829      *     conf->ssl_ciphers = { 0, NULL };
2830      *     conf->ssl_trusted_certificate = { 0, NULL };
2831      *     conf->ssl_crl = { 0, NULL };
2832      *     conf->ssl_certificate = { 0, NULL };
2833      *     conf->ssl_certificate_key = { 0, NULL };
2834      */
2835 
2836     conf->upstream.store = NGX_CONF_UNSET;
2837     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2838     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2839     conf->upstream.buffering = NGX_CONF_UNSET;
2840     conf->upstream.request_buffering = NGX_CONF_UNSET;
2841     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2842     conf->upstream.force_ranges = NGX_CONF_UNSET;
2843 
2844     conf->upstream.local = NGX_CONF_UNSET_PTR;
2845 
2846     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2847     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2848     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2849     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2850 
2851     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2852     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2853     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2854 
2855     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2856     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2857     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2858 
2859     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2860     conf->upstream.pass_request_body = NGX_CONF_UNSET;
2861 
2862 #if (NGX_HTTP_CACHE)
2863     conf->upstream.cache = NGX_CONF_UNSET;
2864     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2865     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2866     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2867     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2868     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2869     conf->upstream.cache_lock = NGX_CONF_UNSET;
2870     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2871     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2872     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2873     conf->upstream.cache_convert_head = NGX_CONF_UNSET;
2874     conf->upstream.cache_background_update = NGX_CONF_UNSET;
2875 #endif
2876 
2877     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2878     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2879 
2880     conf->upstream.intercept_errors = NGX_CONF_UNSET;
2881 
2882 #if (NGX_HTTP_SSL)
2883     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2884     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
2885     conf->upstream.ssl_verify = NGX_CONF_UNSET;
2886     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
2887     conf->ssl_passwords = NGX_CONF_UNSET_PTR;
2888 #endif
2889 
2890     /* "proxy_cyclic_temp_file" is disabled */
2891     conf->upstream.cyclic_temp_file = 0;
2892 
2893     conf->redirect = NGX_CONF_UNSET;
2894     conf->upstream.change_buffering = 1;
2895 
2896     conf->cookie_domains = NGX_CONF_UNSET_PTR;
2897     conf->cookie_paths = NGX_CONF_UNSET_PTR;
2898 
2899     conf->http_version = NGX_CONF_UNSET_UINT;
2900 
2901     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2902     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2903 
2904     ngx_str_set(&conf->upstream.module, "proxy");
2905 
2906     return conf;
2907 }
2908 
2909 
2910 static char *
2911 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2912 {
2913     ngx_http_proxy_loc_conf_t *prev = parent;
2914     ngx_http_proxy_loc_conf_t *conf = child;
2915 
2916     u_char                     *p;
2917     size_t                      size;
2918     ngx_int_t                   rc;
2919     ngx_hash_init_t             hash;
2920     ngx_http_core_loc_conf_t   *clcf;
2921     ngx_http_proxy_rewrite_t   *pr;
2922     ngx_http_script_compile_t   sc;
2923 
2924 #if (NGX_HTTP_CACHE)
2925 
2926     if (conf->upstream.store > 0) {
2927         conf->upstream.cache = 0;
2928     }
2929 
2930     if (conf->upstream.cache > 0) {
2931         conf->upstream.store = 0;
2932     }
2933 
2934 #endif
2935 
2936     if (conf->upstream.store == NGX_CONF_UNSET) {
2937         ngx_conf_merge_value(conf->upstream.store,
2938                               prev->upstream.store, 0);
2939 
2940         conf->upstream.store_lengths = prev->upstream.store_lengths;
2941         conf->upstream.store_values = prev->upstream.store_values;
2942     }
2943 
2944     ngx_conf_merge_uint_value(conf->upstream.store_access,
2945                               prev->upstream.store_access, 0600);
2946 
2947     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2948                               prev->upstream.next_upstream_tries, 0);
2949 
2950     ngx_conf_merge_value(conf->upstream.buffering,
2951                               prev->upstream.buffering, 1);
2952 
2953     ngx_conf_merge_value(conf->upstream.request_buffering,
2954                               prev->upstream.request_buffering, 1);
2955 
2956     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2957                               prev->upstream.ignore_client_abort, 0);
2958 
2959     ngx_conf_merge_value(conf->upstream.force_ranges,
2960                               prev->upstream.force_ranges, 0);
2961 
2962     ngx_conf_merge_ptr_value(conf->upstream.local,
2963                               prev->upstream.local, NULL);
2964 
2965     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2966                               prev->upstream.connect_timeout, 60000);
2967 
2968     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2969                               prev->upstream.send_timeout, 60000);
2970 
2971     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2972                               prev->upstream.read_timeout, 60000);
2973 
2974     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
2975                               prev->upstream.next_upstream_timeout, 0);
2976 
2977     ngx_conf_merge_size_value(conf->upstream.send_lowat,
2978                               prev->upstream.send_lowat, 0);
2979 
2980     ngx_conf_merge_size_value(conf->upstream.buffer_size,
2981                               prev->upstream.buffer_size,
2982                               (size_t) ngx_pagesize);
2983 
2984     ngx_conf_merge_size_value(conf->upstream.limit_rate,
2985                               prev->upstream.limit_rate, 0);
2986 
2987     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2988                               8, ngx_pagesize);
2989 
2990     if (conf->upstream.bufs.num < 2) {
2991         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2992                            "there must be at least 2 \"proxy_buffers\"");
2993         return NGX_CONF_ERROR;
2994     }
2995 
2996 
2997     size = conf->upstream.buffer_size;
2998     if (size < conf->upstream.bufs.size) {
2999         size = conf->upstream.bufs.size;
3000     }
3001 
3002 
3003     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
3004                               prev->upstream.busy_buffers_size_conf,
3005                               NGX_CONF_UNSET_SIZE);
3006 
3007     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
3008         conf->upstream.busy_buffers_size = 2 * size;
3009     } else {
3010         conf->upstream.busy_buffers_size =
3011                                          conf->upstream.busy_buffers_size_conf;
3012     }
3013 
3014     if (conf->upstream.busy_buffers_size < size) {
3015         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3016              "\"proxy_busy_buffers_size\" must be equal to or greater than "
3017              "the maximum of the value of \"proxy_buffer_size\" and "
3018              "one of the \"proxy_buffers\"");
3019 
3020         return NGX_CONF_ERROR;
3021     }
3022 
3023     if (conf->upstream.busy_buffers_size
3024         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
3025     {
3026         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3027              "\"proxy_busy_buffers_size\" must be less than "
3028              "the size of all \"proxy_buffers\" minus one buffer");
3029 
3030         return NGX_CONF_ERROR;
3031     }
3032 
3033 
3034     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
3035                               prev->upstream.temp_file_write_size_conf,
3036                               NGX_CONF_UNSET_SIZE);
3037 
3038     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
3039         conf->upstream.temp_file_write_size = 2 * size;
3040     } else {
3041         conf->upstream.temp_file_write_size =
3042                                       conf->upstream.temp_file_write_size_conf;
3043     }
3044 
3045     if (conf->upstream.temp_file_write_size < size) {
3046         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3047              "\"proxy_temp_file_write_size\" must be equal to or greater "
3048              "than the maximum of the value of \"proxy_buffer_size\" and "
3049              "one of the \"proxy_buffers\"");
3050 
3051         return NGX_CONF_ERROR;
3052     }
3053 
3054     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
3055                               prev->upstream.max_temp_file_size_conf,
3056                               NGX_CONF_UNSET_SIZE);
3057 
3058     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
3059         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
3060     } else {
3061         conf->upstream.max_temp_file_size =
3062                                         conf->upstream.max_temp_file_size_conf;
3063     }
3064 
3065     if (conf->upstream.max_temp_file_size != 0
3066         && conf->upstream.max_temp_file_size < size)
3067     {
3068         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3069              "\"proxy_max_temp_file_size\" must be equal to zero to disable "
3070              "temporary files usage or must be equal to or greater than "
3071              "the maximum of the value of \"proxy_buffer_size\" and "
3072              "one of the \"proxy_buffers\"");
3073 
3074         return NGX_CONF_ERROR;
3075     }
3076 
3077 
3078     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
3079                               prev->upstream.ignore_headers,
3080                               NGX_CONF_BITMASK_SET);
3081 
3082 
3083     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
3084                               prev->upstream.next_upstream,
3085                               (NGX_CONF_BITMASK_SET
3086                                |NGX_HTTP_UPSTREAM_FT_ERROR
3087                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
3088 
3089     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
3090         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
3091                                        |NGX_HTTP_UPSTREAM_FT_OFF;
3092     }
3093 
3094     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
3095                               prev->upstream.temp_path,
3096                               &ngx_http_proxy_temp_path)
3097         != NGX_OK)
3098     {
3099         return NGX_CONF_ERROR;
3100     }
3101 
3102 
3103 #if (NGX_HTTP_CACHE)
3104 
3105     if (conf->upstream.cache == NGX_CONF_UNSET) {
3106         ngx_conf_merge_value(conf->upstream.cache,
3107                               prev->upstream.cache, 0);
3108 
3109         conf->upstream.cache_zone = prev->upstream.cache_zone;
3110         conf->upstream.cache_value = prev->upstream.cache_value;
3111     }
3112 
3113     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
3114         ngx_shm_zone_t  *shm_zone;
3115 
3116         shm_zone = conf->upstream.cache_zone;
3117 
3118         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3119                            "\"proxy_cache\" zone \"%V\" is unknown",
3120                            &shm_zone->shm.name);
3121 
3122         return NGX_CONF_ERROR;
3123     }
3124 
3125     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
3126                               prev->upstream.cache_min_uses, 1);
3127 
3128     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
3129                               prev->upstream.cache_max_range_offset,
3130                               NGX_MAX_OFF_T_VALUE);
3131 
3132     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
3133                               prev->upstream.cache_use_stale,
3134                               (NGX_CONF_BITMASK_SET
3135                                |NGX_HTTP_UPSTREAM_FT_OFF));
3136 
3137     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3138         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3139                                          |NGX_HTTP_UPSTREAM_FT_OFF;
3140     }
3141 
3142     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3143         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3144     }
3145 
3146     if (conf->upstream.cache_methods == 0) {
3147         conf->upstream.cache_methods = prev->upstream.cache_methods;
3148     }
3149 
3150     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3151 
3152     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3153                              prev->upstream.cache_bypass, NULL);
3154 
3155     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3156                              prev->upstream.no_cache, NULL);
3157 
3158     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3159                              prev->upstream.cache_valid, NULL);
3160 
3161     if (conf->cache_key.value.data == NULL) {
3162         conf->cache_key = prev->cache_key;
3163     }
3164 
3165     ngx_conf_merge_value(conf->upstream.cache_lock,
3166                               prev->upstream.cache_lock, 0);
3167 
3168     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3169                               prev->upstream.cache_lock_timeout, 5000);
3170 
3171     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3172                               prev->upstream.cache_lock_age, 5000);
3173 
3174     ngx_conf_merge_value(conf->upstream.cache_revalidate,
3175                               prev->upstream.cache_revalidate, 0);
3176 
3177     ngx_conf_merge_value(conf->upstream.cache_convert_head,
3178                               prev->upstream.cache_convert_head, 1);
3179 
3180     ngx_conf_merge_value(conf->upstream.cache_background_update,
3181                               prev->upstream.cache_background_update, 0);
3182 
3183 #endif
3184 
3185     if (conf->method == NULL) {
3186         conf->method = prev->method;
3187     }
3188 
3189     ngx_conf_merge_value(conf->upstream.pass_request_headers,
3190                               prev->upstream.pass_request_headers, 1);
3191     ngx_conf_merge_value(conf->upstream.pass_request_body,
3192                               prev->upstream.pass_request_body, 1);
3193 
3194     ngx_conf_merge_value(conf->upstream.intercept_errors,
3195                               prev->upstream.intercept_errors, 0);
3196 
3197 #if (NGX_HTTP_SSL)
3198 
3199     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
3200                               prev->upstream.ssl_session_reuse, 1);
3201 
3202     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
3203                                  (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
3204                                   |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
3205 
3206     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
3207                              "DEFAULT");
3208 
3209     if (conf->upstream.ssl_name == NULL) {
3210         conf->upstream.ssl_name = prev->upstream.ssl_name;
3211     }
3212 
3213     ngx_conf_merge_value(conf->upstream.ssl_server_name,
3214                               prev->upstream.ssl_server_name, 0);
3215     ngx_conf_merge_value(conf->upstream.ssl_verify,
3216                               prev->upstream.ssl_verify, 0);
3217     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
3218                               prev->ssl_verify_depth, 1);
3219     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
3220                               prev->ssl_trusted_certificate, "");
3221     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
3222 
3223     ngx_conf_merge_str_value(conf->ssl_certificate,
3224                               prev->ssl_certificate, "");
3225     ngx_conf_merge_str_value(conf->ssl_certificate_key,
3226                               prev->ssl_certificate_key, "");
3227     ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
3228 
3229     if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
3230         return NGX_CONF_ERROR;
3231     }
3232 
3233 #endif
3234 
3235     ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
3236 
3237     if (conf->redirect) {
3238 
3239         if (conf->redirects == NULL) {
3240             conf->redirects = prev->redirects;
3241         }
3242 
3243         if (conf->redirects == NULL && conf->url.data) {
3244 
3245             conf->redirects = ngx_array_create(cf->pool, 1,
3246                                              sizeof(ngx_http_proxy_rewrite_t));
3247             if (conf->redirects == NULL) {
3248                 return NGX_CONF_ERROR;
3249             }
3250 
3251             pr = ngx_array_push(conf->redirects);
3252             if (pr == NULL) {
3253                 return NGX_CONF_ERROR;
3254             }
3255 
3256             ngx_memzero(&pr->pattern.complex,
3257                         sizeof(ngx_http_complex_value_t));
3258 
3259             ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3260 
3261             pr->handler = ngx_http_proxy_rewrite_complex_handler;
3262 
3263             if (conf->vars.uri.len) {
3264                 pr->pattern.complex.value = conf->url;
3265                 pr->replacement.value = conf->location;
3266 
3267             } else {
3268                 pr->pattern.complex.value.len = conf->url.len
3269                                                 + sizeof("/") - 1;
3270 
3271                 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3272                 if (p == NULL) {
3273                     return NGX_CONF_ERROR;
3274                 }
3275 
3276                 pr->pattern.complex.value.data = p;
3277 
3278                 p = ngx_cpymem(p, conf->url.data, conf->url.len);
3279                 *p = '/';
3280 
3281                 ngx_str_set(&pr->replacement.value, "/");
3282             }
3283         }
3284     }
3285 
3286     ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
3287 
3288     ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
3289 
3290     ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
3291                               NGX_HTTP_VERSION_10);
3292 
3293     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
3294                               prev->headers_hash_max_size, 512);
3295 
3296     ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
3297                               prev->headers_hash_bucket_size, 64);
3298 
3299     conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
3300                                                ngx_cacheline_size);
3301 
3302     hash.max_size = conf->headers_hash_max_size;
3303     hash.bucket_size = conf->headers_hash_bucket_size;
3304     hash.name = "proxy_headers_hash";
3305 
3306     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3307             &prev->upstream, ngx_http_proxy_hide_headers, &hash)
3308         != NGX_OK)
3309     {
3310         return NGX_CONF_ERROR;
3311     }
3312 
3313     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3314 
3315     if (clcf->noname
3316         && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
3317     {
3318         conf->upstream.upstream = prev->upstream.upstream;
3319         conf->location = prev->location;
3320         conf->vars = prev->vars;
3321 
3322         conf->proxy_lengths = prev->proxy_lengths;
3323         conf->proxy_values = prev->proxy_values;
3324 
3325 #if (NGX_HTTP_SSL)
3326         conf->upstream.ssl = prev->upstream.ssl;
3327 #endif
3328     }
3329 
3330     if (clcf->lmt_excpt && clcf->handler == NULL
3331         && (conf->upstream.upstream || conf->proxy_lengths))
3332     {
3333         clcf->handler = ngx_http_proxy_handler;
3334     }
3335 
3336     if (conf->body_source.data == NULL) {
3337         conf->body_flushes = prev->body_flushes;
3338         conf->body_source = prev->body_source;
3339         conf->body_lengths = prev->body_lengths;
3340         conf->body_values = prev->body_values;
3341     }
3342 
3343     if (conf->body_source.data && conf->body_lengths == NULL) {
3344 
3345         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3346 
3347         sc.cf = cf;
3348         sc.source = &conf->body_source;
3349         sc.flushes = &conf->body_flushes;
3350         sc.lengths = &conf->body_lengths;
3351         sc.values = &conf->body_values;
3352         sc.complete_lengths = 1;
3353         sc.complete_values = 1;
3354 
3355         if (ngx_http_script_compile(&sc) != NGX_OK) {
3356             return NGX_CONF_ERROR;
3357         }
3358     }
3359 
3360     if (conf->headers_source == NULL) {
3361         conf->headers = prev->headers;
3362 #if (NGX_HTTP_CACHE)
3363         conf->headers_cache = prev->headers_cache;
3364 #endif
3365         conf->headers_source = prev->headers_source;
3366     }
3367 
3368     rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
3369                                      ngx_http_proxy_headers);
3370     if (rc != NGX_OK) {
3371         return NGX_CONF_ERROR;
3372     }
3373 
3374 #if (NGX_HTTP_CACHE)
3375 
3376     if (conf->upstream.cache) {
3377         rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
3378                                          ngx_http_proxy_cache_headers);
3379         if (rc != NGX_OK) {
3380             return NGX_CONF_ERROR;
3381         }
3382     }
3383 
3384 #endif
3385 
3386     /*
3387      * special handling to preserve conf->headers in the "http" section
3388      * to inherit it to all servers
3389      */
3390 
3391     if (prev->headers.hash.buckets == NULL
3392         && conf->headers_source == prev->headers_source)
3393     {
3394         prev->headers = conf->headers;
3395 #if (NGX_HTTP_CACHE)
3396         prev->headers_cache = conf->headers_cache;
3397 #endif
3398     }
3399 
3400     return NGX_CONF_OK;
3401 }
3402 
3403 
3404 static ngx_int_t
3405 ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
3406     ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
3407 {
3408     u_char                       *p;
3409     size_t                        size;
3410     uintptr_t                    *code;
3411     ngx_uint_t                    i;
3412     ngx_array_t                   headers_names, headers_merged;
3413     ngx_keyval_t                 *src, *s, *h;
3414     ngx_hash_key_t               *hk;
3415     ngx_hash_init_t               hash;
3416     ngx_http_script_compile_t     sc;
3417     ngx_http_script_copy_code_t  *copy;
3418 
3419     if (headers->hash.buckets) {
3420         return NGX_OK;
3421     }
3422 
3423     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3424         != NGX_OK)
3425     {
3426         return NGX_ERROR;
3427     }
3428 
3429     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
3430         != NGX_OK)
3431     {
3432         return NGX_ERROR;
3433     }
3434 
3435     headers->lengths = ngx_array_create(cf->pool, 64, 1);
3436     if (headers->lengths == NULL) {
3437         return NGX_ERROR;
3438     }
3439 
3440     headers->values = ngx_array_create(cf->pool, 512, 1);
3441     if (headers->values == NULL) {
3442         return NGX_ERROR;
3443     }
3444 
3445     if (conf->headers_source) {
3446 
3447         src = conf->headers_source->elts;
3448         for (i = 0; i < conf->headers_source->nelts; i++) {
3449 
3450             s = ngx_array_push(&headers_merged);
3451             if (s == NULL) {
3452                 return NGX_ERROR;
3453             }
3454 
3455             *s = src[i];
3456         }
3457     }
3458 
3459     h = default_headers;
3460 
3461     while (h->key.len) {
3462 
3463         src = headers_merged.elts;
3464         for (i = 0; i < headers_merged.nelts; i++) {
3465             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3466                 goto next;
3467             }
3468         }
3469 
3470         s = ngx_array_push(&headers_merged);
3471         if (s == NULL) {
3472             return NGX_ERROR;
3473         }
3474 
3475         *s = *h;
3476 
3477     next:
3478 
3479         h++;
3480     }
3481 
3482 
3483     src = headers_merged.elts;
3484     for (i = 0; i < headers_merged.nelts; i++) {
3485 
3486         hk = ngx_array_push(&headers_names);
3487         if (hk == NULL) {
3488             return NGX_ERROR;
3489         }
3490 
3491         hk->key = src[i].key;
3492         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
3493         hk->value = (void *) 1;
3494 
3495         if (src[i].value.len == 0) {
3496             continue;
3497         }
3498 
3499         if (ngx_http_script_variables_count(&src[i].value) == 0) {
3500             copy = ngx_array_push_n(headers->lengths,
3501                                     sizeof(ngx_http_script_copy_code_t));
3502             if (copy == NULL) {
3503                 return NGX_ERROR;
3504             }
3505 
3506             copy->code = (ngx_http_script_code_pt)
3507                                                  ngx_http_script_copy_len_code;
3508             copy->len = src[i].key.len + sizeof(": ") - 1
3509                         + src[i].value.len + sizeof(CRLF) - 1;
3510 
3511 
3512             size = (sizeof(ngx_http_script_copy_code_t)
3513                        + src[i].key.len + sizeof(": ") - 1
3514                        + src[i].value.len + sizeof(CRLF) - 1
3515                        + sizeof(uintptr_t) - 1)
3516                     & ~(sizeof(uintptr_t) - 1);
3517 
3518             copy = ngx_array_push_n(headers->values, size);
3519             if (copy == NULL) {
3520                 return NGX_ERROR;
3521             }
3522 
3523             copy->code = ngx_http_script_copy_code;
3524             copy->len = src[i].key.len + sizeof(": ") - 1
3525                         + src[i].value.len + sizeof(CRLF) - 1;
3526 
3527             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3528 
3529             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3530             *p++ = ':'; *p++ = ' ';
3531             p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
3532             *p++ = CR; *p = LF;
3533 
3534         } else {
3535             copy = ngx_array_push_n(headers->lengths,
3536                                     sizeof(ngx_http_script_copy_code_t));
3537             if (copy == NULL) {
3538                 return NGX_ERROR;
3539             }
3540 
3541             copy->code = (ngx_http_script_code_pt)
3542                                                  ngx_http_script_copy_len_code;
3543             copy->len = src[i].key.len + sizeof(": ") - 1;
3544 
3545 
3546             size = (sizeof(ngx_http_script_copy_code_t)
3547                     + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
3548                     & ~(sizeof(uintptr_t) - 1);
3549 
3550             copy = ngx_array_push_n(headers->values, size);
3551             if (copy == NULL) {
3552                 return NGX_ERROR;
3553             }
3554 
3555             copy->code = ngx_http_script_copy_code;
3556             copy->len = src[i].key.len + sizeof(": ") - 1;
3557 
3558             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3559             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3560             *p++ = ':'; *p = ' ';
3561 
3562 
3563             ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3564 
3565             sc.cf = cf;
3566             sc.source = &src[i].value;
3567             sc.flushes = &headers->flushes;
3568             sc.lengths = &headers->lengths;
3569             sc.values = &headers->values;
3570 
3571             if (ngx_http_script_compile(&sc) != NGX_OK) {
3572                 return NGX_ERROR;
3573             }
3574 
3575 
3576             copy = ngx_array_push_n(headers->lengths,
3577                                     sizeof(ngx_http_script_copy_code_t));
3578             if (copy == NULL) {
3579                 return NGX_ERROR;
3580             }
3581 
3582             copy->code = (ngx_http_script_code_pt)
3583                                                  ngx_http_script_copy_len_code;
3584             copy->len = sizeof(CRLF) - 1;
3585 
3586 
3587             size = (sizeof(ngx_http_script_copy_code_t)
3588                     + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3589                     & ~(sizeof(uintptr_t) - 1);
3590 
3591             copy = ngx_array_push_n(headers->values, size);
3592             if (copy == NULL) {
3593                 return NGX_ERROR;
3594             }
3595 
3596             copy->code = ngx_http_script_copy_code;
3597             copy->len = sizeof(CRLF) - 1;
3598 
3599             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3600             *p++ = CR; *p = LF;
3601         }
3602 
3603         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3604         if (code == NULL) {
3605             return NGX_ERROR;
3606         }
3607 
3608         *code = (uintptr_t) NULL;
3609 
3610         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
3611         if (code == NULL) {
3612             return NGX_ERROR;
3613         }
3614 
3615         *code = (uintptr_t) NULL;
3616     }
3617 
3618     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3619     if (code == NULL) {
3620         return NGX_ERROR;
3621     }
3622 
3623     *code = (uintptr_t) NULL;
3624 
3625 
3626     hash.hash = &headers->hash;
3627     hash.key = ngx_hash_key_lc;
3628     hash.max_size = conf->headers_hash_max_size;
3629     hash.bucket_size = conf->headers_hash_bucket_size;
3630     hash.name = "proxy_headers_hash";
3631     hash.pool = cf->pool;
3632     hash.temp_pool = NULL;
3633 
3634     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3635 }
3636 
3637 
3638 static char *
3639 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3640 {
3641     ngx_http_proxy_loc_conf_t *plcf = conf;
3642 
3643     size_t                      add;
3644     u_short                     port;
3645     ngx_str_t                  *value, *url;
3646     ngx_url_t                   u;
3647     ngx_uint_t                  n;
3648     ngx_http_core_loc_conf_t   *clcf;
3649     ngx_http_script_compile_t   sc;
3650 
3651     if (plcf->upstream.upstream || plcf->proxy_lengths) {
3652         return "is duplicate";
3653     }
3654 
3655     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3656 
3657     clcf->handler = ngx_http_proxy_handler;
3658 
3659     if (clcf->name.data[clcf->name.len - 1] == '/') {
3660         clcf->auto_redirect = 1;
3661     }
3662 
3663     value = cf->args->elts;
3664 
3665     url = &value[1];
3666 
3667     n = ngx_http_script_variables_count(url);
3668 
3669     if (n) {
3670 
3671         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3672 
3673         sc.cf = cf;
3674         sc.source = url;
3675         sc.lengths = &plcf->proxy_lengths;
3676         sc.values = &plcf->proxy_values;
3677         sc.variables = n;
3678         sc.complete_lengths = 1;
3679         sc.complete_values = 1;
3680 
3681         if (ngx_http_script_compile(&sc) != NGX_OK) {
3682             return NGX_CONF_ERROR;
3683         }
3684 
3685 #if (NGX_HTTP_SSL)
3686         plcf->ssl = 1;
3687 #endif
3688 
3689         return NGX_CONF_OK;
3690     }
3691 
3692     if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3693         add = 7;
3694         port = 80;
3695 
3696     } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3697 
3698 #if (NGX_HTTP_SSL)
3699         plcf->ssl = 1;
3700 
3701         add = 8;
3702         port = 443;
3703 #else
3704         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3705                            "https protocol requires SSL support");
3706         return NGX_CONF_ERROR;
3707 #endif
3708 
3709     } else {
3710         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3711         return NGX_CONF_ERROR;
3712     }
3713 
3714     ngx_memzero(&u, sizeof(ngx_url_t));
3715 
3716     u.url.len = url->len - add;
3717     u.url.data = url->data + add;
3718     u.default_port = port;
3719     u.uri_part = 1;
3720     u.no_resolve = 1;
3721 
3722     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3723     if (plcf->upstream.upstream == NULL) {
3724         return NGX_CONF_ERROR;
3725     }
3726 
3727     plcf->vars.schema.len = add;
3728     plcf->vars.schema.data = url->data;
3729     plcf->vars.key_start = plcf->vars.schema;
3730 
3731     ngx_http_proxy_set_vars(&u, &plcf->vars);
3732 
3733     plcf->location = clcf->name;
3734 
3735     if (clcf->named
3736 #if (NGX_PCRE)
3737         || clcf->regex
3738 #endif
3739         || clcf->noname)
3740     {
3741         if (plcf->vars.uri.len) {
3742             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3743                                "\"proxy_pass\" cannot have URI part in "
3744                                "location given by regular expression, "
3745                                "or inside named location, "
3746                                "or inside \"if\" statement, "
3747                                "or inside \"limit_except\" block");
3748             return NGX_CONF_ERROR;
3749         }
3750 
3751         plcf->location.len = 0;
3752     }
3753 
3754     plcf->url = *url;
3755 
3756     return NGX_CONF_OK;
3757 }
3758 
3759 
3760 static char *
3761 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3762 {
3763     ngx_http_proxy_loc_conf_t *plcf = conf;
3764 
3765     u_char                            *p;
3766     ngx_str_t                         *value;
3767     ngx_http_proxy_rewrite_t          *pr;
3768     ngx_http_compile_complex_value_t   ccv;
3769 
3770     if (plcf->redirect == 0) {
3771         return NGX_CONF_OK;
3772     }
3773 
3774     plcf->redirect = 1;
3775 
3776     value = cf->args->elts;
3777 
3778     if (cf->args->nelts == 2) {
3779         if (ngx_strcmp(value[1].data, "off") == 0) {
3780             plcf->redirect = 0;
3781             plcf->redirects = NULL;
3782             return NGX_CONF_OK;
3783         }
3784 
3785         if (ngx_strcmp(value[1].data, "false") == 0) {
3786             ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3787                            "invalid parameter \"false\", use \"off\" instead");
3788             plcf->redirect = 0;
3789             plcf->redirects = NULL;
3790             return NGX_CONF_OK;
3791         }
3792 
3793         if (ngx_strcmp(value[1].data, "default") != 0) {
3794             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3795                                "invalid parameter \"%V\"", &value[1]);
3796             return NGX_CONF_ERROR;
3797         }
3798     }
3799 
3800     if (plcf->redirects == NULL) {
3801         plcf->redirects = ngx_array_create(cf->pool, 1,
3802                                            sizeof(ngx_http_proxy_rewrite_t));
3803         if (plcf->redirects == NULL) {
3804             return NGX_CONF_ERROR;
3805         }
3806     }
3807 
3808     pr = ngx_array_push(plcf->redirects);
3809     if (pr == NULL) {
3810         return NGX_CONF_ERROR;
3811     }
3812 
3813     if (ngx_strcmp(value[1].data, "default") == 0) {
3814         if (plcf->proxy_lengths) {
3815             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3816                                "\"proxy_redirect default\" cannot be used "
3817                                "with \"proxy_pass\" directive with variables");
3818             return NGX_CONF_ERROR;
3819         }
3820 
3821         if (plcf->url.data == NULL) {
3822             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3823                                "\"proxy_redirect default\" should be placed "
3824                                "after the \"proxy_pass\" directive");
3825             return NGX_CONF_ERROR;
3826         }
3827 
3828         pr->handler = ngx_http_proxy_rewrite_complex_handler;
3829 
3830         ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3831 
3832         ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3833 
3834         if (plcf->vars.uri.len) {
3835             pr->pattern.complex.value = plcf->url;
3836             pr->replacement.value = plcf->location;
3837 
3838         } else {
3839             pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3840 
3841             p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3842             if (p == NULL) {
3843                 return NGX_CONF_ERROR;
3844             }
3845 
3846             pr->pattern.complex.value.data = p;
3847 
3848             p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3849             *p = '/';
3850 
3851             ngx_str_set(&pr->replacement.value, "/");
3852         }
3853 
3854         return NGX_CONF_OK;
3855     }
3856 
3857 
3858     if (value[1].data[0] == '~') {
3859         value[1].len--;
3860         value[1].data++;
3861 
3862         if (value[1].data[0] == '*') {
3863             value[1].len--;
3864             value[1].data++;
3865 
3866             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3867                 return NGX_CONF_ERROR;
3868             }
3869 
3870         } else {
3871             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3872                 return NGX_CONF_ERROR;
3873             }
3874         }
3875 
3876     } else {
3877 
3878         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3879 
3880         ccv.cf = cf;
3881         ccv.value = &value[1];
3882         ccv.complex_value = &pr->pattern.complex;
3883 
3884         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3885             return NGX_CONF_ERROR;
3886         }
3887 
3888         pr->handler = ngx_http_proxy_rewrite_complex_handler;
3889     }
3890 
3891 
3892     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3893 
3894     ccv.cf = cf;
3895     ccv.value = &value[2];
3896     ccv.complex_value = &pr->replacement;
3897 
3898     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3899         return NGX_CONF_ERROR;
3900     }
3901 
3902     return NGX_CONF_OK;
3903 }
3904 
3905 
3906 static char *
3907 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3908 {
3909     ngx_http_proxy_loc_conf_t *plcf = conf;
3910 
3911     ngx_str_t                         *value;
3912     ngx_http_proxy_rewrite_t          *pr;
3913     ngx_http_compile_complex_value_t   ccv;
3914 
3915     if (plcf->cookie_domains == NULL) {
3916         return NGX_CONF_OK;
3917     }
3918 
3919     value = cf->args->elts;
3920 
3921     if (cf->args->nelts == 2) {
3922 
3923         if (ngx_strcmp(value[1].data, "off") == 0) {
3924             plcf->cookie_domains = NULL;
3925             return NGX_CONF_OK;
3926         }
3927 
3928         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3929                            "invalid parameter \"%V\"", &value[1]);
3930         return NGX_CONF_ERROR;
3931     }
3932 
3933     if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3934         plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3935                                      sizeof(ngx_http_proxy_rewrite_t));
3936         if (plcf->cookie_domains == NULL) {
3937             return NGX_CONF_ERROR;
3938         }
3939     }
3940 
3941     pr = ngx_array_push(plcf->cookie_domains);
3942     if (pr == NULL) {
3943         return NGX_CONF_ERROR;
3944     }
3945 
3946     if (value[1].data[0] == '~') {
3947         value[1].len--;
3948         value[1].data++;
3949 
3950         if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3951             return NGX_CONF_ERROR;
3952         }
3953 
3954     } else {
3955 
3956         if (value[1].data[0] == '.') {
3957             value[1].len--;
3958             value[1].data++;
3959         }
3960 
3961         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3962 
3963         ccv.cf = cf;
3964         ccv.value = &value[1];
3965         ccv.complex_value = &pr->pattern.complex;
3966 
3967         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3968             return NGX_CONF_ERROR;
3969         }
3970 
3971         pr->handler = ngx_http_proxy_rewrite_domain_handler;
3972 
3973         if (value[2].data[0] == '.') {
3974             value[2].len--;
3975             value[2].data++;
3976         }
3977     }
3978 
3979     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3980 
3981     ccv.cf = cf;
3982     ccv.value = &value[2];
3983     ccv.complex_value = &pr->replacement;
3984 
3985     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3986         return NGX_CONF_ERROR;
3987     }
3988 
3989     return NGX_CONF_OK;
3990 }
3991 
3992 
3993 static char *
3994 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3995 {
3996     ngx_http_proxy_loc_conf_t *plcf = conf;
3997 
3998     ngx_str_t                         *value;
3999     ngx_http_proxy_rewrite_t          *pr;
4000     ngx_http_compile_complex_value_t   ccv;
4001 
4002     if (plcf->cookie_paths == NULL) {
4003         return NGX_CONF_OK;
4004     }
4005 
4006     value = cf->args->elts;
4007 
4008     if (cf->args->nelts == 2) {
4009 
4010         if (ngx_strcmp(value[1].data, "off") == 0) {
4011             plcf->cookie_paths = NULL;
4012             return NGX_CONF_OK;
4013         }
4014 
4015         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4016                            "invalid parameter \"%V\"", &value[1]);
4017         return NGX_CONF_ERROR;
4018     }
4019 
4020     if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
4021         plcf->cookie_paths = ngx_array_create(cf->pool, 1,
4022                                      sizeof(ngx_http_proxy_rewrite_t));
4023         if (plcf->cookie_paths == NULL) {
4024             return NGX_CONF_ERROR;
4025         }
4026     }
4027 
4028     pr = ngx_array_push(plcf->cookie_paths);
4029     if (pr == NULL) {
4030         return NGX_CONF_ERROR;
4031     }
4032 
4033     if (value[1].data[0] == '~') {
4034         value[1].len--;
4035         value[1].data++;
4036 
4037         if (value[1].data[0] == '*') {
4038             value[1].len--;
4039             value[1].data++;
4040 
4041             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
4042                 return NGX_CONF_ERROR;
4043             }
4044 
4045         } else {
4046             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
4047                 return NGX_CONF_ERROR;
4048             }
4049         }
4050 
4051     } else {
4052 
4053         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4054 
4055         ccv.cf = cf;
4056         ccv.value = &value[1];
4057         ccv.complex_value = &pr->pattern.complex;
4058 
4059         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4060             return NGX_CONF_ERROR;
4061         }
4062 
4063         pr->handler = ngx_http_proxy_rewrite_complex_handler;
4064     }
4065 
4066     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4067 
4068     ccv.cf = cf;
4069     ccv.value = &value[2];
4070     ccv.complex_value = &pr->replacement;
4071 
4072     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4073         return NGX_CONF_ERROR;
4074     }
4075 
4076     return NGX_CONF_OK;
4077 }
4078 
4079 
4080 static ngx_int_t
4081 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
4082     ngx_str_t *regex, ngx_uint_t caseless)
4083 {
4084 #if (NGX_PCRE)
4085     u_char               errstr[NGX_MAX_CONF_ERRSTR];
4086     ngx_regex_compile_t  rc;
4087 
4088     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
4089 
4090     rc.pattern = *regex;
4091     rc.err.len = NGX_MAX_CONF_ERRSTR;
4092     rc.err.data = errstr;
4093 
4094     if (caseless) {
4095         rc.options = NGX_REGEX_CASELESS;
4096     }
4097 
4098     pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
4099     if (pr->pattern.regex == NULL) {
4100         return NGX_ERROR;
4101     }
4102 
4103     pr->handler = ngx_http_proxy_rewrite_regex_handler;
4104 
4105     return NGX_OK;
4106 
4107 #else
4108 
4109     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4110                        "using regex \"%V\" requires PCRE library", regex);
4111     return NGX_ERROR;
4112 
4113 #endif
4114 }
4115 
4116 
4117 static char *
4118 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4119 {
4120     ngx_http_proxy_loc_conf_t *plcf = conf;
4121 
4122     ngx_str_t                  *value;
4123     ngx_http_script_compile_t   sc;
4124 
4125     if (plcf->upstream.store != NGX_CONF_UNSET) {
4126         return "is duplicate";
4127     }
4128 
4129     value = cf->args->elts;
4130 
4131     if (ngx_strcmp(value[1].data, "off") == 0) {
4132         plcf->upstream.store = 0;
4133         return NGX_CONF_OK;
4134     }
4135 
4136 #if (NGX_HTTP_CACHE)
4137     if (plcf->upstream.cache > 0) {
4138         return "is incompatible with \"proxy_cache\"";
4139     }
4140 #endif
4141 
4142     plcf->upstream.store = 1;
4143 
4144     if (ngx_strcmp(value[1].data, "on") == 0) {
4145         return NGX_CONF_OK;
4146     }
4147 
4148     /* include the terminating '\0' into script */
4149     value[1].len++;
4150 
4151     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4152 
4153     sc.cf = cf;
4154     sc.source = &value[1];
4155     sc.lengths = &plcf->upstream.store_lengths;
4156     sc.values = &plcf->upstream.store_values;
4157     sc.variables = ngx_http_script_variables_count(&value[1]);
4158     sc.complete_lengths = 1;
4159     sc.complete_values = 1;
4160 
4161     if (ngx_http_script_compile(&sc) != NGX_OK) {
4162         return NGX_CONF_ERROR;
4163     }
4164 
4165     return NGX_CONF_OK;
4166 }
4167 
4168 
4169 #if (NGX_HTTP_CACHE)
4170 
4171 static char *
4172 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4173 {
4174     ngx_http_proxy_loc_conf_t *plcf = conf;
4175 
4176     ngx_str_t                         *value;
4177     ngx_http_complex_value_t           cv;
4178     ngx_http_compile_complex_value_t   ccv;
4179 
4180     value = cf->args->elts;
4181 
4182     if (plcf->upstream.cache != NGX_CONF_UNSET) {
4183         return "is duplicate";
4184     }
4185 
4186     if (ngx_strcmp(value[1].data, "off") == 0) {
4187         plcf->upstream.cache = 0;
4188         return NGX_CONF_OK;
4189     }
4190 
4191     if (plcf->upstream.store > 0) {
4192         return "is incompatible with \"proxy_store\"";
4193     }
4194 
4195     plcf->upstream.cache = 1;
4196 
4197     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4198 
4199     ccv.cf = cf;
4200     ccv.value = &value[1];
4201     ccv.complex_value = &cv;
4202 
4203     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4204         return NGX_CONF_ERROR;
4205     }
4206 
4207     if (cv.lengths != NULL) {
4208 
4209         plcf->upstream.cache_value = ngx_palloc(cf->pool,
4210                                              sizeof(ngx_http_complex_value_t));
4211         if (plcf->upstream.cache_value == NULL) {
4212             return NGX_CONF_ERROR;
4213         }
4214 
4215         *plcf->upstream.cache_value = cv;
4216 
4217         return NGX_CONF_OK;
4218     }
4219 
4220     plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
4221                                                       &ngx_http_proxy_module);
4222     if (plcf->upstream.cache_zone == NULL) {
4223         return NGX_CONF_ERROR;
4224     }
4225 
4226     return NGX_CONF_OK;
4227 }
4228 
4229 
4230 static char *
4231 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4232 {
4233     ngx_http_proxy_loc_conf_t *plcf = conf;
4234 
4235     ngx_str_t                         *value;
4236     ngx_http_compile_complex_value_t   ccv;
4237 
4238     value = cf->args->elts;
4239 
4240     if (plcf->cache_key.value.data) {
4241         return "is duplicate";
4242     }
4243 
4244     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4245 
4246     ccv.cf = cf;
4247     ccv.value = &value[1];
4248     ccv.complex_value = &plcf->cache_key;
4249 
4250     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4251         return NGX_CONF_ERROR;
4252     }
4253 
4254     return NGX_CONF_OK;
4255 }
4256 
4257 #endif
4258 
4259 
4260 #if (NGX_HTTP_SSL)
4261 
4262 static char *
4263 ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4264 {
4265     ngx_http_proxy_loc_conf_t *plcf = conf;
4266 
4267     ngx_str_t  *value;
4268 
4269     if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
4270         return "is duplicate";
4271     }
4272 
4273     value = cf->args->elts;
4274 
4275     plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
4276 
4277     if (plcf->ssl_passwords == NULL) {
4278         return NGX_CONF_ERROR;
4279     }
4280 
4281     return NGX_CONF_OK;
4282 }
4283 
4284 #endif
4285 
4286 
4287 static char *
4288 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
4289 {
4290 #if (NGX_FREEBSD)
4291     ssize_t *np = data;
4292 
4293     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
4294         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4295                            "\"proxy_send_lowat\" must be less than %d "
4296                            "(sysctl net.inet.tcp.sendspace)",
4297                            ngx_freebsd_net_inet_tcp_sendspace);
4298 
4299         return NGX_CONF_ERROR;
4300     }
4301 
4302 #elif !(NGX_HAVE_SO_SNDLOWAT)
4303     ssize_t *np = data;
4304 
4305     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
4306                        "\"proxy_send_lowat\" is not supported, ignored");
4307 
4308     *np = 0;
4309 
4310 #endif
4311 
4312     return NGX_CONF_OK;
4313 }
4314 
4315 
4316 #if (NGX_HTTP_SSL)
4317 
4318 static ngx_int_t
4319 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
4320 {
4321     ngx_pool_cleanup_t  *cln;
4322 
4323     plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
4324     if (plcf->upstream.ssl == NULL) {
4325         return NGX_ERROR;
4326     }
4327 
4328     plcf->upstream.ssl->log = cf->log;
4329 
4330     if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
4331         != NGX_OK)
4332     {
4333         return NGX_ERROR;
4334     }
4335 
4336     cln = ngx_pool_cleanup_add(cf->pool, 0);
4337     if (cln == NULL) {
4338         return NGX_ERROR;
4339     }
4340 
4341     cln->handler = ngx_ssl_cleanup_ctx;
4342     cln->data = plcf->upstream.ssl;
4343 
4344     if (plcf->ssl_certificate.len) {
4345 
4346         if (plcf->ssl_certificate_key.len == 0) {
4347             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4348                           "no \"proxy_ssl_certificate_key\" is defined "
4349                           "for certificate \"%V\"", &plcf->ssl_certificate);
4350             return NGX_ERROR;
4351         }
4352 
4353         if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate,
4354                                 &plcf->ssl_certificate_key, plcf->ssl_passwords)
4355             != NGX_OK)
4356         {
4357             return NGX_ERROR;
4358         }
4359     }
4360 
4361     if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0)
4362         != NGX_OK)
4363     {
4364         return NGX_ERROR;
4365     }
4366 
4367     if (plcf->upstream.ssl_verify) {
4368         if (plcf->ssl_trusted_certificate.len == 0) {
4369             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4370                       "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
4371             return NGX_ERROR;
4372         }
4373 
4374         if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
4375                                         &plcf->ssl_trusted_certificate,
4376                                         plcf->ssl_verify_depth)
4377             != NGX_OK)
4378         {
4379             return NGX_ERROR;
4380         }
4381 
4382         if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
4383             return NGX_ERROR;
4384         }
4385     }
4386 
4387     return NGX_OK;
4388 }
4389 
4390 #endif
4391 
4392 
4393 static void
4394 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
4395 {
4396     if (u->family != AF_UNIX) {
4397 
4398         if (u->no_port || u->port == u->default_port) {
4399 
4400             v->host_header = u->host;
4401 
4402             if (u->default_port == 80) {
4403                 ngx_str_set(&v->port, "80");
4404 
4405             } else {
4406                 ngx_str_set(&v->port, "443");
4407             }
4408 
4409         } else {
4410             v->host_header.len = u->host.len + 1 + u->port_text.len;
4411             v->host_header.data = u->host.data;
4412             v->port = u->port_text;
4413         }
4414 
4415         v->key_start.len += v->host_header.len;
4416 
4417     } else {
4418         ngx_str_set(&v->host_header, "localhost");
4419         ngx_str_null(&v->port);
4420         v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
4421     }
4422 
4423     v->uri = u->uri;
4424 }