Skip to content

Commit

Permalink
Merge pull request #4 from 3scale/safe-concat
Browse files Browse the repository at this point in the history
serialize variables that have __tostring in their metatable
  • Loading branch information
mikz authored Feb 20, 2018
2 parents 811a73e + c7a2a0a commit 4203133
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 19 deletions.
57 changes: 38 additions & 19 deletions lib/liquid.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1970,14 +1970,14 @@ function Interpreter:visit_Compoud( node )
local output = {}
for k,v in ipairs(node) do
if self.interrupt_flag then
return table.concat(output, '')
return self:safe_concat(output, '')
end
local result = self:visit(v)
if result then
table.insert(output, result)
end
end
return table.concat(output, '')
return self:safe_concat(output, '')
end
--
function Interpreter:visit_Branch( node )
Expand Down Expand Up @@ -2234,7 +2234,7 @@ function Interpreter:visit_ForLoop( node )
self.interrupt_type = nil
self.interrupt_flag = false
end
local result = table.concat(output, '')
local result = self:safe_concat(output, '')
self.resourcelimit:check_length(#result)
return result
end
Expand Down Expand Up @@ -2336,7 +2336,7 @@ function Interpreter:visit_TableLoop( node )
self.interrupt_type = nil
self.interrupt_flag = false
end
local result = table.concat(output, '\n')
local result = self:safe_concat(output, '\n')
self.resourcelimit:check_length(#result)
return result
end
Expand Down Expand Up @@ -2704,19 +2704,38 @@ function string:rstrip( ... )
local ws = [[(\s*\z)]]
return ngx.re.sub(self, ws, '')
end
function Interpreter:obj2str( obj )
-- body
local obj_type = type(obj)
if obj_type == "nil" then
return ''
elseif obj_type == "number" then
return tostring(obj)
elseif obj_type == "string" then
return obj
elseif obj_type == "Boolean" then
return tostring(obj)
elseif obj_type == "table" then
return nil

do
local empty_t = {}
local function mt__tostring(obj)
return (getmetatable(obj) or empty_t).__tostring
end

function Interpreter:obj2str( obj )
-- body
local obj_type = type(obj)
if obj_type == "nil" then
return ''
elseif obj_type == "number" then
return tostring(obj)
elseif obj_type == "string" then
return obj
elseif obj_type == "Boolean" then
return tostring(obj)
elseif type(mt__tostring(obj)) == 'function' then
return tostring(obj)
end
end

function Interpreter:safe_concat(t, d)
local tmp = {}

-- string keys are ignored by concat anyway
for i,v in ipairs(t) do
tmp[i] = Interpreter:obj2str(v)
end

return table.concat(tmp, d)
end
end
------------------------------------------------------------- helper methods end ---------------------------------------------------------
Expand Down Expand Up @@ -2756,7 +2775,7 @@ end
--=== array filter begin
local function join( a, b)
-- body
return table.concat(a, b)
return Interpreter:safe_concat(a, b)
end
local function first( a )
-- body
Expand Down Expand Up @@ -2787,7 +2806,7 @@ local function map( a, map_field)
for i,v in ipairs(a) do
table.insert(temp, v[map_field])
end
return table.concat(temp, '')
return join(temp, '')
end
local function reverse( a )
-- body
Expand Down
22 changes: 22 additions & 0 deletions t/interpreter.t
Original file line number Diff line number Diff line change
Expand Up @@ -682,3 +682,25 @@ GET /t
too many loopcount. limit num:3
--- no_error_log
[error]
=== TEST 26: variable with __tostring metatable
--- http_config eval: $::HttpConfig
--- config
location /t {
content_by_lua_block {
local Liquid = require 'liquid'
local document = [[str = {{ str }}, arr = {{ arr | join: '+' }}]]
local template = Liquid.Template:parse(document)
local str = setmetatable({}, { __tostring = function() return 'val' end })
local context = Liquid.InterpreterContext:new({ str = str, arr = { str, str } })
ngx.say(assert(template:render(context)))
}
}
--- request
GET /t
--- response_body
str = val, arr = val+val
--- no_error_log
[error]

0 comments on commit 4203133

Please sign in to comment.