[PATCH 2 of 4] Tests: tests with variables which change between accesses
Maxim Dounin
mdounin at mdounin.ru
Mon Jun 8 17:46:40 UTC 2026
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1780936528 -10800
# Mon Jun 08 19:35:28 2026 +0300
# Node ID 4af2fea518e2389a44c483ace19f7b4e645989a7
# Parent 29d3b09bcce5c912235a0552db2cb1a3c1996881
Tests: tests with variables which change between accesses.
One example is a named capture, which is changed by a side effect of
a map. Another example is a non-cacheable (volatile) map which uses
captures from its previous evaluation as input, and therefore becomes
longer on each evaluation.
diff --git a/rewrite.t b/rewrite.t
--- a/rewrite.t
+++ b/rewrite.t
@@ -21,7 +21,7 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;
-my $t = Test::Nginx->new()->has(qw/http rewrite proxy/)->plan(25)
+my $t = Test::Nginx->new()->has(qw/http rewrite proxy/)->plan(26)
->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
@@ -34,6 +34,10 @@ events {
http {
%%TEST_GLOBALS_HTTP%%
+ map $uri $map_capture {
+ ~(?<capture>.*) $capture;
+ }
+
server {
listen 127.0.0.1:8080;
server_name localhost;
@@ -142,6 +146,10 @@ http {
return 200 "uri:$uri args:$args";
}
+ location /map/ {
+ rewrite ^ $capture$map_capture redirect;
+ }
+
location /break {
rewrite ^ /return200;
break;
@@ -274,6 +282,17 @@ like(http_get('/capture_nested/%25?a=b')
}
+TODO: {
+todo_skip 'might coredump', 1
+ unless $t->has_version('1.31.3')
+ or $ENV{TEST_NGINX_UNSAFE};
+local $TODO = 'not yet', $t->todo_alerts();
+
+like(http_get('/map/test-long-uri'), qr!Location: .*/map/test-long-uri!ms,
+ 'rewrite and map with side effects');
+
+}
+
# break
like(http_get('/break'), qr/200/, 'valid_location reset');
diff --git a/rewrite_set.t b/rewrite_set.t
--- a/rewrite_set.t
+++ b/rewrite_set.t
@@ -1,5 +1,6 @@
#!/usr/bin/perl
+# (C) Maxim Dounin
# (C) Sergey Kandaurov
# (C) Nginx, Inc.
@@ -22,7 +23,7 @@ use Test::Nginx;
select STDERR; $| = 1;
select STDOUT; $| = 1;
-my $t = Test::Nginx->new()->has(qw/http rewrite ssi/)->plan(10);
+my $t = Test::Nginx->new()->has(qw/http rewrite ssi map/)->plan(16);
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -36,6 +37,21 @@ events {
http {
%%TEST_GLOBALS_HTTP%%
+ map $uri $map_capture {
+ ~(?<capture>.*) $capture;
+ }
+
+ map prefix:$capture $map_volatile {
+ volatile;
+ ~(?<capture>.*) $capture;
+ }
+
+ map $args $map_flush {
+ volatile;
+ default wrong;
+ secret good;
+ }
+
server {
listen 127.0.0.1:8080;
server_name localhost;
@@ -78,6 +94,40 @@ http {
return 200 "X${temp}X";
}
+ location /map {
+ set $temp "$capture $map_capture";
+ return 200 "X${temp}X";
+ }
+
+ location /map_volatile {
+ set $temp "$map_volatile";
+ return 200 "X${temp}X";
+ }
+
+ location /map_root {
+ root html/$pid;
+ return 200 "X${map_volatile}X${document_root}X";
+ }
+
+ location /map_root_root {
+ root html/$pid;
+ return 200 "X${map_volatile}X${document_root}${realpath_root}X";
+ }
+
+ location /map_root_overflow {
+ root html/$capture/$map_capture;
+ set $temp "$document_root";
+ return 200 "X${temp}X";
+ }
+
+ location /map_flush {
+ set $args "wrong";
+ set $temp "$map_flush";
+ set $args "secret";
+ set $temp "$temp:$map_flush";
+ return 200 "X${temp}X";
+ }
+
location /t1 {
set $http_foo "set_foo";
ssi on;
@@ -147,6 +197,48 @@ like(http_get('/args/%20x'), qr!Xset_/ar
}
+TODO: {
+todo_skip 'might coredump', 5
+ unless $t->has_version('1.31.3')
+ or $ENV{TEST_NGINX_UNSAFE};
+local $TODO = 'not yet', $t->todo_alerts();
+
+# map can change other variables via named captures,
+# resulting in invalid buffer length calculations
+
+like(http_get('/map'), qr!X.*/mapX!, 'set and map side effects');
+
+# non-cacheable variable can change its length on each evaluation,
+# resulting in invalid buffer length calculations
+
+like(http_get('/map_volatile'), qr!Xprefix:.*X!,
+ 'set and volatile map');
+
+# even if a separate flush step is used, such as with return,
+# which uses ngx_http_complex_value(), an additional flush might happen
+# as a side effect of a variable lookup (notably $document_root and
+# $realpath_root when using root with variables)
+
+like(http_get('/map_root'), qr!Xprefix:X.*X!,
+ 'return and volatile map with $document_root');
+
+like(http_get('/map_root_root'), qr!Xprefix:X.*X!,
+ 'return and volatile map with $document_root and $realpath_root');
+
+# similarly, map with side effects can cause invalid buffer length
+# during evaluation of $document_root, which uses ngx_http_script_run()
+
+like(http_get('/map_root_overflow'), qr!X.*/map_root_overflowX!,
+ '$document_root with map side effects');
+
+}
+
+# non-cacheable map can be derived from a non-cacheable variable,
+# which also needs to be flushed before getting the map value
+
+like(http_get('/map_flush'), qr!Xwrong:goodX!,
+ 'set and volatile map source flush');
+
# non-indexed access of prefixed variables
like(http_get_extra('/t1.html', 'Foo: http_foo'), qr/Xset_fooX/,
diff --git a/stream_set.t b/stream_set.t
--- a/stream_set.t
+++ b/stream_set.t
@@ -24,7 +24,8 @@ select STDERR; $| = 1;
select STDOUT; $| = 1;
my $t = Test::Nginx->new()
- ->has(qw/stream stream_return stream_map stream_set/);
+ ->has(qw/stream stream_return stream_map stream_set http rewrite/)
+ ->plan(3);
$t->write_file_expand('nginx.conf', <<'EOF');
@@ -42,6 +43,10 @@ stream {
default "original";
}
+ map 0 $map_capture {
+ ~(?<capture>.*) $capture;
+ }
+
server {
listen 127.0.0.1:8082;
return $map_var:$set_var;
@@ -54,15 +59,31 @@ stream {
listen 127.0.0.1:8083;
return $set_var;
}
+
+ server {
+ listen 127.0.0.1:8084;
+ return "$capture $map_capture";
+ }
}
EOF
-$t->run()->plan(2);
+$t->run();
###############################################################################
is(stream('127.0.0.1:' . port(8082))->read(), 'new:original', 'set');
is(stream('127.0.0.1:' . port(8083))->read(), '', 'uninitialized variable');
+TODO: {
+todo_skip 'might coredump', 1
+ unless $t->has_version('1.31.3')
+ or $ENV{TEST_NGINX_UNSAFE};
+local $TODO = 'not yet', $t->todo_alerts();
+
+is(stream('127.0.0.1:' . port(8084))->read(), '0 0',
+ 'set and map with side effects');
+
+}
+
###############################################################################
More information about the nginx-devel
mailing list