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/09/28 02:17:13 UTC

[apisix] branch master updated: feat: add rejected_message support for plugin request-validation (#5122)

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 76540a5  feat: add rejected_message support for plugin request-validation (#5122)
76540a5 is described below

commit 76540a57f5800d74b4ceb5099f1b5132bf05e0ef
Author: leslie <59...@users.noreply.github.com>
AuthorDate: Tue Sep 28 10:17:08 2021 +0800

    feat: add rejected_message support for plugin request-validation (#5122)
---
 apisix/plugins/request-validation.lua        |  33 ++-
 docs/en/latest/plugins/request-validation.md |  43 +++-
 docs/zh/latest/plugins/request-validation.md |  43 +++-
 t/plugin/request-validation.t                | 293 +++++++++++++++++++++++----
 4 files changed, 338 insertions(+), 74 deletions(-)

diff --git a/apisix/plugins/request-validation.lua b/apisix/plugins/request-validation.lua
index a2af3cb..bdd26fa 100644
--- a/apisix/plugins/request-validation.lua
+++ b/apisix/plugins/request-validation.lua
@@ -17,27 +17,20 @@
 local core          = require("apisix.core")
 local plugin_name   = "request-validation"
 local ngx           = ngx
-local io           = io
+local io            = io
 local req_read_body = ngx.req.read_body
 local req_get_body_data = ngx.req.get_body_data
 
 local schema = {
     type = "object",
+    properties = {
+        header_schema = {type = "object"},
+        body_schema = {type = "object"},
+        rejected_msg = {type = "string", minLength = 1, maxLength = 256}
+    },
     anyOf = {
-        {
-            title = "Body schema",
-            properties = {
-                body_schema = {type = "object"}
-            },
-            required = {"body_schema"}
-        },
-        {
-            title = "Header schema",
-            properties = {
-                header_schema = {type = "object"}
-            },
-            required = {"header_schema"}
-        }
+        {required = {"header_schema"}},
+        {required = {"body_schema"}}
     }
 }
 
@@ -82,7 +75,7 @@ function _M.rewrite(conf)
         local ok, err = core.schema.check(conf.header_schema, headers)
         if not ok then
             core.log.error("req schema validation failed", err)
-            return 400, err
+            return 400, conf.rejected_msg or err
         end
     end
 
@@ -94,11 +87,11 @@ function _M.rewrite(conf)
         if not body then
             local filename = ngx.req.get_body_file()
             if not filename then
-                return 500
+                return 500, conf.rejected_msg
             end
             local fd = io.open(filename, 'rb')
             if not fd then
-                return 500
+                return 500, conf.rejected_msg
             end
             body = fd:read('*a')
         end
@@ -111,13 +104,13 @@ function _M.rewrite(conf)
 
         if not req_body then
           core.log.error('failed to decode the req body', error)
-          return 400, error
+          return 400, conf.rejected_msg or error
         end
 
         local ok, err = core.schema.check(conf.body_schema, req_body)
         if not ok then
           core.log.error("req schema validation failed", err)
-          return 400, err
+          return 400, conf.rejected_msg or err
         end
     end
 end
diff --git a/docs/en/latest/plugins/request-validation.md b/docs/en/latest/plugins/request-validation.md
index 94b651f..a474ae6 100644
--- a/docs/en/latest/plugins/request-validation.md
+++ b/docs/en/latest/plugins/request-validation.md
@@ -39,10 +39,13 @@ For more information on schema, refer to [JSON schema](https://github.com/api7/j
 
 ## Attributes
 
-| Name          | Type   | Requirement | Default | Valid | Description                |
-| ------------- | ------ | ----------- | ------- | ----- | -------------------------- |
-| header_schema | object | optional    |         |       | schema for the header data |
-| body_schema   | object | optional    |         |       | schema for the body data   |
+> Note that at least one of `header_schema` and `body_schema` must be filled in.
+
+| Name             | Type   | Requirement | Default | Valid | Description                |
+| ---------------- | ------ | ----------- | ------- | ----- | -------------------------- |
+| header_schema    | object | optional    |         |       | schema for the header data |
+| body_schema      | object | optional    |         |       | schema for the body data   |
+| rejected_message | string | optional    |         |       | the custom rejected message |
 
 ## How To Enable
 
@@ -60,7 +63,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
                 "properties": {
                     "required_payload": {"type": "string"},
                     "boolean_payload": {"type": "boolean"}
-                }
+                },
+                "rejected_message": "customize reject message"
             }
         }
     },
