[nginx] Added helper function to set indexed variables.

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


details:   http://freenginx.org/hg/nginx/rev/7d3b1378f3aa
branches:  
changeset: 9554:7d3b1378f3aa
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Mon Jun 08 17:54:00 2026 +0300
description:
Added helper function to set indexed variables.

The ngx_http_set_indexed_variable() function correctly stores the
variable in r->variables[], and calls v->set_handler() if it is set
(which is now propagated to cmcf->variables).

This reduces amount of code needed in various places which set variables
(currently "set", "auth_request_set", and named captures), and also
unifies the behaviour across these places.  Notable changes include:

- named captures now properly handle variables with v->set_handler(),
  notably $limit_rate and $args, much like "set" currently does;

- the "auth_request_set" directive now does not update the value
  in the r->variables cache if there is a set handler, similarly
  to how "set" does, so invalid $limit_rate values are not returned
  by subsequent variable lookups.

Similar changes were made in the stream module.

diffstat:

 src/http/modules/ngx_http_auth_request_module.c |  27 +--------
 src/http/modules/ngx_http_rewrite_module.c      |  23 +-------
 src/http/ngx_http_script.c                      |  38 +--------------
 src/http/ngx_http_script.h                      |   8 ---
 src/http/ngx_http_variables.c                   |  64 +++++++++++++++++-------
 src/http/ngx_http_variables.h                   |   3 +
 src/stream/ngx_stream_set_module.c              |  18 +-----
 src/stream/ngx_stream_variables.c               |  60 ++++++++++++++++------
 src/stream/ngx_stream_variables.h               |   3 +
 9 files changed, 106 insertions(+), 138 deletions(-)

diffs (457 lines):

