You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by mo...@apache.org on 2023/05/06 08:07:16 UTC

[apisix] branch master updated: feat: proxy_rewrite support miltiple regex pattern matching (#9194)

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

monkeydluffy 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 4f54fa717 feat: proxy_rewrite support miltiple regex pattern matching (#9194)
4f54fa717 is described below

commit 4f54fa7173292d29aa3695957e8ee2272b062025
Author: fengxsong <fe...@outlook.com>
AuthorDate: Sat May 6 16:07:06 2023 +0800

    feat: proxy_rewrite support miltiple regex pattern matching (#9194)
---
 apisix/plugins/proxy-rewrite.lua        | 58 ++++++++++++++++---------
 docs/en/latest/plugins/proxy-rewrite.md |  2 +-
 docs/zh/latest/plugins/proxy-rewrite.md |  2 +-
 t/plugin/proxy-rewrite3.t               | 75 +++++++++++++++++++++++++++++++++
 4 files changed, 114 insertions(+), 23 deletions(-)

diff --git a/apisix/plugins/proxy-rewrite.lua b/apisix/plugins/proxy-rewrite.lua
index c0c52413a..0766463fb 100644
--- a/apisix/plugins/proxy-rewrite.lua
+++ b/apisix/plugins/proxy-rewrite.lua
@@ -66,7 +66,6 @@ local schema = {
             description = "new uri that substitute from client uri " ..
                           "for upstream, lower priority than uri property",
             type        = "array",
-            maxItems    = 2,
             minItems    = 2,
             items       = {
                 description = "regex uri",
@@ -192,11 +191,16 @@ function _M.check_schema(conf)
     end
 
     if conf.regex_uri and #conf.regex_uri > 0 then
-        local _, _, err = re_sub("/fake_uri", conf.regex_uri[1],
-                                   conf.regex_uri[2], "jo")
-        if err then
-            return false, "invalid regex_uri(" .. conf.regex_uri[1] ..
-                            ", " .. conf.regex_uri[2] .. "): " .. err
+        if (#conf.regex_uri % 2 ~= 0) then
+            return false, "The length of regex_uri should be an even number"
+        end
+        for i = 1, #conf.regex_uri, 2 do
+            local _, _, err = re_sub("/fake_uri", conf.regex_uri[i],
+                conf.regex_uri[i + 1], "jo")
+            if err then
+                return false, "invalid regex_uri(" .. conf.regex_uri[i] ..
+                    ", " .. conf.regex_uri[i + 1] .. "): " .. err
+            end
         end
     end
 
@@ -283,24 +287,36 @@ function _M.rewrite(conf, ctx)
             separator_escaped = true
         end
 
-        local uri, _, err = re_sub(upstream_uri, conf.regex_uri[1],
-                                   conf.regex_uri[2], "jo")
-        if not uri then
-            local msg = "failed to substitute the uri " .. ctx.var.uri ..
-                        " (" .. conf.regex_uri[1] .. ") with " ..
-                        conf.regex_uri[2] .. " : " .. err
-            core.log.error(msg)
-            return 500, {message = msg}
-        end
+        local error_msg
+        for i = 1, #conf.regex_uri, 2 do
+            local captures, err = re_match(upstream_uri, conf.regex_uri[i], "jo")
+            if err then
+                error_msg = "failed to match the uri " .. ctx.var.uri ..
+                    " (" .. conf.regex_uri[i] .. ") " .. " : " .. err
+                break
+            end
 
-        local m, err = re_match(upstream_uri, conf.regex_uri[1], "jo")
-        if not m and err then
-            core.log.error("match error in proxy-rewrite plugin, please check: ", err)
-            return 500
+            if captures then
+                ctx.proxy_rewrite_regex_uri_captures = captures
+
+                local uri, _, err = re_sub(upstream_uri,
+                    conf.regex_uri[i], conf.regex_uri[i + 1], "jo")
+                if uri then
+                    upstream_uri = uri
+                else
+                    error_msg = "failed to substitute the uri " .. ngx.var.uri ..
+                        " (" .. conf.regex_uri[i] .. ") with " ..
+                        conf.regex_uri[i + 1] .. " : " .. err
+                end
+
+                break
+            end
         end
-        ctx.proxy_rewrite_regex_uri_captures = m
 
-        upstream_uri = uri
+        if error_msg ~= nil then
+            core.log.error(error_msg)
+            return 500, { error_msg = error_msg }
+        end
     end
 
     if not conf.use_real_request_uri_unsafe then
diff --git a/docs/en/latest/plugins/proxy-rewrite.md b/docs/en/latest/plugins/proxy-rewrite.md
index fb1b65eeb..af00d15d4 100644
--- a/docs/en/latest/plugins/proxy-rewrite.md
+++ b/docs/en/latest/plugins/proxy-rewrite.md
@@ -38,7 +38,7 @@ The `proxy-rewrite` Plugin rewrites Upstream proxy information such as `scheme`,
 |-----------------------------|---------------|----------|---------|----------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [...]
 | uri                         | string        | False    |         |                                                                                                                                        | New Upstream forwarding address. Value supports [Nginx variables](https://nginx.org/en/docs/http/ngx_http_core_module.html). For example, `$arg_name`.                                                                                                                                         [...]
 | method                      | string        | False    |         | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | Rewrites the HTTP method.                                                                                                                                                                                                                                                                      [...]
-| regex_uri                   | array[string] | False    |         |                                                                                                                                        | New upstream forwarding address. Regular expressions can be used to match the URL from client. If it matches, the URL template is forwarded to the Upstream otherwise, the URL from the client is forwarded. When both `uri` and `regex_uri` are configured, `uri` is used first. For example, [...]
+| regex_uri                   | array[string] | False    |         |                                                                                                                                        | Regular expressions can be used to match the URL from client. If it matches, the URL template is forwarded to the upstream. Otherwise, the URL from the client is forwarded. When both `uri` and `regex_uri` are configured, `uri` has a higher priority. Multiple regular expressions are cur [...]
 | host                        | string        | False    |         |                                                                                                                                        | New Upstream host address.                                                                                                                                                                                                                                                                     [...]
 | headers                     | object        | False    |         |                                                                                                                                   |                   |
 | headers.add     | object   | false     |        |                 | Append the new headers. The format is `{"name": "value",...}`. The values in the header can contain Nginx variables like `$remote_addr` and `$balancer_ip`. It also supports referencing the match result of `regex_uri` as a variable like `$1-$2-$3`.                                                                                              |
diff --git a/docs/zh/latest/plugins/proxy-rewrite.md b/docs/zh/latest/plugins/proxy-rewrite.md
index 73ec4c158..9716fd491 100644
--- a/docs/zh/latest/plugins/proxy-rewrite.md
+++ b/docs/zh/latest/plugins/proxy-rewrite.md
@@ -38,7 +38,7 @@ description: 本文介绍了关于 Apache APISIX `proxy-rewrite` 插件的基本
 | --------- | ------------- | ----- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | uri       | string        | 否    |         |                                                                                                                                        | 转发到上游的新 `uri` 地址。支持 [NGINX variables](https://nginx.org/en/docs/http/ngx_http_core_module.html) 变量,例如:`$arg_name`。  |
 | method    | string        | 否    |         | ["GET", "POST", "PUT", "HEAD", "DELETE", "OPTIONS","MKCOL", "COPY", "MOVE", "PROPFIND", "PROPFIND","LOCK", "UNLOCK", "PATCH", "TRACE"] | 将路由的请求方法代理为该请求方法。 |
-| regex_uri | array[string] | 否    |         |                                                                                                                                        | 转发到上游的新 `uri` 地址。使用正则表达式匹配来自客户端的 `uri`,如果匹配成功,则使用模板替换转发到上游的 `uri`,如果没有匹配成功,则将客户端请求的 `uri` 转发至上游。当同时配置 `uri` 和 `regex_uri` 属性时,优先使用 `uri`。例如:["^/iresty/(.*)/(.*)/(.*)","/$1-$2-$3"] 第一个元素代表匹配来自客户端请求的 `uri` 正则表达式,第二个元素代表匹配成功后转发到上游的 `uri` 模板。但是目前 APISIX 仅支持一个 `regex_uri`,所以 `regex_uri` 数组的长度是 `2`。 |
+| regex_uri | array[string] | 否    |         |                                                                                                                                        | 使用正则表达式匹配来自客户端的 `uri`,如果匹配成功,则使用模板替换转发到上游的 `uri`,如果没有匹配成功,则将客户端请求的 `uri` 转发至上游。当同时配置 `uri` 和 `regex_uri` 属性时,优先使用 `uri`。当前支持多组正则表达式进行模式匹配,插件将逐一尝试匹配直至成功或全部失败。例如:`["^/iresty/(.*)/(.*)/(.*)", "/$1-$2-$3", ^/theothers/(.*)/(.*)", "/theothers/$1-$2"]`,奇数索引的元素代表匹配来自客户端请求的 `uri` 正则表达式,偶数索引的元素代表匹配成功后转发到上游的 `uri` 模板 [...]
 | host      | string        | 否    |         |                   | 转发到上游的新 `host` 地址,例如:`iresty.com`。|
 | headers   | object        | 否    |         |                   |   |
 | headers.add     | object   | 否     |        |                 | 添加新的请求头,如果头已经存在,会追加到末尾。格式为 `{"name": "value", ...}`。这个值能够以 `$var` 的格式包含 NGINX 变量,比如 `$remote_addr $balancer_ip`。也支持以变量的形式引用 `regex_uri` 的匹配结果,比如 `$1-$2-$3`。                                                                                              |
diff --git a/t/plugin/proxy-rewrite3.t b/t/plugin/proxy-rewrite3.t
index 33d751bfd..98f27de74 100644
--- a/t/plugin/proxy-rewrite3.t
+++ b/t/plugin/proxy-rewrite3.t
@@ -867,3 +867,78 @@ GET /echo HTTP/1.1
 X-Forwarded-For: 11.11.11.11
 --- response_headers
 X-Forwarded-For: 22.22.22.22, 127.0.0.1
+
+
+
+=== TEST 37: setting multiple regex_uris
+--- 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": {
+                          "proxy-rewrite": {
+                              "regex_uri": [
+                                  "^/test/(.*)/(.*)/(.*)/hello",
+                                  "/hello/$1_$2_$3",
+                                  "^/test/(.*)/(.*)/(.*)/world",
+                                  "/world/$1_$2_$3"
+                              ]
+                          }
+                      },
+                      "upstream": {
+                          "nodes": {
+                              "127.0.0.1:8125": 1
+                          },
+                          "type": "roundrobin"
+                      },
+                      "uri": "/test/*"
+                 }]]
+                 )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 38: hit
+--- request
+GET /test/plugin/proxy/rewrite/hello HTTP/1.1
+--- http_config
+    server {
+        listen 8125;
+        location / {
+            content_by_lua_block {
+                ngx.say(ngx.var.request_uri)
+            }
+        }
+    }
+--- response_body
+/hello/plugin_proxy_rewrite
+
+
+
+=== TEST 39: hit
+--- request
+GET /test/plugin/proxy/rewrite/world HTTP/1.1
+--- http_config
+    server {
+        listen 8125;
+        location / {
+            content_by_lua_block {
+                ngx.say(ngx.var.request_uri)
+            }
+        }
+    }
+--- response_body
+/world/plugin_proxy_rewrite