From fabianofurtado at gmail.com Mon Apr 6 13:16:52 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Mon, 6 Apr 2026 10:16:52 -0300 Subject: 2 minor patches do adjust freenginx name Message-ID: Hi developers! There are 2 minor patches attached to this email to adjust nginx name to freenginx name. Thanks in advance. Fabiano Furtado -------------- next part -------------- A non-text attachment was scrubbed... Name: nginx.c.patch Type: text/x-patch Size: 537 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ngx_setproctitle.c.patch Type: text/x-patch Size: 665 bytes Desc: not available URL: From mdounin at mdounin.ru Tue Apr 7 01:54:32 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 7 Apr 2026 04:54:32 +0300 Subject: 2 minor patches do adjust freenginx name In-Reply-To: References: Message-ID: Hello! On Mon, Apr 06, 2026 at 10:16:52AM -0300, Fabiano Furtado wrote: > There are 2 minor patches attached to this email to adjust nginx name > to freenginx name. The binary is named "nginx", and the same name is used in these two places. The "freenginx" name can be seen in the NGINX_VER_BUILD macro as printed by ngx_show_version_info(). -- Maxim Dounin http://mdounin.ru/ From fabianofurtado at gmail.com Tue Apr 7 12:32:17 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Tue, 7 Apr 2026 09:32:17 -0300 Subject: 2 minor patches do adjust freenginx name In-Reply-To: References: Message-ID: Hi! On Mon, Apr 6, 2026 at 11:00?PM Maxim Dounin wrote: > > Hello! > > On Mon, Apr 06, 2026 at 10:16:52AM -0300, Fabiano Furtado wrote: > > > There are 2 minor patches attached to this email to adjust nginx name > > to freenginx name. > > The binary is named "nginx", and the same name is used in these > two places. The "freenginx" name can be seen in the > NGINX_VER_BUILD macro as printed by ngx_show_version_info(). Sorry to bother you, but could you explain why the freenginx binary is called "nginx"? Thanks in advance. From mdounin at mdounin.ru Wed Apr 8 07:55:33 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 8 Apr 2026 10:55:33 +0300 Subject: 2 minor patches do adjust freenginx name In-Reply-To: References: Message-ID: Hello! On Tue, Apr 07, 2026 at 09:32:17AM -0300, Fabiano Furtado wrote: > On Mon, Apr 6, 2026 at 11:00?PM Maxim Dounin wrote: > > > > Hello! > > > > On Mon, Apr 06, 2026 at 10:16:52AM -0300, Fabiano Furtado wrote: > > > > > There are 2 minor patches attached to this email to adjust nginx name > > > to freenginx name. > > > > The binary is named "nginx", and the same name is used in these > > two places. The "freenginx" name can be seen in the > > NGINX_VER_BUILD macro as printed by ngx_show_version_info(). > > Sorry to bother you, but could you explain why the freenginx binary is > called "nginx"? The freenginx project aims to continue original nginx development and uses the same binary name, as well as other relevant names, such as configuration file name and OpenSSL appname. In particular, this makes switching to freenginx mostly trivial for existing nginx installations, including binary upgrade working flawlessly. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Tue Apr 14 09:30:07 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 14 Apr 2026 12:30:07 +0300 Subject: [nginx] Stable branch. Message-ID: details: http://freenginx.org/hg/nginx/rev/6fe0f4c8690c branches: stable-1.30 changeset: 9496:6fe0f4c8690c user: Maxim Dounin date: Tue Apr 14 11:20:37 2026 +0300 description: Stable branch. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1029007 -#define NGINX_VERSION "1.29.7" +#define nginx_version 1030000 +#define NGINX_VERSION "1.30.0" #define freenginx 1 From mdounin at mdounin.ru Tue Apr 14 09:30:07 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 14 Apr 2026 12:30:07 +0300 Subject: [nginx] Updated OpenSSL used for win32 builds. Message-ID: details: http://freenginx.org/hg/nginx/rev/9354b5fe3dac branches: stable-1.30 changeset: 9497:9354b5fe3dac user: Maxim Dounin date: Tue Apr 14 11:22:43 2026 +0300 description: Updated OpenSSL used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-3.0.19 +OPENSSL = openssl-3.0.20 ZLIB = zlib-1.3.2 PCRE = pcre2-10.47 From mdounin at mdounin.ru Tue Apr 14 09:30:08 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 14 Apr 2026 12:30:08 +0300 Subject: [nginx] freenginx-1.30.0-RELEASE Message-ID: details: http://freenginx.org/hg/nginx/rev/f126ef64a014 branches: stable-1.30 changeset: 9498:f126ef64a014 user: Maxim Dounin date: Tue Apr 14 11:23:26 2026 +0300 description: freenginx-1.30.0-RELEASE diffstat: docs/xml/nginx/changes.xml | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-) diffs (24 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -7,6 +7,20 @@
+ + + + +?????????? ????? 1.30.x. + + +1.30.x stable branch. + + + + + + From mdounin at mdounin.ru Tue Apr 14 09:30:08 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 14 Apr 2026 12:30:08 +0300 Subject: [nginx] release-1.30.0 tag Message-ID: details: http://freenginx.org/hg/nginx/rev/a6f07289dbda branches: stable-1.30 changeset: 9499:a6f07289dbda user: Maxim Dounin date: Tue Apr 14 11:23:27 2026 +0300 description: release-1.30.0 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -493,3 +493,4 @@ 567870bfeb23f2e9c91e2a110d6d332c27c1ceb1 4f4280557d20bc46ebbdc240ffd365f5ca6ce939 release-1.29.5 e4207f631186855d37ac286799c8cd4c9477d166 release-1.29.6 cac0fa5721386abbec57dcc2bb317f2531456e19 release-1.29.7 +f126ef64a014db167927741688c74ffdf1b0fc26 release-1.30.0 From mdounin at mdounin.ru Tue Apr 14 09:32:08 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 14 Apr 2026 12:32:08 +0300 Subject: [nginx-site] freenginx-1.30.0 Message-ID: details: http://freenginx.org/hg/nginx-site/rev/d67473aa4ac0 branches: changeset: 3131:d67473aa4ac0 user: Maxim Dounin date: Tue Apr 14 12:31:27 2026 +0300 description: freenginx-1.30.0 diffstat: text/en/CHANGES-1.30 | 5 +++++ text/ru/CHANGES.ru-1.30 | 5 +++++ xml/index.xml | 29 +++++++++++++++++++++++++++++ xml/versions.xml | 9 ++++++++- 4 files changed, 47 insertions(+), 1 deletions(-) diffs (95 lines): diff --git a/text/en/CHANGES b/text/en/CHANGES-1.30 copy from text/en/CHANGES copy to text/en/CHANGES-1.30 --- a/text/en/CHANGES +++ b/text/en/CHANGES-1.30 @@ -1,4 +1,9 @@ +Changes with freenginx 1.30.0 14 Apr 2026 + + *) 1.30.x stable branch. + + Changes with freenginx 1.29.7 31 Mar 2026 *) Feature: OpenSSL 4.0 compatibility. diff --git a/text/ru/CHANGES.ru b/text/ru/CHANGES.ru-1.30 copy from text/ru/CHANGES.ru copy to text/ru/CHANGES.ru-1.30 --- a/text/ru/CHANGES.ru +++ b/text/ru/CHANGES.ru-1.30 @@ -1,4 +1,9 @@ +????????? ? freenginx 1.30.0 14.04.2026 + + *) ?????????? ????? 1.30.x. + + ????????? ? freenginx 1.29.7 31.03.2026 *) ??????????: ????????????? ? OpenSSL 4.0. diff --git a/xml/index.xml b/xml/index.xml --- a/xml/index.xml +++ b/xml/index.xml @@ -8,6 +8,35 @@ + + +freenginx-1.30.0 +stable version has been released, +incorporating new features and bug fixes from the 1.29.x mainline branch — +including +improved + +handling, + +and + +configuration directives, +connection +limiting +and + +in the mail proxy module, +Encrypted Client Hello (ECH) support, +GeoIP2 databases in the +GeoIP module, +hardening of the +XSLT module, +and more. + + + freenginx-1.29.7 diff --git a/xml/versions.xml b/xml/versions.xml --- a/xml/versions.xml +++ b/xml/versions.xml @@ -10,6 +10,13 @@ + + + + + + + @@ -21,7 +28,7 @@ - + From mdounin at mdounin.ru Fri Apr 17 22:45:35 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:35 +0300 Subject: [PATCH 0 of 7] try_files fixes Message-ID: Hello! The following patch series addresses multiple issues as observed with the "try_files" directive, notably when used with "alias" or when requests are proxied after "try_files". Changes include: - Both variables and static strings in "try_files" arguments are now handled consistently and expected to be in URI space, matching the documentation. Previously, static strings in prefix locations with alias were interpreted as an addition to alias. With this change, configuration like this: location /prefix/ { alias /foo/; try_files /prefix/bar =404; } will actually try the "/foo/bar" file, and not "/foo/prefix/bar", matching what "try_files $uri" does with a request to "/prefix/bar". - In regex locations with alias, "try_files $uri ..." is now properly supported. Previously, only adding extensions worked in such locations, as in "try_files .html ...". Also, using try_files in such locations now produces correct URI. - Proxying with URI replacement after try_files now aware if URI was modified by try_files, and the following configuration will not corrupt URI in requests to backend (or segfault, if URI is shorter than the location prefix), but rather will avoid URI replacement (similarly to what happens after rewrites): location /prefix/ { try_files /prefix.../test =404; proxy_pass http://backend/remote/; } - Proxying after try_files now uses URI modified by try_files even if original unparsed URI is still available, so the following configuration will consistently use the ".html" extension in requests to the backend: location / { try_files $uri.html =404; proxy_pass http://backend; } Review and testing appreciated. -- Maxim Dounin From mdounin at mdounin.ru Fri Apr 17 22:45:36 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:36 +0300 Subject: [PATCH 1 of 7] Version bump In-Reply-To: References: Message-ID: <74f425f1c7650c294435.1776465936@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776465861 -10800 # Sat Apr 18 01:44:21 2026 +0300 # Node ID 74f425f1c7650c29443503ef1934bbe20651c07f # Parent 74fe1629a1a4e04321b7495ad04e0bc26264b843 Version bump. diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1029007 -#define NGINX_VERSION "1.29.7" +#define nginx_version 1031000 +#define NGINX_VERSION "1.31.0" #define freenginx 1 From mdounin at mdounin.ru Fri Apr 17 22:45:37 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:37 +0300 Subject: [PATCH 2 of 7] Fixed try_files with alias on case-insensitive systems In-Reply-To: References: Message-ID: <27388647e0cdc914b874.1776465937@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776465863 -10800 # Sat Apr 18 01:44:23 2026 +0300 # Node ID 27388647e0cdc914b874534d9342b4d59fe5cc68 # Parent 74f425f1c7650c29443503ef1934bbe20651c07f Fixed try_files with alias on case-insensitive systems. Previously, checking that try_files with variables matches an aliased location was done using ngx_strncmp() rather than ngx_filename_cmp(). This works correctly in configurations with $uri, such as: location /prefix/ { alias /foo/; try_files $uri =404; } But this can produce unexpected results on systems with case-insensitive filesystems, such as Windows and macOS, when configuration-provided variables are used to construct file names, such as the following configuration, and assuming a request using different case, such as "GET /Prefix/": location /prefix/ { alias /foo/; set $maintenance "/prefix/maintenance.html"; try_files $maintenance $uri =404; } The fix is to use ngx_filename_cmp(), which properly ignores case on relevant systems. 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 @@ -176,7 +176,7 @@ ngx_http_try_files_handler(ngx_http_requ *e.pos = '\0'; if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_strncmp(name, r->uri.data, alias) == 0) + && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; From mdounin at mdounin.ru Fri Apr 17 22:45:38 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:38 +0300 Subject: [PATCH 3 of 7] Fixed try_files in locations with alias and static strings In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1776465864 -10800 # Sat Apr 18 01:44:24 2026 +0300 # Node ID aad0fdcc2e33df5ae75f6753028b1bf51bcf4d87 # Parent 27388647e0cdc914b874534d9342b4d59fe5cc68 Fixed try_files in locations with alias and static strings. Previously, a configuration like: location /prefix/ { alias /foo/; try_files /prefix/bar =404; } tried the "/foo/prefix/bar" file, unless variables were used in the argument. Similarly, location /prefix/ { alias /foo/; set $fallback /prefix/bar; try_files ... $fallback; } incorrectly redirected to "/bar" instead of "/prefix/bar" if no files were found (and variables were used in the fallback argument). The fix is to move alias prefix matching to a point after fallback handling, and do it for both variables and static strings. 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 @@ -174,23 +174,12 @@ ngx_http_try_files_handler(ngx_http_requ path.len = e.pos - path.data; *e.pos = '\0'; - - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, alias) == 0) - { - ngx_memmove(name, name + alias, len - alias); - path.len -= alias; - } } test_dir = tf->test_dir; tf++; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "trying to use %s: \"%s\" \"%s\"", - test_dir ? "dir" : "file", name, path.data); - if (tf->lengths == NULL && tf->name.len == 0) { if (tf->code) { @@ -213,6 +202,17 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_filename_cmp(name, r->uri.data, alias) == 0) + { + ngx_memmove(name, name + alias, len - alias); + path.len -= alias; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "trying to use %s: \"%s\" \"%s\"", + test_dir ? "dir" : "file", name, path.data); + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; From mdounin at mdounin.ru Fri Apr 17 22:45:39 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:39 +0300 Subject: [PATCH 4 of 7] Support for "try_files $uri ..." in regex locations with alias In-Reply-To: References: Message-ID: <4c206d68284ead757da2.1776465939@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776465866 -10800 # Sat Apr 18 01:44:26 2026 +0300 # Node ID 4c206d68284ead757da213f8ff2a55e960b64a4a # Parent aad0fdcc2e33df5ae75f6753028b1bf51bcf4d87 Support for "try_files $uri ..." in regex locations with alias. Previously, only adding extensions were supported by try_files when used in a regex location with alias, such as in (3534:3711bb1336c3): location ~ /files/(.*) { alias /path/to/$1; try_files .html "" / =404; } With this change, try_files now able to properly handle configurations with $uri being used, similarly to other configurations with try_files, such as in: location ~ /files/(.*) { alias /path/to/$1; try_files $uri.html $uri $uri/ =404; } Note though that this change will break configurations similar to the one in 6226:4bc94faeff66, where alias and try_files in a regex location are used instead of root. 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 @@ -202,8 +202,14 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, alias) == 0) + if (alias == NGX_MAX_SIZE_T_VALUE + && ngx_filename_cmp(name, r->uri.data, r->uri.len) == 0) + { + ngx_memmove(name, name + r->uri.len, len - r->uri.len); + path.len -= r->uri.len; + + } else if (alias + && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; From mdounin at mdounin.ru Fri Apr 17 22:45:40 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:40 +0300 Subject: [PATCH 5 of 7] Reworked try_files in regex locations with alias In-Reply-To: References: Message-ID: <8e4422e216d1fdfabeea.1776465940@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776465868 -10800 # Sat Apr 18 01:44:28 2026 +0300 # Node ID 8e4422e216d1fdfabeea114deccd722a69f3969c # Parent 4c206d68284ead757da213f8ff2a55e960b64a4a Reworked try_files in regex locations with alias. Instead of using special cases for "alias == NGX_MAX_SIZE_T_VALUE" everywhere, we now set alias to r->uri.len when working with such locations. And the r->add_uri_to_alias flag is replaced by the r->alias_in_uri flag, which specifies the URI prefix already covered by alias. This simplifies the code, and also fixes various issues with URI being incorrect after try_files match in such 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 @@ -111,6 +111,11 @@ ngx_http_try_files_handler(ngx_http_requ alias = clcf->alias; + if (alias == NGX_MAX_SIZE_T_VALUE) { + alias = r->uri.len; + r->alias_in_uri = alias; + } + for ( ;; ) { if (tf->lengths) { @@ -134,9 +139,6 @@ ngx_http_try_files_handler(ngx_http_requ if (!alias) { reserve = len > r->uri.len ? len - r->uri.len : 0; - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - reserve = len; - } else { reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; } @@ -202,15 +204,7 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } - if (alias == NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, r->uri.len) == 0) - { - ngx_memmove(name, name + r->uri.len, len - r->uri.len); - path.len -= r->uri.len; - - } else if (alias - && ngx_filename_cmp(name, r->uri.data, alias) == 0) - { + if (alias && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; } @@ -261,12 +255,6 @@ ngx_http_try_files_handler(ngx_http_requ if (!alias) { r->uri = path; - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!test_dir) { - r->uri = path; - r->add_uri_to_alias = 1; - } - } else { name = r->uri.data; 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 @@ -977,6 +977,7 @@ ngx_http_core_find_config_phase(ngx_http r->content_handler = NULL; r->uri_changed = 0; + r->alias_in_uri = 0; rc = ngx_http_core_find_location(r); @@ -1905,6 +1906,10 @@ ngx_http_map_uri_to_path(ngx_http_reques alias = clcf->alias; + if (alias == NGX_MAX_SIZE_T_VALUE) { + alias = r->alias_in_uri ? r->alias_in_uri : r->uri.len; + } + if (alias && !r->valid_location) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "\"alias\" cannot be used in location \"%V\" " @@ -1912,7 +1917,7 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - if (alias > r->uri.len && alias != NGX_MAX_SIZE_T_VALUE) { + if (alias > r->uri.len) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "URI shorter than aliased URI part"); return NULL; @@ -1933,12 +1938,7 @@ ngx_http_map_uri_to_path(ngx_http_reques } else { - if (alias == NGX_MAX_SIZE_T_VALUE) { - reserved += r->add_uri_to_alias ? r->uri.len + 1 : 1; - - } else { - reserved += r->uri.len - alias + 1; - } + reserved += r->uri.len - alias + 1; if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, clcf->root_values->elts) @@ -1955,15 +1955,6 @@ ngx_http_map_uri_to_path(ngx_http_reques *root_length = path->len - reserved; last = path->data + *root_length; - - if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!r->add_uri_to_alias) { - *last = '\0'; - return last; - } - - alias = 0; - } } last = ngx_copy(last, r->uri.data + alias, r->uri.len - alias); @@ -2566,7 +2557,7 @@ ngx_http_internal_redirect(ngx_http_requ r->internal = 1; r->valid_unparsed_uri = 0; - r->add_uri_to_alias = 0; + r->alias_in_uri = 0; r->main->count++; ngx_http_handler(r); @@ -2626,6 +2617,7 @@ ngx_http_named_location(ngx_http_request r->internal = 1; r->content_handler = NULL; r->uri_changed = 0; + r->alias_in_uri = 0; r->loc_conf = (*clcfp)->loc_conf; /* clear the modules contexts */ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -446,6 +446,8 @@ struct ngx_http_request_s { u_char *captures_data; #endif + size_t alias_in_uri; + size_t limit_rate; size_t limit_rate_after; @@ -492,7 +494,6 @@ struct ngx_http_request_s { unsigned invalid_header:1; - unsigned add_uri_to_alias:1; unsigned valid_location:1; unsigned valid_unparsed_uri:1; unsigned uri_changed:1; From mdounin at mdounin.ru Fri Apr 17 22:45:41 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:41 +0300 Subject: [PATCH 6 of 7] Fixed try_files to clear r->valid_location In-Reply-To: References: Message-ID: <75c4159a5ac363763054.1776465941@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # 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); From mdounin at mdounin.ru Fri Apr 17 22:45:42 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:45:42 +0300 Subject: [PATCH 7 of 7] Fixed try_files to clear r->valid_unparsed_uri In-Reply-To: References: Message-ID: <5158f263a08ebf771139.1776465942@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776465873 -10800 # Sat Apr 18 01:44:33 2026 +0300 # Node ID 5158f263a08ebf7711392744296a1c12261924e3 # Parent 75c4159a5ac363763054a2ba49a66f36c45f9bb8 Fixed try_files to clear r->valid_unparsed_uri. Most notably, with this change any URI changes made by try_files are visible with proxy_pass without URI, such as in the following configuration: location / { try_files $uri $uri.html =404; proxy_pass http://u; } Previously, such URI changes were only visible if URI was previously changed by a rewrite or an internal redirect. To minimize compatibility issues, this is only done when the new URI is not equal to the original one. That is, a configuration like this will work as before, preserving the original URI as sent by the client: location / { try_files $uri =404; proxy_pass http://u; } Note that URI checking uses ngx_strncmp() rather than ngx_filename_cmp() to properly reflect case-only changes on case-insensitive systems as well. 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 @@ -251,12 +251,13 @@ ngx_http_try_files_handler(ngx_http_requ path.len -= root; path.data += root; + name = r->uri.data; + len = r->uri.len; + if (!alias) { r->uri = path; } else { - name = r->uri.data; - r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { @@ -283,6 +284,18 @@ ngx_http_try_files_handler(ngx_http_requ != 0) { r->valid_location = 0; + r->valid_unparsed_uri = 0; + } + } + + if (r->valid_unparsed_uri) { + + /* clear r->valid_unparsed_uri if URI was changed */ + + if (r->uri.len != len + || ngx_strncmp(r->uri.data, name, len) != 0) + { + r->valid_unparsed_uri = 0; } } From mdounin at mdounin.ru Fri Apr 17 22:50:20 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:20 +0300 Subject: [PATCH 1 of 7] Tests: sorted try_files locations for better locality In-Reply-To: References: Message-ID: <2e3ccde7b2a0e44ed512.1776466220@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776466161 -10800 # Sat Apr 18 01:49:21 2026 +0300 # Node ID 2e3ccde7b2a0e44ed512d324333424057a57d4fe # Parent 1b153e4703cf27768ce20fa6fede2a032a4ef254 Tests: sorted try_files locations for better locality. diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -42,10 +42,18 @@ http { try_files $uri /fallback; } + location /fallback { + proxy_pass http://127.0.0.1:8081/fallback; + } + location /nouri/ { try_files $uri /fallback-nouri; } + location /fallback-nouri { + proxy_pass http://127.0.0.1:8081; + } + location /short/ { try_files /short $uri =404; } @@ -77,13 +85,6 @@ http { try_files $uri =404; } } - - location /fallback { - proxy_pass http://127.0.0.1:8081/fallback; - } - location /fallback-nouri { - proxy_pass http://127.0.0.1:8081; - } } server { From mdounin at mdounin.ru Fri Apr 17 22:50:21 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:21 +0300 Subject: [PATCH 2 of 7] Tests: try_files in a regex location with alias additional tests In-Reply-To: References: Message-ID: <764b07be5a7404745664.1776466221@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1775283321 -10800 # Sat Apr 04 09:15:21 2026 +0300 # Node ID 764b07be5a74047456643df286ffb0b9149bcea4 # Parent 2e3ccde7b2a0e44ed512d324333424057a57d4fe Tests: try_files in a regex location with alias additional tests. When alias is used in a regex location, alias is expected to specify full file system path to the file corresponding to the request. When try_files is used in such a location, it is expected to be able to add extensions to the path, such as in the following configuration (see 3534:3711bb1336c3): location ~ ^/users/(.*)/files/(.*) { alias /files/$1/$2; try_files .html "" / =404; } Previously, the only test was for the bug (fixed by 6226:4bc94faeff66), where a configuration is essentially misuses alias with try_files instead of root. That is, all requests are mapped to a single file path using alias, and then try_files used to add $uri to this path: location ~ /mail { alias /path/to/directory; try_files $uri =404; } While handling such case without a segmentation fault is important, it is not to be confused with intended try_files usage. Further, handling of this specific case is expected to be changed to universally support aliased prefix replacement and configurations like this: location ~ ^/users/(.*)/files/(.*) { alias /files/$1/$2; try_files $uri.html $uri $uri/ =404; } That is, with matching URI part (the whole URI for regex locations) replaced with alias, so "try_files $uri.html ..." will be universally interpreted as $request_filename with the ".html" extension added in all cases (with root, alias, and alias in regex location). diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(10) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(12) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -79,6 +79,16 @@ http { try_files $uri =404; } + location ~ /alias-re-add/(.*) { + alias %%TESTDIR%%/$1; + try_files .htm .html =404; + } + + location ~ /alias-re-prefix/(.*) { + alias %%TESTDIR%%/$1; + try_files $uri.htm $uri.html =404; + } + location /alias-nested/ { alias %%TESTDIR%%/; location ~ html { @@ -117,7 +127,19 @@ like(http_get('/file-dir/'), qr!404 Not! like(http_get('/dir-dir/'), qr!301 Moved Permanently!, 'dir matches dir'); like(http_get('/dir-file/'), qr!404 Not!, 'dir does not match file'); -like(http_get('/alias-re.html'), qr!SEE THIS!, 'alias in regex location'); +like(http_get('/alias-re.html'), qr!SEE THIS|404 Not!, + 'alias in regex location as root'); +like(http_get('/alias-re-add/found'), qr!SEE THIS!, + 'alias in regex location with just extension'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-re-prefix/found'), qr!SEE THIS!, + 'alias in regex location with uri prefix'); + +} + like(http_get('/alias-nested/found.html'), qr!SEE THIS!, 'alias with nested location'); From mdounin at mdounin.ru Fri Apr 17 22:50:22 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:22 +0300 Subject: [PATCH 3 of 7] Tests: try_files with alias additional tests In-Reply-To: References: Message-ID: <1b0215d2bf862ceabc93.1776466222@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776466165 -10800 # Sat Apr 18 01:49:25 2026 +0300 # Node ID 1b0215d2bf862ceabc938de20e9e65d025d39a3d # Parent 764b07be5a74047456643df286ffb0b9149bcea4 Tests: try_files with alias additional tests. diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(12) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(17) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -95,6 +95,34 @@ http { try_files $uri =404; } } + + location /alias-static/ { + alias %%TESTDIR%%/; + try_files /alias-static/found.html =404; + } + + location /alias-vars/ { + alias %%TESTDIR%%/; + set $file /alias-vars/found.html; + try_files $file =404; + } + + location /alias-fallback-static/ { + alias %%TESTDIR%%/; + try_files $uri /alias-fallback-static/found.html; + } + + location /alias-fallback-vars/ { + alias %%TESTDIR%%/; + set $fallback /alias-fallback-vars/found.html; + try_files $uri $fallback; + } + + location /alias-caseless/ { + alias %%TESTDIR%%/; + set $file /alias-caseless/found.html; + try_files $file =404; + } } server { @@ -143,4 +171,47 @@ like(http_get('/alias-re-prefix/found'), like(http_get('/alias-nested/found.html'), qr!SEE THIS!, 'alias with nested location'); +# when a file matches location prefix covered by alias, +# prefix needs to be removed; this used to work only with +# variables, but not with static strings + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-static/found.html'), qr!SEE THIS!, + 'alias with static string'); + +} + +like(http_get('/alias-vars/found.html'), qr!SEE THIS!, + 'alias with variables'); + +# in contrast, for the fallback URI we don't need to remove +# anything (yet it was removed with variables) + +like(http_get('/alias-fallback-static/notfound'), qr!SEE THIS!, + 'alias fallback to matching static string'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-fallback-vars/notfound'), qr!SEE THIS!, + 'alias fallback to matching string with variables'); + +} + +# with caseless systems, aliased prefix needs to be checked in a +# case-insensitive way; this automatically happens with "try_files $uri", +# since aliased prefix is compared to the original request URI, but was +# not working with configuration-provided paths + +SKIP: { +skip 'not caseless os', 1 + unless $^O eq 'MSWin32' or $^O eq 'darwin'; +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-CASELESS/found.html'), qr!SEE THIS!, 'alias caseless'); + +} + ############################################################################### From mdounin at mdounin.ru Fri Apr 17 22:50:23 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:23 +0300 Subject: [PATCH 4 of 7] Tests: additional try_files test with nested prefix location In-Reply-To: References: Message-ID: <6ea4efddc9a36f034e3a.1776466223@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776466173 -10800 # Sat Apr 18 01:49:33 2026 +0300 # Node ID 6ea4efddc9a36f034e3a8420414a52daac62004e # Parent 1b0215d2bf862ceabc938de20e9e65d025d39a3d Tests: additional try_files test with nested prefix location. diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(17) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(18) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -91,9 +91,14 @@ http { location /alias-nested/ { alias %%TESTDIR%%/; + location ~ html { try_files $uri =404; } + + location /alias-nested/prefix { + try_files /found.html =404; + } } location /alias-static/ { @@ -169,7 +174,9 @@ like(http_get('/alias-re-prefix/found'), } like(http_get('/alias-nested/found.html'), qr!SEE THIS!, - 'alias with nested location'); + 'alias with nested regex location'); +like(http_get('/alias-nested/prefix'), qr!SEE THIS!, + 'alias with nested prefix location'); # when a file matches location prefix covered by alias, # prefix needs to be removed; this used to work only with From mdounin at mdounin.ru Fri Apr 17 22:50:24 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:24 +0300 Subject: [PATCH 5 of 7] Tests: try_files tests with proxying In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1776466184 -10800 # Sat Apr 18 01:49:44 2026 +0300 # Node ID d384c458eae03012252c37694a8f81b01d932817 # Parent 6ea4efddc9a36f034e3a8420414a52daac62004e Tests: try_files tests with proxying. Most notably, when URI is changed by try_files to something that does not match the location prefix, the code tried to replace things anyway (and caused a segfault if the URI set by try_files was shorter than the location prefix). diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(18) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(23) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -128,6 +128,32 @@ http { set $file /alias-caseless/found.html; try_files $file =404; } + + location /prefix-proxy/ { + try_files $uri =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + + location /prefix-proxy-alias/ { + alias %%TESTDIR%%/; + try_files $uri =404; + proxy_pass http://127.0.0.1:8081/changed/; + + location /prefix-proxy-alias/nested-short { + try_files /prefix-proxy-alias/nested =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + } + + location /prefix-proxy-long/ { + try_files /prefix-proxy/found.html =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + + location /prefix-proxy-short/ { + try_files /found.html =404; + proxy_pass http://127.0.0.1:8081/changed/; + } } server { @@ -143,9 +169,12 @@ http { EOF +$t->write_file('found.html', 'SEE THIS'); +$t->write_file('nested', 'SEE THIS'); mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); -$t->write_file('found.html', 'SEE THIS'); +mkdir($t->testdir() . '/prefix-proxy/'); +$t->write_file('prefix-proxy/found.html', 'SEE THIS'); $t->run(); ############################################################################### @@ -221,4 +250,34 @@ like(http_get('/alias-CASELESS/found.htm } +# when an URI is changed by try_files, this could be a surprise +# for proxy_pass with URI part + +like(http_get('/prefix-proxy/found.html'), qr!X-URI: /changed/found.html!, + 'proxy after try_files'); +like(http_get('/prefix-proxy-alias/found.html'), + qr!X-URI: /changed/found.html!, 'proxy after try_files with alias'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/prefix-proxy-long/found.html'), + qr!X-URI: /prefix-proxy/found.html!, 'proxy after try_files no match'); + +} + +TODO: { +todo_skip 'leaves coredump', 2 + unless $t->has_version('1.31.0') or $ENV{TEST_NGINX_UNSAFE}; +local $TODO = 'not yet', $t->todo_alerts() + unless $t->has_version('1.31.0'); + +like(http_get('/prefix-proxy-short/foo'), qr!X-URI: /found.html!, + 'proxy after try_files with short uri'); +like(http_get('/prefix-proxy-alias/nested-short'), + qr!X-URI: /prefix-proxy-alias/nested!, + 'proxy after try_files with short uri, alias nested'); + +} + ############################################################################### From mdounin at mdounin.ru Fri Apr 17 22:50:25 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:25 +0300 Subject: [PATCH 6 of 7] Tests: try_files with proxying without URI part In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1776466186 -10800 # Sat Apr 18 01:49:46 2026 +0300 # Node ID e6cd7d62aff1676e567e039c61bc6470b60de39b # Parent d384c458eae03012252c37694a8f81b01d932817 Tests: try_files with proxying without URI part. Proxying without URI part uses original unparsed URI if available, yet since try_files modifies the effective URI, it should use the modified URI after try_files. This is what used to happen if the URI was rewritten or changed by an index redirection, and then modified by try_files. diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(23) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(29) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -154,6 +154,32 @@ http { try_files /found.html =404; proxy_pass http://127.0.0.1:8081/changed/; } + + location /uri-after/ { + rewrite ^/uri-after/rewrite /uri-after/notfound break; + try_files /uri-after/found.html =404; + proxy_pass http://127.0.0.1:8081; + } + + location /uri-after-alias/ { + alias %%TESTDIR%%/; + try_files /uri-after-alias/found.html =404; + proxy_pass http://127.0.0.1:8081; + } + + location = /uri-after-alias-redirect { + try_files /notfound /uri-after-alias/found; + } + + location ~ /uri-after-alias-add/(.*) { + alias %%TESTDIR%%/$1; + try_files .htm .html =404; + proxy_pass http://127.0.0.1:8081; + } + + location = /uri-after-alias-add-redirect { + try_files /notfound /uri-after-alias-add/found; + } } server { @@ -175,6 +201,8 @@ mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); mkdir($t->testdir() . '/prefix-proxy/'); $t->write_file('prefix-proxy/found.html', 'SEE THIS'); +mkdir($t->testdir() . '/uri-after/'); +$t->write_file('uri-after/found.html', 'SEE THIS'); $t->run(); ############################################################################### @@ -280,4 +308,49 @@ like(http_get('/prefix-proxy-alias/neste } +# try_files changes URI, so make sure that proxy_pass without the URI part +# uses the modified URI, and not the original unparsed URI + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after/found'), qr!X-URI: /uri-after/found.html!, + 'proxy without uri, unparsed uri not used'); + +} + +like(http_get('/uri-after/rewrite'), qr!X-URI: /uri-after/found.html!, + 'proxy without uri, after rewrite'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after-alias/found'), + qr!X-URI: /uri-after-alias/found.html!, + 'proxy without uri, alias'); + +like(http_get('/uri-after-alias-redirect'), + qr!X-URI: /uri-after-alias/found.html!, + 'proxy without uri, alias, after redirect'); + +} + +# when try_files adds an extension in a regex location with alias, +# this used to result in bogus URI (".html") and the r->add_uri_to_alias +# flag set; this was handled by ngx_http_map_uri_to_alias() and worked for +# static files, but produced unexpected results when proxying + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after-alias-add/found'), + qr!X-URI: /uri-after-alias-add/found.html!, + 'proxy without uri, alias in regex location'); + +like(http_get('/uri-after-alias-add-redirect'), + qr!X-URI: /uri-after-alias-add/found.html!, + 'proxy without uri, alias in regex location, after redirect'); + +} + ############################################################################### From mdounin at mdounin.ru Fri Apr 17 22:50:26 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 18 Apr 2026 01:50:26 +0300 Subject: [PATCH 7 of 7] Tests: added more basic try_files tests In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1776466189 -10800 # Sat Apr 18 01:49:49 2026 +0300 # Node ID ff476932c9806e6b8b6d9d934186fb9e43aa7aee # Parent e6cd7d62aff1676e567e039c61bc6470b60de39b Tests: added more basic try_files tests. diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(29) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(48) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -39,6 +39,25 @@ http { server_name localhost; location / { + try_files $uri $uri.html $uri/ =404; + } + + location /alias/ { + alias %%TESTDIR%%/; + try_files $uri $uri.html $uri/ =404; + } + + location ~ /alias-re-add/(.*) { + alias %%TESTDIR%%/$1; + try_files "" .html / =404; + } + + location ~ /alias-re-prefix/(.*) { + alias %%TESTDIR%%/$1; + try_files $uri $uri.html $uri/ =404; + } + + location /uri/ { try_files $uri /fallback; } @@ -79,16 +98,6 @@ http { try_files $uri =404; } - location ~ /alias-re-add/(.*) { - alias %%TESTDIR%%/$1; - try_files .htm .html =404; - } - - location ~ /alias-re-prefix/(.*) { - alias %%TESTDIR%%/$1; - try_files $uri.htm $uri.html =404; - } - location /alias-nested/ { alias %%TESTDIR%%/; @@ -199,6 +208,7 @@ EOF $t->write_file('nested', 'SEE THIS'); mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); +$t->write_file('directory/index.html', 'SEE THIS'); mkdir($t->testdir() . '/prefix-proxy/'); $t->write_file('prefix-proxy/found.html', 'SEE THIS'); mkdir($t->testdir() . '/uri-after/'); @@ -207,7 +217,40 @@ mkdir($t->testdir() . '/uri-after/'); ############################################################################### -like(http_get('/found.html'), qr!SEE THIS!, 'found'); +# basic tests with "try_files $uri $uri.html $uri/ =404" + +like(http_get('/found.html'), qr!SEE THIS!, 'root $uri'); +like(http_get('/found'), qr!SEE THIS!, 'root $uri.html'); +like(http_get('/directory'), qr!301 Moved Permanently!, 'root $uri/ redirect'); +like(http_get('/directory/'), qr!SEE THIS!, 'root $uri/ index'); +like(http_get('/notfound'), qr!404 Not!, 'root not found'); + +like(http_get('/alias/found.html'), qr!SEE THIS!, 'alias $uri'); +like(http_get('/alias/found'), qr!SEE THIS!, 'alias $uri.html'); +like(http_get('/alias/directory'), qr!301 Moved Permanently!, 'alias $uri/ redirect'); +like(http_get('/alias/directory/'), qr!SEE THIS!, 'alias $uri/ index'); +like(http_get('/alias/notfound'), qr!404 Not!, 'alias not found'); + +like(http_get('/alias-re-add/found.html'), qr!SEE THIS!, 'alias regex ""'); +like(http_get('/alias-re-add/found'), qr!SEE THIS!, 'alias regex .html'); +like(http_get('/alias-re-add/directory'), qr!301 Moved Permanently!, 'alias regex / redirect'); +like(http_get('/alias-re-add/directory/'), qr!SEE THIS!, 'alias regex / index'); +like(http_get('/alias-re-add/notfound'), qr!404 Not!, 'alias regex not found'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-re-prefix/found.html'), qr!SEE THIS!, 'alias regex $uri'); +like(http_get('/alias-re-prefix/found'), qr!SEE THIS!, 'alias regex $uri.html'); +like(http_get('/alias-re-prefix/directory'), qr!301 Moved Permanently!, 'alias regex $uri/ redirect'); +like(http_get('/alias-re-prefix/directory/'), qr!SEE THIS!, 'alias regex $uri/ index'); + +} + +like(http_get('/alias-re-prefix/notfound'), qr!404 Not!, 'alias regex not found with prefix'); + +# various specific tests + like(http_get('/uri/notfound'), qr!X-URI: /fallback!, 'not found uri'); like(http_get('/nouri/notfound'), qr!X-URI: /fallback!, 'not found nouri'); like(http_get('/short/long'), qr!404 Not!, 'short uri in try_files'); From fabianofurtado at gmail.com Sat Apr 18 21:40:43 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Sat, 18 Apr 2026 18:40:43 -0300 Subject: [PATCH] New directive and variable to log module Message-ID: Dear freenginx developers, I would appreciate it if you could take a look at this patch and provide your feedback or suggestions for improvements, or let me know if you think it would be a valuable addition to the project. This patch introduces the new "log_tag" directive to freenginx, which allows you to define a custom tag for each http, server or location block. This tag is then referenced using the "$tag" variable within the "log_format" directive, making it easier to filter and match logs, especially in configurations with many location blocks or complex ones using regular expressions. As an alternative, the directive and variable could be named as: * "log_label" / "$label" * "log_id" / "$id" Thanks in advance. Fabiano Furtado -------------- next part -------------- A non-text attachment was scrubbed... Name: ngx_http_log_module.c.patch Type: text/x-patch Size: 5958 bytes Desc: not available URL: From mdounin at mdounin.ru Sun Apr 19 17:51:08 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 19 Apr 2026 20:51:08 +0300 Subject: [PATCH] New directive and variable to log module In-Reply-To: References: Message-ID: Hello! On Sat, Apr 18, 2026 at 06:40:43PM -0300, Fabiano Furtado wrote: > Dear freenginx developers, > > I would appreciate it if you could take a look at this patch and > provide your feedback or suggestions for improvements, or let me know > if you think it would be a valuable addition to the project. > > This patch introduces the new "log_tag" directive to freenginx, which > allows you to define a custom tag for each http, server or location > block. This tag is then referenced using the "$tag" variable within > the "log_format" directive, making it easier to filter and match logs, > especially in configurations with many location blocks or complex ones > using regular expressions. > > As an alternative, the directive and variable could be named as: > * "log_label" / "$label" > * "log_id" / "$id" First of all, I would like to note that there should be no log-specific variables. All variables should be universally supported by the generic variables infrastructure, without exceptions. In particular, this is an important factor to properly support alternative logging modules. Last log-specific variables were changed to universally supported ones in nginx 1.3.12 in Feb 2013 (http://freenginx.org/hg/nginx/rev/829cc5872186). Variables handled directly by the access log module exist only as an optimization and exactly match corresponding generic variables. As for the idea of introducing a (generic) variable to identify locations used to handle the request, I don't have a strong opinion here. If I understand the use case correctly, my personal approach would be to use "set" to construct appropriate variables while in progress, and rewrite the configuration to something manageable as soon as possible. -- Maxim Dounin http://mdounin.ru/ From fabianofurtado at gmail.com Wed Apr 22 16:33:52 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Wed, 22 Apr 2026 13:33:52 -0300 Subject: [PATCH] New directive and variable to log module In-Reply-To: References: Message-ID: Hi! On Sun, Apr 19, 2026 at 2:51?PM Maxim Dounin wrote: > > Hello! > > On Sat, Apr 18, 2026 at 06:40:43PM -0300, Fabiano Furtado wrote: > > > Dear freenginx developers, > > > > I would appreciate it if you could take a look at this patch and > > provide your feedback or suggestions for improvements, or let me know > > if you think it would be a valuable addition to the project. > > > > This patch introduces the new "log_tag" directive to freenginx, which > > allows you to define a custom tag for each http, server or location > > block. This tag is then referenced using the "$tag" variable within > > the "log_format" directive, making it easier to filter and match logs, > > especially in configurations with many location blocks or complex ones > > using regular expressions. > > > > As an alternative, the directive and variable could be named as: > > * "log_label" / "$label" > > * "log_id" / "$id" > > First of all, I would like to note that there should be no > log-specific variables. All variables should be universally > supported by the generic variables infrastructure, without > exceptions. In particular, this is an important factor to > properly support alternative logging modules. > > Last log-specific variables were changed to universally supported > ones in nginx 1.3.12 in Feb 2013 > (http://freenginx.org/hg/nginx/rev/829cc5872186). Variables > handled directly by the access log module exist only as an > optimization and exactly match corresponding generic variables. > > As for the idea of introducing a (generic) variable to identify > locations used to handle the request, I don't have a strong > opinion here. If I understand the use case correctly, my personal > approach would be to use "set" to construct appropriate variables > while in progress, and rewrite the configuration to something > manageable as soon as possible. First of all, thank you for the explanations. I tested the "set" directive and it worked well. However, why doesn?t it have NGX_HTTP_MAIN_CONF visibility in its context? I believe it could be used inside the "http{}" block with a default value for all "server{}" blocks. Thanks in advance. Fabiano Furtado From mdounin at mdounin.ru Thu Apr 23 00:18:02 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 23 Apr 2026 03:18:02 +0300 Subject: [PATCH] New directive and variable to log module In-Reply-To: References: Message-ID: Hello! On Wed, Apr 22, 2026 at 01:33:52PM -0300, Fabiano Furtado wrote: > Hi! > > On Sun, Apr 19, 2026 at 2:51?PM Maxim Dounin wrote: > > > > Hello! > > > > On Sat, Apr 18, 2026 at 06:40:43PM -0300, Fabiano Furtado wrote: > > > > > Dear freenginx developers, > > > > > > I would appreciate it if you could take a look at this patch and > > > provide your feedback or suggestions for improvements, or let me know > > > if you think it would be a valuable addition to the project. > > > > > > This patch introduces the new "log_tag" directive to freenginx, which > > > allows you to define a custom tag for each http, server or location > > > block. This tag is then referenced using the "$tag" variable within > > > the "log_format" directive, making it easier to filter and match logs, > > > especially in configurations with many location blocks or complex ones > > > using regular expressions. > > > > > > As an alternative, the directive and variable could be named as: > > > * "log_label" / "$label" > > > * "log_id" / "$id" > > > > First of all, I would like to note that there should be no > > log-specific variables. All variables should be universally > > supported by the generic variables infrastructure, without > > exceptions. In particular, this is an important factor to > > properly support alternative logging modules. > > > > Last log-specific variables were changed to universally supported > > ones in nginx 1.3.12 in Feb 2013 > > (http://freenginx.org/hg/nginx/rev/829cc5872186). Variables > > handled directly by the access log module exist only as an > > optimization and exactly match corresponding generic variables. > > > > As for the idea of introducing a (generic) variable to identify > > locations used to handle the request, I don't have a strong > > opinion here. If I understand the use case correctly, my personal > > approach would be to use "set" to construct appropriate variables > > while in progress, and rewrite the configuration to something > > manageable as soon as possible. > > First of all, thank you for the explanations. > > I tested the "set" directive and it worked well. However, why doesn?t > it have NGX_HTTP_MAIN_CONF visibility in its context? I believe it > could be used inside the "http{}" block with a default value for all > "server{}" blocks. The "set" directive is a rewrite module instruction, and it defines an action which is executed when rewrite instructions are executed, see here for details: https://freenginx.org/en/docs/http/ngx_http_rewrite_module.html That is, the directive itself is not about providing a default value, it's about changing a variable. And it is only available in contexts where rewrite instructions are expected to appear. If you need some default value and not happy with an empty string as the default, consider using a map to provide one, for example: map "" $tag { default "foo"; } This will define a variable with "foo" as a default value, and it will be possible to change the variable with "set" where appropriate. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu Apr 23 02:43:49 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 23 Apr 2026 05:43:49 +0300 Subject: [PATCH 1 of 2] SSL: logging levels of various errors reported with tlsfuzzer Message-ID: # HG changeset patch # User Maxim Dounin # Date 1776912197 -10800 # Thu Apr 23 05:43:17 2026 +0300 # Node ID b49a45f7121b199c9e5fce6e3a1359fd6deb1943 # Parent 5158f263a08ebf7711392744296a1c12261924e3 SSL: logging levels of various errors reported with tlsfuzzer. The following errors were observed during tlsfuzzer runs with OpenSSL 3.0.20, and indicate invalid data got from the client: SSL_do_handshake() failed (SSL: error:0A000104:SSL routines::invalid ccs message) SSL_read() failed (SSL: error:0A0000B6:SSL routines::not on record boundary) And the following error was observed during tlsfuzzer runs with OpenSSL 3.4.5: SSL_do_handshake() failed (SSL: error:0A000156:SSL routines::required compression algorithm missing) Accordingly, the SSL_R_INVALID_CCS_MESSAGE ("invalid ccs message"), SSL_R_NOT_ON_RECORD_BOUNDARY ("not on record boundary"), and SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING ("required compression algorithm missing") errors are now logged at the "info" level. Also, starting with OpenSSL 3.2.0, many errors observed in previous versions are additionally followed by the SSL_R_RECORD_LAYER_FAILURE ("record layer failure") error, for example: SSL_do_handshake() failed (SSL: error:0A000119:SSL routines::decryption failed or bad record mac error:0A000139:SSL routines::record layer failure) SSL_read() failed (SSL: error:0A000119:SSL routines::decryption failed or bad record mac error:0A000139:SSL routines::record layer failure) SSL_do_handshake() failed (SSL: error:0A000092:SSL routines::data length too long error:0A000139:SSL routines::record layer failure) SSL_do_handshake() failed (SSL: error:0A00010B:SSL routines::wrong version number error:0A000139:SSL routines::record layer failure) SSL_do_handshake() failed (SSL: error:0A0001BB:SSL routines::bad record type error:0A000139:SSL routines::record layer failure) SSL_read() failed (SSL: error:0A0001BB:SSL routines::bad record type error:0A000139:SSL routines::record layer failure) The SSL_R_RECORD_LAYER_FAILURE ("record layer failure") error, however, might be generated for a number of reasons, including memory allocation failures, and therefore it is wrong to log all such errors at the "info" level. Instead, we now try to fallback to ERR_peek_error() in order to decide which logging level should be used. With these changes, no additional errors were observed with OpenSSL 3.0.20, OpenSSL 3.2.6, OpenSSL 3.3.7, OpenSSL 3.4.5, OpenSSL 3.5.6, OpenSSL 3.6.2, and OpenSSL 4.0.0. diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -4048,6 +4048,22 @@ ngx_ssl_connection_error(ngx_connection_ n = ERR_GET_REASON(ERR_peek_last_error()); +#ifdef SSL_R_RECORD_LAYER_FAILURE + + if (n == SSL_R_RECORD_LAYER_FAILURE + && ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL) + { + /* + * OpenSSL 3.2.0+ returns SSL_R_RECORD_LAYER_FAILURE in the + * error queue after many different errors, including memory + * allocation failures, so fallback to ERR_peek_error() + */ + + n = ERR_GET_REASON(ERR_peek_error()); + } + +#endif + /* handshake failures */ if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC /* 103 */ #ifdef SSL_R_NO_SUITABLE_KEY_SHARE @@ -4101,6 +4117,9 @@ ngx_ssl_connection_error(ngx_connection_ #ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ #endif +#ifdef SSL_R_NOT_ON_RECORD_BOUNDARY + || n == SSL_R_NOT_ON_RECORD_BOUNDARY /* 182 */ +#endif || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ #ifdef SSL_R_BAD_CIPHER || n == SSL_R_BAD_CIPHER /* 186 */ @@ -4146,6 +4165,9 @@ ngx_ssl_connection_error(ngx_connection_ || n == SSL_R_MISSING_KEY_SHARE /* 258 */ #endif || n == SSL_R_UNSUPPORTED_PROTOCOL /* 258 */ +#ifdef SSL_R_INVALID_CCS_MESSAGE + || n == SSL_R_INVALID_CCS_MESSAGE /* 260 */ +#endif #ifdef SSL_R_NO_SHARED_GROUP || n == SSL_R_NO_SHARED_GROUP /* 266 */ #endif @@ -4184,6 +4206,9 @@ ngx_ssl_connection_error(ngx_connection_ #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED || n == SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED /* 338 */ #endif +#ifdef SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING + || n == SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING /* 342 */ +#endif #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING || n == SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING /* 345 */ #endif From mdounin at mdounin.ru Thu Apr 23 02:43:50 2026 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 23 Apr 2026 05:43:50 +0300 Subject: [PATCH 2 of 2] SSL: logging levels of errors observed with BoringSSL In-Reply-To: References: Message-ID: <82d41494c3cbd93fd0f0.1776912230@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1776912204 -10800 # Thu Apr 23 05:43:24 2026 +0300 # Node ID 82d41494c3cbd93fd0f04d77758d1011f9ddbb0b # Parent b49a45f7121b199c9e5fce6e3a1359fd6deb1943 SSL: logging levels of errors observed with BoringSSL. The following client-related errors were observed during tlsfuzzer runs with BoringSSL: SSL_do_handshake() failed (SSL: error:100000f3:SSL routines:OPENSSL_internal:WRONG_CURVE) SSL_do_handshake() failed (SSL: error:10000083:SSL routines:OPENSSL_internal:CLIENTHELLO_PARSE_FAILED) Accordingly, the SSL_R_WRONG_CURVE and SSL_R_CLIENTHELLO_PARSE_FAILED errors are now logged at the "info" level. diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -4090,6 +4090,9 @@ ngx_ssl_connection_error(ngx_connection_ || n == SSL_R_BAD_KEY_UPDATE /* 122 */ #endif || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */ +#ifdef SSL_R_CLIENTHELLO_PARSE_FAILED + || n == SSL_R_CLIENTHELLO_PARSE_FAILED /* 131 */ +#endif || n == SSL_R_CCS_RECEIVED_EARLY /* 133 */ #ifdef SSL_R_DECODE_ERROR || n == SSL_R_DECODE_ERROR /* 137 */ @@ -4151,6 +4154,9 @@ ngx_ssl_connection_error(ngx_connection_ #ifdef SSL_R_NO_APPLICATION_PROTOCOL || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif +#ifdef SSL_R_WRONG_CURVE + || n == SSL_R_WRONG_CURVE /* 243 */ +#endif || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ || n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */ From fabianofurtado at gmail.com Thu Apr 23 22:45:42 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Thu, 23 Apr 2026 19:45:42 -0300 Subject: [PATCH] New directive and variable to log module In-Reply-To: References: Message-ID: Hi! On Wed, Apr 22, 2026 at 9:18?PM Maxim Dounin wrote: > > Hello! > > On Wed, Apr 22, 2026 at 01:33:52PM -0300, Fabiano Furtado wrote: > > > Hi! > > > > On Sun, Apr 19, 2026 at 2:51?PM Maxim Dounin wrote: > > > > > > Hello! > > > > > > On Sat, Apr 18, 2026 at 06:40:43PM -0300, Fabiano Furtado wrote: > > > > > > > Dear freenginx developers, > > > > > > > > I would appreciate it if you could take a look at this patch and > > > > provide your feedback or suggestions for improvements, or let me know > > > > if you think it would be a valuable addition to the project. > > > > > > > > This patch introduces the new "log_tag" directive to freenginx, which > > > > allows you to define a custom tag for each http, server or location > > > > block. This tag is then referenced using the "$tag" variable within > > > > the "log_format" directive, making it easier to filter and match logs, > > > > especially in configurations with many location blocks or complex ones > > > > using regular expressions. > > > > > > > > As an alternative, the directive and variable could be named as: > > > > * "log_label" / "$label" > > > > * "log_id" / "$id" > > > > > > First of all, I would like to note that there should be no > > > log-specific variables. All variables should be universally > > > supported by the generic variables infrastructure, without > > > exceptions. In particular, this is an important factor to > > > properly support alternative logging modules. > > > > > > Last log-specific variables were changed to universally supported > > > ones in nginx 1.3.12 in Feb 2013 > > > (http://freenginx.org/hg/nginx/rev/829cc5872186). Variables > > > handled directly by the access log module exist only as an > > > optimization and exactly match corresponding generic variables. > > > > > > As for the idea of introducing a (generic) variable to identify > > > locations used to handle the request, I don't have a strong > > > opinion here. If I understand the use case correctly, my personal > > > approach would be to use "set" to construct appropriate variables > > > while in progress, and rewrite the configuration to something > > > manageable as soon as possible. > > > > First of all, thank you for the explanations. > > > > I tested the "set" directive and it worked well. However, why doesn?t > > it have NGX_HTTP_MAIN_CONF visibility in its context? I believe it > > could be used inside the "http{}" block with a default value for all > > "server{}" blocks. > > The "set" directive is a rewrite module instruction, and it > defines an action which is executed when rewrite instructions are > executed, see here for details: > > https://freenginx.org/en/docs/http/ngx_http_rewrite_module.html > > That is, the directive itself is not about providing a default > value, it's about changing a variable. And it is only available in > contexts where rewrite instructions are expected to appear. > > If you need some default value and not happy with an empty string > as the default, consider using a map to provide one, for example: > > map "" $tag { > default "foo"; > } > > This will define a variable with "foo" as a default value, and it > will be possible to change the variable with "set" where > appropriate. Thanks for this default map config. It helped me a lot. Fabiano Furtado From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Version bump. Message-ID: details: http://freenginx.org/hg/nginx/rev/74f425f1c765 branches: changeset: 9500:74f425f1c765 user: Maxim Dounin date: Sat Apr 18 01:44:21 2026 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1029007 -#define NGINX_VERSION "1.29.7" +#define nginx_version 1031000 +#define NGINX_VERSION "1.31.0" #define freenginx 1 From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Fixed try_files with alias on case-insensitive systems. Message-ID: details: http://freenginx.org/hg/nginx/rev/27388647e0cd branches: changeset: 9501:27388647e0cd user: Maxim Dounin date: Sat Apr 18 01:44:23 2026 +0300 description: Fixed try_files with alias on case-insensitive systems. Previously, checking that try_files with variables matches an aliased location was done using ngx_strncmp() rather than ngx_filename_cmp(). This works correctly in configurations with $uri, such as: location /prefix/ { alias /foo/; try_files $uri =404; } But this can produce unexpected results on systems with case-insensitive filesystems, such as Windows and macOS, when configuration-provided variables are used to construct file names, such as the following configuration, and assuming a request using different case, such as "GET /Prefix/": location /prefix/ { alias /foo/; set $maintenance "/prefix/maintenance.html"; try_files $maintenance $uri =404; } The fix is to use ngx_filename_cmp(), which properly ignores case on relevant systems. diffstat: src/http/modules/ngx_http_try_files_module.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): 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 @@ -176,7 +176,7 @@ ngx_http_try_files_handler(ngx_http_requ *e.pos = '\0'; if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_strncmp(name, r->uri.data, alias) == 0) + && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Fixed try_files in locations with alias and static strings. Message-ID: details: http://freenginx.org/hg/nginx/rev/aad0fdcc2e33 branches: changeset: 9502:aad0fdcc2e33 user: Maxim Dounin date: Sat Apr 18 01:44:24 2026 +0300 description: Fixed try_files in locations with alias and static strings. Previously, a configuration like: location /prefix/ { alias /foo/; try_files /prefix/bar =404; } tried the "/foo/prefix/bar" file, unless variables were used in the argument. Similarly, location /prefix/ { alias /foo/; set $fallback /prefix/bar; try_files ... $fallback; } incorrectly redirected to "/bar" instead of "/prefix/bar" if no files were found (and variables were used in the fallback argument). The fix is to move alias prefix matching to a point after fallback handling, and do it for both variables and static strings. diffstat: src/http/modules/ngx_http_try_files_module.c | 22 +++++++++++----------- 1 files changed, 11 insertions(+), 11 deletions(-) diffs (45 lines): 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 @@ -174,23 +174,12 @@ ngx_http_try_files_handler(ngx_http_requ path.len = e.pos - path.data; *e.pos = '\0'; - - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, alias) == 0) - { - ngx_memmove(name, name + alias, len - alias); - path.len -= alias; - } } test_dir = tf->test_dir; tf++; - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "trying to use %s: \"%s\" \"%s\"", - test_dir ? "dir" : "file", name, path.data); - if (tf->lengths == NULL && tf->name.len == 0) { if (tf->code) { @@ -213,6 +202,17 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_filename_cmp(name, r->uri.data, alias) == 0) + { + ngx_memmove(name, name + alias, len - alias); + path.len -= alias; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "trying to use %s: \"%s\" \"%s\"", + test_dir ? "dir" : "file", name, path.data); + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Support for "try_files $uri ..." in regex locations with... Message-ID: details: http://freenginx.org/hg/nginx/rev/4c206d68284e branches: changeset: 9503:4c206d68284e user: Maxim Dounin date: Sat Apr 18 01:44:26 2026 +0300 description: Support for "try_files $uri ..." in regex locations with alias. Previously, only adding extensions were supported by try_files when used in a regex location with alias, such as in (3534:3711bb1336c3): location ~ /files/(.*) { alias /path/to/$1; try_files .html "" / =404; } With this change, try_files now able to properly handle configurations with $uri being used, similarly to other configurations with try_files, such as in: location ~ /files/(.*) { alias /path/to/$1; try_files $uri.html $uri $uri/ =404; } Note though that this change will break configurations similar to the one in 6226:4bc94faeff66, where alias and try_files in a regex location are used instead of root. diffstat: src/http/modules/ngx_http_try_files_module.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diffs (20 lines): 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 @@ -202,8 +202,14 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, alias) == 0) + if (alias == NGX_MAX_SIZE_T_VALUE + && ngx_filename_cmp(name, r->uri.data, r->uri.len) == 0) + { + ngx_memmove(name, name + r->uri.len, len - r->uri.len); + path.len -= r->uri.len; + + } else if (alias + && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Reworked try_files in regex locations with alias. Message-ID: details: http://freenginx.org/hg/nginx/rev/8e4422e216d1 branches: changeset: 9504:8e4422e216d1 user: Maxim Dounin date: Sat Apr 18 01:44:28 2026 +0300 description: Reworked try_files in regex locations with alias. Instead of using special cases for "alias == NGX_MAX_SIZE_T_VALUE" everywhere, we now set alias to r->uri.len when working with such locations. And the r->add_uri_to_alias flag is replaced by the r->alias_in_uri flag, which specifies the URI prefix already covered by alias. This simplifies the code, and also fixes various issues with URI being incorrect after try_files match in such locations. diffstat: src/http/modules/ngx_http_try_files_module.c | 24 ++++++------------------ src/http/ngx_http_core_module.c | 26 +++++++++----------------- src/http/ngx_http_request.h | 3 ++- 3 files changed, 17 insertions(+), 36 deletions(-) diffs (153 lines): 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 @@ -111,6 +111,11 @@ ngx_http_try_files_handler(ngx_http_requ alias = clcf->alias; + if (alias == NGX_MAX_SIZE_T_VALUE) { + alias = r->uri.len; + r->alias_in_uri = alias; + } + for ( ;; ) { if (tf->lengths) { @@ -134,9 +139,6 @@ ngx_http_try_files_handler(ngx_http_requ if (!alias) { reserve = len > r->uri.len ? len - r->uri.len : 0; - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - reserve = len; - } else { reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; } @@ -202,15 +204,7 @@ ngx_http_try_files_handler(ngx_http_requ return NGX_DONE; } - if (alias == NGX_MAX_SIZE_T_VALUE - && ngx_filename_cmp(name, r->uri.data, r->uri.len) == 0) - { - ngx_memmove(name, name + r->uri.len, len - r->uri.len); - path.len -= r->uri.len; - - } else if (alias - && ngx_filename_cmp(name, r->uri.data, alias) == 0) - { + if (alias && ngx_filename_cmp(name, r->uri.data, alias) == 0) { ngx_memmove(name, name + alias, len - alias); path.len -= alias; } @@ -261,12 +255,6 @@ ngx_http_try_files_handler(ngx_http_requ if (!alias) { r->uri = path; - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!test_dir) { - r->uri = path; - r->add_uri_to_alias = 1; - } - } else { name = r->uri.data; 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 @@ -977,6 +977,7 @@ ngx_http_core_find_config_phase(ngx_http r->content_handler = NULL; r->uri_changed = 0; + r->alias_in_uri = 0; rc = ngx_http_core_find_location(r); @@ -1905,6 +1906,10 @@ ngx_http_map_uri_to_path(ngx_http_reques alias = clcf->alias; + if (alias == NGX_MAX_SIZE_T_VALUE) { + alias = r->alias_in_uri ? r->alias_in_uri : r->uri.len; + } + if (alias && !r->valid_location) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "\"alias\" cannot be used in location \"%V\" " @@ -1912,7 +1917,7 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - if (alias > r->uri.len && alias != NGX_MAX_SIZE_T_VALUE) { + if (alias > r->uri.len) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "URI shorter than aliased URI part"); return NULL; @@ -1933,12 +1938,7 @@ ngx_http_map_uri_to_path(ngx_http_reques } else { - if (alias == NGX_MAX_SIZE_T_VALUE) { - reserved += r->add_uri_to_alias ? r->uri.len + 1 : 1; - - } else { - reserved += r->uri.len - alias + 1; - } + reserved += r->uri.len - alias + 1; if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, clcf->root_values->elts) @@ -1955,15 +1955,6 @@ ngx_http_map_uri_to_path(ngx_http_reques *root_length = path->len - reserved; last = path->data + *root_length; - - if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!r->add_uri_to_alias) { - *last = '\0'; - return last; - } - - alias = 0; - } } last = ngx_copy(last, r->uri.data + alias, r->uri.len - alias); @@ -2566,7 +2557,7 @@ ngx_http_internal_redirect(ngx_http_requ r->internal = 1; r->valid_unparsed_uri = 0; - r->add_uri_to_alias = 0; + r->alias_in_uri = 0; r->main->count++; ngx_http_handler(r); @@ -2626,6 +2617,7 @@ ngx_http_named_location(ngx_http_request r->internal = 1; r->content_handler = NULL; r->uri_changed = 0; + r->alias_in_uri = 0; r->loc_conf = (*clcfp)->loc_conf; /* clear the modules contexts */ diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -446,6 +446,8 @@ struct ngx_http_request_s { u_char *captures_data; #endif + size_t alias_in_uri; + size_t limit_rate; size_t limit_rate_after; @@ -492,7 +494,6 @@ struct ngx_http_request_s { unsigned invalid_header:1; - unsigned add_uri_to_alias:1; unsigned valid_location:1; unsigned valid_unparsed_uri:1; unsigned uri_changed:1; From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Fixed try_files to clear r->valid_location. Message-ID: details: http://freenginx.org/hg/nginx/rev/75c4159a5ac3 branches: changeset: 9505:75c4159a5ac3 user: Maxim Dounin date: Sat Apr 18 01:44:30 2026 +0300 description: 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. diffstat: src/http/modules/ngx_http_try_files_module.c | 19 ++++++++++++++++++- src/http/ngx_http_core_module.c | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diffs (48 lines): 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); From mdounin at mdounin.ru Sat Apr 25 05:47:52 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:47:52 +0300 Subject: [nginx] Fixed try_files to clear r->valid_unparsed_uri. Message-ID: details: http://freenginx.org/hg/nginx/rev/5158f263a08e branches: changeset: 9506:5158f263a08e user: Maxim Dounin date: Sat Apr 18 01:44:33 2026 +0300 description: Fixed try_files to clear r->valid_unparsed_uri. Most notably, with this change any URI changes made by try_files are visible with proxy_pass without URI, such as in the following configuration: location / { try_files $uri $uri.html =404; proxy_pass http://u; } Previously, such URI changes were only visible if URI was previously changed by a rewrite or an internal redirect. To minimize compatibility issues, this is only done when the new URI is not equal to the original one. That is, a configuration like this will work as before, preserving the original URI as sent by the client: location / { try_files $uri =404; proxy_pass http://u; } Note that URI checking uses ngx_strncmp() rather than ngx_filename_cmp() to properly reflect case-only changes on case-insensitive systems as well. diffstat: src/http/modules/ngx_http_try_files_module.c | 17 +++++++++++++++-- 1 files changed, 15 insertions(+), 2 deletions(-) diffs (38 lines): 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 @@ -251,12 +251,13 @@ ngx_http_try_files_handler(ngx_http_requ path.len -= root; path.data += root; + name = r->uri.data; + len = r->uri.len; + if (!alias) { r->uri = path; } else { - name = r->uri.data; - r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { @@ -283,6 +284,18 @@ ngx_http_try_files_handler(ngx_http_requ != 0) { r->valid_location = 0; + r->valid_unparsed_uri = 0; + } + } + + if (r->valid_unparsed_uri) { + + /* clear r->valid_unparsed_uri if URI was changed */ + + if (r->uri.len != len + || ngx_strncmp(r->uri.data, name, len) != 0) + { + r->valid_unparsed_uri = 0; } } From mdounin at mdounin.ru Sat Apr 25 05:48:21 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:21 +0300 Subject: [nginx-tests] Tests: sorted try_files locations for better local... Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/2e3ccde7b2a0 branches: changeset: 2047:2e3ccde7b2a0 user: Maxim Dounin date: Sat Apr 18 01:49:21 2026 +0300 description: Tests: sorted try_files locations for better locality. diffstat: http_try_files.t | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diffs (36 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -42,10 +42,18 @@ http { try_files $uri /fallback; } + location /fallback { + proxy_pass http://127.0.0.1:8081/fallback; + } + location /nouri/ { try_files $uri /fallback-nouri; } + location /fallback-nouri { + proxy_pass http://127.0.0.1:8081; + } + location /short/ { try_files /short $uri =404; } @@ -77,13 +85,6 @@ http { try_files $uri =404; } } - - location /fallback { - proxy_pass http://127.0.0.1:8081/fallback; - } - location /fallback-nouri { - proxy_pass http://127.0.0.1:8081; - } } server { From mdounin at mdounin.ru Sat Apr 25 05:48:21 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:21 +0300 Subject: [nginx-tests] Tests: try_files in a regex location with alias ad... Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/764b07be5a74 branches: changeset: 2048:764b07be5a74 user: Maxim Dounin date: Sat Apr 04 09:15:21 2026 +0300 description: Tests: try_files in a regex location with alias additional tests. When alias is used in a regex location, alias is expected to specify full file system path to the file corresponding to the request. When try_files is used in such a location, it is expected to be able to add extensions to the path, such as in the following configuration (see 3534:3711bb1336c3): location ~ ^/users/(.*)/files/(.*) { alias /files/$1/$2; try_files .html "" / =404; } Previously, the only test was for the bug (fixed by 6226:4bc94faeff66), where a configuration is essentially misuses alias with try_files instead of root. That is, all requests are mapped to a single file path using alias, and then try_files used to add $uri to this path: location ~ /mail { alias /path/to/directory; try_files $uri =404; } While handling such case without a segmentation fault is important, it is not to be confused with intended try_files usage. Further, handling of this specific case is expected to be changed to universally support aliased prefix replacement and configurations like this: location ~ ^/users/(.*)/files/(.*) { alias /files/$1/$2; try_files $uri.html $uri $uri/ =404; } That is, with matching URI part (the whole URI for regex locations) replaced with alias, so "try_files $uri.html ..." will be universally interpreted as $request_filename with the ".html" extension added in all cases (with root, alias, and alias in regex location). diffstat: http_try_files.t | 26 ++++++++++++++++++++++++-- 1 files changed, 24 insertions(+), 2 deletions(-) diffs (50 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(10) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(12) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -79,6 +79,16 @@ http { try_files $uri =404; } + location ~ /alias-re-add/(.*) { + alias %%TESTDIR%%/$1; + try_files .htm .html =404; + } + + location ~ /alias-re-prefix/(.*) { + alias %%TESTDIR%%/$1; + try_files $uri.htm $uri.html =404; + } + location /alias-nested/ { alias %%TESTDIR%%/; location ~ html { @@ -117,7 +127,19 @@ like(http_get('/file-dir/'), qr!404 Not! like(http_get('/dir-dir/'), qr!301 Moved Permanently!, 'dir matches dir'); like(http_get('/dir-file/'), qr!404 Not!, 'dir does not match file'); -like(http_get('/alias-re.html'), qr!SEE THIS!, 'alias in regex location'); +like(http_get('/alias-re.html'), qr!SEE THIS|404 Not!, + 'alias in regex location as root'); +like(http_get('/alias-re-add/found'), qr!SEE THIS!, + 'alias in regex location with just extension'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-re-prefix/found'), qr!SEE THIS!, + 'alias in regex location with uri prefix'); + +} + like(http_get('/alias-nested/found.html'), qr!SEE THIS!, 'alias with nested location'); From mdounin at mdounin.ru Sat Apr 25 05:48:21 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:21 +0300 Subject: [nginx-tests] Tests: try_files with alias additional tests. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/1b0215d2bf86 branches: changeset: 2049:1b0215d2bf86 user: Maxim Dounin date: Sat Apr 18 01:49:25 2026 +0300 description: Tests: try_files with alias additional tests. diffstat: http_try_files.t | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 72 insertions(+), 1 deletions(-) diffs (95 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(12) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(17) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -95,6 +95,34 @@ http { try_files $uri =404; } } + + location /alias-static/ { + alias %%TESTDIR%%/; + try_files /alias-static/found.html =404; + } + + location /alias-vars/ { + alias %%TESTDIR%%/; + set $file /alias-vars/found.html; + try_files $file =404; + } + + location /alias-fallback-static/ { + alias %%TESTDIR%%/; + try_files $uri /alias-fallback-static/found.html; + } + + location /alias-fallback-vars/ { + alias %%TESTDIR%%/; + set $fallback /alias-fallback-vars/found.html; + try_files $uri $fallback; + } + + location /alias-caseless/ { + alias %%TESTDIR%%/; + set $file /alias-caseless/found.html; + try_files $file =404; + } } server { @@ -143,4 +171,47 @@ like(http_get('/alias-re-prefix/found'), like(http_get('/alias-nested/found.html'), qr!SEE THIS!, 'alias with nested location'); +# when a file matches location prefix covered by alias, +# prefix needs to be removed; this used to work only with +# variables, but not with static strings + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-static/found.html'), qr!SEE THIS!, + 'alias with static string'); + +} + +like(http_get('/alias-vars/found.html'), qr!SEE THIS!, + 'alias with variables'); + +# in contrast, for the fallback URI we don't need to remove +# anything (yet it was removed with variables) + +like(http_get('/alias-fallback-static/notfound'), qr!SEE THIS!, + 'alias fallback to matching static string'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-fallback-vars/notfound'), qr!SEE THIS!, + 'alias fallback to matching string with variables'); + +} + +# with caseless systems, aliased prefix needs to be checked in a +# case-insensitive way; this automatically happens with "try_files $uri", +# since aliased prefix is compared to the original request URI, but was +# not working with configuration-provided paths + +SKIP: { +skip 'not caseless os', 1 + unless $^O eq 'MSWin32' or $^O eq 'darwin'; +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-CASELESS/found.html'), qr!SEE THIS!, 'alias caseless'); + +} + ############################################################################### From mdounin at mdounin.ru Sat Apr 25 05:48:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:22 +0300 Subject: [nginx-tests] Tests: additional try_files test with nested prefi... Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/6ea4efddc9a3 branches: changeset: 2050:6ea4efddc9a3 user: Maxim Dounin date: Sat Apr 18 01:49:33 2026 +0300 description: Tests: additional try_files test with nested prefix location. diffstat: http_try_files.t | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diffs (38 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(17) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(18) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -91,9 +91,14 @@ http { location /alias-nested/ { alias %%TESTDIR%%/; + location ~ html { try_files $uri =404; } + + location /alias-nested/prefix { + try_files /found.html =404; + } } location /alias-static/ { @@ -169,7 +174,9 @@ like(http_get('/alias-re-prefix/found'), } like(http_get('/alias-nested/found.html'), qr!SEE THIS!, - 'alias with nested location'); + 'alias with nested regex location'); +like(http_get('/alias-nested/prefix'), qr!SEE THIS!, + 'alias with nested prefix location'); # when a file matches location prefix covered by alias, # prefix needs to be removed; this used to work only with From mdounin at mdounin.ru Sat Apr 25 05:48:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:22 +0300 Subject: [nginx-tests] Tests: try_files tests with proxying. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/d384c458eae0 branches: changeset: 2051:d384c458eae0 user: Maxim Dounin date: Sat Apr 18 01:49:44 2026 +0300 description: Tests: try_files tests with proxying. Most notably, when URI is changed by try_files to something that does not match the location prefix, the code tried to replace things anyway (and caused a segfault if the URI set by try_files was shorter than the location prefix). diffstat: http_try_files.t | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 61 insertions(+), 2 deletions(-) diffs (94 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(18) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(23) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -128,6 +128,32 @@ http { set $file /alias-caseless/found.html; try_files $file =404; } + + location /prefix-proxy/ { + try_files $uri =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + + location /prefix-proxy-alias/ { + alias %%TESTDIR%%/; + try_files $uri =404; + proxy_pass http://127.0.0.1:8081/changed/; + + location /prefix-proxy-alias/nested-short { + try_files /prefix-proxy-alias/nested =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + } + + location /prefix-proxy-long/ { + try_files /prefix-proxy/found.html =404; + proxy_pass http://127.0.0.1:8081/changed/; + } + + location /prefix-proxy-short/ { + try_files /found.html =404; + proxy_pass http://127.0.0.1:8081/changed/; + } } server { @@ -143,9 +169,12 @@ http { EOF +$t->write_file('found.html', 'SEE THIS'); +$t->write_file('nested', 'SEE THIS'); mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); -$t->write_file('found.html', 'SEE THIS'); +mkdir($t->testdir() . '/prefix-proxy/'); +$t->write_file('prefix-proxy/found.html', 'SEE THIS'); $t->run(); ############################################################################### @@ -221,4 +250,34 @@ like(http_get('/alias-CASELESS/found.htm } +# when an URI is changed by try_files, this could be a surprise +# for proxy_pass with URI part + +like(http_get('/prefix-proxy/found.html'), qr!X-URI: /changed/found.html!, + 'proxy after try_files'); +like(http_get('/prefix-proxy-alias/found.html'), + qr!X-URI: /changed/found.html!, 'proxy after try_files with alias'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/prefix-proxy-long/found.html'), + qr!X-URI: /prefix-proxy/found.html!, 'proxy after try_files no match'); + +} + +TODO: { +todo_skip 'leaves coredump', 2 + unless $t->has_version('1.31.0') or $ENV{TEST_NGINX_UNSAFE}; +local $TODO = 'not yet', $t->todo_alerts() + unless $t->has_version('1.31.0'); + +like(http_get('/prefix-proxy-short/foo'), qr!X-URI: /found.html!, + 'proxy after try_files with short uri'); +like(http_get('/prefix-proxy-alias/nested-short'), + qr!X-URI: /prefix-proxy-alias/nested!, + 'proxy after try_files with short uri, alias nested'); + +} + ############################################################################### From mdounin at mdounin.ru Sat Apr 25 05:48:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:22 +0300 Subject: [nginx-tests] Tests: try_files with proxying without URI part. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/e6cd7d62aff1 branches: changeset: 2052:e6cd7d62aff1 user: Maxim Dounin date: Sat Apr 18 01:49:46 2026 +0300 description: Tests: try_files with proxying without URI part. Proxying without URI part uses original unparsed URI if available, yet since try_files modifies the effective URI, it should use the modified URI after try_files. This is what used to happen if the URI was rewritten or changed by an index redirection, and then modified by try_files. diffstat: http_try_files.t | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 74 insertions(+), 1 deletions(-) diffs (104 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(23) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(29) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -154,6 +154,32 @@ http { try_files /found.html =404; proxy_pass http://127.0.0.1:8081/changed/; } + + location /uri-after/ { + rewrite ^/uri-after/rewrite /uri-after/notfound break; + try_files /uri-after/found.html =404; + proxy_pass http://127.0.0.1:8081; + } + + location /uri-after-alias/ { + alias %%TESTDIR%%/; + try_files /uri-after-alias/found.html =404; + proxy_pass http://127.0.0.1:8081; + } + + location = /uri-after-alias-redirect { + try_files /notfound /uri-after-alias/found; + } + + location ~ /uri-after-alias-add/(.*) { + alias %%TESTDIR%%/$1; + try_files .htm .html =404; + proxy_pass http://127.0.0.1:8081; + } + + location = /uri-after-alias-add-redirect { + try_files /notfound /uri-after-alias-add/found; + } } server { @@ -175,6 +201,8 @@ mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); mkdir($t->testdir() . '/prefix-proxy/'); $t->write_file('prefix-proxy/found.html', 'SEE THIS'); +mkdir($t->testdir() . '/uri-after/'); +$t->write_file('uri-after/found.html', 'SEE THIS'); $t->run(); ############################################################################### @@ -280,4 +308,49 @@ like(http_get('/prefix-proxy-alias/neste } +# try_files changes URI, so make sure that proxy_pass without the URI part +# uses the modified URI, and not the original unparsed URI + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after/found'), qr!X-URI: /uri-after/found.html!, + 'proxy without uri, unparsed uri not used'); + +} + +like(http_get('/uri-after/rewrite'), qr!X-URI: /uri-after/found.html!, + 'proxy without uri, after rewrite'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after-alias/found'), + qr!X-URI: /uri-after-alias/found.html!, + 'proxy without uri, alias'); + +like(http_get('/uri-after-alias-redirect'), + qr!X-URI: /uri-after-alias/found.html!, + 'proxy without uri, alias, after redirect'); + +} + +# when try_files adds an extension in a regex location with alias, +# this used to result in bogus URI (".html") and the r->add_uri_to_alias +# flag set; this was handled by ngx_http_map_uri_to_alias() and worked for +# static files, but produced unexpected results when proxying + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/uri-after-alias-add/found'), + qr!X-URI: /uri-after-alias-add/found.html!, + 'proxy without uri, alias in regex location'); + +like(http_get('/uri-after-alias-add-redirect'), + qr!X-URI: /uri-after-alias-add/found.html!, + 'proxy without uri, alias in regex location, after redirect'); + +} + ############################################################################### From mdounin at mdounin.ru Sat Apr 25 05:48:22 2026 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 25 Apr 2026 08:48:22 +0300 Subject: [nginx-tests] Tests: added more basic try_files tests. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/ff476932c980 branches: changeset: 2053:ff476932c980 user: Maxim Dounin date: Sat Apr 18 01:49:49 2026 +0300 description: Tests: added more basic try_files tests. diffstat: http_try_files.t | 67 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 55 insertions(+), 12 deletions(-) diffs (105 lines): diff --git a/http_try_files.t b/http_try_files.t --- a/http_try_files.t +++ b/http_try_files.t @@ -21,7 +21,7 @@ use Test::Nginx; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(29) +my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(48) ->write_file_expand('nginx.conf', <<'EOF'); %%TEST_GLOBALS%% @@ -39,6 +39,25 @@ http { server_name localhost; location / { + try_files $uri $uri.html $uri/ =404; + } + + location /alias/ { + alias %%TESTDIR%%/; + try_files $uri $uri.html $uri/ =404; + } + + location ~ /alias-re-add/(.*) { + alias %%TESTDIR%%/$1; + try_files "" .html / =404; + } + + location ~ /alias-re-prefix/(.*) { + alias %%TESTDIR%%/$1; + try_files $uri $uri.html $uri/ =404; + } + + location /uri/ { try_files $uri /fallback; } @@ -79,16 +98,6 @@ http { try_files $uri =404; } - location ~ /alias-re-add/(.*) { - alias %%TESTDIR%%/$1; - try_files .htm .html =404; - } - - location ~ /alias-re-prefix/(.*) { - alias %%TESTDIR%%/$1; - try_files $uri.htm $uri.html =404; - } - location /alias-nested/ { alias %%TESTDIR%%/; @@ -199,6 +208,7 @@ EOF $t->write_file('nested', 'SEE THIS'); mkdir($t->testdir() . '/directory'); $t->write_file('directory/alias-re.html', 'SEE THIS'); +$t->write_file('directory/index.html', 'SEE THIS'); mkdir($t->testdir() . '/prefix-proxy/'); $t->write_file('prefix-proxy/found.html', 'SEE THIS'); mkdir($t->testdir() . '/uri-after/'); @@ -207,7 +217,40 @@ mkdir($t->testdir() . '/uri-after/'); ############################################################################### -like(http_get('/found.html'), qr!SEE THIS!, 'found'); +# basic tests with "try_files $uri $uri.html $uri/ =404" + +like(http_get('/found.html'), qr!SEE THIS!, 'root $uri'); +like(http_get('/found'), qr!SEE THIS!, 'root $uri.html'); +like(http_get('/directory'), qr!301 Moved Permanently!, 'root $uri/ redirect'); +like(http_get('/directory/'), qr!SEE THIS!, 'root $uri/ index'); +like(http_get('/notfound'), qr!404 Not!, 'root not found'); + +like(http_get('/alias/found.html'), qr!SEE THIS!, 'alias $uri'); +like(http_get('/alias/found'), qr!SEE THIS!, 'alias $uri.html'); +like(http_get('/alias/directory'), qr!301 Moved Permanently!, 'alias $uri/ redirect'); +like(http_get('/alias/directory/'), qr!SEE THIS!, 'alias $uri/ index'); +like(http_get('/alias/notfound'), qr!404 Not!, 'alias not found'); + +like(http_get('/alias-re-add/found.html'), qr!SEE THIS!, 'alias regex ""'); +like(http_get('/alias-re-add/found'), qr!SEE THIS!, 'alias regex .html'); +like(http_get('/alias-re-add/directory'), qr!301 Moved Permanently!, 'alias regex / redirect'); +like(http_get('/alias-re-add/directory/'), qr!SEE THIS!, 'alias regex / index'); +like(http_get('/alias-re-add/notfound'), qr!404 Not!, 'alias regex not found'); + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.31.0'); + +like(http_get('/alias-re-prefix/found.html'), qr!SEE THIS!, 'alias regex $uri'); +like(http_get('/alias-re-prefix/found'), qr!SEE THIS!, 'alias regex $uri.html'); +like(http_get('/alias-re-prefix/directory'), qr!301 Moved Permanently!, 'alias regex $uri/ redirect'); +like(http_get('/alias-re-prefix/directory/'), qr!SEE THIS!, 'alias regex $uri/ index'); + +} + +like(http_get('/alias-re-prefix/notfound'), qr!404 Not!, 'alias regex not found with prefix'); + +# various specific tests + like(http_get('/uri/notfound'), qr!X-URI: /fallback!, 'not found uri'); like(http_get('/nouri/notfound'), qr!X-URI: /fallback!, 'not found nouri'); like(http_get('/short/long'), qr!404 Not!, 'short uri in try_files'); From fabianofurtado at gmail.com Sun Apr 26 00:40:35 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Sat, 25 Apr 2026 21:40:35 -0300 Subject: "index off;" directive? Message-ID: Hello! Recently, I encountered a peculiar situation in my freenginx config where I needed to use autoindex to list the contents of a directory, but the directory contained an index.html file, causing the autoindex to fail. As a workaround, I used "index file_not_found.fnf;", and it worked fine! However, I started thinking about the implementation of an "off" parameter for the index directive. In a situation where the index file does not exist, and using "autoindex off;", the system returns a HTTP 403, writing "directory index of ".../" is forbidden" in the error_log. In other words, this is the default return value of freenginx when it can't find the index file. In this scenario, could the "index off;" feature be implemented in freenginx? I believe there must be solid reasons why this feature isn?t present yet, especially since it is an old and mandatory module in the system, but I can't imagine why. Thank you in advance. Fabiano Furtado From mdounin at mdounin.ru Sun Apr 26 22:44:31 2026 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 27 Apr 2026 01:44:31 +0300 Subject: "index off;" directive? In-Reply-To: References: Message-ID: Hello! On Sat, Apr 25, 2026 at 09:40:35PM -0300, Fabiano Furtado wrote: > Recently, I encountered a peculiar situation in my freenginx config > where I needed to use autoindex to list the contents of a directory, > but the directory contained an index.html file, causing the autoindex > to fail. > > As a workaround, I used "index file_not_found.fnf;", and it worked > fine! However, I started thinking about the implementation of an "off" > parameter for the index directive. > > In a situation where the index file does not exist, and using > "autoindex off;", the system returns a HTTP 403, writing "directory > index of ".../" is forbidden" in the error_log. In other words, this > is the default return value of freenginx when it can't find the index > file. > > In this scenario, could the "index off;" feature be implemented in freenginx? > > I believe there must be solid reasons why this feature isn?t present > yet, especially since it is an old and mandatory module in the system, > but I can't imagine why. I believe the main reason why this feature is not implemented yet is that nobody asked for it yet, probably because the workaround is trivial. Also, in most cases it is better to use index rather than autoindex, since autoindex is costly compared to sending an index file. I've asked Igor about this to make sure there are no other reasons I've overlooked, and he thinks the same. I personally don't mind implementing "index off;" to save a syscall when checking index files is not needed. -- Maxim Dounin http://mdounin.ru/ From fabianofurtado at gmail.com Mon Apr 27 12:22:59 2026 From: fabianofurtado at gmail.com (Fabiano Furtado) Date: Mon, 27 Apr 2026 09:22:59 -0300 Subject: "index off;" directive? In-Reply-To: References: Message-ID: Hi! On Sun, Apr 26, 2026 at 7:53?PM Maxim Dounin wrote: > > Hello! > > On Sat, Apr 25, 2026 at 09:40:35PM -0300, Fabiano Furtado wrote: > ... > I believe the main reason why this feature is not implemented yet > is that nobody asked for it yet, probably because the workaround > is trivial. Also, in most cases it is better to use index rather > than autoindex, since autoindex is costly compared to sending an > index file. > > I've asked Igor about this to make sure there are no other reasons > I've overlooked, and he thinks the same. > > I personally don't mind implementing "index off;" to save a syscall > when checking index files is not needed. Wow! I honestly wasn't expecting this response, since I assumed there was some technical reason why this feature hadn't been implemented yet. Anyway, I'm not sure if it's possible, but I'd like to try developing this patch. Would it be okay if I tried to create this new patch? Personally, I think the architecture and code quality of this project are excellent, and I'm still learning the codebase. I see this as a great opportunity to learn a bit more. Thanks in advance. Fabiano Furtado