diff --git a/src/http/modules/ngx_http_auth_request_module.c b/src/http/modules/ngx_http_auth_request_module.c
--- a/src/http/modules/ngx_http_auth_request_module.c
+++ b/src/http/modules/ngx_http_auth_request_module.c
@@ -26,7 +26,6 @@ typedef struct {
 typedef struct {
     ngx_int_t                 index;
     ngx_http_complex_value_t  value;
-    ngx_http_set_variable_pt  set_handler;
 } ngx_http_auth_request_variable_t;
 
 
@@ -239,10 +238,8 @@ ngx_http_auth_request_set_variables(ngx_
     ngx_http_auth_request_conf_t *arcf, ngx_http_auth_request_ctx_t *ctx)
 {
     ngx_str_t                          val;
-    ngx_http_variable_t               *v;
-    ngx_http_variable_value_t         *vv;
+    ngx_http_variable_value_t          vv;
     ngx_http_auth_request_variable_t  *av, *last;
-    ngx_http_core_main_conf_t         *cmcf;
 
     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "auth request set variables");
@@ -251,9 +248,6 @@ ngx_http_auth_request_set_variables(ngx_
         return NGX_OK;
     }
 
-    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-    v = cmcf->variables.elts;
-
     av = arcf->vars->elts;
     last = av + arcf->vars->nelts;
 
@@ -263,27 +257,16 @@ ngx_http_auth_request_set_variables(ngx_
          * internal redirects
          */
 
-        vv = &r->variables[av->index];
-
         if (ngx_http_complex_value(ctx->subrequest, &av->value, &val)
             != NGX_OK)
         {
             return NGX_ERROR;
         }
 
-        vv->valid = 1;
-        vv->not_found = 0;
-        vv->data = val.data;
-        vv->len = val.len;
+        vv.data = val.data;
+        vv.len = val.len;
 
-        if (av->set_handler) {
-            /*
-             * set_handler only available in cmcf->variables_keys, so we store
-             * it explicitly
-             */
-
-            av->set_handler(r, vv, v[av->index].data);
-        }
+        ngx_http_set_indexed_variable(r, av->index, &vv);
 
         av++;
     }
@@ -434,8 +417,6 @@ ngx_http_auth_request_set(ngx_conf_t *cf
         v->get_handler = ngx_http_auth_request_variable;
     }
 
-    av->set_handler = v->set_handler;
-
     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
 
     ccv.cf = cf;
diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -893,11 +893,10 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_int_t                            index;
-    ngx_str_t                           *value;
-    ngx_http_variable_t                 *v;
-    ngx_http_script_var_code_t          *vcode;
-    ngx_http_script_var_handler_code_t  *vhcode;
+    ngx_int_t                    index;
+    ngx_str_t                   *value;
+    ngx_http_variable_t         *v;
+    ngx_http_script_var_code_t  *vcode;
 
     value = cf->args->elts;
 
@@ -930,20 +929,6 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    if (v->set_handler) {
-        vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
-                                   sizeof(ngx_http_script_var_handler_code_t));
-        if (vhcode == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        vhcode->code = ngx_http_script_var_set_handler_code;
-        vhcode->handler = v->set_handler;
-        vhcode->data = v->data;
-
-        return NGX_CONF_OK;
-    }
-
     vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
                                        sizeof(ngx_http_script_var_code_t));
     if (vcode == NULL) {
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1781,43 +1781,7 @@ ngx_http_script_set_var_code(ngx_http_sc
 
     e->sp--;
 
-    r->variables[code->index].len = e->sp->len;
-    r->variables[code->index].valid = 1;
-    r->variables[code->index].no_cacheable = 0;
-    r->variables[code->index].not_found = 0;
-    r->variables[code->index].data = e->sp->data;
-
-#if (NGX_DEBUG)
-    {
-    ngx_http_variable_t        *v;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-    v = cmcf->variables.elts;
-
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http script set $%V", &v[code->index].name);
-    }
-#endif
-}
-
-
-void
-ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
-{
-    ngx_http_script_var_handler_code_t  *code;
-
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http script set var handler");
-
-    code = (ngx_http_script_var_handler_code_t *) e->ip;
-
-    e->ip += sizeof(ngx_http_script_var_handler_code_t);
-
-    e->sp--;
-
-    code->handler(e->request, e->sp, code->data);
+    ngx_http_set_indexed_variable(r, code->index, e->sp);
 }
 
 
diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -102,13 +102,6 @@ typedef struct {
 
 typedef struct {
     ngx_http_script_code_pt     code;
-    ngx_http_set_variable_pt    handler;
-    uintptr_t                   data;
-} ngx_http_script_var_handler_code_t;
-
-
-typedef struct {
-    ngx_http_script_code_pt     code;
     uintptr_t                   n;
 } ngx_http_script_copy_capture_code_t;
 
@@ -259,7 +252,6 @@ void ngx_http_script_file_code(ngx_http_
 void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
-void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
 void ngx_http_script_var_code(ngx_http_script_engine_t *e);
 void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
 
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -745,6 +745,43 @@ ngx_http_get_variable(ngx_http_request_t
 }
 
 
+void
+ngx_http_set_indexed_variable(ngx_http_request_t *r, ngx_uint_t index,
+    ngx_http_variable_value_t *value)
+{
+    ngx_http_variable_t        *v;
+    ngx_http_variable_value_t  *vv;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    if (cmcf->variables.nelts <= index) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      "unknown variable index: %ui", index);
+        return;
+    }
+
+    v = cmcf->variables.elts;
+
+    if (v[index].set_handler) {
+        v[index].set_handler(r, value, v[index].data);
+
+    } else {
+        vv = &r->variables[index];
+
+        vv->len = value->len;
+        vv->valid = 1;
+        vv->no_cacheable = 0;
+        vv->not_found = 0;
+        vv->escape = 0;
+        vv->data = value->data;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http set $%V to \"%v\"", &v[index].name, value);
+}
+
+
 static ngx_int_t
 ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
@@ -2616,7 +2653,7 @@ ngx_http_regex_exec(ngx_http_request_t *
 {
     ngx_int_t                   rc, index;
     ngx_uint_t                  i, n, len;
-    ngx_http_variable_value_t  *vv;
+    ngx_http_variable_value_t   vv;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
@@ -2654,24 +2691,11 @@ ngx_http_regex_exec(ngx_http_request_t *
 
         n = re->variables[i].capture;
         index = re->variables[i].index;
-        vv = &r->variables[index];
-
-        vv->len = r->captures[n + 1] - r->captures[n];
-        vv->valid = 1;
-        vv->no_cacheable = 0;
-        vv->not_found = 0;
-        vv->data = &s->data[r->captures[n]];
-
-#if (NGX_DEBUG)
-        {
-        ngx_http_variable_t  *v;
-
-        v = cmcf->variables.elts;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http regex set $%V to \"%v\"", &v[index].name, vv);
-        }
-#endif
+
+        vv.len = r->captures[n + 1] - r->captures[n];
+        vv.data = &s->data[r->captures[n]];
+
+        ngx_http_set_indexed_variable(r, index, &vv);
     }
 
     r->ncaptures = rc * 2;
@@ -2754,6 +2778,7 @@ ngx_http_variables_init_vars(ngx_conf_t 
                 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
                    == 0)
             {
+                v[i].set_handler = av->set_handler;
                 v[i].get_handler = av->get_handler;
                 v[i].data = av->data;
 
@@ -2786,6 +2811,7 @@ ngx_http_variables_init_vars(ngx_conf_t 
         }
 
         if (av) {
+            v[i].set_handler = av->set_handler;
             v[i].get_handler = av->get_handler;
             v[i].data = (uintptr_t) &v[i].name;
             v[i].flags = av->flags;
diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -57,6 +57,9 @@ ngx_http_variable_value_t *ngx_http_get_
 ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r,
     ngx_str_t *name, ngx_uint_t key);
 
+void ngx_http_set_indexed_variable(ngx_http_request_t *r, ngx_uint_t index,
+    ngx_http_variable_value_t *value);
+
 ngx_int_t ngx_http_variable_unknown_header(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part,
     size_t prefix);
diff --git a/src/stream/ngx_stream_set_module.c b/src/stream/ngx_stream_set_module.c
--- a/src/stream/ngx_stream_set_module.c
+++ b/src/stream/ngx_stream_set_module.c
@@ -12,8 +12,6 @@
 
 typedef struct {
     ngx_int_t                   index;
-    ngx_stream_set_variable_pt  set_handler;
-    uintptr_t                   data;
     ngx_stream_complex_value_t  value;
 } ngx_stream_set_cmd_t;
 
@@ -90,18 +88,10 @@ ngx_stream_set_handler(ngx_stream_sessio
             return NGX_ERROR;
         }
 
-        if (cmds[i].set_handler != NULL) {
-            vv.len = str.len;
-            vv.data = str.data;
-            cmds[i].set_handler(s, &vv, cmds[i].data);
+        vv.len = str.len;
+        vv.data = str.data;
 
-        } else {
-            s->variables[cmds[i].index].len = str.len;
-            s->variables[cmds[i].index].valid = 1;
-            s->variables[cmds[i].index].no_cacheable = 0;
-            s->variables[cmds[i].index].not_found = 0;
-            s->variables[cmds[i].index].data = str.data;
-        }
+        ngx_stream_set_indexed_variable(s, cmds[i].index, &vv);
     }
 
     return NGX_DECLINED;
@@ -209,8 +199,6 @@ ngx_stream_set(ngx_conf_t *cf, ngx_comma
     }
 
     set_cmd->index = index;
-    set_cmd->set_handler = v->set_handler;
-    set_cmd->data = v->data;
 
     ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
 
diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c
--- a/src/stream/ngx_stream_variables.c
+++ b/src/stream/ngx_stream_variables.c
@@ -477,6 +477,43 @@ ngx_stream_get_variable(ngx_stream_sessi
 }
 
 
+void
+ngx_stream_set_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index,
+    ngx_stream_variable_value_t *value)
+{
+    ngx_stream_variable_t        *v;
+    ngx_stream_variable_value_t  *vv;
+    ngx_stream_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
+
+    if (cmcf->variables.nelts <= index) {
+        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
+                      "unknown variable index: %ui", index);
+        return;
+    }
+
+    v = cmcf->variables.elts;
+
+    if (v[index].set_handler) {
+        v[index].set_handler(s, value, v[index].data);
+
+    } else {
+        vv = &s->variables[index];
+
+        vv->len = value->len;
+        vv->valid = 1;
+        vv->no_cacheable = 0;
+        vv->not_found = 0;
+        vv->escape = 0;
+        vv->data = value->data;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+                   "stream set $%V to \"%v\"", &v[index].name, value);
+}
+
+
 static ngx_int_t
 ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s,
      ngx_stream_variable_value_t *v, uintptr_t data)
