Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: response-rewrite filters.regex does not apply when content-encoding is gzip #10637

Merged
merged 12 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apisix-master-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ dependencies = {
"lua-resty-mediador = 0.1.2-1",
"lua-resty-ldap = 0.1.0-0",
"lua-resty-t1k = 1.1.0",
"brotli-ffi = 0.3-1"
"brotli-ffi = 0.3-1",
"lua-ffi-zlib = 0.6-0"
}

build = {
Expand Down
43 changes: 43 additions & 0 deletions apisix/plugins/response-rewrite.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ 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 ngx_header = ngx.header
local re_match = ngx.re.match
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 zlib = require("ffi-zlib")
local str_buffer = require("string.buffer")


local lrucache = core.lrucache.new({
Expand Down Expand Up @@ -199,6 +202,31 @@ local function check_set_headers(headers)
end


local function inflate_gzip(data)
local inputs = str_buffer.new():set(data)
local outputs = str_buffer.new()

local read_inputs = function(size)
local data = inputs:get(size)
if data == "" then
return nil
end
return data
end

local write_outputs = function(data)
return outputs:put(data)
end

local ok, err = zlib.inflateGzip(read_inputs, write_outputs)
if not ok then
return nil, err
end

return outputs:get()
end


function _M.check_schema(conf)
local ok, err = core.schema.check(schema, conf)
if not ok then
Expand Down Expand Up @@ -260,6 +288,19 @@ function _M.body_filter(conf, ctx)
end

local err
if ctx.response_encoding == "gzip" then
body, err = inflate_gzip(body)
if err ~= nil then
core.log.error("filters may not work as expected, inflate gzip err: ", err)
return
end
elseif ctx.response_encoding ~= nil then
core.log.error("filters may not work as expected ",
"due to unsupported compression encoding type: ",
ctx.response_encoding)
return
end

for _, filter in ipairs(conf.filters) do
if filter.scope == "once" then
body, _, err = re_sub(body, filter.regex, filter.replace, filter.options)
Expand Down Expand Up @@ -333,7 +374,9 @@ function _M.header_filter(conf, ctx)

-- if filters have no any match, response body won't be modified.
if conf.filters or conf.body then
local response_encoding = ngx_header["Content-Encoding"]
core.response.clear_header_as_body_modified()
ctx.response_encoding = response_encoding
end

if not conf.headers then
Expand Down
Loading
Loading