[go: nahoru, domu]

Skip to content

Commit

Permalink
feat(response-rewrite): support filters (#6750)
Browse files Browse the repository at this point in the history
Co-authored-by: 罗泽轩 <spacewanderlzx@gmail.com>
  • Loading branch information
kwanhur and spacewander committed Apr 11, 2022
1 parent 3a83240 commit e89ab8d
Show file tree
Hide file tree
Showing 4 changed files with 649 additions and 15 deletions.
75 changes: 74 additions & 1 deletion apisix/plugins/response-rewrite.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
--
local core = require("apisix.core")
local expr = require("resty.expr.v1")
local re_compile = require("resty.core.regex").re_match_compile
local plugin_name = "response-rewrite"
local ngx = ngx
local re_sub = ngx.re.sub
local re_gsub = ngx.re.gsub
local pairs = pairs
local ipairs = ipairs
local type = type
local pcall = pcall


local schema = {
Expand Down Expand Up @@ -48,6 +53,40 @@ local schema = {
vars = {
type = "array",
},
filters = {
description = "a group of filters that modify response body" ..
"by replacing one specified string by another",
type = "array",
minItems = 1,
items = {
description = "filter that modifies response body",
type = "object",
required = {"regex", "replace"},
properties = {
regex = {
description = "match pattern on response body",
type = "string",
minLength = 1,
},
scope = {
description = "regex substitution range",
type = "string",
enum = {"once", "global"},
default = "once",
},
replace = {
description = "regex substitution content",
type = "string",
},
options = {
description = "regex options",
type = "string",
default = "jo",
}
},
},
},
oneOf = {"body", "filters"},
},
minProperties = 1,
}
Expand Down Expand Up @@ -115,6 +154,16 @@ function _M.check_schema(conf)
end
end

if conf.filters then
for _, filter in ipairs(conf.filters) do
local ok, err = pcall(re_compile, filter.regex, filter.options)
if not ok then
return false, "regex \"" .. filter.regex ..
"\" validation failed: " .. err
end
end
end

return true
end

Expand All @@ -126,6 +175,29 @@ function _M.body_filter(conf, ctx)
return
end

if conf.filters then

local body = core.response.hold_body_chunk(ctx)
if not body then
return
end

local err
for _, filter in ipairs(conf.filters) do
if filter.scope == "once" then
body, _, err = re_sub(body, filter.regex, filter.replace, filter.options)
else
body, _, err = re_gsub(body, filter.regex, filter.replace, filter.options)
end
if err ~= nil then
core.log.error("regex \"" .. filter.regex .. "\" substitutes failed:" .. err)
end
end

ngx.arg[1] = body
return
end

if conf.body then

if conf.body_base64 then
Expand All @@ -148,7 +220,8 @@ function _M.header_filter(conf, ctx)
ngx.status = conf.status_code
end

if conf.body then
-- if filters have no any match, response body won't be modified.
if conf.filters or conf.body then
core.response.clear_header_as_body_modified()
end

Expand Down
21 changes: 14 additions & 7 deletions docs/en/latest/plugins/response-rewrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ response rewrite plugin, rewrite the content returned by the upstream as well as

## Attributes

| Name | Type | Requirement | Default | Valid | Description |
| ----------- | ------- | ----------- | ------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| status_code | integer | optional | | [200, 598] | New `status code` to client, keep the original response code by default. |
| 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. The value can contain Nginx variables in `$var` format, like `$remote_addr $balancer_ip` |
| 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 |
| Name | Type | Requirement | Default | Valid | Description |
|-----------------|---------|-------------|---------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| status_code | integer | optional | | [200, 598] | New `status code` to client, keep the original response code by default. |
| 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. The value can contain Nginx variables in `$var` format, like `$remote_addr $balancer_ip`. |
| 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. |
| filters | array[] | optional | | | A group of filters that modify response body by replacing one specified string by another. |
| filters.regex | string | required | | | match pattern on response body. |
| filters.scope | string | optional | "once" | "once","global" | substitution range, "once" substitutes the first match of `filters.regex` on response body, "global" does global substitution. |
| filters.replace | string | required | | | substitution content. |
| filters.options | string | optional | "jo" | | regex options, See [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch). |

Only one of `body`, `filters` can be specified.

## How To Enable

Expand Down
21 changes: 14 additions & 7 deletions docs/zh/latest/plugins/response-rewrite.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,20 @@ title: response-rewrite

## 属性

| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
| ----------- | ------- | ------ | ------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| status_code | integer | 可选 | | [200, 598] | 修改上游返回状态码,默认保留原始响应代码。 |
| body | string | 可选 | | | 修改上游返回的 `body` 内容,如果设置了新内容,header 里面的 content-length 字段也会被去掉 |
| body_base64 | boolean | 可选 | false | | 描述 `body` 字段是否需要 base64 解码之后再返回给客户端,用在某些图片和 Protobuffer 场景 |
| headers | object | 可选 | | | 返回给客户端的 `headers`,这里可以设置多个。头信息如果存在将重写,不存在则添加。想要删除某个 header 的话,把对应的值设置为空字符串即可。这个值能够以 `$var` 的格式包含 Nginx 变量,比如 `$remote_addr $balancer_ip` |
| vars | array[] | 可选 | | | `vars` 是一个表达式列表,只有满足条件的请求和响应才会修改 body 和 header 信息,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。如果 `vars` 字段为空,那么所有的重写动作都会被无条件的执行。 |
| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 |
|-----------------|---------|-----|--------|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| status_code | integer | 可选 | | [200, 598] | 修改上游返回状态码,默认保留原始响应代码。 |
| body | string | 可选 | | | 修改上游返回的 `body` 内容,如果设置了新内容,header 里面的 content-length 字段也会被去掉。 |
| body_base64 | boolean | 可选 | false | | 描述 `body` 字段是否需要 base64 解码之后再返回给客户端,用在某些图片和 Protobuffer 场景。 |
| headers | object | 可选 | | | 返回给客户端的 `headers`,这里可以设置多个。头信息如果存在将重写,不存在则添加。想要删除某个 header 的话,把对应的值设置为空字符串即可。这个值能够以 `$var` 的格式包含 Nginx 变量,比如 `$remote_addr $balancer_ip`|
| vars | array[] | 可选 | | | `vars` 是一个表达式列表,只有满足条件的请求和响应才会修改 body 和 header 信息,来自 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list)。如果 `vars` 字段为空,那么所有的重写动作都会被无条件的执行。 |
| filters | array[] | 可选 | | | 一组过滤器,采用指定字符串表达式修改响应体。 |
| filters.regex | string | 必选 | | | 用于匹配响应体正则表达式。 |
| filters.scope | string | 可选 | "once" | "once","global" | 替换范围,"once" 表达式 `filters.regex` 仅替换首次匹配上响应体的内容,"global" 则进行全局替换。 |
| filters.replace | string | 必选 | | | 替换后的内容。 |
| filters.options | string | 可选 | "jo" | | 正则匹配有效参数,可选项见 [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch)|

`body``filters`,两个只能配置其中一个。

## 示例

Expand Down
Loading

0 comments on commit e89ab8d

Please sign in to comment.