@@ -1100,7 +1137,7 @@ ngx_stream_regex_exec(ngx_stream_session
 {
     ngx_int_t                     rc, index;
     ngx_uint_t                    i, n, len;
-    ngx_stream_variable_value_t  *vv;
+    ngx_stream_variable_value_t   vv;
     ngx_stream_core_main_conf_t  *cmcf;
 
     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
@@ -1136,24 +1173,11 @@ ngx_stream_regex_exec(ngx_stream_session
 
         n = re->variables[i].capture;
         index = re->variables[i].index;
-        vv = &s->variables[index];
-
-        vv->len = s->captures[n + 1] - s->captures[n];
-        vv->valid = 1;
-        vv->no_cacheable = 0;
-        vv->not_found = 0;
-        vv->data = &str->data[s->captures[n]];
 
-#if (NGX_DEBUG)
-        {
-        ngx_stream_variable_t  *v;
+        vv.len = s->captures[n + 1] - s->captures[n];
+        vv.data = &str->data[s->captures[n]];
 
-        v = cmcf->variables.elts;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
-                       "stream regex set $%V to \"%v\"", &v[index].name, vv);
-        }
-#endif
+        ngx_stream_set_indexed_variable(s, index, &vv);
     }
 
     s->ncaptures = rc * 2;
@@ -1236,6 +1260,7 @@ ngx_stream_variables_init_vars(ngx_conf_
                 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
                    == 0)
             {
+                v[i].set_handler = av->set_handler;
                 v[i].get_handler = av->get_handler;
                 v[i].data = av->data;
 
@@ -1268,6 +1293,7 @@ ngx_stream_variables_init_vars(ngx_conf_
         }
 
         if (av) {
+            v[i].set_handler = av->set_handler;
             v[i].get_handler = av->get_handler;
             v[i].data = (uintptr_t) &v[i].name;
             v[i].flags = av->flags;
diff --git a/src/stream/ngx_stream_variables.h b/src/stream/ngx_stream_variables.h
--- a/src/stream/ngx_stream_variables.h
+++ b/src/stream/ngx_stream_variables.h
@@ -57,6 +57,9 @@ ngx_stream_variable_value_t *ngx_stream_
 ngx_stream_variable_value_t *ngx_stream_get_variable(ngx_stream_session_t *s,
     ngx_str_t *name, ngx_uint_t key);
 
+void ngx_stream_set_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index,
+    ngx_stream_variable_value_t *value);
+
 
 #if (NGX_PCRE)
 


More information about the nginx-devel mailing list