1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #24029 from rthbound/dont-call-each-when-calling-body-on-response

Dont call each when calling body on response to fix #23964

Fixes #23964
This commit is contained in:
Sean Griffin 2016-05-06 14:22:05 -05:00
commit 21a3b180f1
6 changed files with 70 additions and 19 deletions

View file

@ -163,14 +163,6 @@ module ActionController
end
end
def each
@response.sending!
while str = @buf.pop
yield str
end
@response.sent!
end
# Write a 'close' event to the buffer; the producer/writing thread
# uses this to notify us that it's finished supplying content.
#
@ -210,6 +202,14 @@ module ActionController
def call_on_error
@error_callback.call
end
private
def each_chunk(&block)
while str = @buf.pop
yield str
end
end
end
class Response < ActionDispatch::Response #:nodoc: all

View file

@ -554,6 +554,8 @@ module ActionController
end
@request.query_string = ''
@response.sent!
@response
end

View file

@ -68,7 +68,13 @@ module ActionDispatch # :nodoc:
alias_method :headers, :header
delegate :[], :[]=, :to => :@header
delegate :each, :to => :@stream
def each(&block)
sending!
x = @stream.each(&block)
sent!
x
end
CONTENT_TYPE = "Content-Type".freeze
SET_COOKIE = "Set-Cookie".freeze
@ -112,10 +118,13 @@ module ActionDispatch # :nodoc:
end
def each(&block)
@response.sending!
x = @buf.each(&block)
@response.sent!
x
if @str_body
return enum_for(:each) unless block_given?
yield @str_body
else
each_chunk(&block)
end
end
def abort
@ -129,6 +138,12 @@ module ActionDispatch # :nodoc:
def closed?
@closed
end
private
def each_chunk(&block)
@buf.each(&block) # extract into own method
end
end
def self.create(status = 200, header = {}, body = [], default_headers: self.default_headers)

View file

@ -246,7 +246,8 @@ module ActionController
def assert_stream_closed
assert response.stream.closed?, 'stream should be closed'
assert response.sent?, 'stream should be sent'
assert response.committed?, 'response should be committed'
assert response.sent?, 'response should be sent'
end
def capture_log_output

View file

@ -65,7 +65,7 @@ module ActionController
latch = Concurrent::CountDownLatch.new
t = Thread.new {
@response.stream.each do
@response.each do
latch.count_down
end
}

View file

@ -37,6 +37,39 @@ class ResponseTest < ActiveSupport::TestCase
assert_equal "closed stream", e.message
end
def test_each_isnt_called_if_str_body_is_written
# Controller writes and reads response body
each_counter = 0
@response.body = Object.new.tap {|o| o.singleton_class.send(:define_method, :each) { |&block| each_counter += 1; block.call 'foo' } }
@response['X-Foo'] = @response.body
assert_equal 1, each_counter, "#each was not called once"
# Build response
status, headers, body = @response.to_a
assert_equal 200, status
assert_equal "foo", headers['X-Foo']
assert_equal "foo", body.each.to_a.join
# Show that #each was not called twice
assert_equal 1, each_counter, "#each was not called once"
end
def test_set_header_after_read_body_during_action
@response.body
# set header after the action reads back @response.body
@response['x-header'] = "Best of all possible worlds."
# the response can be built.
status, headers, body = @response.to_a
assert_equal 200, status
assert_equal "", body.body
assert_equal "Best of all possible worlds.", headers['x-header']
end
def test_read_body_during_action
@response.body = "Hello, World!"