[nginx] Fixed named captures to don't redefine get handler.

Maxim Dounin mdounin at mdounin.ru
Mon Jun 8 14:56:05 UTC 2026


details:   http://freenginx.org/hg/nginx/rev/623210753d47
branches:  
changeset: 9553:623210753d47
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Mon Jun 08 17:53:50 2026 +0300
description:
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.

diffstat:

 src/http/ngx_http_variables.c     |  7 +++++--
 src/stream/ngx_stream_variables.c |  7 +++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diffs (48 lines):

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