Skip to content

Commit

Permalink
fix(resp-tranformer) handle already existing headers
Browse files Browse the repository at this point in the history
Now add will only add header/json if it does not exist, config `append` added to support adding new value to existing header/json. If header does not exist, a new one will be added. config `replace added to replace the value of existing header/json with new value
  • Loading branch information
Shashi Ranjan committed Dec 24, 2015
1 parent 88f2930 commit 7b7d388
Show file tree
Hide file tree
Showing 12 changed files with 786 additions and 232 deletions.
4 changes: 2 additions & 2 deletions kong-0.5.4-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ build = {
["kong.plugins.request-transformer.schema"] = "kong/plugins/request-transformer/schema.lua",

["kong.plugins.response-transformer.handler"] = "kong/plugins/response-transformer/handler.lua",
["kong.plugins.response-transformer.body_filter"] = "kong/plugins/response-transformer/body_filter.lua",
["kong.plugins.response-transformer.header_filter"] = "kong/plugins/response-transformer/header_filter.lua",
["kong.plugins.response-transformer.body_transformer"] = "kong/plugins/response-transformer/body_transformer.lua",
["kong.plugins.response-transformer.header_transformer"] = "kong/plugins/response-transformer/header_transformer.lua",
["kong.plugins.response-transformer.schema"] = "kong/plugins/response-transformer/schema.lua",

["kong.plugins.cors.handler"] = "kong/plugins/cors/handler.lua",
Expand Down
92 changes: 0 additions & 92 deletions kong/plugins/response-transformer/body_filter.lua

This file was deleted.

93 changes: 93 additions & 0 deletions kong/plugins/response-transformer/body_transformer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
local stringy = require "stringy"
local cjson = require "cjson"

local table_insert = table.insert
local pcall = pcall
local string_find = string.find
local unpack = unpack
local type = type

local _M = {}

local function read_json_body(body)
if body then
local status, res = pcall(cjson.decode, body)
if status then
return res
end
end
end

local function append_value(current_value, value)
local current_value_type = type(current_value)

if current_value_type == "string" then
return {current_value, value}
elseif current_value_type == "table" then
table_insert(current_value, value)
return current_value
else
return {value}
end
end

local function iter(config_array)
return function(config_array, i, previous_name, previous_value)
i = i + 1
local current_pair = config_array[i]
if current_pair == nil then -- n + 1
return nil
end
local current_name, current_value = unpack(stringy.split(current_pair, ":"))
return i, current_name, current_value
end, config_array, 0
end

function _M.is_json_body(content_type)
return content_type and string_find(content_type:lower(), "application/json", nil, true)
end

function _M.transform_json_body(conf, buffered_data)
local json_body = read_json_body(buffered_data)
if json_body == nil then return end

-- remove key:value to body
for _, name in iter(conf.remove.json) do
json_body[name] = nil
end

-- replace key:value to body
for _, name, value in iter(conf.replace.json) do
local v = cjson.encode(value)
if stringy.startswith(v, "\"") and stringy.endswith(v, "\"") then
v = v:sub(2, v:len() - 1):gsub("\\\"", "\"") -- To prevent having double encoded quotes
end
if json_body[name] then
json_body[name] = v
end
end

-- add new key:value to body
for _, name, value in iter(conf.add.json) do
local v = cjson.encode(value)
if stringy.startswith(v, "\"") and stringy.endswith(v, "\"") then
v = v:sub(2, v:len() - 1):gsub("\\\"", "\"") -- To prevent having double encoded quotes
end
if not json_body[name] then
json_body[name] = v
end
end

-- append new key:value or value to existing key
for _, name, value in iter(conf.append.json) do
local v = cjson.encode(value)
if stringy.startswith(v, "\"") and stringy.endswith(v, "\"") then
v = v:sub(2, v:len() - 1):gsub("\\\"", "\"") -- To prevent having double encoded quotes
end
json_body[name] = append_value(json_body[name],v)
end

return cjson.encode(json_body)
end

return _M
22 changes: 18 additions & 4 deletions kong/plugins/response-transformer/handler.lua
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
local BasePlugin = require "kong.plugins.base_plugin"
local body_filter = require "kong.plugins.response-transformer.body_filter"
local header_filter = require "kong.plugins.response-transformer.header_filter"
local body_filter = require "kong.plugins.response-transformer.body_transformer"
local header_filter = require "kong.plugins.response-transformer.header_transformer"

local ResponseTransformerHandler = BasePlugin:extend()

function ResponseTransformerHandler:new()
ResponseTransformerHandler.super.new(self, "response-transformer")
end

function ResponseTransformerHandler:access(conf)
ResponseTransformerHandler.super.access(self)
ngx.ctx.buffer = ""
end

function ResponseTransformerHandler:header_filter(conf)
ResponseTransformerHandler.super.header_filter(self)
header_filter.execute(conf)
header_filter.transform_headers(conf, ngx.header)
end

function ResponseTransformerHandler:body_filter(conf)
ResponseTransformerHandler.super.body_filter(self)
body_filter.execute(conf)
if body_filter.is_json_body(ngx.header["content-type"]) then
local chunk, eof = ngx.arg[1], ngx.arg[2]
if eof then
local body = body_filter.transform_json_body(conf, ngx.ctx.buffer)
ngx.arg[1] = body
else
ngx.ctx.buffer = ngx.ctx.buffer..chunk
ngx.arg[1] = nil
end
end
end

ResponseTransformerHandler.PRIORITY = 800
Expand Down
64 changes: 0 additions & 64 deletions kong/plugins/response-transformer/header_filter.lua

This file was deleted.

81 changes: 81 additions & 0 deletions kong/plugins/response-transformer/header_transformer.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
local stringy = require "stringy"

local table_insert = table.insert
local unpack = unpack
local type = type
local string_find = string.find

local _M = {}

local function iter(config_array)
return function(config_array, i, previous_header_name, previous_header_value)
i = i + 1
local header_to_test = config_array[i]
if header_to_test == nil then -- n + 1
return nil
end
local header_to_test_name, header_to_test_value = unpack(stringy.split(header_to_test, ":"))
return i, header_to_test_name, header_to_test_value
end, config_array, 0
end

local function append_value(current_value, value)
local current_value_type = type(current_value)

if current_value_type == "string" then
return {current_value, value}
elseif current_value_type == "table" then
table_insert(current_value, value)
return current_value
else
return {value}
end
end

local function is_json_body(content_type)
return content_type and string_find(content_type:lower(), "application/json", nil, true)
end

local function is_body_transform_set(conf)
return #conf.add.json > 0 or #conf.remove.json > 0 or #conf.replace.json > 0 or #conf.append.json > 0
end

---
-- # Example:
-- ngx.headers = header_filter.transform_headers(conf, ngx.headers)
-- We run transformations in following order: remove, replace, add, append.
-- @param[type=table] conf Plugin configuration.
-- @param[type=table] ngx_headers Table of headers, that should be `ngx.headers`
-- @return table A table containing the new headers.
function _M.transform_headers(conf, ngx_headers)
-- remove headers
for _, header_name, header_value in iter(conf.remove.headers) do
ngx_headers[header_name] = nil
end

-- replace headers
for _, header_name, header_value in iter(conf.replace.headers) do
if ngx_headers[header_name] ~= nil then
ngx_headers[header_name] = header_value
end
end

-- add headers
for _, header_name, header_value in iter(conf.add.headers) do
if ngx_headers[header_name] == nil then
ngx_headers[header_name] = header_value
end
end

-- append headers
for _, header_name, header_value in iter(conf.append.headers) do
ngx_headers[header_name] = append_value(ngx_headers[header_name], header_value)
end

-- Removing the content-length header because the body is going to change
if is_body_transform_set(conf) and is_json_body(ngx_headers["content-type"]) then
ngx_headers["content-length"] = nil
end
end

return _M
Loading

0 comments on commit 7b7d388

Please sign in to comment.