@@ -82,7 +86,7 @@ curl --header "Content-Type: application/json" \
   http://127.0.0.1:9080/get
 ```
 
-If the schema is violated the plugin will yield a `400` bad request.
+If the schema is violated the plugin will yield a `400` bad request with the reject response.
 
 ## Disable Plugin
 
@@ -252,3 +256,30 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
     }
 }
 ```
+
+**Custom rejected message:**
+
+```json
+{
+  "uri": "/get",
+  "plugins": {
+    "request-validation": {
+      "body_schema": {
+        "type": "object",
+        "required": ["required_payload"],
+        "properties": {
+          "required_payload": {"type": "string"},
+          "boolean_payload": {"type": "boolean"}
+        },
+        "rejected_message": "customize reject message"
+      }
+    }
+  },
+  "upstream": {
+    "type": "roundrobin",
+    "nodes": {
+      "127.0.0.1:8080": 1
+    }
+  }
+}
+```
diff --git a/docs/zh/latest/plugins/request-validation.md b/docs/zh/latest/plugins/request-validation.md
index f9ab2c4..c332bf4 100644
--- a/docs/zh/latest/plugins/request-validation.md
+++ b/docs/zh/latest/plugins/request-validation.md
@@ -38,10 +38,13 @@ title: request-validation
 
 ## 属性
 
-| Name          | Type   | Requirement | Default | Valid | Description                       |
-| ------------- | ------ | ----------- | ------- | ----- | --------------------------------- |
-| header_schema | object | 可选        |         |       | `header` 数据的 `schema` 数据结构 |
-| body_schema   | object | 可选        |         |       | `body` 数据的 `schema` 数据结构   |
+> 注意, `header_schema` 与 `body_schema` 至少填写其中一个
+
+| Name             | Type   | Requirement | Default | Valid | Description                       |
+| ---------------- | ------ | ----------- | ------- | ----- | --------------------------------- |
+| header_schema    | object | 可选        |         |       | `header` 数据的 `schema` 数据结构 |
+| body_schema      | object | 可选        |         |       | `body` 数据的 `schema` 数据结构   |
+| rejected_message | string | 可选        |         |       | 自定义拒绝信息 |
 
 ## 如何启用
 
@@ -59,7 +62,8 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
                 "properties": {
                     "required_payload": {"type": "string"},
                     "boolean_payload": {"type": "boolean"}
-                }
+                },
+                "rejected_message": "customize reject message"
             }
         }
     },
@@ -81,7 +85,7 @@ curl --header "Content-Type: application/json" \
   http://127.0.0.1:9080/get
 ```
 
-如果 `Schema` 验证失败,将返回 `400 bad request` 错误。
+如果 `Schema` 验证失败,将返回 `400` 状态码与相应的拒绝信息。
 
 ## 禁用插件
 
@@ -250,3 +254,30 @@ curl http://127.0.0.1:9080/apisix/admin/routes/5 -H 'X-API-KEY: edd1c9f034335f13
     }
 }
 ```
+
+**自定义拒绝信息:**
+
+```json
+{
+  "uri": "/get",
+  "plugins": {
+    "request-validation": {
+      "body_schema": {
+        "type": "object",
+        "required": ["required_payload"],
+        "properties": {
+          "required_payload": {"type": "string"},
+          "boolean_payload": {"type": "boolean"}
+        },
+        "rejected_message": "customize reject message"
+      }
+    }
+  },
+  "upstream": {
+    "type": "roundrobin",
+    "nodes": {
+      "127.0.0.1:8080": 1
+    }
+  }
+}
+```
diff --git a/t/plugin/request-validation.t b/t/plugin/request-validation.t
index f870768..35edd03 100644
--- a/t/plugin/request-validation.t
+++ b/t/plugin/request-validation.t
@@ -61,9 +61,8 @@ done
     }
 --- request
 GET /t
---- response_body
-object matches none of the requireds: ["body_schema"] or ["header_schema"]
-done
+--- response_body_like eval
+qr/object matches none of the requireds/
 --- no_error_log
 [error]
 
