[http_rewrite] Avoid duplicate non-cacheable variable calls for complex expressions

Thomas P. tpxp at live.fr
Wed Aug 7 11:54:17 UTC 2024


Hello,

I'm experimenting with non-cacheable variables to compute some values used in http_rewrite. I've noticed that, for directives like "set $var $computed_var", I'm getting 2 calls to $computed_var's get_handler. After reading the code behind this directive, I've noticed it goes through ngx_http_get_flushed_variable twice for every external variable: once to determine its length, then another time to copy contents (after allocating the total length of the result). While I expect the get_handler function to be called every time the variable is referred to, I think calling it once shall suffice. Switching to ngx_http_get_indexed_variable fixes the issue, and the cache is still cleared after evaluating the set directive it seems, as calling the non cacheable variable in another expression calls get_handler another time. All tests still pass with this change.

Here's the only behaviour change I could observe:
> Consider a non-cached variable $weird_var keeping track of its call numbers, and returning "0" then N times the number of calls so far: 01, 022, 0333...
> Use it twice in the same directive: "set $stuff $weird_var$weird_var"
> The variable's get_handler will be called twice (which sort of makes sense since the variable is referred to twice) but the resulting value is the result of the last call, truncated since it doesn't fit in the allocated buffer: stuff is 02202 (intuitively, it would be 01022)
> Without this patch, the result would be 03330 which is also not the expected result anyway, so I doubt this would break anyone's workflow. On the other side, this speeds up complex value processing as we don't make unnecessary calls.

The changeset is pretty basic, happy reviewing!

Thomas P.

# HG changeset patch
# User Thomas P. <tpxp at live.fr>
# Date 1722959175 -7200
#      Tue Aug 06 17:46:15 2024 +0200
# Node ID d6283a655f35a03f49427a2d88ebbc27f6946e3d
# Parent  d1b8568f3042f6019a2302dda4afbadd051fe54b
[http_rewrite] Avoid duplicate non-cacheable variable calls for complex expressions

The http_rewrite module's rewrite handler called twice variables'
get_handler for non-cacheable variables referenced in expressions like
"set $a $upstream_code;". It goes through ngx_http_get_flushed_variable
once to determine variable length, and one more time to get the variable
contents.

Setting the flushed attribute on the script engine fixes the
issue. This flag is already set in other parts that rely on http_script and
it did not break any test, so it can be safely set. Besides, this only impacts
non-cacheable variables processing.

diff -r d1b8568f3042 -r d6283a655f35 src/http/modules/ngx_http_rewrite_module.c
--- a/src/http/modules/ngx_http_rewrite_module.c        Thu Jul 18 17:43:25 2024 +0400
+++ b/src/http/modules/ngx_http_rewrite_module.c        Tue Aug 06 17:46:15 2024 +0200
@@ -174,6 +174,7 @@
     e->quote = 1;
     e->log = rlcf->log;
     e->status = NGX_DECLINED;
+    e->flushed = 1;

     while (*(uintptr_t *) e->ip) {
         code = *(ngx_http_script_code_pt *) e->ip;


More information about the nginx-devel mailing list