id summary reporter owner description type status priority milestone component version resolution keywords cc uname nginx_version 2213 The get_handler of ngx_http_variable_t is overwritten by ngx_http_regex_compile if existing sansanvang@… "I'm developing a dynamical NGINX module. I added a variable at preconfiguration stage and print its `get_handler` at postconfiguration stage. Because I added a named capture group in a regex location directive of nginx.conf, i.e. the variable would be set/defined (set access) at configuration stage, I used the `NGX_HTTP_VAR_CHANGEABLE` flag. However, I found this variable was empty when it's used in a subrequest location block. Then I checked its `get_handler` at postconfiguration stage and I found it was overrided. So I think we should check its value of `get_handler` before setting it. The key C++ code snippet (some omitted for brevity), {{{ #define NGX_HTTP_VAR_sp_resid ""sp_resid"" static const ngx_str_t sp_resid_name = ngx_string(NGX_HTTP_VAR_sp_resid) #define NGX_HTTP_EM_VAR_NAME(name) const_cast(&::name##_name) /* The module context. */ static ngx_http_module_t ngx_http_em_module_ctx = { ngx_http_em_preconfiguration, /* preconfiguration */ ngx_http_em_postconfiguration, /* postconfiguration */ ngx_http_em_create_main_conf, /* create main configuration */ ngx_http_em_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_em_create_loc_conf, /* create location-specific configuration */ ngx_http_em_merge_loc_conf, /* merge location configuration */ }; static ngx_int_t ngx_http_sp_resid_variable(ngx_http_request_t *req, ngx_http_variable_value_t *vv, uintptr_t data) { const auto ctx = ngx_http_em_get_module_ctx(req->main); logdf(""ctx@%p, req=%.*s?%.*s, spResId=%.*s"", ctx, ARGS_NGX_STR(req->uri), ARGS_NGX_STR(req->args), ARGS_NGX_STR(ctx->spResId)); if (ctx == NULL) { vv->not_found = 1; return NGX_OK; } vv->valid = 1; vv->no_cacheable = 0; vv->not_found = 0; vv->data = ctx->spResId.data; vv->len = ctx->spResId.len; return NGX_OK; } ngx_int_t ngx_http_em_preconfiguration(ngx_conf_t *cf) { ngx_http_variable_t *var; var = ngx_http_add_variable(cf, NGX_HTTP_EM_VAR_NAME(sp_resid), NGX_HTTP_VAR_CHANGEABLE | NGX_HTTP_VAR_NOCACHEABLE); if (var == NULL) { return NGX_ERROR; } var->get_handler = ngx_http_sp_resid_variable; return NGX_OK; } ngx_int_t ngx_http_em_postconfiguration(ngx_conf_t *cf) { // Restore v->get_handler = ngx_http_variable_not_found set // by ngx_http_regex_t *ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc) // in nginx\nginx\src\http\ngx_http_variables.c auto vars_keys = cmcf->variables_keys->keys; auto keys = static_cast(vars_keys.elts); for (auto idx = vars_keys.nelts; idx > 0;) { const auto& var_entry = keys[--idx]; // ngx_strncasecmp if (sizeof(NGX_HTTP_VAR_sp_resid) - 1 == var_entry.key.len && 0 == ngx_strncasecmp(PUChar(NGX_HTTP_VAR_sp_resid), var_entry.key.data, sizeof(NGX_HTTP_VAR_sp_resid) - 1)) { const auto var = static_cast(var_entry.value); logdf(""var->get_handler=%p, ngx_http_sp_resid_variable=%p"", var->get_handler, ngx_http_sp_resid_variable); var->get_handler = ngx_http_sp_resid_variable; // workaround } } } }}} nginx.conf {{{ location / { proxy_pass $scheme://$host; } location ~ ""^/_api/(?[[:xdigit:]]{8}(?:-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12})/driveItem$"" { proxy_pass $scheme://$host; } location = /GetList { internal; subrequest_output_buffer_size 128k; proxy_set_header Content-Length """"; proxy_set_header Accept-Encoding """"; proxy_set_header Accept ""application/json;odata=nometadata""; proxy_pass $scheme://$host/_api/web/GetList(@a1)?@a1='$sp_resid'&%24expand=RootFolder; } }}} " defect new major nginx-module 1.19.x get_handler, ngx_http_variable_t Linux emsp 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux "nginx version: nginx/1.19.3 (emsp-1.0.1) built by gcc 8.3.1 20191121 (Red Hat 8.3.1-5) (GCC) built with OpenSSL 1.1.1g FIPS 21 Apr 2020 TLS SNI support enabled configure arguments: --builddir=../objs --prefix=/usr/local/nginx --user=nginx --group=nginx --with-pcre --with-http_ssl_module --with-http_stub_status_module --with-http_gzip_static_module --with-compat --add-dynamic-module=../nginx-emsp-module --with-threads --with-debug --with-cc-opt='-O0 -DNGX_BUILD=""emsp-1.0.1"" -DNGX_API= -Wno-error=unused-function -Wno-missing-field-initializers'"