Merge pull request #298 from Shopify/respond_to_resource_counting_bug

Fix resource counting bug with respond_to?(:length)
This commit is contained in:
Florian Weingarten
2014-01-08 10:37:48 -08:00
6 changed files with 26 additions and 3 deletions

View File

@@ -3,6 +3,7 @@
## 3.0.0 / not yet released / branch "master"
* ...
* Fix resource counting bug with respond_to?(:length), see #263 [Florian Weingarten, fw42]
* Allow specifying custom patterns for template filenames, see #284 [Andrei Gladkyi, agladkyi]
* Allow drops to optimize loading a slice of elements, see #282 [Tom Burns, boourns]
* Support for passing variables to snippets in subdirs, see #271 [Joost Hietbrink, joost]

View File

@@ -135,7 +135,7 @@ module Liquid
end
token_output = (token.respond_to?(:render) ? token.render(context) : token)
context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
context.increment_used_resources(:render_length_current, token_output)
if context.resource_limits_reached?
context.resource_limits[:reached] = true
raise MemoryError.new("Memory limits exceeded")

View File

@@ -28,6 +28,14 @@ module Liquid
@filters = []
end
def increment_used_resources(key, obj)
@resource_limits[key] += if obj.class.ancestors & [ String, Array, Hash ] != []
obj.length
else
1
end
end
def resource_limits_reached?
(@resource_limits[:render_length_limit] && @resource_limits[:render_length_current] > @resource_limits[:render_length_limit]) ||
(@resource_limits[:render_score_limit] && @resource_limits[:render_score_current] > @resource_limits[:render_score_limit] ) ||

View File

@@ -25,7 +25,7 @@ module Liquid
def render(context)
val = @from.render(context)
context.scopes.last[@to] = val
context.resource_limits[:assign_score_current] += (val.respond_to?(:length) ? val.length : 1)
context.increment_used_resources(:assign_score_current, val)
''
end

View File

@@ -27,7 +27,7 @@ module Liquid
def render(context)
output = super
context.scopes.last[@to] = output
context.resource_limits[:assign_score_current] += (output.respond_to?(:length) ? output.length : 1)
context.increment_used_resources(:assign_score_current, output)
''
end

View File

@@ -14,6 +14,14 @@ class TemplateContextDrop < Liquid::Drop
end
end
class SomethingWithLength
def length
nil
end
liquid_methods :length
end
class TemplateTest < Test::Unit::TestCase
include Liquid
@@ -86,6 +94,12 @@ class TemplateTest < Test::Unit::TestCase
@global = nil
end
def test_resource_limits_works_with_custom_length_method
t = Template.parse("{% assign foo = bar %}")
t.resource_limits = { :render_length_limit => 42 }
assert_equal "", t.render("bar" => SomethingWithLength.new)
end
def test_resource_limits_render_length
t = Template.parse("0123456789")
t.resource_limits = { :render_length_limit => 5 }