fc0db35fb1
Right now many helpers have to deal with two modes of operation to capture view output. The main one is to swap the `@output_buffer` variable with a new buffer. But since some view implementations such as `builder` keep a reference on the buffer they were initialized with, this doesn't always work. So additionally, the various capturing helpers also record the buffer length prior to executing the block, and then `slice!` the buffer back to its original size. This is wasteful and make the code rather unclear. Now that `OutputBuffer` is a delegator, I'd like to refactor all this so that: - @output_buffer is no longer re-assigned - A single OutputBuffer instance is used for the entire response rendering - Instead capturing is done through `OutputBuffer#capture` Once the above is achieved, it should allow us to enabled Erubi's `:chain_appends` option and get some reduced template size and some performance. Not re-assigning `@output_buffer` will also allow template to access the local variable instead of an instance variable, which is cheaper. But more importantly, that should make the code easier to understand and easier to be compatible with `StreamingBuffer`.
90 lines
2.2 KiB
Ruby
90 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "abstract_unit"
|
|
|
|
module SharedBufferTests
|
|
def self.included(test_case)
|
|
test_case.test "#<< maintains HTML safety" do
|
|
@buffer << "<script>alert('pwned!')</script>"
|
|
assert_predicate @buffer, :html_safe?
|
|
assert_predicate output, :html_safe?
|
|
assert_equal "<script>alert('pwned!')</script>", output
|
|
end
|
|
|
|
test_case.test "#safe_append= bypasses HTML safety" do
|
|
@buffer.safe_append = "<p>This is fine</p>"
|
|
assert_predicate @buffer, :html_safe?
|
|
assert_predicate output, :html_safe?
|
|
assert_equal "<p>This is fine</p>", output
|
|
end
|
|
|
|
test_case.test "#raw allow to bypass HTML escaping" do
|
|
raw_buffer = @buffer.raw
|
|
raw_buffer << "<script>alert('pwned!')</script>"
|
|
assert_predicate @buffer, :html_safe?
|
|
assert_predicate output, :html_safe?
|
|
assert_equal "<script>alert('pwned!')</script>", output
|
|
end
|
|
|
|
test_case.test "#capture allow to intercept writes" do
|
|
@buffer << "Hello"
|
|
result = @buffer.capture do
|
|
@buffer << "George!"
|
|
end
|
|
assert_equal "George!", result
|
|
assert_predicate result, :html_safe?
|
|
|
|
@buffer << " World!"
|
|
assert_equal "Hello World!", output
|
|
end
|
|
|
|
test_case.test "#raw respects #capture" do
|
|
@buffer << "Hello"
|
|
raw_buffer = @buffer.raw
|
|
result = @buffer.capture do
|
|
raw_buffer << "George!"
|
|
end
|
|
assert_equal "George!", result
|
|
assert_predicate result, :html_safe?
|
|
|
|
@buffer << " World!"
|
|
assert_equal "Hello World!", output
|
|
end
|
|
end
|
|
end
|
|
|
|
class TestOutputBuffer < ActiveSupport::TestCase
|
|
include SharedBufferTests
|
|
|
|
setup do
|
|
@buffer = ActionView::OutputBuffer.new
|
|
end
|
|
|
|
test "can be duped" do
|
|
@buffer << "Hello"
|
|
copy = @buffer.dup
|
|
copy << " World!"
|
|
assert_equal "Hello World!", copy.to_s
|
|
assert_equal "Hello", output
|
|
end
|
|
|
|
private
|
|
def output
|
|
@buffer.to_s
|
|
end
|
|
end
|
|
|
|
class TestStreamingBuffer < ActiveSupport::TestCase
|
|
include SharedBufferTests
|
|
|
|
setup do
|
|
@raw_buffer = +""
|
|
@buffer = ActionView::StreamingBuffer.new(@raw_buffer.method(:<<))
|
|
end
|
|
|
|
private
|
|
def output
|
|
@raw_buffer.html_safe
|
|
end
|
|
end
|