[PATCH 4 of 6] Fixed named captures to don't redefine get handler

Maxim Dounin mdounin at mdounin.ru
Wed Jun 3 15:46:52 UTC 2026


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1780500569 -10800
#      Wed Jun 03 18:29:29 2026 +0300
# Node ID 54ab4e1a0d1f0d51e98b1b3b998fee4641d00492
# Parent  9fc7ceee87c6fb6f96be73450d715200e3174a11
Fixed named captures to don't redefine get handler.

Previously, named captures unconditionally changed v->get_handler to
ngx_http_variable_not_found(), so merely defining a regular expression
with a named captures was enough to hide an existing variable.  For
example, in the following configuration the $foo variable was always
empty in requests to "/":

    map $uri $foo {
        default "a value from map";
    }

    location / {
        return 200 "value: $foo";
    }

    location ~ /re/(?<foo>.*) {
        return 200 "value: $foo";
    }

Similarly, for variables within an existing prefix, such as for
$http_foo, using a regular expression with a named captures was enough
to hide the original prefix variable.  For example, in the following
configuration the $http_foo variable was always empty in requests to "/",
even if the "Foo" header was present in requests:

    location / {
        return 200 "value: $http_foo";
    }

    location ~ /re/(?<http_foo>.*) {
        return 200 "value: $http_foo";
    }

The fix is to avoid changing v->get_handler if it's already present, and
to use the NGX_HTTP_VAR_WEAK flag to avoid redefining get handler for
prefix variables, similarly to what the "set" directive does.

diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -2589,7 +2589,8 @@ ngx_http_regex_compile(ngx_conf_t *cf, n
         name.data = &p[2];
         name.len = ngx_strlen(name.data);
 
-        v = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
+        v = ngx_http_add_variable(cf, &name,
+                                  NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_WEAK);
         if (v == NULL) {
             return NULL;
         }
@@ -2599,7 +2600,9 @@ ngx_http_regex_compile(ngx_conf_t *cf, n
             return NULL;
         }
 
-        v->get_handler = ngx_http_variable_not_found;
+        if (v->get_handler == NULL) {
+            v->get_handler = ngx_http_variable_not_found;
+        }
 
         p += size;
     }
diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c
--- a/src/stream/ngx_stream_variables.c
+++ b/src/stream/ngx_stream_variables.c
@@ -1072,7 +1072,8 @@ ngx_stream_regex_compile(ngx_conf_t *cf,
         name.data = &p[2];
         name.len = ngx_strlen(name.data);
 
-        v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
+        v = ngx_stream_add_variable(cf, &name,
+                                NGX_STREAM_VAR_CHANGEABLE|NGX_STREAM_VAR_WEAK);
         if (v == NULL) {
             return NULL;
         }
@@ -1082,7 +1083,9 @@ ngx_stream_regex_compile(ngx_conf_t *cf,
             return NULL;
         }
 
-        v->get_handler = ngx_stream_variable_not_found;
+        if (v->get_handler == NULL) {
+            v->get_handler = ngx_stream_variable_not_found;
+        }
 
         p += size;
     }



More information about the nginx-devel mailing list