@@ -375,8 +374,6 @@ hello1 world
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -415,8 +412,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -455,8 +450,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -495,8 +488,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -535,8 +526,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -575,8 +564,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -615,8 +602,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -655,8 +640,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -787,8 +770,6 @@ qr/table expected, got string/
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -881,8 +862,6 @@ qr/table expected, got string/
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -939,8 +918,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -979,8 +956,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1019,8 +994,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1059,8 +1032,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1099,8 +1070,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1139,8 +1108,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1179,8 +1146,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1219,8 +1184,6 @@ passed
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1351,8 +1314,6 @@ qr/table expected, got string/
 GET /t
 --- response_body
 passed
---- error_code chomp
-200
 --- no_error_log
 [error]
 
@@ -1445,7 +1406,255 @@ qr/table expected, got string/
 GET /t
 --- response_body
 passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 35: add route (test request validation `header_schema.required` success with custom reject message)
+--- 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": {
+                        "request-validation": {
+                            "header_schema": {
+                                "type": "object",
+                                "properties": {
+                                    "test": {
+                                        "type": "string",
+                                        "enum": ["a", "b", "c"]
+                                    }
+                                },
+                                "required": ["test"]
+                            },
+                            "rejected_msg": "customize reject message for header_schema.required"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1982": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/opentracing"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 36: use empty header to hit `header_schema.required with custom reject message` rule
+--- request
+GET /opentracing
+--- error_code: 400
+--- response_body chomp
+customize reject message for header_schema.required
+--- error_log eval
+qr/schema validation failed/
+
+
+
+=== TEST 37: use bad header value to hit `header_schema.required with custom reject message` rule
+--- request
+GET /opentracing
+--- more_headers
+test: abc
+--- error_code: 400
+--- response_body chomp
+customize reject message for header_schema.required
+--- error_log eval
+qr/schema validation failed/
+
+
+
+=== TEST 38: pass `header_schema.required with custom reject message` rule
+--- request
+GET /opentracing
+--- more_headers
+test: a
+--- error_code: 200
+--- response_body eval
+qr/opentracing/
+--- no_error_log
+[error]
+
+
+
+=== TEST 39: add route (test request validation `body_schema.required` success with custom reject message)
+--- 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": {
+                        "request-validation": {
+                            "body_schema": {
+                                "type": "object",
+                                "properties": {
+                                    "test": {
+                                        "type": "string",
+                                        "enum": ["a", "b", "c"]
+                                    }
+                                },
+                                "required": ["test"]
+                            },
+                            "rejected_msg": "customize reject message for body_schema.required"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1982": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/opentracing"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 40: use empty body to hit `body_schema.required with custom reject message` rule
+--- request
+GET /opentracing
+--- error_code: 500
+--- response_body chomp
+customize reject message for body_schema.required
+--- no_error_log
+[error]
+
+
+
+=== TEST 41: use bad body value to hit `body_schema.required with custom reject message` rule
+--- request
+POST /opentracing
+{"test":"abc"}
+--- error_code: 400
+--- response_body chomp
+customize reject message for body_schema.required
+--- error_log eval
+qr/schema validation failed/
+
+
+
+=== TEST 42: pass `body_schema.required with custom reject message` rule
+--- request
+POST /opentracing
+{"test":"a"}
+--- error_code: 200
+--- response_body eval
+qr/opentracing/
+--- no_error_log
+[error]
+
+
+
+=== TEST 43: add route (test request validation `header_schema.required` failure with custom reject message)
+--- 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": {
+                        "request-validation": {
+                            "header_schema": {
+                                "type": "object",
+                                "properties": {
+                                    "test": {
+                                        "type": "string",
+                                        "enum": ["a", "b", "c"]
+                                    }
+                                },
+                                "required": ["test"]
+                            },
+                            "rejected_msg": "customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message customize reject message"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1982": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/plugin/request/validation"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body_like eval
+qr/string too long/
 --- error_code chomp
-200
+400
+--- no_error_log
+[error]
+
+
+
+=== TEST 44: add route (test request validation schema with custom reject message only)
+--- 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": {
+                        "request-validation": {
+                            "rejected_message": "customize reject message"
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1982": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/plugin/request/validation"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body_like eval
+qr/object matches none of the requireds/
+--- error_code chomp
+400
 --- no_error_log
 [error]