Skip to content
Open
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
42 changes: 41 additions & 1 deletion apisix/core/json.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,54 @@ local cached_tab = {}

cjson.encode_escape_forward_slash(false)
cjson.decode_array_with_array_mt(true)


local dkjson = require("dkjson")
local dkjson_null = dkjson.null


local function convert_cjson_null(data, seen)
if data == cjson_null then
return dkjson_null
end

if type(data) ~= "table" then
return data
end

seen = seen or {}
if seen[data] then
return data
end
seen[data] = true

local t = {}
for k, v in pairs(data) do
t[convert_cjson_null(k, seen)] = convert_cjson_null(v, seen)
end

return t
end


local function stably_encode(data)
if data == cjson_null then
data = dkjson_null
elseif type(data) == "table" then
data = convert_cjson_null(data)
end
return dkjson.encode(data)
end


local _M = {
version = 0.1,
array_mt = cjson.array_mt,
null = cjson_null,
-- This method produces the same encoded string when the input is not changed.
-- Different calls with cjson.encode will produce different string because
-- it doesn't maintain the object key order.
stably_encode = require("dkjson").encode
stably_encode = stably_encode
}


Expand Down
56 changes: 56 additions & 0 deletions t/core/json.t
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,59 @@ b.d: 1
e: text
a or default: default
top-level null: nil



=== TEST 9: stably_encode with cjson.null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local data = {a = 1, b = core.json.null}
ngx.say(core.json.stably_encode(data))
}
}
--- response_body
{"a":1,"b":null}



=== TEST 10: stably_encode with nested cjson.null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local data = {outer = {inner = core.json.null, val = "test"}}
ngx.say(core.json.stably_encode(data))
}
}
--- response_body
{"outer":{"inner":null,"val":"test"}}



=== TEST 11: stably_encode stability with cjson.null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
local data1 = {z = 1, a = core.json.null}
local data2 = {a = core.json.null, z = 1}
ngx.say(core.json.stably_encode(data1) == core.json.stably_encode(data2))
}
}
--- response_body
true



=== TEST 12: stably_encode top-level cjson.null
--- config
location /t {
content_by_lua_block {
local core = require("apisix.core")
ngx.say(core.json.stably_encode(core.json.null))
}
}
--- response_body
null
Loading