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

liling 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 66539b3  feat: support conditional response rewrite (#3577)
66539b3 is described below

commit 66539b36e7d04197c95dbb9ba894417e71beb720
Author: Lien Li <[email protected]>
AuthorDate: Thu Mar 4 10:10:13 2021 +0800

    feat: support conditional response rewrite (#3577)
    
    * support conditinal response rewrite
    
    * fix code style
    
    * fix typo
    
    * fix typo
    
    * fix test case
    
    * add test case and fix code style
    
    * drop space
    
    * add fail test cases
    
    * enhance docs
---
 apisix/plugins/response-rewrite.lua        |  43 ++++++++++-
 docs/en/latest/plugins/response-rewrite.md |   8 +-
 docs/zh/latest/plugins/response-rewrite.md |   8 +-
 t/plugin/response-rewrite.t                | 120 +++++++++++++++++++++++++++++
 4 files changed, 174 insertions(+), 5 deletions(-)

diff --git a/apisix/plugins/response-rewrite.lua 
b/apisix/plugins/response-rewrite.lua
index a601f7a..2614fcb 100644
--- a/apisix/plugins/response-rewrite.lua
+++ b/apisix/plugins/response-rewrite.lua
@@ -15,6 +15,7 @@
 -- limitations under the License.
 --
 local core        = require("apisix.core")
+local expr        = require("resty.expr.v1")
 local plugin_name = "response-rewrite"
 local ngx         = ngx
 local pairs       = pairs
@@ -43,7 +44,16 @@ local schema = {
             type = "integer",
             minimum = 200,
             maximum = 598,
-        }
+        },
+        vars = {
+            type = "array",
+            items = {
+                description = "Nginx builtin variable name and value",
+                type = "array",
+                maxItems = 4,
+                minItems = 2,
+            },
+        },
     },
     minProperties = 1,
     additionalProperties = false,
@@ -57,6 +67,21 @@ local _M = {
     schema   = schema,
 }
 
+local function vars_matched(conf, ctx)
+    if not conf.vars then
+        return true
+    end
+
+    if not conf.response_expr then
+        local response_expr, _ = expr.new(conf.vars)
+        conf.response_expr = response_expr
+    end
+
+    local match_result = conf.response_expr:eval(ctx.var)
+
+    return match_result
+end
+
 
 function _M.check_schema(conf)
     local ok, err = core.schema.check(schema, conf)
@@ -87,6 +112,13 @@ function _M.check_schema(conf)
         end
     end
 
+    if conf.vars then
+        local ok, err = expr.new(conf.vars)
+        if not ok then
+            return false, "failed to validate the 'vars' expression: " .. err
+        end
+    end
+
     return true
 end
 
@@ -94,6 +126,10 @@ end
 do
 
 function _M.body_filter(conf, ctx)
+    if not ctx.reponse_rewrite_matched then
+        return
+    end
+
     if conf.body then
 
         if conf.body_base64 then
@@ -107,6 +143,11 @@ function _M.body_filter(conf, ctx)
 end
 
 function _M.header_filter(conf, ctx)
+    ctx.reponse_rewrite_matched = vars_matched(conf, ctx)
+    if not ctx.reponse_rewrite_matched then
+        return
+    end
+
     if conf.status_code then
         ngx.status = conf.status_code
     end
diff --git a/docs/en/latest/plugins/response-rewrite.md 
b/docs/en/latest/plugins/response-rewrite.md
index 95ef63e..f95d6a3 100644
--- a/docs/en/latest/plugins/response-rewrite.md
+++ b/docs/en/latest/plugins/response-rewrite.md
@@ -47,6 +47,7 @@ response rewrite plugin, rewrite the content returned by the 
upstream as well as
 | body        | string  | optional    |         |            | New `body` to 
client, and the content-length will be reset too.                               
                                                                                
                                                |
 | body_base64 | boolean | optional    | false   |            | Identify if 
`body` in configuration need base64 decoded before rewrite to client.           
                                                                                
                                                  |
 | headers     | object  | optional    |         |            | Set the new 
`headers` for client, can set up multiple. If it exists already from upstream, 
will rewrite the header, otherwise will add the header. You can set the 
corresponding value to an empty string to remove a header. |
+| vars     | array[]  | optional    |         |            | A DSL to evaluate 
with the given ngx.var. See `vars` 
[lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list). if the 
`vars` is empty, then all rewrite operations will be executed unconditionally |
 
 ## How To Enable
 
