This is an automated email from the ASF dual-hosted git repository.
nic-6443 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 97e3800d4 feat: chaitin waf response logging (#13763)
97e3800d4 is described below
commit 97e3800d4af5a6d9a1a5b475388ede1e72027754
Author: Blaise Wang <[email protected]>
AuthorDate: Thu Aug 27 18:26:55 2026 +0800
feat: chaitin waf response logging (#13763)
---
apisix-master-0.rockspec | 2 +-
apisix/plugins/chaitin-waf.lua | 84 +++++--
docs/en/latest/plugins/chaitin-waf.md | 16 ++
docs/zh/latest/plugins/chaitin-waf.md | 16 ++
t/plugin/chaitin-waf-log-resp.t | 413 ++++++++++++++++++++++++++++++++++
t/plugin/chaitin-waf.t | 208 +++++++++++++++++
6 files changed, 719 insertions(+), 20 deletions(-)
diff --git a/apisix-master-0.rockspec b/apisix-master-0.rockspec
index bba7cdc1d..064aaea90 100644
--- a/apisix-master-0.rockspec
+++ b/apisix-master-0.rockspec
@@ -80,7 +80,7 @@ dependencies = {
"xml2lua = 1.6-2",
"lua-resty-mediador = 0.1.2-1",
"lua-resty-ldap = 0.3.1-0",
- "lua-resty-t1k = 1.1.6-0",
+ "lua-resty-t1k = 1.2.1-0",
"brotli-ffi = 0.3-1",
"lua-ffi-zlib = 0.6-0",
"jsonpath = 1.0-1",
diff --git a/apisix/plugins/chaitin-waf.lua b/apisix/plugins/chaitin-waf.lua
index ed364bb9a..b87b40e42 100644
--- a/apisix/plugins/chaitin-waf.lua
+++ b/apisix/plugins/chaitin-waf.lua
@@ -88,6 +88,16 @@ local plugin_schema = {
},
real_client_ip = {
type = "boolean"
+ },
+ log_resp = {
+ type = "boolean"
+ },
+ resp_body_size = {
+ type = "integer",
+ minimum = 0
+ },
+ extra_ignored_content_types = {
+ type = "string"
}
},
},
@@ -152,6 +162,23 @@ local metadata_schema = {
real_client_ip = {
type = "boolean",
default = true
+ },
+ -- report the response to the WAF detection service
+ log_resp = {
+ type = "boolean",
+ default = false
+ },
+ -- amount of the response body to report, in KB,
+ -- 0 disables body buffering
+ resp_body_size = {
+ type = "integer",
+ minimum = 0,
+ default = 4
+ },
+ -- extra response content types (comma separated) to skip
+ -- on top of the built-in ignored list
+ extra_ignored_content_types = {
+ type = "string"
}
},
default = {},
@@ -160,6 +187,20 @@ local metadata_schema = {
required = { "nodes" },
}
+-- every field of the config object, both in plugin_schema and metadata_schema
+local config_fields = {
+ "connect_timeout",
+ "send_timeout",
+ "read_timeout",
+ "req_body_size",
+ "keepalive_size",
+ "keepalive_timeout",
+ "real_client_ip",
+ "log_resp",
+ "resp_body_size",
+ "extra_ignored_content_types",
+}
+
local _M = {
version = 0.1,
priority = 2700,
@@ -273,30 +314,25 @@ local function get_conf(conf, metadata)
real_client_ip = true,
}
- if metadata.config then
- t.connect_timeout = metadata.config.connect_timeout
- t.send_timeout = metadata.config.send_timeout
- t.read_timeout = metadata.config.read_timeout
- t.req_body_size = metadata.config.req_body_size
- t.keepalive_size = metadata.config.keepalive_size
- t.keepalive_timeout = metadata.config.keepalive_timeout
- if metadata.config.real_client_ip ~= nil then
- t.real_client_ip = metadata.config.real_client_ip
+ -- only copy what the config actually sets, so that a plugin level config
+ -- overrides the metadata defaults field by field instead of wholesale
+ local function apply(config)
+ if not config then
+ return
end
- end
- if conf.config then
- t.connect_timeout = conf.config.connect_timeout
- t.send_timeout = conf.config.send_timeout
- t.read_timeout = conf.config.read_timeout
- t.req_body_size = conf.config.req_body_size
- t.keepalive_size = conf.config.keepalive_size
- t.keepalive_timeout = conf.config.keepalive_timeout
- if conf.config.real_client_ip ~= nil then
- t.real_client_ip = conf.config.real_client_ip
+ for _, name in ipairs(config_fields) do
+ local value = config[name]
+ if value ~= nil then
+ t[name] = value
+ end
end
end
+ -- metadata config first, then route/service level config overrides it
+ apply(metadata.config)
+ apply(conf.config)
+
t.mode = conf.mode or metadata.mode or t.mode
return t
@@ -421,4 +457,14 @@ function _M.header_filter(conf, ctx)
end
+function _M.body_filter(conf, ctx)
+ t1k.do_body_filter()
+end
+
+
+function _M.log(conf, ctx)
+ t1k.do_log()
+end
+
+
return _M
diff --git a/docs/en/latest/plugins/chaitin-waf.md
b/docs/en/latest/plugins/chaitin-waf.md
index dd8ef5a6a..39f0577ba 100644
--- a/docs/en/latest/plugins/chaitin-waf.md
+++ b/docs/en/latest/plugins/chaitin-waf.md
@@ -65,6 +65,9 @@ The Plugin can add the following response headers, depending
on the configuratio
| config.keepalive_size | integer | false | 256 |
| The maximum number of idle connections to the WAF detection
service that can be maintained concurrently. |
| config.keepalive_timeout | integer | false | 60000 |
| The idle connection timeout for the WAF service, in milliseconds.
|
| config.real_client_ip | boolean | false | true |
| If true, the Plugin sends APISIX's resolved client IP to the WAF
service (the same value used elsewhere in APISIX, derived from the connection
and `apisix.trusted_addresses`). If false, the Plugin sends the IP of the peer
directly connected to APISIX. |
+| config.log_resp | boolean | false | false |
| If true, the Plugin also reports the response to the WAF service.
See [Response Logging](#response-logging). |
+| config.resp_body_size | integer | false | 4 | >= 0
| The amount of the response body to report, in KB. Set to `0` to
report only the status line and response headers. Effective only when
`config.log_resp` is `true`. |
+| config.extra_ignored_content_types | string | false | |
| A comma separated list of response `Content-Type` values to
skip, in addition to the built-in ignored list. Effective only when
`config.log_resp` is `true`. |
## Plugin Metadata
@@ -82,6 +85,19 @@ The Plugin can add the following response headers, depending
on the configuratio
| config.keepalive_size | integer | False | 256 |
| The maximum number of idle connections to the WAF detection service that can
be maintained concurrently. |
| config.keepalive_timeout | integer | False | 60000 |
| The idle connection timeout for the WAF service, in milliseconds. |
| config.real_client_ip | boolean | False | true |
| If true, the Plugin sends APISIX's resolved client IP to the WAF service (the
same value used elsewhere in APISIX, derived from the connection and
`apisix.trusted_addresses`). If false, the Plugin sends the IP of the peer
directly connected to APISIX. |
+| config.log_resp | boolean | False | false |
| If true, the Plugin also reports the response to the WAF service. See
[Response Logging](#response-logging). |
+| config.resp_body_size | integer | False | 4 | >= 0
| The amount of the response body to report, in KB. Set to `0` to report only
the status line and response headers. Effective only when `config.log_resp` is
`true`. |
+| config.extra_ignored_content_types | string | False | |
| A comma separated list of response `Content-Type` values to skip, in
addition to the built-in ignored list. Effective only when `config.log_resp` is
`true`. |
+
+## Response Logging
+
+By default the Plugin only reports the request to the WAF service. Setting
`config.log_resp` to `true` makes it report the response as well: the status
line, the response headers, and up to `config.resp_body_size` KB of the
response body.
+
+The report is sent from an `ngx.timer` during the log phase, after the
response has been handed back to the client, so it does not block the response
or add latency to it. Detection results are visible in the SafeLine WAF console
rather than acted on by APISIX, meaning a response is never blocked or modified
based on this report.
+
+Responses are not reported when the request itself was already blocked, or
when the response `Content-Type` matches an ignored type. Audio, video, font,
image and other binary media types are ignored out of the box; use
`config.extra_ignored_content_types` to skip more, for example
`text/csv,application/pdf`.
+
+Note that buffering the response body costs memory per in-flight request, so
raise `config.resp_body_size` with care on routes serving large responses.
## Examples
diff --git a/docs/zh/latest/plugins/chaitin-waf.md
b/docs/zh/latest/plugins/chaitin-waf.md
index 73a29b60d..2c7c17bde 100644
--- a/docs/zh/latest/plugins/chaitin-waf.md
+++ b/docs/zh/latest/plugins/chaitin-waf.md
@@ -65,6 +65,9 @@ description: chaitin-waf 插件与长亭雷池 WAF 集成,以检测和阻止
| config.keepalive_size | integer | 否 | 256 |
| 可同时维持的与 WAF 检测服务的空闲连接数上限。 |
| config.keepalive_timeout | integer | 否 | 60000 |
| 与 WAF 服务的空闲连接超时时间,单位为毫秒。 |
| config.real_client_ip | boolean | 否 | true |
| 若为 true,则插件将 APISIX 解析得到的客户端 IP(与 APISIX 其他地方使用的相同,由连接信息以及
`apisix.trusted_addresses` 共同决定)发送给 WAF 服务。若为 false,则插件发送与 APISIX 直接建立连接的对端 IP。
|
+| config.log_resp | boolean | 否 | false |
| 若为 true,则插件同时将响应上报给 WAF 服务。参见 [响应上报](#响应上报)。 |
+| config.resp_body_size | integer | 否 | 4 | >= 0
| 上报的响应体大小,单位为 KB。设置为 `0` 表示仅上报状态行与响应头。仅当 `config.log_resp` 为 true
时生效。 |
+| config.extra_ignored_content_types | string | 否 | |
| 以逗号分隔的响应 `Content-Type` 列表,在内置忽略列表之外额外跳过这些类型。仅当 `config.log_resp`
为 true 时生效。 |
## 插件元数据
@@ -82,6 +85,19 @@ description: chaitin-waf 插件与长亭雷池 WAF 集成,以检测和阻止
| config.keepalive_size | integer | 否 | 256 |
| 可同时维持的与 WAF 检测服务的空闲连接数上限。 |
| config.keepalive_timeout | integer | 否 | 60000 |
| 与 WAF 服务的空闲连接超时时间,单位为毫秒。 |
| config.real_client_ip | boolean | 否 | true |
| 若为 true,则插件将 APISIX 解析得到的客户端 IP(与 APISIX 其他地方使用的相同,由连接信息以及
`apisix.trusted_addresses` 共同决定)发送给 WAF 服务。若为 false,则插件发送与 APISIX 直接建立连接的对端 IP。
|
+| config.log_resp | boolean | 否 | false |
| 若为 true,则插件同时将响应上报给 WAF 服务。参见 [响应上报](#响应上报)。 |
+| config.resp_body_size | integer | 否 | 4 | >= 0
| 上报的响应体大小,单位为 KB。设置为 `0` 表示仅上报状态行与响应头。仅当 `config.log_resp` 为 true 时生效。 |
+| config.extra_ignored_content_types | string | 否 | |
| 以逗号分隔的响应 `Content-Type` 列表,在内置忽略列表之外额外跳过这些类型。仅当 `config.log_resp` 为 true 时生效。
|
+
+## 响应上报
+
+插件默认只将请求上报给 WAF 服务。将 `config.log_resp` 设置为 true 后,插件会同时上报响应:状态行、响应头,以及最多
`config.resp_body_size` KB 的响应体。
+
+上报在 log 阶段通过 `ngx.timer` 发出,此时响应已经返回给客户端,因此不会阻塞响应、也不会增加响应延迟。检测结果在雷池 WAF
控制台查看,APISIX 不会依据该上报结果拦截或修改响应。
+
+以下情况不会上报响应:请求本身已被拦截,或响应 `Content-Type` 属于被忽略的类型。音频、视频、字体、图片等二进制媒体类型默认被忽略,可通过
`config.extra_ignored_content_types` 追加,例如 `text/csv,application/pdf`。
+
+请注意,缓冲响应体会为每个进行中的请求占用内存,在返回大响应的路由上调高 `config.resp_body_size` 需谨慎。
## 示例
diff --git a/t/plugin/chaitin-waf-log-resp.t b/t/plugin/chaitin-waf-log-resp.t
new file mode 100644
index 000000000..38036fa12
--- /dev/null
+++ b/t/plugin/chaitin-waf-log-resp.t
@@ -0,0 +1,413 @@
+#
+# 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();
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ my $stream_default_server = <<_EOC_;
+ server {
+ listen 8088;
+ content_by_lua_block {
+ require("lib.chaitin_waf_server").pass()
+ }
+ }
+_EOC_
+
+ $block->set_value("extra_stream_config", $stream_default_server);
+ $block->set_value("stream_conf_enable", 1);
+
+ # setup default conf.yaml
+ my $extra_yaml_config = $block->extra_yaml_config // <<_EOC_;
+apisix:
+ stream_proxy: # TCP/UDP L4 proxy
+ only: true # Enable L4 proxy only without L7 proxy.
+ tcp:
+ - addr: 9100 # Set the TCP proxy listening ports.
+ tls: true
+ - addr: "127.0.0.1:9101"
+ udp: # Set the UDP proxy listening ports.
+ - 9200
+ - "127.0.0.1:9201"
+plugins:
+ - chaitin-waf
+_EOC_
+
+ $block->set_value("extra_yaml_config", $extra_yaml_config);
+
+ if (!$block->request) {
+ # use /do instead of /t because stream server will inject a default /t
location
+ $block->set_value("request", "GET /do");
+ }
+
+ if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
+ $block->set_value("no_error_log", "[error]");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: configure the WAF service
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": [
+ {
+ "host": "127.0.0.1",
+ "port": 8088
+ }
+ ]
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+ ngx.say("passed")
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 2: the response is reported to the WAF service
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/hello")
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ -- res.body already ends in a newline
+ ngx.print("upstream response: ", res.body)
+ ngx.say("waf header: ", res.headers["X-APISIX-CHAITIN-WAF"])
+
+ -- give the timer that reports the response a chance to run
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+upstream response: hello world
+waf header: yes
+--- error_log
+lua-resty-t1k: reported response
+--- log_level: debug
+
+
+
+=== TEST 3: buffer the whole response body when it fits
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["POST"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ -- /echo answers with the request body, so this yields a 100 byte
+ -- response, well under the 4 KB default
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/echo", {
+ method = "POST",
+ body = string.rep("a", 100),
+ })
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ ngx.say("client body size: ", #res.body)
+
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+client body size: 100
+--- error_log
+lua-resty-t1k: response body received completely, total size: 100 bytes,
truncated size: 100 bytes
+--- log_level: debug
+
+
+
+=== TEST 4: truncate the buffered response body to resp_body_size
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["POST"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true,
+ "resp_body_size": 1
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/echo", {
+ method = "POST",
+ body = string.rep("a", 4096),
+ })
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ -- the client still receives the whole response
+ ngx.say("client body size: ", #res.body)
+
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+client body size: 4096
+--- error_log
+lua-resty-t1k: response body received completely, total size: 4096 bytes,
truncated size: 1024 bytes
+--- log_level: debug
+
+
+
+=== TEST 5: buffer no response body when resp_body_size is zero
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true,
+ "resp_body_size": 0
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/hello")
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ -- res.body already ends in a newline
+ ngx.print("upstream response: ", res.body)
+
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+upstream response: hello world
+--- error_log
+lua-resty-t1k: skip response body buffering for non-positive limit: 0
+--- log_level: debug
+
+
+
+=== TEST 6: skip an extra ignored content type
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["POST"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true,
+ "extra_ignored_content_types": "text/csv"
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ -- /echo reflects a resp-* request header as a response header, so
+ -- this makes the upstream answer with an ignored content type
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/echo", {
+ method = "POST",
+ body = "a,b,c",
+ headers = { ["resp-content-type"] = "text/csv" },
+ })
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ ngx.say("content type: ", res.headers["Content-Type"])
+
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+content type: text/csv
+--- error_log
+lua-resty-t1k: skip response logging
+--- log_level: debug
+
+
+
+=== TEST 7: do not report the response when log_resp is off
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "plugins": {
+ "chaitin-waf": {}
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/hello")
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ ngx.say("waf header: ", res.headers["X-APISIX-CHAITIN-WAF"])
+
+ ngx.sleep(0.3)
+ }
+ }
+--- response_body
+waf header: yes
+--- error_log
+lua-resty-t1k: skip response logging
+--- log_level: debug
diff --git a/t/plugin/chaitin-waf.t b/t/plugin/chaitin-waf.t
index df7f7ed36..2da2cb094 100644
--- a/t/plugin/chaitin-waf.t
+++ b/t/plugin/chaitin-waf.t
@@ -519,3 +519,211 @@ trigger: true
chaitin-waf client_ip: 127.0.0.1
--- no_error_log
chaitin-waf client_ip: 192.0.2.10
+
+
+
+=== TEST 16: wrong schema: negative resp_body_size
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": [
+ {
+ "host": "127.0.0.1",
+ "port": 8088
+ }
+ ],
+ "config": {
+ "log_resp": true,
+ "resp_body_size": -1
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"invalid configuration: property \"config\" validation failed:
property \"resp_body_size\" validation failed: expected -1 to be at least 0"}
+
+
+
+=== TEST 17: wrong schema: extra_ignored_content_types wrong type
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": [
+ {
+ "host": "127.0.0.1",
+ "port": 8088
+ }
+ ],
+ "config": {
+ "log_resp": true,
+ "extra_ignored_content_types": ["text/csv"]
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ end
+ ngx.print(body)
+ }
+ }
+--- error_code: 400
+--- response_body
+{"error_msg":"invalid configuration: property \"config\" validation failed:
property \"extra_ignored_content_types\" validation failed: wrong type:
expected string, got table"}
+
+
+
+=== TEST 18: response logging enabled prepare
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+
+ local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": [
+ {
+ "host": "127.0.0.1",
+ "port": 8088
+ }
+ ]
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["GET"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "log_resp": true,
+ "resp_body_size": 1,
+ "extra_ignored_content_types": "text/csv"
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+ ngx.say("passed")
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 19: response logging does not affect the response
+--- request
+GET /hello
+--- error_code: 200
+--- response_body
+hello world
+--- response_headers
+X-APISIX-CHAITIN-WAF: yes
+X-APISIX-CHAITIN-WAF-ACTION: pass
+X-APISIX-CHAITIN-WAF-STATUS: 200
+
+
+
+=== TEST 20: a plugin config keeps the metadata fields it does not set
+--- config
+ location /do {
+ content_by_lua_block {
+ local t = require("lib.test_admin").test
+ local http = require("resty.http")
+
+ -- the metadata caps the reported request body at one KB, which is
+ -- what the assertion below observes
+ local code, body = t('/apisix/admin/plugin_metadata/chaitin-waf',
+ ngx.HTTP_PUT,
+ [[{
+ "nodes": [
+ {
+ "host": "127.0.0.1",
+ "port": 8088
+ }
+ ],
+ "config": {
+ "req_body_size": 1
+ }
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ -- a plugin config that sets an unrelated field must not discard it
+ local code, body = t('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "methods": ["POST"],
+ "plugins": {
+ "chaitin-waf": {
+ "config": {
+ "real_client_ip": false
+ }
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ },
+ "uri": "/*"
+ }]]
+ )
+ if code >= 300 then
+ ngx.status = code
+ return ngx.print(body)
+ end
+
+ local httpc = http.new()
+ local res, err = httpc:request_uri("http://127.0.0.1:1984/echo", {
+ method = "POST",
+ body = string.rep("a", 2048),
+ })
+ if not res then
+ return ngx.say("request failed: ", err)
+ end
+ ngx.say("client body size: ", #res.body)
+ }
+ }
+--- response_body
+client body size: 2048
+--- error_log
+lua-resty-t1k: request body is too long, total size: 2048 bytes, truncated
size: 1024 bytes
+--- log_level: debug