Proxy: added variables and regexp support to the first parameter of
the "proxy_redirect" directive.
This commit is contained in:
parent
a9d1027b80
commit
288775577a
1 changed files with 119 additions and 99 deletions
|
@ -16,18 +16,15 @@ typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
|
|||
|
||||
struct ngx_http_proxy_redirect_s {
|
||||
ngx_http_proxy_redirect_pt handler;
|
||||
ngx_str_t redirect;
|
||||
|
||||
union {
|
||||
ngx_str_t text;
|
||||
ngx_http_complex_value_t complex;
|
||||
#if (NGX_PCRE)
|
||||
ngx_http_regex_t *regex;
|
||||
#endif
|
||||
} redirect;
|
||||
|
||||
struct {
|
||||
void *lengths;
|
||||
void *values;
|
||||
} vars;
|
||||
|
||||
void *regex;
|
||||
} replacement;
|
||||
ngx_http_complex_value_t replacement;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2289,20 +2286,29 @@ ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
|
|||
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
size_t len;
|
||||
u_char *data, *p;
|
||||
size_t len;
|
||||
u_char *data, *p;
|
||||
ngx_str_t redirect, replacement;
|
||||
|
||||
if (pr->redirect.len > h->value.len - prefix
|
||||
|| ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
|
||||
pr->redirect.len) != 0)
|
||||
if (ngx_http_complex_value(r, &pr->redirect.complex, &redirect) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (redirect.len > h->value.len - prefix
|
||||
|| ngx_rstrncmp(h->value.data + prefix, redirect.data,
|
||||
redirect.len) != 0)
|
||||
{
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
len = pr->replacement.text.len + h->value.len - pr->redirect.len;
|
||||
if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = replacement.len + h->value.len - redirect.len;
|
||||
|
||||
data = ngx_pnalloc(r->pool, len);
|
||||
if (data == NULL) {
|
||||
|
@ -2311,12 +2317,12 @@ ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
|
|||
|
||||
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);
|
||||
if (replacement.len) {
|
||||
p = ngx_copy(p, replacement.data, replacement.len);
|
||||
}
|
||||
|
||||
ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
|
||||
h->value.len - pr->redirect.len - prefix);
|
||||
ngx_memcpy(p, h->value.data + prefix + redirect.len,
|
||||
h->value.len - redirect.len - prefix);
|
||||
|
||||
h->value.len = len;
|
||||
h->value.data = data;
|
||||
|
@ -2325,59 +2331,32 @@ ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
|
|||
}
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
ngx_str_t redirect, replacement;
|
||||
|
||||
if (pr->redirect.len > h->value.len - prefix
|
||||
|| ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
|
||||
pr->redirect.len) != 0)
|
||||
{
|
||||
redirect.len = h->value.len - prefix;
|
||||
redirect.data = h->value.data + prefix;
|
||||
|
||||
if (ngx_http_regex_exec(r, pr->redirect.regex, &redirect) != NGX_OK) {
|
||||
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) {
|
||||
if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
|
||||
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;
|
||||
h->value = replacement;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_proxy_add_variables(ngx_conf_t *cf)
|
||||
|
@ -2749,26 +2728,32 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
pr->handler = ngx_http_proxy_rewrite_redirect_text;
|
||||
ngx_memzero(&pr->redirect.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;
|
||||
|
||||
if (conf->vars.uri.len) {
|
||||
pr->redirect = conf->url;
|
||||
pr->replacement.text = conf->location;
|
||||
pr->redirect.complex.value = conf->url;
|
||||
pr->replacement.value = conf->location;
|
||||
|
||||
} else {
|
||||
pr->redirect.len = conf->url.len + sizeof("/") - 1;
|
||||
pr->redirect.complex.value.len = conf->url.len
|
||||
+ sizeof("/") - 1;
|
||||
|
||||
p = ngx_pnalloc(cf->pool, pr->redirect.len);
|
||||
p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
pr->redirect.data = p;
|
||||
pr->redirect.complex.value.data = p;
|
||||
|
||||
p = ngx_cpymem(p, conf->url.data, conf->url.len);
|
||||
*p = '/';
|
||||
|
||||
ngx_str_set(&pr->replacement.text, "/");
|
||||
ngx_str_set(&pr->replacement.value, "/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3256,11 +3241,10 @@ 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;
|
||||
u_char *p;
|
||||
ngx_str_t *value;
|
||||
ngx_http_proxy_redirect_t *pr;
|
||||
ngx_http_compile_complex_value_t ccv;
|
||||
|
||||
if (plcf->redirect == 0) {
|
||||
return NGX_CONF_OK;
|
||||
|
@ -3318,60 +3302,96 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
pr->handler = ngx_http_proxy_rewrite_redirect_text;
|
||||
pr->handler = ngx_http_proxy_rewrite_redirect_complex;
|
||||
|
||||
ngx_memzero(&pr->redirect.complex, sizeof(ngx_http_complex_value_t));
|
||||
|
||||
ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
|
||||
|
||||
if (plcf->vars.uri.len) {
|
||||
pr->redirect = plcf->url;
|
||||
pr->replacement.text = plcf->location;
|
||||
pr->redirect.complex.value = plcf->url;
|
||||
pr->replacement.value = plcf->location;
|
||||
|
||||
} else {
|
||||
pr->redirect.len = plcf->url.len + sizeof("/") - 1;
|
||||
pr->redirect.complex.value.len = plcf->url.len + sizeof("/") - 1;
|
||||
|
||||
p = ngx_pnalloc(cf->pool, pr->redirect.len);
|
||||
p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
pr->redirect.data = p;
|
||||
pr->redirect.complex.value.data = p;
|
||||
|
||||
p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
|
||||
*p = '/';
|
||||
|
||||
ngx_str_set(&pr->replacement.text, "/");
|
||||
ngx_str_set(&pr->replacement.value, "/");
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
pr->handler = ngx_http_proxy_rewrite_redirect_complex;
|
||||
}
|
||||
|
||||
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
|
||||
|
||||
vars_lengths = NULL;
|
||||
vars_values = NULL;
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
|
||||
|
||||
sc.cf = cf;
|
||||
sc.source = &value[2];
|
||||
sc.lengths = &vars_lengths;
|
||||
sc.values = &vars_values;
|
||||
sc.complete_lengths = 1;
|
||||
sc.complete_values = 1;
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[2];
|
||||
ccv.complex_value = &pr->replacement;
|
||||
|
||||
if (ngx_http_script_compile(&sc) != NGX_OK) {
|
||||
if (ngx_http_compile_complex_value(&ccv) != 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue