Mercurial > hg > nginx-vendor-current
diff src/http/modules/ngx_http_proxy_module.c @ 662:e5fa0a4a7d27 NGINX_1_1_15
nginx 1.1.15
*) Feature: the "disable_symlinks" directive.
*) Feature: the "proxy_cookie_domain" and "proxy_cookie_path"
directives.
*) Bugfix: nginx might log incorrect error "upstream prematurely closed
connection" instead of correct "upstream sent too big header" one.
Thanks to Feibo Li.
*) Bugfix: nginx could not be built with the ngx_http_perl_module if the
--with-openssl option was used.
*) Bugfix: internal redirects to named locations were not limited.
*) Bugfix: calling $r->flush() multiple times might cause errors in the
ngx_http_gzip_filter_module.
*) Bugfix: temporary files might be not removed if the "proxy_store"
directive were used with SSI includes.
*) Bugfix: in some cases non-cacheable variables (such as the $args
variable) returned old empty cached value.
*) Bugfix: a segmentation fault might occur in a worker process if too
many SSI subrequests were issued simultaneously; the bug had appeared
in 0.7.25.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 15 Feb 2012 00:00:00 +0400 |
parents | d0f7a625f27c |
children | f5b859b2f097 |
line wrap: on
line diff
--- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -10,20 +10,21 @@ #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; +typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; + +typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, + ngx_http_proxy_rewrite_t *pr); + +struct ngx_http_proxy_rewrite_s { + ngx_http_proxy_rewrite_pt handler; union { ngx_http_complex_value_t complex; #if (NGX_PCRE) ngx_http_regex_t *regex; #endif - } redirect; + } pattern; ngx_http_complex_value_t replacement; }; @@ -54,6 +55,8 @@ typedef struct { ngx_array_t *proxy_values; ngx_array_t *redirects; + ngx_array_t *cookie_domains; + ngx_array_t *cookie_paths; ngx_str_t body_source; @@ -123,6 +126,12 @@ static ngx_int_t 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_rewrite_cookie(ngx_http_request_t *r, + ngx_table_elt_t *h); +static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, + ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites); +static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement); 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); @@ -135,6 +144,10 @@ static char *ngx_http_proxy_pass(ngx_con void *conf); static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_proxy_cookie_path(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) @@ -146,6 +159,9 @@ static char *ngx_http_proxy_cache_key(ng static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); +static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, + ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless); + #if (NGX_HTTP_SSL) static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf); @@ -198,6 +214,20 @@ static ngx_command_t ngx_http_proxy_com 0, NULL }, + { ngx_string("proxy_cookie_domain"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_proxy_cookie_domain, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_cookie_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_proxy_cookie_path, + 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, @@ -649,6 +679,10 @@ ngx_http_proxy_handler(ngx_http_request_ u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; } + if (plcf->cookie_domains || plcf->cookie_paths) { + u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; + } + u->buffering = plcf->upstream.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); @@ -2272,10 +2306,11 @@ static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix) { + size_t len; ngx_int_t rc; ngx_uint_t i; + ngx_http_proxy_rewrite_t *pr; 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); @@ -2285,8 +2320,95 @@ ngx_http_proxy_rewrite_redirect(ngx_http return NGX_DECLINED; } + len = h->value.len - prefix; + for (i = 0; i < plcf->redirects->nelts; i++) { - rc = pr[i].handler(r, h, prefix, &pr[i]); + rc = pr[i].handler(r, h, prefix, len, &pr[i]); + + if (rc != NGX_DECLINED) { + return rc; + } + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) +{ + size_t prefix; + u_char *p; + ngx_int_t rc, rv; + ngx_http_proxy_loc_conf_t *plcf; + + p = (u_char *) ngx_strchr(h->value.data, ';'); + if (p == NULL) { + return NGX_DECLINED; + } + + prefix = p + 1 - h->value.data; + + rv = NGX_DECLINED; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + if (plcf->cookie_domains) { + p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1); + + if (p) { + rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7, + plcf->cookie_domains); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_DECLINED) { + rv = rc; + } + } + } + + if (plcf->cookie_paths) { + p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1); + + if (p) { + rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5, + plcf->cookie_paths); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_DECLINED) { + rv = rc; + } + } + } + + return rv; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h, + u_char *value, ngx_array_t *rewrites) +{ + size_t len, prefix; + u_char *p; + ngx_int_t rc; + ngx_uint_t i; + ngx_http_proxy_rewrite_t *pr; + + prefix = value - h->value.data; + + p = (u_char *) ngx_strchr(value, ';'); + + len = p ? (size_t) (p - value) : (h->value.len - prefix); + + pr = rewrites->elts; + + for (i = 0; i < rewrites->nelts; i++) { + rc = pr[i].handler(r, h, prefix, len, &pr[i]); if (rc != NGX_DECLINED) { return rc; @@ -2298,20 +2420,18 @@ ngx_http_proxy_rewrite_redirect(ngx_http static ngx_int_t -ngx_http_proxy_rewrite_redirect_complex(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr) +ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { - size_t len; - u_char *data, *p; - ngx_str_t redirect, replacement; - - if (ngx_http_complex_value(r, &pr->redirect.complex, &redirect) != NGX_OK) { + ngx_str_t pattern, replacement; + + if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { return NGX_ERROR; } - if (redirect.len > h->value.len - prefix - || ngx_rstrncmp(h->value.data + prefix, redirect.data, - redirect.len) != 0) + if (pattern.len > len + || ngx_rstrncmp(h->value.data + prefix, pattern.data, + pattern.len) != 0) { return NGX_DECLINED; } @@ -2320,43 +2440,22 @@ ngx_http_proxy_rewrite_redirect_complex( return NGX_ERROR; } - len = replacement.len + h->value.len - redirect.len; - - data = ngx_pnalloc(r->pool, len); - if (data == NULL) { - return NGX_ERROR; - } - - p = ngx_copy(data, h->value.data, prefix); - - if (replacement.len) { - p = ngx_copy(p, replacement.data, replacement.len); - } - - ngx_memcpy(p, h->value.data + prefix + redirect.len, - h->value.len - redirect.len - prefix); - - h->value.len = len; - h->value.data = data; - - return NGX_OK; + return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement); } #if (NGX_PCRE) static ngx_int_t -ngx_http_proxy_rewrite_redirect_regex(ngx_http_request_t *r, ngx_table_elt_t *h, - size_t prefix, ngx_http_proxy_redirect_t *pr) +ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h, + size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { - size_t len; - u_char *data; - ngx_str_t redirect, replacement; - - redirect.len = h->value.len - prefix; - redirect.data = h->value.data + prefix; - - if (ngx_http_regex_exec(r, pr->redirect.regex, &redirect) != NGX_OK) { + ngx_str_t pattern, replacement; + + pattern.len = len; + pattern.data = h->value.data + prefix; + + if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) { return NGX_DECLINED; } @@ -2364,29 +2463,85 @@ ngx_http_proxy_rewrite_redirect_regex(ng return NGX_ERROR; } - if (!prefix) { + if (prefix == 0 && h->value.len == len) { h->value = replacement; return NGX_OK; } - len = prefix + replacement.len; - - data = ngx_pnalloc(r->pool, len); - if (data == NULL) { + return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); +} + +#endif + + +static ngx_int_t +ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) +{ + u_char *p; + ngx_str_t pattern, replacement; + + if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { + return NGX_ERROR; + } + + p = h->value.data + prefix; + + if (p[0] == '.') { + p++; + prefix++; + len--; + } + + if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) { + return NGX_DECLINED; + } + + if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { return NGX_ERROR; } - ngx_memcpy(data, h->value.data, prefix); - ngx_memcpy(data + prefix, replacement.data, replacement.len); - - h->value.len = len; - h->value.data = data; + return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); +} + + +static ngx_int_t +ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, + size_t len, ngx_str_t *replacement) +{ + u_char *p, *data; + size_t new_len; + + new_len = replacement->len + h->value.len - len; + + if (replacement->len > len) { + + data = ngx_pnalloc(r->pool, new_len); + if (data == NULL) { + return NGX_ERROR; + } + + p = ngx_copy(data, h->value.data, prefix); + p = ngx_copy(p, replacement->data, replacement->len); + + ngx_memcpy(p, h->value.data + prefix + len, + h->value.len - len - prefix); + + h->value.data = data; + + } else { + p = ngx_copy(h->value.data + prefix, replacement->data, + replacement->len); + + ngx_memmove(p, h->value.data + prefix + len, + h->value.len - len - prefix); + } + + h->value.len = new_len; return NGX_OK; } -#endif - static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf) @@ -2486,6 +2641,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->redirect = NGX_CONF_UNSET; conf->upstream.change_buffering = 1; + conf->cookie_domains = NGX_CONF_UNSET_PTR; + conf->cookie_paths = NGX_CONF_UNSET_PTR; + conf->http_version = NGX_CONF_UNSET_UINT; conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; @@ -2507,7 +2665,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t size_t size; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - ngx_http_proxy_redirect_t *pr; + ngx_http_proxy_rewrite_t *pr; ngx_http_script_compile_t sc; if (conf->upstream.store != 0) { @@ -2760,7 +2918,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t if (conf->redirects == NULL && conf->url.data) { conf->redirects = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_proxy_redirect_t)); + sizeof(ngx_http_proxy_rewrite_t)); if (conf->redirects == NULL) { return NGX_CONF_ERROR; } @@ -2770,27 +2928,27 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t return NGX_CONF_ERROR; } - ngx_memzero(&pr->redirect.complex, + ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t)); ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); - pr->handler = ngx_http_proxy_rewrite_redirect_complex; + pr->handler = ngx_http_proxy_rewrite_complex_handler; if (conf->vars.uri.len) { - pr->redirect.complex.value = conf->url; + pr->pattern.complex.value = conf->url; pr->replacement.value = conf->location; } else { - pr->redirect.complex.value.len = conf->url.len - + sizeof("/") - 1; - - p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); + pr->pattern.complex.value.len = conf->url.len + + sizeof("/") - 1; + + p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); if (p == NULL) { return NGX_CONF_ERROR; } - pr->redirect.complex.value.data = p; + pr->pattern.complex.value.data = p; p = ngx_cpymem(p, conf->url.data, conf->url.len); *p = '/'; @@ -2800,6 +2958,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } } + ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL); + + ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); + #if (NGX_HTTP_SSL) if (conf->upstream.ssl == NULL) { conf->upstream.ssl = prev->upstream.ssl; @@ -3285,7 +3447,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, u_char *p; ngx_str_t *value; - ngx_http_proxy_redirect_t *pr; + ngx_http_proxy_rewrite_t *pr; ngx_http_compile_complex_value_t ccv; if (plcf->redirect == 0) { @@ -3320,7 +3482,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, if (plcf->redirects == NULL) { plcf->redirects = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_proxy_redirect_t)); + sizeof(ngx_http_proxy_rewrite_t)); if (plcf->redirects == NULL) { return NGX_CONF_ERROR; } @@ -3346,25 +3508,25 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, return NGX_CONF_ERROR; } - pr->handler = ngx_http_proxy_rewrite_redirect_complex; - - ngx_memzero(&pr->redirect.complex, sizeof(ngx_http_complex_value_t)); + pr->handler = ngx_http_proxy_rewrite_complex_handler; + + ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t)); ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); if (plcf->vars.uri.len) { - pr->redirect.complex.value = plcf->url; + pr->pattern.complex.value = plcf->url; pr->replacement.value = plcf->location; } else { - pr->redirect.complex.value.len = plcf->url.len + sizeof("/") - 1; - - p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); + pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1; + + p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); if (p == NULL) { return NGX_CONF_ERROR; } - pr->redirect.complex.value.data = p; + pr->pattern.complex.value.data = p; p = ngx_cpymem(p, plcf->url.data, plcf->url.len); *p = '/'; @@ -3377,52 +3539,36 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, if (value[1].data[0] == '~') { -#if (NGX_PCRE) - u_char errstr[NGX_MAX_CONF_ERRSTR]; - ngx_regex_compile_t rc; - value[1].len--; value[1].data++; - ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); - if (value[1].data[0] == '*') { value[1].len--; value[1].data++; - rc.options = NGX_REGEX_CASELESS; - } - - rc.pattern = value[1]; - rc.err.len = NGX_MAX_CONF_ERRSTR; - rc.err.data = errstr; - - pr->redirect.regex = ngx_http_regex_compile(cf, &rc); - if (pr->redirect.regex == NULL) { - return NGX_CONF_ERROR; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } } - pr->handler = ngx_http_proxy_rewrite_redirect_regex; - -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "using regex \"%V\" requires PCRE library", - &value[1]); - - return NGX_CONF_ERROR; -#endif } else { ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; - ccv.complex_value = &pr->redirect.complex; + ccv.complex_value = &pr->pattern.complex; if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } - pr->handler = ngx_http_proxy_rewrite_redirect_complex; + pr->handler = ngx_http_proxy_rewrite_complex_handler; } @@ -3441,6 +3587,217 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, static char * +ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_proxy_rewrite_t *pr; + ngx_http_compile_complex_value_t ccv; + + if (plcf->cookie_domains == NULL) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->cookie_domains = NULL; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) { + plcf->cookie_domains = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_rewrite_t)); + if (plcf->cookie_domains == NULL) { + return NGX_CONF_ERROR; + } + } + + pr = ngx_array_push(plcf->cookie_domains); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + if (value[1].data[0] == '~') { + value[1].len--; + value[1].data++; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + + if (value[1].data[0] == '.') { + value[1].len--; + value[1].data++; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pr->pattern.complex; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_domain_handler; + + if (value[2].data[0] == '.') { + value[2].len--; + value[2].data++; + } + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &pr->replacement; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_proxy_rewrite_t *pr; + ngx_http_compile_complex_value_t ccv; + + if (plcf->cookie_paths == NULL) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->cookie_paths = NULL; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) { + plcf->cookie_paths = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_rewrite_t)); + if (plcf->cookie_paths == NULL) { + return NGX_CONF_ERROR; + } + } + + pr = ngx_array_push(plcf->cookie_paths); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + if (value[1].data[0] == '~') { + value[1].len--; + value[1].data++; + + if (value[1].data[0] == '*') { + value[1].len--; + value[1].data++; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + } else { + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pr->pattern.complex; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_complex_handler; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &pr->replacement; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, + ngx_str_t *regex, ngx_uint_t caseless) +{ +#if (NGX_PCRE) + u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_regex_compile_t rc; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = *regex; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + if (caseless) { + rc.options = NGX_REGEX_CASELESS; + } + + pr->pattern.regex = ngx_http_regex_compile(cf, &rc); + if (pr->pattern.regex == NULL) { + return NGX_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_regex_handler; + + return NGX_OK; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "using regex \"%V\" requires PCRE library", regex); + return NGX_ERROR; + +#endif +} + + +static char * ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_proxy_loc_conf_t *plcf = conf;