Opened 3 years ago
Last modified 3 years ago
#2213 new defect
The get_handler of ngx_http_variable_t is overwritten by ngx_http_regex_compile if existing
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | major | Milestone: | |
Component: | nginx-module | Version: | 1.19.x |
Keywords: | get_handler, ngx_http_variable_t | Cc: | |
uname -a: | 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 -V: |
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' |
Description
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<ngx_str_t*>(&::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<ngx_hash_key_t*>(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<ngx_http_variable_t*>(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/(?<sp_resid>[[: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; }