You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/10/25 02:34:31 UTC

[apisix] branch master updated: feat(proxy-rewrite): add method proxy (#5292)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new a348fff  feat(proxy-rewrite): add method proxy (#5292)
a348fff is described below

commit a348ffffe47649b504a42e3d5a73431d1add71d9
Author: Zhendong Qi <88...@users.noreply.github.com>
AuthorDate: Mon Oct 25 10:34:25 2021 +0800

    feat(proxy-rewrite): add method proxy (#5292)
    
    Co-authored-by: qizhendong <qi...@cmss.chinamobile.com>
---
 apisix/plugins/proxy-rewrite.lua        |  22 +++++
 docs/en/latest/plugins/proxy-rewrite.md |   1 +
 docs/zh/latest/plugins/proxy-rewrite.md |   1 +
 t/lib/server.lua                        |   1 +
 t/plugin/proxy-rewrite3.t               | 153 ++++++++++++++++++++++++++++++++
 5 files changed, 178 insertions(+)

diff --git a/apisix/plugins/proxy-rewrite.lua b/apisix/plugins/proxy-rewrite.lua
index 397d6d0..ca9210e 100644
--- a/apisix/plugins/proxy-rewrite.lua
+++ b/apisix/plugins/proxy-rewrite.lua
@@ -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 = {
@@ -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",
@@ -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
diff --git a/docs/en/latest/plugins/proxy-rewrite.md b/docs/en/latest/plugins/proxy-rewrite.md
index f5adf1f..a538ecb 100644
--- a/docs/en/latest/plugins/proxy-rewrite.md
+++ b/docs/en/latest/plugins/proxy-rewrite.md
@@ -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    | string        | optional    |         | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | rewrite the HTTP method.|
 | 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 re [...]
 | 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. |
diff --git a/docs/zh/latest/plugins/proxy-rewrite.md b/docs/zh/latest/plugins/proxy-rewrite.md
index e544909..d30a270 100644
--- a/docs/zh/latest/plugins/proxy-rewrite.md
+++ b/docs/zh/latest/plugins/proxy-rewrite.md
@@ -39,6 +39,7 @@ proxy-rewrite 是上游代理信息重写插件,支持对 `scheme`、`uri`、`
 | --------- | ------------- | ----------- | ------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | scheme    | string        | 可选        | "http"  | ["http", "https"] | 不推荐使用。应该在 Upstream 的 scheme 字段设置上游的 scheme。
 | uri       | string        | 可选        |         |                   | 转发到上游的新 `uri` 地址。                                                                                                                                                                                                                                                                             |
+| method    | string        | 可选        |         | ["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。                                                                               |
diff --git a/t/lib/server.lua b/t/lib/server.lua
index d72a308..02550d6 100644
--- a/t/lib/server.lua
+++ b/t/lib/server.lua
@@ -76,6 +76,7 @@ function _M.plugin_proxy_rewrite()
     ngx.say("uri: ", ngx.var.uri)
     ngx.say("host: ", ngx.var.host)
     ngx.say("scheme: ", ngx.var.scheme)
+    ngx.log(ngx.WARN, "plugin_proxy_rewrite get method: ", ngx.req.get_method())
 end
 
 
diff --git a/t/plugin/proxy-rewrite3.t b/t/plugin/proxy-rewrite3.t
new file mode 100644
index 0000000..31364d0
--- /dev/null
+++ b/t/plugin/proxy-rewrite3.t
@@ -0,0 +1,153 @@
+#
+# 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)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 2: hit route(upstream uri: should be /hello)
+--- request
+GET /hello
+--- grep_error_log_out
+plugin_proxy_rewrite get method: POST
+
+
+
+=== TEST 3: set route(update 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": "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)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 4: hit route(upstream uri: should be /hello)
+--- request
+GET /hello
+--- grep_error_log_out
+plugin_proxy_rewrite get method: GET
+
+
+
+=== TEST 5: 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")
+        }
+    }
+--- response_body
+property "method" validation failed: matches none of the enum values
+done