summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
diff options
context:
space:
mode:
authorrobert <robert@openbsd.org>2011-09-22 23:32:10 +0000
committerrobert <robert@openbsd.org>2011-09-22 23:32:10 +0000
commit40ffe171a7951d3019b3c8b488be87bfad405509 (patch)
tree7634bff211814a539a15e4e34db747e4d7b46006 /usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
parentAlways install all manuals on all architectures. (diff)
downloadwireguard-openbsd-40ffe171a7951d3019b3c8b488be87bfad405509.tar.xz
wireguard-openbsd-40ffe171a7951d3019b3c8b488be87bfad405509.zip
import of nginx 1.0.6 with a bundled libpcre needed for pcre to work
properly. this is not yet linked to the build but we would like to work on it in tree to provide an apache replacement for base
Diffstat (limited to 'usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c')
-rw-r--r--usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c2812
1 files changed, 2812 insertions, 0 deletions
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
new file mode 100644
index 00000000000..495b1743d8b
--- /dev/null
+++ b/usr.sbin/nginx/src/http/modules/ngx_http_proxy_module.c
@@ -0,0 +1,2812 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t;
+
+typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
+
+struct ngx_http_proxy_redirect_s {
+ ngx_http_proxy_redirect_pt handler;
+ ngx_str_t redirect;
+
+ union {
+ ngx_str_t text;
+
+ struct {
+ void *lengths;
+ void *values;
+ } vars;
+
+ void *regex;
+ } replacement;
+};
+
+
+typedef struct {
+ ngx_str_t key_start;
+ ngx_str_t schema;
+ ngx_str_t host_header;
+ ngx_str_t port;
+ ngx_str_t uri;
+} ngx_http_proxy_vars_t;
+
+
+typedef struct {
+ ngx_http_upstream_conf_t upstream;
+
+ ngx_array_t *flushes;
+ ngx_array_t *body_set_len;
+ ngx_array_t *body_set;
+ ngx_array_t *headers_set_len;
+ ngx_array_t *headers_set;
+ ngx_hash_t headers_set_hash;
+
+ ngx_array_t *headers_source;
+
+ ngx_array_t *proxy_lengths;
+ ngx_array_t *proxy_values;
+
+ ngx_array_t *redirects;
+
+ ngx_str_t body_source;
+
+ ngx_str_t method;
+ ngx_str_t location;
+ ngx_str_t url;
+
+#if (NGX_HTTP_CACHE)
+ ngx_http_complex_value_t cache_key;
+#endif
+
+ ngx_http_proxy_vars_t vars;
+
+ ngx_flag_t redirect;
+
+ ngx_uint_t headers_hash_max_size;
+ ngx_uint_t headers_hash_bucket_size;
+} ngx_http_proxy_loc_conf_t;
+
+
+typedef struct {
+ ngx_http_status_t status;
+ ngx_http_proxy_vars_t vars;
+ size_t internal_body_length;
+} ngx_http_proxy_ctx_t;
+
+
+static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
+ ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
+#if (NGX_HTTP_CACHE)
+static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
+#endif
+static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
+static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
+static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
+static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
+ ngx_int_t rc);
+
+static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t
+ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t
+ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix);
+
+static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
+static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
+ void *parent, void *child);
+static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
+ ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
+
+static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+#if (NGX_HTTP_CACHE)
+static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+#endif
+
+static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
+
+#if (NGX_HTTP_SSL)
+static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
+ ngx_http_proxy_loc_conf_t *plcf);
+#endif
+static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
+
+
+static ngx_conf_post_t ngx_http_proxy_lowat_post =
+ { ngx_http_proxy_lowat_check };
+
+
+static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
+ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
+ { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
+ { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
+ { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
+ { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
+ { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
+ { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+ { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
+ { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
+ { ngx_null_string, 0 }
+};
+
+
+ngx_module_t ngx_http_proxy_module;
+
+
+static ngx_command_t ngx_http_proxy_commands[] = {
+
+ { ngx_string("proxy_pass"),
+ NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
+ ngx_http_proxy_pass,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_redirect"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_proxy_redirect,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_store"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_proxy_store,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_store_access"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+ ngx_conf_set_access_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
+ NULL },
+
+ { ngx_string("proxy_buffering"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
+ NULL },
+
+ { ngx_string("proxy_ignore_client_abort"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
+ NULL },
+
+ { ngx_string("proxy_bind"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_upstream_bind_set_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
+ NULL },
+
+ { ngx_string("proxy_connect_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
+ NULL },
+
+ { ngx_string("proxy_send_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
+ NULL },
+
+ { ngx_string("proxy_send_lowat"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
+ &ngx_http_proxy_lowat_post },
+
+ { ngx_string("proxy_intercept_errors"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
+ NULL },
+
+ { ngx_string("proxy_set_header"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_conf_set_keyval_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, headers_source),
+ NULL },
+
+ { ngx_string("proxy_headers_hash_max_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
+ NULL },
+
+ { ngx_string("proxy_headers_hash_bucket_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
+ NULL },
+
+ { ngx_string("proxy_set_body"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, body_source),
+ NULL },
+
+ { ngx_string("proxy_method"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, method),
+ NULL },
+
+ { ngx_string("proxy_pass_request_headers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
+ NULL },
+
+ { ngx_string("proxy_pass_request_body"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
+ NULL },
+
+ { ngx_string("proxy_buffer_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
+ NULL },
+
+ { ngx_string("proxy_read_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
+ NULL },
+
+ { ngx_string("proxy_buffers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_conf_set_bufs_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
+ NULL },
+
+ { ngx_string("proxy_busy_buffers_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
+ NULL },
+
+#if (NGX_HTTP_CACHE)
+
+ { ngx_string("proxy_cache"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_proxy_cache,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_cache_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_proxy_cache_key,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("proxy_cache_path"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
+ ngx_http_file_cache_set_slot,
+ 0,
+ 0,
+ &ngx_http_proxy_module },
+
+ { ngx_string("proxy_cache_bypass"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_http_set_predicate_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
+ NULL },
+
+ { ngx_string("proxy_no_cache"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_http_set_predicate_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
+ NULL },
+
+ { ngx_string("proxy_cache_valid"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_http_file_cache_valid_set_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
+ NULL },
+
+ { ngx_string("proxy_cache_min_uses"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
+ NULL },
+
+ { ngx_string("proxy_cache_use_stale"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
+ &ngx_http_proxy_next_upstream_masks },
+
+ { ngx_string("proxy_cache_methods"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
+ &ngx_http_upstream_cache_method_mask },
+
+#endif
+
+ { ngx_string("proxy_temp_path"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+ ngx_conf_set_path_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
+ NULL },
+
+ { ngx_string("proxy_max_temp_file_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
+ NULL },
+
+ { ngx_string("proxy_temp_file_write_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
+ NULL },
+
+ { ngx_string("proxy_next_upstream"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
+ &ngx_http_proxy_next_upstream_masks },
+
+ { ngx_string("proxy_pass_header"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
+ NULL },
+
+ { ngx_string("proxy_hide_header"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
+ NULL },
+
+ { ngx_string("proxy_ignore_headers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
+ &ngx_http_upstream_ignore_headers_masks },
+
+#if (NGX_HTTP_SSL)
+
+ { ngx_string("proxy_ssl_session_reuse"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
+ NULL },
+
+#endif
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_proxy_module_ctx = {
+ ngx_http_proxy_add_variables, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_proxy_create_loc_conf, /* create location configration */
+ ngx_http_proxy_merge_loc_conf /* merge location configration */
+};
+
+
+ngx_module_t ngx_http_proxy_module = {
+ NGX_MODULE_V1,
+ &ngx_http_proxy_module_ctx, /* module context */
+ ngx_http_proxy_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
+
+
+static ngx_keyval_t ngx_http_proxy_headers[] = {
+ { ngx_string("Host"), ngx_string("$proxy_host") },
+ { ngx_string("Connection"), ngx_string("close") },
+ { ngx_string("Keep-Alive"), ngx_string("") },
+ { ngx_string("Expect"), ngx_string("") },
+ { ngx_null_string, ngx_null_string }
+};
+
+
+static ngx_str_t ngx_http_proxy_hide_headers[] = {
+ ngx_string("Date"),
+ ngx_string("Server"),
+ ngx_string("X-Pad"),
+ ngx_string("X-Accel-Expires"),
+ ngx_string("X-Accel-Redirect"),
+ ngx_string("X-Accel-Limit-Rate"),
+ ngx_string("X-Accel-Buffering"),
+ ngx_string("X-Accel-Charset"),
+ ngx_null_string
+};
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
+ { ngx_string("Host"), ngx_string("$proxy_host") },
+ { ngx_string("Connection"), ngx_string("close") },
+ { ngx_string("Keep-Alive"), ngx_string("") },
+ { ngx_string("Expect"), ngx_string("") },
+ { ngx_string("If-Modified-Since"), ngx_string("") },
+ { ngx_string("If-Unmodified-Since"), ngx_string("") },
+ { ngx_string("If-None-Match"), ngx_string("") },
+ { ngx_string("If-Match"), ngx_string("") },
+ { ngx_string("Range"), ngx_string("") },
+ { ngx_string("If-Range"), ngx_string("") },
+ { ngx_null_string, ngx_null_string }
+};
+
+#endif
+
+
+static ngx_http_variable_t ngx_http_proxy_vars[] = {
+
+ { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
+ { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
+
+ { ngx_string("proxy_add_x_forwarded_for"), NULL,
+ ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
+
+#if 0
+ { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
+#endif
+
+ { ngx_string("proxy_internal_body_length"), NULL,
+ ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
+
+ { ngx_null_string, NULL, NULL, 0, 0, 0 }
+};
+
+
+static ngx_path_init_t ngx_http_proxy_temp_path = {
+ ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
+};
+
+
+static ngx_int_t
+ngx_http_proxy_handler(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+ ngx_http_proxy_loc_conf_t *plcf;
+
+ if (ngx_http_upstream_create(r) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ u = r->upstream;
+
+ if (plcf->proxy_lengths == NULL) {
+ ctx->vars = plcf->vars;
+ u->schema = plcf->vars.schema;
+#if (NGX_HTTP_SSL)
+ u->ssl = (plcf->upstream.ssl != NULL);
+#endif
+
+ } else {
+ if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+
+ u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
+
+ u->conf = &plcf->upstream;
+
+#if (NGX_HTTP_CACHE)
+ u->create_key = ngx_http_proxy_create_key;
+#endif
+ u->create_request = ngx_http_proxy_create_request;
+ u->reinit_request = ngx_http_proxy_reinit_request;
+ u->process_header = ngx_http_proxy_process_status_line;
+ u->abort_request = ngx_http_proxy_abort_request;
+ u->finalize_request = ngx_http_proxy_finalize_request;
+ r->state = 0;
+
+ if (plcf->redirects) {
+ u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
+ }
+
+ u->buffering = plcf->upstream.buffering;
+
+ u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
+ if (u->pipe == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
+
+ u->accel = 1;
+
+ rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
+
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ return rc;
+ }
+
+ return NGX_DONE;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
+ ngx_http_proxy_loc_conf_t *plcf)
+{
+ u_char *p;
+ size_t add;
+ u_short port;
+ ngx_str_t proxy;
+ ngx_url_t url;
+ ngx_http_upstream_t *u;
+
+ if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
+ plcf->proxy_values->elts)
+ == NULL)
+ {
+ return NGX_ERROR;
+ }
+
+ if (proxy.len > 7
+ && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
+ {
+ add = 7;
+ port = 80;
+
+#if (NGX_HTTP_SSL)
+
+ } else if (proxy.len > 8
+ && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
+ {
+ add = 8;
+ port = 443;
+ r->upstream->ssl = 1;
+
+#endif
+
+ } else {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "invalid URL prefix in \"%V\"", &proxy);
+ return NGX_ERROR;
+ }
+
+ u = r->upstream;
+
+ u->schema.len = add;
+ u->schema.data = proxy.data;
+
+ ngx_memzero(&url, sizeof(ngx_url_t));
+
+ url.url.len = proxy.len - add;
+ url.url.data = proxy.data + add;
+ url.default_port = port;
+ url.uri_part = 1;
+ url.no_resolve = 1;
+
+ if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+ if (url.err) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "%s in upstream \"%V\"", url.err, &url.url);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (url.uri.len) {
+ if (url.uri.data[0] == '?') {
+ p = ngx_pnalloc(r->pool, url.uri.len + 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ *p++ = '/';
+ ngx_memcpy(p, url.uri.data, url.uri.len);
+
+ url.uri.len++;
+ url.uri.data = p - 1;
+ }
+
+ } else {
+ url.uri = r->unparsed_uri;
+ }
+
+ ctx->vars.key_start = u->schema;
+
+ ngx_http_proxy_set_vars(&url, &ctx->vars);
+
+ u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+ if (u->resolved == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (url.addrs && url.addrs[0].sockaddr) {
+ u->resolved->sockaddr = url.addrs[0].sockaddr;
+ u->resolved->socklen = url.addrs[0].socklen;
+ u->resolved->naddrs = 1;
+ u->resolved->host = url.addrs[0].name;
+
+ } else {
+ u->resolved->host = url.host;
+ u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
+ u->resolved->no_port = url.no_port;
+ }
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_int_t
+ngx_http_proxy_create_key(ngx_http_request_t *r)
+{
+ size_t len, loc_len;
+ u_char *p;
+ uintptr_t escape;
+ ngx_str_t *key;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+ ngx_http_proxy_loc_conf_t *plcf;
+
+ u = r->upstream;
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ key = ngx_array_push(&r->cache->keys);
+ if (key == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (plcf->cache_key.value.len) {
+
+ if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+ }
+
+ *key = ctx->vars.key_start;
+
+ key = ngx_array_push(&r->cache->keys);
+ if (key == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (plcf->proxy_lengths) {
+
+ *key = ctx->vars.uri;
+ u->uri = ctx->vars.uri;
+
+ return NGX_OK;
+
+ } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
+ {
+ *key = r->unparsed_uri;
+ u->uri = r->unparsed_uri;
+
+ return NGX_OK;
+ }
+
+ loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
+
+ if (r->quoted_uri || r->internal) {
+ escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ } else {
+ escape = 0;
+ }
+
+ len = ctx->vars.uri.len + r->uri.len - loc_len + escape
+ + sizeof("?") - 1 + r->args.len;
+
+ p = ngx_pnalloc(r->pool, len);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ key->data = p;
+
+ if (r->valid_location) {
+ p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
+ }
+
+ if (escape) {
+ ngx_escape_uri(p, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ p += r->uri.len - loc_len + escape;
+
+ } else {
+ p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
+ }
+
+ if (r->args.len > 0) {
+ *p++ = '?';
+ p = ngx_copy(p, r->args.data, r->args.len);
+ }
+
+ key->len = p - key->data;
+ u->uri = *key;
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_http_proxy_create_request(ngx_http_request_t *r)
+{
+ size_t len, uri_len, loc_len, body_len;
+ uintptr_t escape;
+ ngx_buf_t *b;
+ ngx_str_t method;
+ ngx_uint_t i, unparsed_uri;
+ ngx_chain_t *cl, *body;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+ ngx_http_script_code_pt code;
+ ngx_http_script_engine_t e, le;
+ ngx_http_proxy_loc_conf_t *plcf;
+ ngx_http_script_len_code_pt lcode;
+
+ u = r->upstream;
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ if (u->method.len) {
+ /* HEAD was changed to GET to cache response */
+ method = u->method;
+ method.len++;
+
+ } else if (plcf->method.len) {
+ method = plcf->method;
+
+ } else {
+ method = r->method_name;
+ method.len++;
+ }
+
+ len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
+
+ escape = 0;
+ loc_len = 0;
+ unparsed_uri = 0;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (plcf->proxy_lengths) {
+ uri_len = ctx->vars.uri.len;
+
+ } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
+ {
+ unparsed_uri = 1;
+ uri_len = r->unparsed_uri.len;
+
+ } else {
+ loc_len = (r->valid_location && ctx->vars.uri.len) ?
+ plcf->location.len : 0;
+
+ if (r->quoted_uri || r->space_in_uri || r->internal) {
+ escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ }
+
+ uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
+ + sizeof("?") - 1 + r->args.len;
+ }
+
+ if (uri_len == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "zero length URI to proxy");
+ return NGX_ERROR;
+ }
+
+ len += uri_len;
+
+ ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
+
+ if (plcf->body_set_len) {
+ le.ip = plcf->body_set_len->elts;
+ le.request = r;
+ le.flushed = 1;
+ body_len = 0;
+
+ while (*(uintptr_t *) le.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ body_len += lcode(&le);
+ }
+
+ ctx->internal_body_length = body_len;
+ len += body_len;
+ }
+
+ le.ip = plcf->headers_set_len->elts;
+ le.request = r;
+ le.flushed = 1;
+
+ while (*(uintptr_t *) le.ip) {
+ while (*(uintptr_t *) le.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ len += lcode(&le);
+ }
+ le.ip += sizeof(uintptr_t);
+ }
+
+
+ if (plcf->upstream.pass_request_headers) {
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
+ header[i].lowcase_key, header[i].key.len))
+ {
+ continue;
+ }
+
+ len += header[i].key.len + sizeof(": ") - 1
+ + header[i].value.len + sizeof(CRLF) - 1;
+ }
+ }
+
+
+ b = ngx_create_temp_buf(r->pool, len);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl = ngx_alloc_chain_link(r->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = b;
+
+
+ /* the request line */
+
+ b->last = ngx_copy(b->last, method.data, method.len);
+
+ u->uri.data = b->last;
+
+ if (plcf->proxy_lengths) {
+ b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
+
+ } else if (unparsed_uri) {
+ b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
+
+ } else {
+ if (r->valid_location) {
+ b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
+ }
+
+ if (escape) {
+ ngx_escape_uri(b->last, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ b->last += r->uri.len - loc_len + escape;
+
+ } else {
+ b->last = ngx_copy(b->last, r->uri.data + loc_len,
+ r->uri.len - loc_len);
+ }
+
+ if (r->args.len > 0) {
+ *b->last++ = '?';
+ b->last = ngx_copy(b->last, r->args.data, r->args.len);
+ }
+ }
+
+ u->uri.len = b->last - u->uri.data;
+
+ b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
+ sizeof(ngx_http_proxy_version) - 1);
+
+ ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+ e.ip = plcf->headers_set->elts;
+ e.pos = b->last;
+ e.request = r;
+ e.flushed = 1;
+
+ le.ip = plcf->headers_set_len->elts;
+
+ while (*(uintptr_t *) le.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+
+ /* skip the header line name length */
+ (void) lcode(&le);
+
+ if (*(ngx_http_script_len_code_pt *) le.ip) {
+
+ for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
+ }
+
+ e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
+
+ } else {
+ e.skip = 0;
+ }
+
+ le.ip += sizeof(uintptr_t);
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+ e.ip += sizeof(uintptr_t);
+ }
+
+ b->last = e.pos;
+
+
+ if (plcf->upstream.pass_request_headers) {
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
+ header[i].lowcase_key, header[i].key.len))
+ {
+ continue;
+ }
+
+ b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
+
+ *b->last++ = ':'; *b->last++ = ' ';
+
+ b->last = ngx_copy(b->last, header[i].value.data,
+ header[i].value.len);
+
+ *b->last++ = CR; *b->last++ = LF;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy header: \"%V: %V\"",
+ &header[i].key, &header[i].value);
+ }
+ }
+
+
+ /* add "\r\n" at the header end */
+ *b->last++ = CR; *b->last++ = LF;
+
+ if (plcf->body_set) {
+ e.ip = plcf->body_set->elts;
+ e.pos = b->last;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+
+ b->last = e.pos;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy header:\n\"%*s\"",
+ (size_t) (b->last - b->pos), b->pos);
+
+ if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
+
+ body = u->request_bufs;
+ u->request_bufs = cl;
+
+ while (body) {
+ b = ngx_alloc_buf(r->pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
+
+ cl->next = ngx_alloc_chain_link(r->pool);
+ if (cl->next == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl = cl->next;
+ cl->buf = b;
+
+ body = body->next;
+ }
+
+ b->flush = 1;
+
+ } else {
+ u->request_bufs = cl;
+ }
+
+ cl->next = NULL;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_reinit_request(ngx_http_request_t *r)
+{
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_OK;
+ }
+
+ ctx->status.code = 0;
+ ctx->status.count = 0;
+ ctx->status.start = NULL;
+ ctx->status.end = NULL;
+
+ r->upstream->process_header = ngx_http_proxy_process_status_line;
+ r->state = 0;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_process_status_line(ngx_http_request_t *r)
+{
+ size_t len;
+ ngx_int_t rc;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ u = r->upstream;
+
+ rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
+
+ if (rc == NGX_AGAIN) {
+ return rc;
+ }
+
+ if (rc == NGX_ERROR) {
+
+#if (NGX_HTTP_CACHE)
+
+ if (r->cache) {
+ r->http_version = NGX_HTTP_VERSION_9;
+ return NGX_OK;
+ }
+
+#endif
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent no valid HTTP/1.0 header");
+
+#if 0
+ if (u->accel) {
+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+ }
+#endif
+
+ r->http_version = NGX_HTTP_VERSION_9;
+ u->state->status = NGX_HTTP_OK;
+
+ return NGX_OK;
+ }
+
+ if (u->state) {
+ u->state->status = ctx->status.code;
+ }
+
+ u->headers_in.status_n = ctx->status.code;
+
+ len = ctx->status.end - ctx->status.start;
+ u->headers_in.status_line.len = len;
+
+ u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
+ if (u->headers_in.status_line.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy status %ui \"%V\"",
+ u->headers_in.status_n, &u->headers_in.status_line);
+
+ u->process_header = ngx_http_proxy_process_header;
+
+ return ngx_http_proxy_process_header(r);
+}
+
+
+static ngx_int_t
+ngx_http_proxy_process_header(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_table_elt_t *h;
+ ngx_http_upstream_header_t *hh;
+ ngx_http_upstream_main_conf_t *umcf;
+
+ umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+
+ for ( ;; ) {
+
+ rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
+
+ if (rc == NGX_OK) {
+
+ /* a header line has been parsed successfully */
+
+ h = ngx_list_push(&r->upstream->headers_in.headers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->hash = r->header_hash;
+
+ h->key.len = r->header_name_end - r->header_name_start;
+ h->value.len = r->header_end - r->header_start;
+
+ h->key.data = ngx_pnalloc(r->pool,
+ h->key.len + 1 + h->value.len + 1 + h->key.len);
+ if (h->key.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->value.data = h->key.data + h->key.len + 1;
+ h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
+
+ ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
+ ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
+
+ if (h->key.len == r->lowcase_index) {
+ ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
+
+ } else {
+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
+ }
+
+ hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
+ h->lowcase_key, h->key.len);
+
+ if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy header: \"%V: %V\"",
+ &h->key, &h->value);
+
+ continue;
+ }
+
+ if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+
+ /* a whole header has been parsed successfully */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http proxy header done");
+
+ /*
+ * if no "Server" and "Date" in header line,
+ * then add the special empty headers
+ */
+
+ if (r->upstream->headers_in.server == NULL) {
+ h = ngx_list_push(&r->upstream->headers_in.headers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
+ ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
+
+ ngx_str_set(&h->key, "Server");
+ ngx_str_null(&h->value);
+ h->lowcase_key = (u_char *) "server";
+ }
+
+ if (r->upstream->headers_in.date == NULL) {
+ h = ngx_list_push(&r->upstream->headers_in.headers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
+
+ ngx_str_set(&h->key, "Date");
+ ngx_str_null(&h->value);
+ h->lowcase_key = (u_char *) "date";
+ }
+
+ return NGX_OK;
+ }
+
+ if (rc == NGX_AGAIN) {
+ return NGX_AGAIN;
+ }
+
+ /* there was error while a header line parsing */
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent invalid header");
+
+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+ }
+}
+
+
+static void
+ngx_http_proxy_abort_request(ngx_http_request_t *r)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "abort http proxy request");
+
+ return;
+}
+
+
+static void
+ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "finalize http proxy request");
+
+ return;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_host_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->len = ctx->vars.host_header.len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = ctx->vars.host_header.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_port_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->len = ctx->vars.port.len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = ctx->vars.port.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ u_char *p;
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ if (r->headers_in.x_forwarded_for == NULL) {
+ v->len = r->connection->addr_text.len;
+ v->data = r->connection->addr_text.data;
+ return NGX_OK;
+ }
+
+ v->len = r->headers_in.x_forwarded_for->value.len
+ + sizeof(", ") - 1 + r->connection->addr_text.len;
+
+ p = ngx_pnalloc(r->pool, v->len);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->data = p;
+
+ p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data,
+ r->headers_in.x_forwarded_for->value.len);
+
+ *p++ = ','; *p++ = ' ';
+
+ ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_http_proxy_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ if (ctx == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN);
+
+ if (v->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
+ size_t prefix)
+{
+ ngx_int_t rc;
+ ngx_uint_t i;
+ ngx_http_proxy_loc_conf_t *plcf;
+ ngx_http_proxy_redirect_t *pr;
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ pr = plcf->redirects->elts;
+
+ if (pr == NULL) {
+ return NGX_DECLINED;
+ }
+
+ for (i = 0; i < plcf->redirects->nelts; i++) {
+ rc = pr[i].handler(r, h, prefix, &pr[i]);
+
+ if (rc != NGX_DECLINED) {
+ return rc;
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
+ size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+ size_t len;
+ u_char *data, *p;
+
+ if (pr->redirect.len > h->value.len - prefix
+ || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+ pr->redirect.len) != 0)
+ {
+ return NGX_DECLINED;
+ }
+
+ len = pr->replacement.text.len + h->value.len - pr->redirect.len;
+
+ data = ngx_pnalloc(r->pool, len);
+ if (data == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_copy(data, h->value.data, prefix);
+
+ if (pr->replacement.text.len) {
+ p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len);
+ }
+
+ ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
+ h->value.len - pr->redirect.len - prefix);
+
+ h->value.len = len;
+ h->value.data = data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
+ size_t prefix, ngx_http_proxy_redirect_t *pr)
+{
+ size_t len;
+ u_char *data, *p;
+ ngx_http_script_code_pt code;
+ ngx_http_script_engine_t e;
+ ngx_http_script_len_code_pt lcode;
+
+ if (pr->redirect.len > h->value.len - prefix
+ || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
+ pr->redirect.len) != 0)
+ {
+ return NGX_DECLINED;
+ }
+
+ ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+ e.ip = pr->replacement.vars.lengths;
+ e.request = r;
+
+ len = h->value.len - pr->redirect.len;
+
+ while (*(uintptr_t *) e.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) e.ip;
+ len += lcode(&e);
+ }
+
+ data = ngx_pnalloc(r->pool, len);
+ if (data == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_copy(data, h->value.data, prefix);
+
+ e.ip = pr->replacement.vars.values;
+ e.pos = p;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code(&e);
+ }
+
+ ngx_memcpy(e.pos, h->value.data + prefix + pr->redirect.len,
+ h->value.len - pr->redirect.len - prefix);
+
+ h->value.len = len;
+ h->value.data = data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_add_variables(ngx_conf_t *cf)
+{
+ ngx_http_variable_t *var, *v;
+
+ for (v = ngx_http_proxy_vars; v->name.len; v++) {
+ var = ngx_http_add_variable(cf, &v->name, v->flags);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = v->get_handler;
+ var->data = v->data;
+ }
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
+{
+ ngx_http_proxy_loc_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->upstream.bufs.num = 0;
+ * conf->upstream.ignore_headers = 0;
+ * conf->upstream.next_upstream = 0;
+ * conf->upstream.cache_use_stale = 0;
+ * conf->upstream.cache_methods = 0;
+ * conf->upstream.temp_path = NULL;
+ * conf->upstream.hide_headers_hash = { NULL, 0 };
+ * conf->upstream.uri = { 0, NULL };
+ * conf->upstream.location = NULL;
+ * conf->upstream.store_lengths = NULL;
+ * conf->upstream.store_values = NULL;
+ *
+ * conf->method = NULL;
+ * conf->headers_source = NULL;
+ * conf->headers_set_len = NULL;
+ * conf->headers_set = NULL;
+ * conf->headers_set_hash = NULL;
+ * conf->body_set_len = NULL;
+ * conf->body_set = NULL;
+ * conf->body_source = { 0, NULL };
+ * conf->redirects = NULL;
+ */
+
+ conf->upstream.store = NGX_CONF_UNSET;
+ conf->upstream.store_access = NGX_CONF_UNSET_UINT;
+ conf->upstream.buffering = NGX_CONF_UNSET;
+ conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
+
+ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
+ conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
+
+ conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
+ conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
+
+ conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
+ conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
+ conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
+
+ conf->upstream.pass_request_headers = NGX_CONF_UNSET;
+ conf->upstream.pass_request_body = NGX_CONF_UNSET;
+
+#if (NGX_HTTP_CACHE)
+ conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+ conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
+ conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+#endif
+
+ conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
+ conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
+
+ conf->upstream.intercept_errors = NGX_CONF_UNSET;
+#if (NGX_HTTP_SSL)
+ conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
+#endif
+
+ /* "proxy_cyclic_temp_file" is disabled */
+ conf->upstream.cyclic_temp_file = 0;
+
+ conf->redirect = NGX_CONF_UNSET;
+ conf->upstream.change_buffering = 1;
+
+ conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
+ conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
+
+ ngx_str_set(&conf->upstream.module, "proxy");
+
+ return conf;
+}
+
+
+static char *
+ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_proxy_loc_conf_t *prev = parent;
+ ngx_http_proxy_loc_conf_t *conf = child;
+
+ u_char *p;
+ size_t size;
+ ngx_keyval_t *s;
+ ngx_hash_init_t hash;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_proxy_redirect_t *pr;
+ ngx_http_script_compile_t sc;
+
+ if (conf->upstream.store != 0) {
+ ngx_conf_merge_value(conf->upstream.store,
+ prev->upstream.store, 0);
+
+ if (conf->upstream.store_lengths == NULL) {
+ conf->upstream.store_lengths = prev->upstream.store_lengths;
+ conf->upstream.store_values = prev->upstream.store_values;
+ }
+ }
+
+ ngx_conf_merge_uint_value(conf->upstream.store_access,
+ prev->upstream.store_access, 0600);
+
+ ngx_conf_merge_value(conf->upstream.buffering,
+ prev->upstream.buffering, 1);
+
+ ngx_conf_merge_value(conf->upstream.ignore_client_abort,
+ prev->upstream.ignore_client_abort, 0);
+
+ ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
+ prev->upstream.connect_timeout, 60000);
+
+ ngx_conf_merge_msec_value(conf->upstream.send_timeout,
+ prev->upstream.send_timeout, 60000);
+
+ ngx_conf_merge_msec_value(conf->upstream.read_timeout,
+ prev->upstream.read_timeout, 60000);
+
+ ngx_conf_merge_size_value(conf->upstream.send_lowat,
+ prev->upstream.send_lowat, 0);
+
+ ngx_conf_merge_size_value(conf->upstream.buffer_size,
+ prev->upstream.buffer_size,
+ (size_t) ngx_pagesize);
+
+ ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
+ 8, ngx_pagesize);
+
+ if (conf->upstream.bufs.num < 2) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "there must be at least 2 \"proxy_buffers\"");
+ return NGX_CONF_ERROR;
+ }
+
+
+ size = conf->upstream.buffer_size;
+ if (size < conf->upstream.bufs.size) {
+ size = conf->upstream.bufs.size;
+ }
+
+
+ ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
+ prev->upstream.busy_buffers_size_conf,
+ NGX_CONF_UNSET_SIZE);
+
+ if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
+ conf->upstream.busy_buffers_size = 2 * size;
+ } else {
+ conf->upstream.busy_buffers_size =
+ conf->upstream.busy_buffers_size_conf;
+ }
+
+ if (conf->upstream.busy_buffers_size < size) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_busy_buffers_size\" must be equal or bigger than "
+ "maximum of the value of \"proxy_buffer_size\" and "
+ "one of the \"proxy_buffers\"");
+
+ return NGX_CONF_ERROR;
+ }
+
+ if (conf->upstream.busy_buffers_size
+ > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_busy_buffers_size\" must be less than "
+ "the size of all \"proxy_buffers\" minus one buffer");
+
+ return NGX_CONF_ERROR;
+ }
+
+
+ ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
+ prev->upstream.temp_file_write_size_conf,
+ NGX_CONF_UNSET_SIZE);
+
+ if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
+ conf->upstream.temp_file_write_size = 2 * size;
+ } else {
+ conf->upstream.temp_file_write_size =
+ conf->upstream.temp_file_write_size_conf;
+ }
+
+ if (conf->upstream.temp_file_write_size < size) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_temp_file_write_size\" must be equal or bigger than "
+ "maximum of the value of \"proxy_buffer_size\" and "
+ "one of the \"proxy_buffers\"");
+
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
+ prev->upstream.max_temp_file_size_conf,
+ NGX_CONF_UNSET_SIZE);
+
+ if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
+ conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
+ } else {
+ conf->upstream.max_temp_file_size =
+ conf->upstream.max_temp_file_size_conf;
+ }
+
+ if (conf->upstream.max_temp_file_size != 0
+ && conf->upstream.max_temp_file_size < size)
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_max_temp_file_size\" must be equal to zero to disable "
+ "the temporary files usage or must be equal or bigger than "
+ "maximum of the value of \"proxy_buffer_size\" and "
+ "one of the \"proxy_buffers\"");
+
+ return NGX_CONF_ERROR;
+ }
+
+
+ ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
+ prev->upstream.ignore_headers,
+ NGX_CONF_BITMASK_SET);
+
+
+ ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
+ prev->upstream.next_upstream,
+ (NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_ERROR
+ |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
+
+ if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
+ conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_OFF;
+ }
+
+ if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
+ prev->upstream.temp_path,
+ &ngx_http_proxy_temp_path)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+
+#if (NGX_HTTP_CACHE)
+
+ ngx_conf_merge_ptr_value(conf->upstream.cache,
+ prev->upstream.cache, NULL);
+
+ if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ ngx_shm_zone_t *shm_zone;
+
+ shm_zone = conf->upstream.cache;
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_cache\" zone \"%V\" is unknown",
+ &shm_zone->shm.name);
+
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
+ prev->upstream.cache_min_uses, 1);
+
+ ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
+ prev->upstream.cache_use_stale,
+ (NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_OFF));
+
+ if (conf->upstream.cache_methods == 0) {
+ conf->upstream.cache_methods = prev->upstream.cache_methods;
+ }
+
+ conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
+
+ if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
+ conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_OFF;
+ }
+
+ ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
+ prev->upstream.cache_bypass, NULL);
+
+ ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+ prev->upstream.no_cache, NULL);
+
+ if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
+ ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+ "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
+ "now it should be used together with \"proxy_cache_bypass\"");
+ }
+
+ ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
+ prev->upstream.cache_valid, NULL);
+
+ if (conf->cache_key.value.data == NULL) {
+ conf->cache_key = prev->cache_key;
+ }
+
+#endif
+
+ if (conf->method.len == 0) {
+ conf->method = prev->method;
+
+ } else {
+ conf->method.data[conf->method.len] = ' ';
+ conf->method.len++;
+ }
+
+ ngx_conf_merge_value(conf->upstream.pass_request_headers,
+ prev->upstream.pass_request_headers, 1);
+ ngx_conf_merge_value(conf->upstream.pass_request_body,
+ prev->upstream.pass_request_body, 1);
+
+ ngx_conf_merge_value(conf->upstream.intercept_errors,
+ prev->upstream.intercept_errors, 0);
+
+#if (NGX_HTTP_SSL)
+ ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
+ prev->upstream.ssl_session_reuse, 1);
+#endif
+
+ ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
+
+ if (conf->redirect) {
+
+ if (conf->redirects == NULL) {
+ conf->redirects = prev->redirects;
+ }
+
+ if (conf->redirects == NULL && conf->url.data) {
+
+ conf->redirects = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_proxy_redirect_t));
+ if (conf->redirects == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr = ngx_array_push(conf->redirects);
+ if (pr == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_redirect_text;
+
+ if (conf->vars.uri.len) {
+ pr->redirect = conf->url;
+ pr->replacement.text = conf->location;
+
+ } else {
+ pr->redirect.len = conf->url.len + sizeof("/") - 1;
+
+ p = ngx_pnalloc(cf->pool, pr->redirect.len);
+ if (p == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->redirect.data = p;
+
+ p = ngx_cpymem(p, conf->url.data, conf->url.len);
+ *p = '/';
+
+ ngx_str_set(&pr->replacement.text, "/");
+ }
+ }
+ }
+
+#if (NGX_HTTP_SSL)
+ if (conf->upstream.ssl == NULL) {
+ conf->upstream.ssl = prev->upstream.ssl;
+ }
+#endif
+
+ ngx_conf_merge_uint_value(conf->headers_hash_max_size,
+ prev->headers_hash_max_size, 512);
+
+ ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
+ prev->headers_hash_bucket_size, 64);
+
+ conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
+ ngx_cacheline_size);
+
+ hash.max_size = conf->headers_hash_max_size;
+ hash.bucket_size = conf->headers_hash_bucket_size;
+ hash.name = "proxy_headers_hash";
+
+ if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
+ &prev->upstream, ngx_http_proxy_hide_headers, &hash)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ if (conf->upstream.upstream == NULL) {
+ conf->upstream.upstream = prev->upstream.upstream;
+ conf->vars = prev->vars;
+ }
+
+ if (conf->proxy_lengths == NULL) {
+ conf->proxy_lengths = prev->proxy_lengths;
+ conf->proxy_values = prev->proxy_values;
+ }
+
+ if (conf->upstream.upstream || conf->proxy_lengths) {
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+ if (clcf->handler == NULL && clcf->lmt_excpt) {
+ clcf->handler = ngx_http_proxy_handler;
+ conf->location = prev->location;
+ }
+ }
+
+ if (conf->body_source.data == NULL) {
+ conf->body_source = prev->body_source;
+ conf->body_set_len = prev->body_set_len;
+ conf->body_set = prev->body_set;
+ }
+
+ if (conf->body_source.data && conf->body_set_len == NULL) {
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = &conf->body_source;
+ sc.flushes = &conf->flushes;
+ sc.lengths = &conf->body_set_len;
+ sc.values = &conf->body_set;
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (conf->headers_source == NULL) {
+ conf->headers_source = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_keyval_t));
+ if (conf->headers_source == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ s = ngx_array_push(conf->headers_source);
+ if (s == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_str_set(&s->key, "Content-Length");
+ ngx_str_set(&s->value, "$proxy_internal_body_length");
+ }
+
+ if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
+ ngx_http_proxy_loc_conf_t *prev)
+{
+ u_char *p;
+ size_t size;
+ uintptr_t *code;
+ ngx_uint_t i;
+ ngx_array_t headers_names;
+ ngx_keyval_t *src, *s, *h;
+ ngx_hash_key_t *hk;
+ ngx_hash_init_t hash;
+ ngx_http_script_compile_t sc;
+ ngx_http_script_copy_code_t *copy;
+
+ if (conf->headers_source == NULL) {
+ conf->flushes = prev->flushes;
+ conf->headers_set_len = prev->headers_set_len;
+ conf->headers_set = prev->headers_set;
+ conf->headers_set_hash = prev->headers_set_hash;
+ conf->headers_source = prev->headers_source;
+ }
+
+ if (conf->headers_set_hash.buckets
+#if (NGX_HTTP_CACHE)
+ && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
+#endif
+ )
+ {
+ return NGX_OK;
+ }
+
+
+ if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (conf->headers_source == NULL) {
+ conf->headers_source = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_keyval_t));
+ if (conf->headers_source == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
+ if (conf->headers_set_len == NULL) {
+ return NGX_ERROR;
+ }
+
+ conf->headers_set = ngx_array_create(cf->pool, 512, 1);
+ if (conf->headers_set == NULL) {
+ return NGX_ERROR;
+ }
+
+
+ src = conf->headers_source->elts;
+
+#if (NGX_HTTP_CACHE)
+
+ h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
+ ngx_http_proxy_headers;
+#else
+
+ h = ngx_http_proxy_headers;
+
+#endif
+
+ while (h->key.len) {
+
+ for (i = 0; i < conf->headers_source->nelts; i++) {
+ if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
+ goto next;
+ }
+ }
+
+ s = ngx_array_push(conf->headers_source);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = *h;
+
+ src = conf->headers_source->elts;
+
+ next:
+
+ h++;
+ }
+
+
+ src = conf->headers_source->elts;
+ for (i = 0; i < conf->headers_source->nelts; i++) {
+
+ hk = ngx_array_push(&headers_names);
+ if (hk == NULL) {
+ return NGX_ERROR;
+ }
+
+ hk->key = src[i].key;
+ hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
+ hk->value = (void *) 1;
+
+ if (src[i].value.len == 0) {
+ continue;
+ }
+
+ if (ngx_http_script_variables_count(&src[i].value) == 0) {
+ copy = ngx_array_push_n(conf->headers_set_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt)
+ ngx_http_script_copy_len_code;
+ copy->len = src[i].key.len + sizeof(": ") - 1
+ + src[i].value.len + sizeof(CRLF) - 1;
+
+
+ size = (sizeof(ngx_http_script_copy_code_t)
+ + src[i].key.len + sizeof(": ") - 1
+ + src[i].value.len + sizeof(CRLF) - 1
+ + sizeof(uintptr_t) - 1)
+ & ~(sizeof(uintptr_t) - 1);
+
+ copy = ngx_array_push_n(conf->headers_set, size);
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = ngx_http_script_copy_code;
+ copy->len = src[i].key.len + sizeof(": ") - 1
+ + src[i].value.len + sizeof(CRLF) - 1;
+
+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+
+ p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+ *p++ = ':'; *p++ = ' ';
+ p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
+ *p++ = CR; *p = LF;
+
+ } else {
+ copy = ngx_array_push_n(conf->headers_set_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt)
+ ngx_http_script_copy_len_code;
+ copy->len = src[i].key.len + sizeof(": ") - 1;
+
+
+ size = (sizeof(ngx_http_script_copy_code_t)
+ + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
+ & ~(sizeof(uintptr_t) - 1);
+
+ copy = ngx_array_push_n(conf->headers_set, size);
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = ngx_http_script_copy_code;
+ copy->len = src[i].key.len + sizeof(": ") - 1;
+
+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+ p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
+ *p++ = ':'; *p = ' ';
+
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = &src[i].value;
+ sc.flushes = &conf->flushes;
+ sc.lengths = &conf->headers_set_len;
+ sc.values = &conf->headers_set;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+
+ copy = ngx_array_push_n(conf->headers_set_len,
+ sizeof(ngx_http_script_copy_code_t));
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = (ngx_http_script_code_pt)
+ ngx_http_script_copy_len_code;
+ copy->len = sizeof(CRLF) - 1;
+
+
+ size = (sizeof(ngx_http_script_copy_code_t)
+ + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
+ & ~(sizeof(uintptr_t) - 1);
+
+ copy = ngx_array_push_n(conf->headers_set, size);
+ if (copy == NULL) {
+ return NGX_ERROR;
+ }
+
+ copy->code = ngx_http_script_copy_code;
+ copy->len = sizeof(CRLF) - 1;
+
+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
+ *p++ = CR; *p = LF;
+ }
+
+ code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+ if (code == NULL) {
+ return NGX_ERROR;
+ }
+
+ *code = (uintptr_t) NULL;
+
+ code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
+ if (code == NULL) {
+ return NGX_ERROR;
+ }
+
+ *code = (uintptr_t) NULL;
+ }
+
+ code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
+ if (code == NULL) {
+ return NGX_ERROR;
+ }
+
+ *code = (uintptr_t) NULL;
+
+
+ hash.hash = &conf->headers_set_hash;
+ hash.key = ngx_hash_key_lc;
+ hash.max_size = conf->headers_hash_max_size;
+ hash.bucket_size = conf->headers_hash_bucket_size;
+ hash.name = "proxy_headers_hash";
+ hash.pool = cf->pool;
+ hash.temp_pool = NULL;
+
+ return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
+}
+
+
+static char *
+ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ size_t add;
+ u_short port;
+ ngx_str_t *value, *url;
+ ngx_url_t u;
+ ngx_uint_t n;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_script_compile_t sc;
+
+ if (plcf->upstream.upstream || plcf->proxy_lengths) {
+ return "is duplicate";
+ }
+
+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+
+ clcf->handler = ngx_http_proxy_handler;
+
+ if (clcf->name.data[clcf->name.len - 1] == '/') {
+ clcf->auto_redirect = 1;
+ }
+
+ value = cf->args->elts;
+
+ url = &value[1];
+
+ n = ngx_http_script_variables_count(url);
+
+ if (n) {
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = url;
+ sc.lengths = &plcf->proxy_lengths;
+ sc.values = &plcf->proxy_values;
+ sc.variables = n;
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+#if (NGX_HTTP_SSL)
+ if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+#endif
+
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
+ add = 7;
+ port = 80;
+
+ } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
+
+#if (NGX_HTTP_SSL)
+ if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ add = 8;
+ port = 443;
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "https protocol requires SSL support");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url.len = url->len - add;
+ u.url.data = url->data + add;
+ u.default_port = port;
+ u.uri_part = 1;
+ u.no_resolve = 1;
+
+ plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
+ if (plcf->upstream.upstream == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ plcf->vars.schema.len = add;
+ plcf->vars.schema.data = url->data;
+ plcf->vars.key_start = plcf->vars.schema;
+
+ ngx_http_proxy_set_vars(&u, &plcf->vars);
+
+ plcf->location = clcf->name;
+
+ if (clcf->named
+#if (NGX_PCRE)
+ || clcf->regex
+#endif
+ || clcf->noname)
+ {
+ if (plcf->vars.uri.len) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_pass\" may not have URI part in "
+ "location given by regular expression, "
+ "or inside named location, "
+ "or inside the \"if\" statement, "
+ "or inside the \"limit_except\" block");
+ return NGX_CONF_ERROR;
+ }
+
+ plcf->location.len = 0;
+ }
+
+ plcf->url = *url;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ u_char *p;
+ ngx_str_t *value;
+ ngx_array_t *vars_lengths, *vars_values;
+ ngx_http_script_compile_t sc;
+ ngx_http_proxy_redirect_t *pr;
+
+ if (plcf->redirect == 0) {
+ return NGX_CONF_OK;
+ }
+
+ value = cf->args->elts;
+
+ if (cf->args->nelts == 2) {
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->redirect = 0;
+ plcf->redirects = NULL;
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strcmp(value[1].data, "false") == 0) {
+ ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
+ "invalid parameter \"false\", use \"off\" instead");
+ plcf->redirect = 0;
+ plcf->redirects = NULL;
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strcmp(value[1].data, "default") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ if (plcf->redirects == NULL) {
+ plcf->redirects = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_proxy_redirect_t));
+ if (plcf->redirects == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ pr = ngx_array_push(plcf->redirects);
+ if (pr == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_strcmp(value[1].data, "default") == 0) {
+ if (plcf->proxy_lengths) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_redirect default\" may not be used "
+ "with \"proxy_pass\" directive with variables");
+ return NGX_CONF_ERROR;
+ }
+
+ if (plcf->url.data == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_redirect default\" must go "
+ "after the \"proxy_pass\" directive");
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_redirect_text;
+
+ if (plcf->vars.uri.len) {
+ pr->redirect = plcf->url;
+ pr->replacement.text = plcf->location;
+
+ } else {
+ pr->redirect.len = plcf->url.len + sizeof("/") - 1;
+
+ p = ngx_pnalloc(cf->pool, pr->redirect.len);
+ if (p == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->redirect.data = p;
+
+ p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
+ *p = '/';
+
+ ngx_str_set(&pr->replacement.text, "/");
+ }
+
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_http_script_variables_count(&value[2]) == 0) {
+ pr->handler = ngx_http_proxy_rewrite_redirect_text;
+ pr->redirect = value[1];
+ pr->replacement.text = value[2];
+
+ return NGX_CONF_OK;
+ }
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ vars_lengths = NULL;
+ vars_values = NULL;
+
+ sc.cf = cf;
+ sc.source = &value[2];
+ sc.lengths = &vars_lengths;
+ sc.values = &vars_values;
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ pr->handler = ngx_http_proxy_rewrite_redirect_vars;
+ pr->redirect = value[1];
+ pr->replacement.vars.lengths = vars_lengths->elts;
+ pr->replacement.vars.values = vars_values->elts;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_script_compile_t sc;
+
+ if (plcf->upstream.store != NGX_CONF_UNSET
+ || plcf->upstream.store_lengths)
+ {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->upstream.store = 0;
+ return NGX_CONF_OK;
+ }
+
+#if (NGX_HTTP_CACHE)
+
+ if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
+ && plcf->upstream.cache != NULL)
+ {
+ return "is incompatible with \"proxy_cache\"";
+ }
+
+#endif
+
+ if (ngx_strcmp(value[1].data, "on") == 0) {
+ plcf->upstream.store = 1;
+ return NGX_CONF_OK;
+ }
+
+ /* include the terminating '\0' into script */
+ value[1].len++;
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = &value[1];
+ sc.lengths = &plcf->upstream.store_lengths;
+ sc.values = &plcf->upstream.store_values;
+ sc.variables = ngx_http_script_variables_count(&value[1]);
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static char *
+ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->upstream.cache = NULL;
+ return NGX_CONF_OK;
+ }
+
+ if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
+ return "is incompatible with \"proxy_store\"";
+ }
+
+ plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_proxy_module);
+ if (plcf->upstream.cache == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+ ngx_http_compile_complex_value_t ccv;
+
+ value = cf->args->elts;
+
+ if (plcf->cache_key.value.len) {
+ return "is duplicate";
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &plcf->cache_key;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+#endif
+
+
+static char *
+ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
+{
+#if (NGX_FREEBSD)
+ ssize_t *np = data;
+
+ if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_send_lowat\" must be less than %d "
+ "(sysctl net.inet.tcp.sendspace)",
+ ngx_freebsd_net_inet_tcp_sendspace);
+
+ return NGX_CONF_ERROR;
+ }
+
+#elif !(NGX_HAVE_SO_SNDLOWAT)
+ ssize_t *np = data;
+
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "\"proxy_send_lowat\" is not supported, ignored");
+
+ *np = 0;
+
+#endif
+
+ return NGX_CONF_OK;
+}
+
+
+#if (NGX_HTTP_SSL)
+
+static ngx_int_t
+ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
+{
+ ngx_pool_cleanup_t *cln;
+
+ plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+ if (plcf->upstream.ssl == NULL) {
+ return NGX_ERROR;
+ }
+
+ plcf->upstream.ssl->log = cf->log;
+
+ if (ngx_ssl_create(plcf->upstream.ssl,
+ NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = plcf->upstream.ssl;
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static void
+ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
+{
+ if (u->family != AF_UNIX) {
+
+ if (u->no_port || u->port == u->default_port) {
+
+ v->host_header = u->host;
+
+ if (u->default_port == 80) {
+ ngx_str_set(&v->port, "80");
+
+ } else {
+ ngx_str_set(&v->port, "443");
+ }
+
+ } else {
+ v->host_header.len = u->host.len + 1 + u->port_text.len;
+ v->host_header.data = u->host.data;
+ v->port = u->port_text;
+ }
+
+ v->key_start.len += v->host_header.len;
+
+ } else {
+ ngx_str_set(&v->host_header, "localhost");
+ ngx_str_null(&v->port);
+ v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
+ }
+
+ v->uri = u->uri;
+}