Mercurial > hg > nginx
comparison src/http/modules/ngx_http_proxy_module.c @ 4336:99437094e86f
Proxy: added variables and regexp support to the first parameter of
the "proxy_redirect" directive.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Mon, 12 Dec 2011 09:02:29 +0000 |
parents | a0f18c78db3b |
children | 726a1ca9b52b |
comparison
equal
deleted
inserted
replaced
4335:1003326eccc5 | 4336:99437094e86f |
---|---|
14 typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r, | 14 typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r, |
15 ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); | 15 ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); |
16 | 16 |
17 struct ngx_http_proxy_redirect_s { | 17 struct ngx_http_proxy_redirect_s { |
18 ngx_http_proxy_redirect_pt handler; | 18 ngx_http_proxy_redirect_pt handler; |
19 ngx_str_t redirect; | |
20 | 19 |
21 union { | 20 union { |
22 ngx_str_t text; | 21 ngx_http_complex_value_t complex; |
23 | 22 #if (NGX_PCRE) |
24 struct { | 23 ngx_http_regex_t *regex; |
25 void *lengths; | 24 #endif |
26 void *values; | 25 } redirect; |
27 } vars; | 26 |
28 | 27 ngx_http_complex_value_t replacement; |
29 void *regex; | |
30 } replacement; | |
31 }; | 28 }; |
32 | 29 |
33 | 30 |
34 typedef struct { | 31 typedef struct { |
35 ngx_str_t key_start; | 32 ngx_str_t key_start; |
2287 return NGX_DECLINED; | 2284 return NGX_DECLINED; |
2288 } | 2285 } |
2289 | 2286 |
2290 | 2287 |
2291 static ngx_int_t | 2288 static ngx_int_t |
2292 ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h, | 2289 ngx_http_proxy_rewrite_redirect_complex(ngx_http_request_t *r, |
2293 size_t prefix, ngx_http_proxy_redirect_t *pr) | 2290 ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr) |
2294 { | 2291 { |
2295 size_t len; | 2292 size_t len; |
2296 u_char *data, *p; | 2293 u_char *data, *p; |
2297 | 2294 ngx_str_t redirect, replacement; |
2298 if (pr->redirect.len > h->value.len - prefix | 2295 |
2299 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | 2296 if (ngx_http_complex_value(r, &pr->redirect.complex, &redirect) != NGX_OK) { |
2300 pr->redirect.len) != 0) | 2297 return NGX_ERROR; |
2298 } | |
2299 | |
2300 if (redirect.len > h->value.len - prefix | |
2301 || ngx_rstrncmp(h->value.data + prefix, redirect.data, | |
2302 redirect.len) != 0) | |
2301 { | 2303 { |
2302 return NGX_DECLINED; | 2304 return NGX_DECLINED; |
2303 } | 2305 } |
2304 | 2306 |
2305 len = pr->replacement.text.len + h->value.len - pr->redirect.len; | 2307 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { |
2308 return NGX_ERROR; | |
2309 } | |
2310 | |
2311 len = replacement.len + h->value.len - redirect.len; | |
2306 | 2312 |
2307 data = ngx_pnalloc(r->pool, len); | 2313 data = ngx_pnalloc(r->pool, len); |
2308 if (data == NULL) { | 2314 if (data == NULL) { |
2309 return NGX_ERROR; | 2315 return NGX_ERROR; |
2310 } | 2316 } |
2311 | 2317 |
2312 p = ngx_copy(data, h->value.data, prefix); | 2318 p = ngx_copy(data, h->value.data, prefix); |
2313 | 2319 |
2314 if (pr->replacement.text.len) { | 2320 if (replacement.len) { |
2315 p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); | 2321 p = ngx_copy(p, replacement.data, replacement.len); |
2316 } | 2322 } |
2317 | 2323 |
2318 ngx_memcpy(p, h->value.data + prefix + pr->redirect.len, | 2324 ngx_memcpy(p, h->value.data + prefix + redirect.len, |
2319 h->value.len - pr->redirect.len - prefix); | 2325 h->value.len - redirect.len - prefix); |
2320 | 2326 |
2321 h->value.len = len; | 2327 h->value.len = len; |
2322 h->value.data = data; | 2328 h->value.data = data; |
2323 | 2329 |
2324 return NGX_OK; | 2330 return NGX_OK; |
2325 } | 2331 } |
2326 | 2332 |
2327 | 2333 |
2334 #if (NGX_PCRE) | |
2335 | |
2328 static ngx_int_t | 2336 static ngx_int_t |
2329 ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h, | 2337 ngx_http_proxy_rewrite_redirect_regex(ngx_http_request_t *r, ngx_table_elt_t *h, |
2330 size_t prefix, ngx_http_proxy_redirect_t *pr) | 2338 size_t prefix, ngx_http_proxy_redirect_t *pr) |
2331 { | 2339 { |
2332 size_t len; | 2340 ngx_str_t redirect, replacement; |
2333 u_char *data, *p; | 2341 |
2334 ngx_http_script_code_pt code; | 2342 redirect.len = h->value.len - prefix; |
2335 ngx_http_script_engine_t e; | 2343 redirect.data = h->value.data + prefix; |
2336 ngx_http_script_len_code_pt lcode; | 2344 |
2337 | 2345 if (ngx_http_regex_exec(r, pr->redirect.regex, &redirect) != NGX_OK) { |
2338 if (pr->redirect.len > h->value.len - prefix | |
2339 || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data, | |
2340 pr->redirect.len) != 0) | |
2341 { | |
2342 return NGX_DECLINED; | 2346 return NGX_DECLINED; |
2343 } | 2347 } |
2344 | 2348 |
2345 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | 2349 if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { |
2346 | |
2347 e.ip = pr->replacement.vars.lengths; | |
2348 e.request = r; | |
2349 | |
2350 len = h->value.len - pr->redirect.len; | |
2351 | |
2352 while (*(uintptr_t *) e.ip) { | |
2353 lcode = *(ngx_http_script_len_code_pt *) e.ip; | |
2354 len += lcode(&e); | |
2355 } | |
2356 | |
2357 data = ngx_pnalloc(r->pool, len); | |
2358 if (data == NULL) { | |
2359 return NGX_ERROR; | 2350 return NGX_ERROR; |
2360 } | 2351 } |
2361 | 2352 |
2362 p = ngx_copy(data, h->value.data, prefix); | 2353 h->value = replacement; |
2363 | |
2364 e.ip = pr->replacement.vars.values; | |
2365 e.pos = p; | |
2366 | |
2367 while (*(uintptr_t *) e.ip) { | |
2368 code = *(ngx_http_script_code_pt *) e.ip; | |
2369 code(&e); | |
2370 } | |
2371 | |
2372 ngx_memcpy(e.pos, h->value.data + prefix + pr->redirect.len, | |
2373 h->value.len - pr->redirect.len - prefix); | |
2374 | |
2375 h->value.len = len; | |
2376 h->value.data = data; | |
2377 | 2354 |
2378 return NGX_OK; | 2355 return NGX_OK; |
2379 } | 2356 } |
2357 | |
2358 #endif | |
2380 | 2359 |
2381 | 2360 |
2382 static ngx_int_t | 2361 static ngx_int_t |
2383 ngx_http_proxy_add_variables(ngx_conf_t *cf) | 2362 ngx_http_proxy_add_variables(ngx_conf_t *cf) |
2384 { | 2363 { |
2747 pr = ngx_array_push(conf->redirects); | 2726 pr = ngx_array_push(conf->redirects); |
2748 if (pr == NULL) { | 2727 if (pr == NULL) { |
2749 return NGX_CONF_ERROR; | 2728 return NGX_CONF_ERROR; |
2750 } | 2729 } |
2751 | 2730 |
2752 pr->handler = ngx_http_proxy_rewrite_redirect_text; | 2731 ngx_memzero(&pr->redirect.complex, |
2732 sizeof(ngx_http_complex_value_t)); | |
2733 | |
2734 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); | |
2735 | |
2736 pr->handler = ngx_http_proxy_rewrite_redirect_complex; | |
2753 | 2737 |
2754 if (conf->vars.uri.len) { | 2738 if (conf->vars.uri.len) { |
2755 pr->redirect = conf->url; | 2739 pr->redirect.complex.value = conf->url; |
2756 pr->replacement.text = conf->location; | 2740 pr->replacement.value = conf->location; |
2757 | 2741 |
2758 } else { | 2742 } else { |
2759 pr->redirect.len = conf->url.len + sizeof("/") - 1; | 2743 pr->redirect.complex.value.len = conf->url.len |
2760 | 2744 + sizeof("/") - 1; |
2761 p = ngx_pnalloc(cf->pool, pr->redirect.len); | 2745 |
2746 p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); | |
2762 if (p == NULL) { | 2747 if (p == NULL) { |
2763 return NGX_CONF_ERROR; | 2748 return NGX_CONF_ERROR; |
2764 } | 2749 } |
2765 | 2750 |
2766 pr->redirect.data = p; | 2751 pr->redirect.complex.value.data = p; |
2767 | 2752 |
2768 p = ngx_cpymem(p, conf->url.data, conf->url.len); | 2753 p = ngx_cpymem(p, conf->url.data, conf->url.len); |
2769 *p = '/'; | 2754 *p = '/'; |
2770 | 2755 |
2771 ngx_str_set(&pr->replacement.text, "/"); | 2756 ngx_str_set(&pr->replacement.value, "/"); |
2772 } | 2757 } |
2773 } | 2758 } |
2774 } | 2759 } |
2775 | 2760 |
2776 #if (NGX_HTTP_SSL) | 2761 #if (NGX_HTTP_SSL) |
3254 static char * | 3239 static char * |
3255 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 3240 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
3256 { | 3241 { |
3257 ngx_http_proxy_loc_conf_t *plcf = conf; | 3242 ngx_http_proxy_loc_conf_t *plcf = conf; |
3258 | 3243 |
3259 u_char *p; | 3244 u_char *p; |
3260 ngx_str_t *value; | 3245 ngx_str_t *value; |
3261 ngx_array_t *vars_lengths, *vars_values; | 3246 ngx_http_proxy_redirect_t *pr; |
3262 ngx_http_script_compile_t sc; | 3247 ngx_http_compile_complex_value_t ccv; |
3263 ngx_http_proxy_redirect_t *pr; | |
3264 | 3248 |
3265 if (plcf->redirect == 0) { | 3249 if (plcf->redirect == 0) { |
3266 return NGX_CONF_OK; | 3250 return NGX_CONF_OK; |
3267 } | 3251 } |
3268 | 3252 |
3316 "\"proxy_redirect default\" must go " | 3300 "\"proxy_redirect default\" must go " |
3317 "after the \"proxy_pass\" directive"); | 3301 "after the \"proxy_pass\" directive"); |
3318 return NGX_CONF_ERROR; | 3302 return NGX_CONF_ERROR; |
3319 } | 3303 } |
3320 | 3304 |
3321 pr->handler = ngx_http_proxy_rewrite_redirect_text; | 3305 pr->handler = ngx_http_proxy_rewrite_redirect_complex; |
3306 | |
3307 ngx_memzero(&pr->redirect.complex, sizeof(ngx_http_complex_value_t)); | |
3308 | |
3309 ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); | |
3322 | 3310 |
3323 if (plcf->vars.uri.len) { | 3311 if (plcf->vars.uri.len) { |
3324 pr->redirect = plcf->url; | 3312 pr->redirect.complex.value = plcf->url; |
3325 pr->replacement.text = plcf->location; | 3313 pr->replacement.value = plcf->location; |
3326 | 3314 |
3327 } else { | 3315 } else { |
3328 pr->redirect.len = plcf->url.len + sizeof("/") - 1; | 3316 pr->redirect.complex.value.len = plcf->url.len + sizeof("/") - 1; |
3329 | 3317 |
3330 p = ngx_pnalloc(cf->pool, pr->redirect.len); | 3318 p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); |
3331 if (p == NULL) { | 3319 if (p == NULL) { |
3332 return NGX_CONF_ERROR; | 3320 return NGX_CONF_ERROR; |
3333 } | 3321 } |
3334 | 3322 |
3335 pr->redirect.data = p; | 3323 pr->redirect.complex.value.data = p; |
3336 | 3324 |
3337 p = ngx_cpymem(p, plcf->url.data, plcf->url.len); | 3325 p = ngx_cpymem(p, plcf->url.data, plcf->url.len); |
3338 *p = '/'; | 3326 *p = '/'; |
3339 | 3327 |
3340 ngx_str_set(&pr->replacement.text, "/"); | 3328 ngx_str_set(&pr->replacement.value, "/"); |
3341 } | 3329 } |
3342 | 3330 |
3343 return NGX_CONF_OK; | 3331 return NGX_CONF_OK; |
3344 } | 3332 } |
3345 | 3333 |
3346 if (ngx_http_script_variables_count(&value[2]) == 0) { | 3334 |
3347 pr->handler = ngx_http_proxy_rewrite_redirect_text; | 3335 if (value[1].data[0] == '~') { |
3348 pr->redirect = value[1]; | 3336 #if (NGX_PCRE) |
3349 pr->replacement.text = value[2]; | 3337 u_char errstr[NGX_MAX_CONF_ERRSTR]; |
3350 | 3338 ngx_regex_compile_t rc; |
3351 return NGX_CONF_OK; | 3339 |
3352 } | 3340 value[1].len--; |
3353 | 3341 value[1].data++; |
3354 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); | 3342 |
3355 | 3343 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); |
3356 vars_lengths = NULL; | 3344 |
3357 vars_values = NULL; | 3345 if (value[1].data[0] == '*') { |
3358 | 3346 value[1].len--; |
3359 sc.cf = cf; | 3347 value[1].data++; |
3360 sc.source = &value[2]; | 3348 rc.options = NGX_REGEX_CASELESS; |
3361 sc.lengths = &vars_lengths; | 3349 } |
3362 sc.values = &vars_values; | 3350 |
3363 sc.complete_lengths = 1; | 3351 rc.pattern = value[1]; |
3364 sc.complete_values = 1; | 3352 rc.err.len = NGX_MAX_CONF_ERRSTR; |
3365 | 3353 rc.err.data = errstr; |
3366 if (ngx_http_script_compile(&sc) != NGX_OK) { | 3354 |
3355 pr->redirect.regex = ngx_http_regex_compile(cf, &rc); | |
3356 if (pr->redirect.regex == NULL) { | |
3357 return NGX_CONF_ERROR; | |
3358 } | |
3359 | |
3360 pr->handler = ngx_http_proxy_rewrite_redirect_regex; | |
3361 | |
3362 #else | |
3363 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
3364 "using regex \"%V\" requires PCRE library", | |
3365 &value[1]); | |
3366 | |
3367 return NGX_CONF_ERROR; | 3367 return NGX_CONF_ERROR; |
3368 } | 3368 #endif |
3369 | 3369 } else { |
3370 pr->handler = ngx_http_proxy_rewrite_redirect_vars; | 3370 |
3371 pr->redirect = value[1]; | 3371 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
3372 pr->replacement.vars.lengths = vars_lengths->elts; | 3372 |
3373 pr->replacement.vars.values = vars_values->elts; | 3373 ccv.cf = cf; |
3374 ccv.value = &value[1]; | |
3375 ccv.complex_value = &pr->redirect.complex; | |
3376 | |
3377 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { | |
3378 return NGX_CONF_ERROR; | |
3379 } | |
3380 | |
3381 pr->handler = ngx_http_proxy_rewrite_redirect_complex; | |
3382 } | |
3383 | |
3384 | |
3385 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); | |
3386 | |
3387 ccv.cf = cf; | |
3388 ccv.value = &value[2]; | |
3389 ccv.complex_value = &pr->replacement; | |
3390 | |
3391 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { | |
3392 return NGX_CONF_ERROR; | |
3393 } | |
3374 | 3394 |
3375 return NGX_CONF_OK; | 3395 return NGX_CONF_OK; |
3376 } | 3396 } |
3377 | 3397 |
3378 | 3398 |