diff src/http/modules/ngx_http_proxy_module.c @ 654:753f505670e0 NGINX_1_1_11

nginx 1.1.11 *) Feature: the "so_keepalive" parameter of the "listen" directive. Thanks to Vsevolod Stakhov. *) Feature: the "if_not_empty" parameter of the "fastcgi/scgi/uwsgi_param" directives. *) Feature: the $https variable. *) Feature: the "proxy_redirect" directive supports variables in the first parameter. *) Feature: the "proxy_redirect" directive supports regular expressions. *) Bugfix: the $sent_http_cache_control variable might contain a wrong value if the "expires" directive was used. Thanks to Yichun Zhang. *) Bugfix: the "read_ahead" directive might not work combined with "try_files" and "open_file_cache". *) Bugfix: a segmentation fault might occur in a worker process if small time was used in the "inactive" parameter of the "proxy_cache_path" directive. *) Bugfix: responses from cache might hang.
author Igor Sysoev <http://sysoev.ru>
date Mon, 12 Dec 2011 00:00:00 +0400
parents f200748c0ac8
children 9d21dad0b5a1
line wrap: on
line diff
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -16,18 +16,15 @@ typedef ngx_int_t (*ngx_http_proxy_redir
 
 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;
+        ngx_http_complex_value_t   complex;
+#if (NGX_PCRE)
+        ngx_http_regex_t          *regex;
+#endif
+    } redirect;
+
+    ngx_http_complex_value_t       replacement;
 };
 
 
@@ -2289,20 +2286,29 @@ ngx_http_proxy_rewrite_redirect(ngx_http
 
 
 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;
-
-    if (pr->redirect.len > h->value.len - prefix
-        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
-                        pr->redirect.len) != 0)
+    size_t      len;
+    u_char     *data, *p;
+    ngx_str_t   redirect, replacement;
+
+    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
 
     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
 }
 
 
+#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;
-
-    if (pr->redirect.len > h->value.len - prefix
-        || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
-                        pr->redirect.len) != 0)
-    {
+    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) {
         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
                 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;
-
-                p = ngx_pnalloc(cf->pool, pr->redirect.len);
+                pr->redirect.complex.value.len = conf->url.len
+                                                 + sizeof("/") - 1;
+
+                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_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, 
             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;
-
-            p = ngx_pnalloc(cf->pool, pr->redirect.len);
+            pr->redirect.complex.value.len = plcf->url.len + sizeof("/") - 1;
+
+            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;
-
-    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) {
+
+    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;
     }
 
-    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;
 }