[PATCH 6 of 7] Fixed try_files to clear r->valid_location

Maxim Dounin mdounin at mdounin.ru
Fri Apr 17 22:45:41 UTC 2026


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1776465870 -10800
#      Sat Apr 18 01:44:30 2026 +0300
# Node ID 75c4159a5ac363763054a2ba49a66f36c45f9bb8
# Parent  8e4422e216d1fdfabeea114deccd722a69f3969c
Fixed try_files to clear r->valid_location.

To minimize compatibility issues, this is only done when the new URI
set by try_files is outside of the static location prefix.  Most notably,
this fixes segfaults as observed with proxy_pass with URI part when
the URI set by try_files is shorter than the location prefix which
proxy_pass tries to replace, for example:

    location /prefix/ {
        try_files /short =404;
        proxy_pass http://u/remote/;
    }

Similarly, this also fixes URI corruption when the URI set by try_files
is longer than the location prefix, but does not match it, as in the
following configuration:

    location /prefix/ {
        try_files /prefix.../test =404;
        proxy_pass http://u/remote/;
    }

Previously, this resulted in the "/remote/../test" URI in the request
to the proxied server (if the "/prefix.../test" file was found).

With this approach, when a file within the location prefix is selected by
try_files, everything works as before.  But when the file is outside of
the prefix, proxying continues as if there were no URI part in proxy_pass,
similarly to how rewrites are handled.

Note that the r->valid_location flag is also used as an indicator that
alias cannot be applied by the ngx_http_map_uri_to_path() function, and
clearing r->valid_location might result in errors in otherwise valid
configurations, for example:

    location /prefix/ {
        alias /foo/;

        location /prefix/nested/ {
            try_files /prefix/bar =404;
        }
    }

To fix this, the r->alias_in_uri flag is now set for all requests using
alias, and it is now additionally checked by ngx_http_map_uri_to_path().

Note well that the test uses clcf->name, which might not be correct for
regex locations (or noname locations inside regex locations).  This is
not an issue for proxy, however, since proxying with URI replacement is
not allowed inside regex locations.

diff --git a/src/http/modules/ngx_http_try_files_module.c b/src/http/modules/ngx_http_try_files_module.c
--- a/src/http/modules/ngx_http_try_files_module.c
+++ b/src/http/modules/ngx_http_try_files_module.c
@@ -113,7 +113,6 @@ ngx_http_try_files_handler(ngx_http_requ
 
     if (alias == NGX_MAX_SIZE_T_VALUE) {
         alias = r->uri.len;
-        r->alias_in_uri = alias;
     }
 
     for ( ;; ) {
@@ -267,6 +266,24 @@ ngx_http_try_files_handler(ngx_http_requ
 
             p = ngx_copy(r->uri.data, name, alias);
             ngx_memcpy(p, path.data, path.len);
+
+            r->alias_in_uri = alias;
+        }
+
+        if (r->valid_location) {
+
+            /*
+             * clear r->valid_location if the new URI
+             * does not match location prefix
+             */
+
+            if (r->uri.len < clcf->name.len
+                || ngx_filename_cmp(r->uri.data, clcf->name.data,
+                                    clcf->name.len)
+                   != 0)
+            {
+                r->valid_location = 0;
+            }
         }
 
         ngx_http_set_exten(r);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1910,7 +1910,7 @@ ngx_http_map_uri_to_path(ngx_http_reques
         alias = r->alias_in_uri ? r->alias_in_uri : r->uri.len;
     }
 
-    if (alias && !r->valid_location) {
+    if (alias && !r->valid_location && !r->alias_in_uri) {
         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                       "\"alias\" cannot be used in location \"%V\" "
                       "where URI was rewritten", &clcf->name);



More information about the nginx-devel mailing list