Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix improper detection and handling of html_safe buffer in CacheHelper #2080

Merged
merged 3 commits into from

3 participants

@lhahne

This fixes the latest incarnation of #1537 where CacheHelper might try to use splice! for a html_safe buffer which converts the buffer unsafe. This change has been tested against Rails's tests and slim-lang which originally raised this issue.

@spastorino
Owner

We need a test case in order to merge this.

@lhahne

I think test_fragment_caching in caching_tests.rb already tests the bahavior of this function. In addition, even larger changes to this function, such as 114b5e4, have been accepted without specific tests. Anyways, I'll see if I can write a test case over the weekend.

@spastorino
Owner

@lhahne the commit you're pointing fixes some previously committed failing tests.

@lhahne

Ok. I know a way to break the old code so I can write some tests once I discover how to change the buffer in tests.

lhahne added some commits
@lhahne lhahne Added tests for the output_buffer returned by CacheHelper
The output_buffer returned by CacheHelper should be html_safe if the original buffer is html_safe.
bc5ccd0
@lhahne lhahne made sure that the possible new output_buffer created by CacheHelper …
…is of the same type as the original
39a4f67
@lhahne

Ok. I added two tests one of which fails against the current 3-0-stable. After my fix, both tests pass. In addition, I modified CacheBuffer so that any possible new output_buffer is of the original type and made the tests reflect this.

@kommen

This seems to be related to #2150

@kommen

@lhahne: As the output_buffer variable in this line is still pointing to the OutputBuffer created at the beginning of the test, you're explicitly testing here that the old output_buffer is still html_safe. Is this intended? It makes little sense to me, as it is replaced anyway.

Acutally, that depends. If you run this test against the current 3-0-stable with an html_safe output buffer which isn't ActionView::OutputBuffer (that's actually the second test), the execution will reach the else part of the if in fragment_for which causes the buffer to stay the same but converts it to unsafe when splice! is called.

You're right. This is true for 3-0-stable. However, since 03d01ec, which is in 3-1-stable, we don't test for ActionView::OutputBuffer explicitly any more, just for html_safe?. So I guess these asserts can stay for 3-0-stable, we don't need them in 3-1-stable (and master)?

If you are going to remove this, then I think you could also remove the assert_nothing_raised because there isn't much raising happening anymore.

@spastorino
Owner

Closed in PR 2219

@spastorino spastorino closed this
@spastorino spastorino reopened this
@spastorino
Owner

We need to backport PR 2219 to 3-0-stable

@kommen

@spastorino in #2219 the regression fixed there is introduced by 03d01ec, which is not in 3-0-stable. So merging this pull request will suffice (assuming we're not backporting 03d01ec to 3-0-stable as well).

Though I think we should update the cache helper test to match the test from master.

@spastorino spastorino merged commit eead13f into rails:3-0-stable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 15, 2011
  1. @lhahne
Commits on Jul 17, 2011
  1. @lhahne

    Added tests for the output_buffer returned by CacheHelper

    lhahne authored
    The output_buffer returned by CacheHelper should be html_safe if the original buffer is html_safe.
  2. @lhahne

    made sure that the possible new output_buffer created by CacheHelper …

    lhahne authored
    …is of the same type as the original
This page is out of date. Refresh to see the latest.
View
4 actionpack/lib/action_view/helpers/cache_helper.rb
@@ -53,10 +53,10 @@ def fragment_for(name = {}, options = nil, &block) #:nodoc:
# This dance is needed because Builder can't use capture
pos = output_buffer.length
yield
- if output_buffer.is_a?(ActionView::OutputBuffer)
+ if output_buffer.html_safe?
safe_output_buffer = output_buffer.to_str
fragment = safe_output_buffer.slice!(pos..-1)
- self.output_buffer = ActionView::OutputBuffer.new(safe_output_buffer)
+ self.output_buffer = output_buffer.class.new(safe_output_buffer)
else
fragment = output_buffer.slice!(pos..-1)
end
View
50 actionpack/test/controller/caching_test.rb
@@ -785,3 +785,53 @@ def test_xml_formatted_fragment_caching
assert_equal " <p>Builder</p>\n", @store.read('views/test.host/functional_caching/formatted_fragment_cached')
end
end
+
+class CacheHelperOutputBufferTest < ActionController::TestCase
+
+ class MockController
+ def read_fragment(name, options)
+ return false
+ end
+
+ def write_fragment(name, fragment, options)
+ fragment
+ end
+ end
+
+ def setup
+ super
+ end
+
+ def test_output_buffer
+ output_buffer = ActionView::OutputBuffer.new
+ controller = MockController.new
+ cache_helper = Object.new
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+ cache_helper.expects(:controller).returns(controller).at_least(0)
+ cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
+ # if the output_buffer is changed, the new one should be html_safe and of the same type
+ cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
+
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ assert output_buffer.html_safe?, "Output buffer should stay html_safe"
+ end
+ end
+
+ def test_safe_buffer
+ output_buffer = ActiveSupport::SafeBuffer.new
+ controller = MockController.new
+ cache_helper = Object.new
+ cache_helper.extend(ActionView::Helpers::CacheHelper)
+ cache_helper.expects(:controller).returns(controller).at_least(0)
+ cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0)
+ # if the output_buffer is changed, the new one should be html_safe and of the same type
+ cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0)
+
+ assert_nothing_raised do
+ cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
+ assert output_buffer.html_safe?, "Output buffer should stay html_safe"
+ end
+ end
+
+end
Something went wrong with that request. Please try again.