Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support uri encoding in redirect #4244

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions apisix/plugins/redirect.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ local re_gmatch = ngx.re.gmatch
local re_sub = ngx.re.sub
local ipairs = ipairs
local ngx = ngx
local str_find = core.string.find
local sub_str = string.sub
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved

local lrucache = core.lrucache.new({
ttl = 300, count = 100
Expand Down Expand Up @@ -49,6 +51,7 @@ local schema = {
}
},
http_to_https = {type = "boolean"},
encode_uri = {type = "boolean", default = false}
},
oneOf = {
{required = {"uri"}},
Expand Down Expand Up @@ -160,17 +163,17 @@ function _M.rewrite(conf, ctx)
end

if ret_code then
local new_uri
if uri then
local new_uri, err = concat_new_uri(uri, ctx)
local err
new_uri, err = concat_new_uri(uri, ctx)
if not new_uri then
core.log.error("failed to generate new uri by: " .. uri .. err)
return 500
end

core.response.set_header("Location", new_uri)
return ret_code
elseif regex_uri then
local new_uri, n, err = re_sub(ctx.var.uri, regex_uri[1],
local n, err
new_uri, n, err = re_sub(ctx.var.uri, regex_uri[1],
regex_uri[2], "jo")
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved
if not new_uri then
local msg = string_format("failed to substitute the uri:%s (%s) with %s, error:%s",
Expand All @@ -179,11 +182,23 @@ function _M.rewrite(conf, ctx)
return 500
end

if n > 0 then
core.response.set_header("Location", new_uri)
return ret_code
if n < 1 then
return
end
end

if conf.encode_uri then
local index = str_find(new_uri, "?")
if index then
new_uri = core.utils.uri_safe_encode(sub_str(new_uri, 1, index-1)) ..
sub_str(new_uri, index)
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved
else
new_uri = core.utils.uri_safe_encode(new_uri)
end
end

core.response.set_header("Location", new_uri)
return ret_code
end

end
Expand Down
3 changes: 2 additions & 1 deletion docs/en/latest/plugins/redirect.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ URI redirect.
| uri | string | optional | | | New URL which can contain Nginx variable, eg: `/test/index.html`, `$uri/index.html`. You can refer to variables in a way similar to `${xxx}` to avoid ambiguity, eg: `${uri}foo/index.html`. If you just need the original `$` character, add `\` in front of it, like this one: `/\$foo/index.html`. If you refer to a variable name that does not exist, this will not produce an error, and it will be used as an empty string. |
| regex_uri | array[string] | optional | | | Use regular expression to match URL from client, when the match is successful, the URL template will be redirected to. If the match is not successful, the URL from the client will be forwarded to the upstream. Only one of `uri` and `regex_uri` can be exist. For example: [" ^/iresty/(.*)/(.*)/(.*)", "/$1-$2-$3"], the first element represents the matching regular expression and the second element represents the URL template that is redirected to. |
| ret_code | integer | optional | 302 | [200, ...] | Response code |
| encode_uri | boolean | optional | false | | When set to `true` the uri in `Location` header will be encoded. |
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved

Only one of `http_to_https` or `uri` can be specified.
Only one of `http_to_https`, `uri`, `regex_uri` can be specified.
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved

## How To Enable

Expand Down
3 changes: 2 additions & 1 deletion docs/zh/latest/plugins/redirect.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ URI 重定向插件。
| uri | string | 可选 | | | 可以包含 Nginx 变量的 URI,例如:`/test/index.html`, `$uri/index.html`。你可以通过类似于 `$ {xxx}` 的方式引用变量,以避免产生歧义,例如:`${uri}foo/index.html`。若你需要保留 `$` 字符,那么使用如下格式:`/\$foo/index.html` |
| regex_uri | array[string] | 可选 | | | 转发到上游的新 `uri` 地址, 使用正则表达式匹配来自客户端的 `uri`,当匹配成功后使用模板替换发送重定向到客户端, 未匹配成功时将客户端请求的 `uri` 转发至上游。`uri` 和 `regex_uri` 不可以同时存在。例如:["^/iresty/(.*)/(.*)/(.*)","/$1-$2-$3"] 第一个元素代表匹配来自客户端请求的 `uri` 正则表达式,第二个元素代表匹配成功后发送重定向到客户端的 `uri` 模板。 |
| ret_code | integer | 可选 | 302 | [200, ...] | 请求响应码 |
| encode_uri | boolean | 可选 | false | | 当设置为 `true` 时,对返回的 `Location` header进行编码. |

`http_to_https``uri` 两个中只能配置一个
`http_to_https``uri`,`regex_uri` 三个中只能配置一个
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved

### 示例

Expand Down
97 changes: 97 additions & 0 deletions t/plugin/redirect.t
Original file line number Diff line number Diff line change
Expand Up @@ -813,3 +813,100 @@ GET /hello
hello world
--- no_error_log
[error]



=== TEST 33: add plugin with new regex_uri: encode_uri = true
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"redirect": {
"regex_uri": ["^/test/(.*)", "http://test.com/${1}"],
"ret_code": 301,
"encode_uri": true
}
},
"uri": "/test/*",
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
}
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 34: regex_uri redirect with special characters
--- request
GET /test/with%20space
--- error_code: 200
--- response_headers
Location: http://test.com/with%20space
--- error_code: 301
--- no_error_log
[error]



=== TEST 35: add plugin with new uri: encode_uri = true
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"redirect": {
"uri": "$uri",
"ret_code": 301,
"encode_uri": true
}
},
"uri": "/hello*"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 36: redirect with special characters
--- request
GET /hello/with%20space
--- response_headers
Location: /hello/with%20space
--- error_code: 301
--- no_error_log
[error]
Gary-Airwallex marked this conversation as resolved.
Show resolved Hide resolved