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(proxy-rewrite): add method proxy #5292

Merged
merged 11 commits into from
Oct 25, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
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
22 changes: 22 additions & 0 deletions apisix/plugins/proxy-rewrite.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ local re_sub = ngx.re.sub
local sub_str = string.sub
local str_find = core.string.find

local switch_map = {GET = ngx.HTTP_GET, POST = ngx.HTTP_POST, PUT = ngx.HTTP_PUT,
HEAD = ngx.HTTP_HEAD, DELETE = ngx.HTTP_DELETE,
OPTIONS = ngx.HTTP_OPTIONS, MKCOL = ngx.HTTP_MKCOL,
COPY = ngx.HTTP_COPY, MOVE = ngx.HTTP_MOVE,
PROPFIND = ngx.HTTP_PROPFIND, LOCK = ngx.HTTP_LOCK,
UNLOCK = ngx.HTTP_UNLOCK, PATCH = ngx.HTTP_PATCH,
TRACE = ngx.HTTP_TRACE,
}
local schema_method_enum = {}
for key in pairs(switch_map) do
core.table.insert(schema_method_enum, key)
end

local schema = {
type = "object",
properties = {
Expand All @@ -34,6 +47,11 @@ local schema = {
maxLength = 4096,
pattern = [[^\/.*]],
},
method = {
description = "proxy route method",
type = "string",
enum = schema_method_enum
},
regex_uri = {
description = "new uri that substitute from client uri " ..
"for upstream, lower priority than uri property",
Expand Down Expand Up @@ -196,6 +214,10 @@ function _M.rewrite(conf, ctx)
ngx.req.set_header(conf.headers_arr[i],
core.utils.resolve_var(conf.headers_arr[i+1], ctx.var))
end

if conf.method then
ngx.req.set_method(switch_map[conf.method])
end
end

end -- do
Expand Down
1 change: 1 addition & 0 deletions docs/en/latest/plugins/proxy-rewrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The `proxy-rewrite` is an upstream proxy information rewriting plugin, which sup
| --------- | ------------- | ----------- | ------- | ----------------- | ------------------------------------------------------------ |
| scheme | string | optional | "http" | ["http", "https"] | Upstream new `schema` forwarding protocol. This option is deprecated. It's recommended to set the proxy `scheme` in the Upstream object's `scheme` field instead.|
| uri | string | optional | | | Upstream new `uri` forwarding address. Supports the use of [Nginx variables](https://nginx.org/en/docs/http/ngx_http_core_module.html). Variables must start with `$`, such as `$arg_name`. |
| method | enum | optional | | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | rewrite the HTTP method.|
qizhendong1 marked this conversation as resolved.
Show resolved Hide resolved
| regex_uri | array[string] | optional | | | Upstream new `uri` forwarding address. Use regular expression to match URL from client, when the match is successful, the URL template will be forwarded upstream. If the match is not successful, the URL from the client will be forwarded to the upstream. When `uri` and `regex_uri` are both exist, `uri` is used first. For example: [" ^/iresty/(.*)/(.*)/(.*)", "/$1-$2-$3"], the first element represents the matching regular expression and the second element represents the URL template that is forwarded to the upstream. |
| host | string | optional | | | Upstream new `host` forwarding address, example `iresty.com`. |
| headers | object | optional | | | Forward to the new `headers` of the upstream, can set up multiple. If it exists, will rewrite the header, otherwise will add the header. You can set the corresponding value to an empty string to remove a header. Support the use of Nginx variables. Need to start with `$`, such as `client_addr: $remote_addr`: it means that the request header `client_addr` is the client IP. |
Expand Down
1 change: 1 addition & 0 deletions docs/zh/latest/plugins/proxy-rewrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ proxy-rewrite 是上游代理信息重写插件,支持对 `scheme`、`uri`、`
| --------- | ------------- | ----------- | ------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| scheme | string | 可选 | "http" | ["http", "https"] | 不推荐使用。应该在 Upstream 的 scheme 字段设置上游的 scheme。
| uri | string | 可选 | | | 转发到上游的新 `uri` 地址。 |
| method | enum | 可选 | | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | 将route的请求方法代理为该请求方法。 |
| regex_uri | array[string] | 可选 | | | 转发到上游的新 `uri` 地址, 使用正则表达式匹配来自客户端的uri,当匹配成功后使用模板替换转发到上游的uri, 未匹配成功时将客户端请求的uri转发至上游。当`uri`和`regex_uri`同时存在时,`uri`优先被使用。例如:["^/iresty/(.*)/(.*)/(.*)","/$1-$2-$3"] 第一个元素代表匹配来自客户端请求的uri正则表达式,第二个元素代表匹配成功后转发到上游的uri模板。 |
| host | string | 可选 | | | 转发到上游的新 `host` 地址,例如:`iresty.com` 。 |
| headers | object | 可选 | | | 转发到上游的新`headers`,可以设置多个。头信息如果存在将重写,不存在则添加。想要删除某个 header 的话,把对应的值设置为空字符串即可。支持使用 Nginx 的变量,需要以 `$` 开头,如 `client_addr: $remote_addr` :表示请求头 `client_addr` 为客户端IP。 |
Expand Down
149 changes: 149 additions & 0 deletions t/plugin/proxy-rewrite3.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
use t::APISIX 'no_plan';

repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();
log_level("info");

add_block_preprocessor(sub {
my ($block) = @_;

if (!$block->request) {
$block->set_value("request", "GET /t");
}

if (!$block->no_error_log && !$block->error_log) {
$block->set_value("no_error_log", "[error]\n[alert]");
}
});

run_tests;

__DATA__

=== TEST 1: set route(rewrite method)
--- 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,
[[{
"methods": ["GET"],
"plugins": {
"proxy-rewrite": {
"uri": "/plugin_proxy_rewrite",
"method": "POST",
"scheme": "http",
"host": "apisix.iresty.com"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
qizhendong1 marked this conversation as resolved.
Show resolved Hide resolved
--- response_body
passed
--- no_error_log
qizhendong1 marked this conversation as resolved.
Show resolved Hide resolved
[error]



=== TEST 2: set route(update rewrite method)
qizhendong1 marked this conversation as resolved.
Show resolved Hide resolved
--- 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,
[[{
"methods": ["GET"],
"plugins": {
"proxy-rewrite": {
"uri": "/plugin_proxy_rewrite",
"method": "GET",
"scheme": "http",
"host": "apisix.iresty.com"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
qizhendong1 marked this conversation as resolved.
Show resolved Hide resolved
[error]



=== TEST 3: wrong value of method key
--- config
location /t {
content_by_lua_block {
local plugin = require("apisix.plugins.proxy-rewrite")
local ok, err = plugin.check_schema({
uri = '/apisix/home',
method = 'GET1',
host = 'apisix.iresty.com',
scheme = 'http'
})
if not ok then
ngx.say(err)
end

ngx.say("done")
}
}
--- request
GET /t
--- response_body
property "method" validation failed: matches none of the enum values
done
--- no_error_log
[error]