feat(proxy-rewrite): support NGINX variables in regex_uri - #13800
feat(proxy-rewrite): support NGINX variables in regex_uri#13800ruanweihong-aaa wants to merge 2 commits into
Conversation
| if test_replacement ~= "" then | ||
| local err | ||
| test_replacement, err = escape_nginx_vars(test_replacement) | ||
| if err then | ||
| return false, "invalid regex_uri replacement(" .. | ||
| replacement .. "): " .. err | ||
| end | ||
| end |
There was a problem hiding this comment.
This is needed because check_schema compiles the replacement with ngx.re.sub to validate both the regex pattern and replacement syntax.
Without escaping NGINX variables, $arg_name is interpreted as a named PCRE capture and route creation fails with "failed to compile the replacement template", which is the original issue.
Escaping only NGINX variable markers as $$ allows PCRE to keep validating regular captures such as $1 and invalid replacement syntax, while treating $arg_name as a literal during schema validation. The existing invalid replacement test also depends on this validation.
I can add a comment here to explain this.
There was a problem hiding this comment.
Added an inline comment in d1b362b explaining that schema validation must keep validating PCRE captures without treating NGINX variables as named captures.
| local replacement = preserve_literal_dollars(conf.regex_uri[i + 1]) | ||
| replacement = core.utils.resolve_var_with_captures(replacement, captures) | ||
| replacement = core.utils.resolve_var(replacement, ctx.var, escape_separator) | ||
| replacement = restore_literal_dollars(replacement) | ||
| local uri, _, err = re_sub(upstream_uri, | ||
| conf.regex_uri[i], conf.regex_uri[i + 1], "jo") | ||
| conf.regex_uri[i], function() | ||
| return replacement | ||
| end, "jo") |
There was a problem hiding this comment.
It's too complicated. Is there a simpler way?
There was a problem hiding this comment.
The additional steps preserve three different replacement semantics:
$1and$2are regex captures.$arg_nameand values fromctx.varare NGINX variables.$$xmust remain the literal string$x.
Resolving NGINX variables directly would also consume $1, while letting ngx.re.sub process the replacement after variable resolution could interpret dollar signs from resolved values again.
I also tested resolving variables after ngx.re.sub, but at that point an escaped NGINX variable and an existing literal $$x both become $..., so they can no longer be distinguished.
I can move these stages into a focused helper to make the rewrite path easier to read. Would that address the concern, or would you prefer a different replacement behavior for literal $$?
Description
Currently,
proxy-rewrite.urisupports NGINX variables, but the replacement part ofproxy-rewrite.regex_urionly supports regular expression captures such as$1and$2.This PR adds NGINX variable resolution support to
regex_urireplacements.For example:
{ "regex_uri": [ "^/api/(.*)/users/(.*)$", "/v2/$1/external-users/$arg_name" ] }The replacement is processed in explicit stages:
$$x.$1and$2.$arg_nameand variables stored inctx.var.Schema validation also distinguishes NGINX variables from regular expression captures. This allows a route containing both forms to be saved successfully.
Existing
$1and$2capture behavior and$$literal-dollar behavior remain compatible.The English and Chinese
proxy-rewritedocumentation have also been updated to describe the new behavior.Which issue(s) this PR fixes:
Fixes #13140
Tests
t/plugin/proxy-rewrite4.t.$1and$2capture behavior.$$xbehavior.t/plugin/proxy-rewrite4.t: 6/6 passed.luacheck: 0 warnings and 0 errors for the modified Lua file.lj-releng: passed for the modified Lua file.Checklist