@@ -63,7 +64,10 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1  -H 
'X-API-KEY: edd1c9f034335f1
             "headers": {
                 "X-Server-id": 3,
                 "X-Server-status": "on"
-            }
+            },
+            "vars":[
+                [ "status","==","200" ]
+            ]
         }
     },
     "upstream": {
@@ -83,7 +87,7 @@ Testing based on the above examples :
 curl -X GET -i  http://127.0.0.1:9080/test/index.html
 ```
 
-It will output like below,no matter what kind of content from upstream.
+It will output like below,no matter what kind of content from upstream, the 
`vars` will make sure that only rewrite response that http status is `200`.
 
 ```
 
diff --git a/docs/zh/latest/plugins/response-rewrite.md 
b/docs/zh/latest/plugins/response-rewrite.md
index 2f23b87..bc352bd 100644
--- a/docs/zh/latest/plugins/response-rewrite.md
+++ b/docs/zh/latest/plugins/response-rewrite.md
@@ -46,6 +46,7 @@ title: response-rewrite
 | body        | string  | 可选   |        |            | 修改上游返回的 `body` 
内容,如果设置了新内容,header 里面的 content-length 字段也会被去掉                                   
           |
 | body_base64 | boolean | 可选   | false  |            | 描述 `body` 字段是否需要 base64 
解码之后再返回给客户端,用在某些图片和 Protobuffer 场景                                              
  |
 | headers     | object  | 可选   |        |            | 返回给客户端的 
`headers`,这里可以设置多个。头信息如果存在将重写,不存在则添加。想要删除某个 header 的话,把对应的值设置为空字符串即可 |
+| vars        | array[] | 可选   |        |            | `vars` 
是一个表达式列表,只有满足条件的请求和响应才会修改 body 和 header 信息,来自 
[lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。如果 
`vars` 字段为空,那么所有的重写动作都会被无条件的执行。 |
 
 ## 示例
 
@@ -64,7 +65,10 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1  -H 
'X-API-KEY: edd1c9f034335f1
             "headers": {
                 "X-Server-id": 3,
                 "X-Server-status": "on"
-            }
+            },
+            "vars":[
+                [ "status","==","200" ]
+            ]
         }
     },
     "upstream": {
@@ -84,7 +88,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1  -H 
'X-API-KEY: edd1c9f034335f1
 curl -X GET -i  http://127.0.0.1:9080/test/index.html
 ```
 
-如果看到返回的头部信息和内容都被修改了,即表示 `response rewrite` 插件生效了。
+如果看到返回的头部信息和内容都被修改了,即表示 `response rewrite` 插件生效了,`vars` 将确保仅覆盖状态为 200 的响应。
 
 ```shell
 HTTP/1.1 200 OK
diff --git a/t/plugin/response-rewrite.t b/t/plugin/response-rewrite.t
index 8d67de2..90e231b 100644
--- a/t/plugin/response-rewrite.t
+++ b/t/plugin/response-rewrite.t
@@ -509,3 +509,123 @@ GET /t
 additional properties forbidden, found invalid_att
 --- no_error_log
 [error]
+
+
+
+=== TEST 17: add validate vars
+--- config
+    location /t {
+        content_by_lua_block {
+            local plugin = require("apisix.plugins.response-rewrite")
+            local ok, err = plugin.check_schema({
+                vars = {
+                    {"status","==",200}
+                }
+            })
+
+            if not ok then
+                ngx.say(err)
+            else
+                ngx.say("done")
+            end
+        }
+    }
+--- request
+GET /t
+--- response_body
+done
+--- no_error_log
+[error]
+
+
+
+=== TEST 18: add plugin with invalidate vars
+--- config
+    location /t {
+        content_by_lua_block {
+            local plugin = require("apisix.plugins.response-rewrite")
+            local ok, err = plugin.check_schema({
+                vars = {
+                    {}
+                }
+            })
+
+            if not ok then
+                ngx.say(err)
+            else
+                ngx.say("done")
+            end
+        }
+    }
+--- request
+GET /t
+--- response_body
+property "vars" validation failed: failed to validate item 1: expect array to 
have at least 2 items
+--- no_error_log
+[error]
+
+
+
+=== TEST 19: set route with http status code as expr
+--- 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": {
+                        "response-rewrite": {
+                            "body": "new body3\n",
+                            "status_code": 403,
+                            "vars": [
+                                ["status","==",500]
+                            ]
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uris": ["/server_error","/hello"]
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 20: check http code that matchs http_status
+--- request
+GET /server_error
+--- response_body
+new body3
+--- error_code eval
+403
+--- error_log
+500 Internal Server Error
+
+
+
+=== TEST 21: check http code that not matchs http_status
+--- request
+GET /hello
+--- response_body
+hello world
+--- error_code eval
+200
+--- no_error_log
+[error]

Reply via email to