From 8fec479eb6cccdf392464b8e468d870eeb6a215b Mon Sep 17 00:00:00 2001 From: minwoo-choi Date: Sat, 24 Jan 2026 16:10:55 +0900 Subject: [PATCH 1/2] feat: add $uarg_ variable family --- src/http/ngx_http_variables.c | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index dd69bcfcd..bee2ed039 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -42,6 +42,8 @@ static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_argument_unescape(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); #if (NGX_HAVE_TCP_INFO) static ngx_int_t ngx_http_variable_tcpinfo(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -408,6 +410,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("arg_"), NULL, ngx_http_variable_argument, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, + { ngx_string("uarg_"), NULL, ngx_http_variable_argument_unescape, + 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, + ngx_http_null_variable }; @@ -1133,6 +1138,44 @@ ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v, } +static ngx_int_t +ngx_http_variable_argument_unescape(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *name = (ngx_str_t *) data; + + u_char *arg, *dst, *src; + size_t len; + ngx_str_t value; + + len = name->len - (sizeof("uarg_") - 1); + arg = name->data + sizeof("uarg_") - 1; + + if (len == 0 || ngx_http_arg(r, arg, len, &value) != NGX_OK) { + v->not_found = 1; + return NGX_OK; + } + + /* allocate buffer for unescaped value (can only shrink or stay same) */ + dst = ngx_pnalloc(r->pool, value.len); + if (dst == NULL) { + return NGX_ERROR; + } + + v->data = dst; + src = value.data; + + ngx_unescape_uri(&dst, &src, value.len, 0); + + v->len = dst - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + #if (NGX_HAVE_TCP_INFO) static ngx_int_t From 0d9b85ab82dbd7b5a9f591a4f03f139dae508362 Mon Sep 17 00:00:00 2001 From: minwoo-choi Date: Sat, 24 Jan 2026 16:11:11 +0900 Subject: [PATCH 2/2] feat: add $uargs variable --- src/http/ngx_http_variables.c | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index bee2ed039..b6c5ea4b5 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -81,6 +81,8 @@ static void ngx_http_variable_set_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_uargs(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r, @@ -272,6 +274,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { offsetof(ngx_http_request_t, args), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("uargs"), NULL, ngx_http_variable_uargs, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("is_args"), NULL, ngx_http_variable_is_args, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -1667,6 +1672,37 @@ ngx_http_variable_is_args(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_uargs(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *dst, *src; + + if (r->args.len == 0) { + *v = ngx_http_variable_null_value; + return NGX_OK; + } + + /* allocate buffer for unescaped value (can only shrink or stay same) */ + dst = ngx_pnalloc(r->pool, r->args.len); + if (dst == NULL) { + return NGX_ERROR; + } + + v->data = dst; + src = r->args.data; + + ngx_unescape_uri(&dst, &src, r->args.len, 0); + + v->len = dst - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data)