mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Return body parts directly to Rack rather than building a response string ourselves. Allows Rack middleware to orchestrate response building.
This commit is contained in:
parent
c8c2b3820e
commit
91d2740595
6 changed files with 44 additions and 27 deletions
|
@ -984,6 +984,7 @@ module ActionController #:nodoc:
|
||||||
# of sending it as the response body to the browser.
|
# of sending it as the response body to the browser.
|
||||||
def render_to_string(options = nil, &block) #:doc:
|
def render_to_string(options = nil, &block) #:doc:
|
||||||
render(options, &block)
|
render(options, &block)
|
||||||
|
response.body
|
||||||
ensure
|
ensure
|
||||||
response.content_type = nil
|
response.content_type = nil
|
||||||
erase_render_results
|
erase_render_results
|
||||||
|
@ -1020,7 +1021,7 @@ module ActionController #:nodoc:
|
||||||
|
|
||||||
# Clears the rendered results, allowing for another render to be performed.
|
# Clears the rendered results, allowing for another render to be performed.
|
||||||
def erase_render_results #:nodoc:
|
def erase_render_results #:nodoc:
|
||||||
response.body = nil
|
response.body = []
|
||||||
@performed_render = false
|
@performed_render = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1247,13 +1248,12 @@ module ActionController #:nodoc:
|
||||||
response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
|
response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
|
||||||
|
|
||||||
if append_response
|
if append_response
|
||||||
response.body ||= ''
|
response.body_parts << text.to_s
|
||||||
response.body << text.to_s
|
|
||||||
else
|
else
|
||||||
response.body = case text
|
response.body = case text
|
||||||
when Proc then text
|
when Proc then text
|
||||||
when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
|
when nil then [" "] # Safari doesn't pass the headers of the return if the response is zero length
|
||||||
else text.to_s
|
else [text.to_s]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -332,11 +332,13 @@ module ActionController
|
||||||
@cookies[name] = value
|
@cookies[name] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
@body = ""
|
|
||||||
if body.is_a?(String)
|
if body.is_a?(String)
|
||||||
@body << body
|
@body_parts = [body]
|
||||||
|
@body = body
|
||||||
else
|
else
|
||||||
body.each { |part| @body << part }
|
@body_parts = []
|
||||||
|
body.each { |part| @body_parts << part.to_s }
|
||||||
|
@body = @body_parts.join
|
||||||
end
|
end
|
||||||
|
|
||||||
if @controller = ActionController::Base.last_instantiation
|
if @controller = ActionController::Base.last_instantiation
|
||||||
|
@ -349,7 +351,7 @@ module ActionController
|
||||||
@response = Response.new
|
@response = Response.new
|
||||||
@response.status = status.to_s
|
@response.status = status.to_s
|
||||||
@response.headers.replace(@headers)
|
@response.headers.replace(@headers)
|
||||||
@response.body = @body
|
@response.body = @body_parts
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decorate the response with the standard behavior of the
|
# Decorate the response with the standard behavior of the
|
||||||
|
|
|
@ -40,16 +40,30 @@ module ActionController # :nodoc:
|
||||||
delegate :default_charset, :to => 'ActionController::Base'
|
delegate :default_charset, :to => 'ActionController::Base'
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@status = 200
|
super
|
||||||
@header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS)
|
@header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS)
|
||||||
|
|
||||||
@writer = lambda { |x| @body << x }
|
|
||||||
@block = nil
|
|
||||||
|
|
||||||
@body = "",
|
|
||||||
@session, @assigns = [], []
|
@session, @assigns = [], []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def body
|
||||||
|
str = ''
|
||||||
|
each { |part| str << part.to_s }
|
||||||
|
str
|
||||||
|
end
|
||||||
|
|
||||||
|
def body=(body)
|
||||||
|
@body =
|
||||||
|
if body.is_a?(String)
|
||||||
|
[body]
|
||||||
|
else
|
||||||
|
body
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def body_parts
|
||||||
|
@body
|
||||||
|
end
|
||||||
|
|
||||||
def location; headers['Location'] end
|
def location; headers['Location'] end
|
||||||
def location=(url) headers['Location'] = url end
|
def location=(url) headers['Location'] = url end
|
||||||
|
|
||||||
|
@ -152,7 +166,7 @@ module ActionController # :nodoc:
|
||||||
@writer = lambda { |x| callback.call(x) }
|
@writer = lambda { |x| callback.call(x) }
|
||||||
@body.call(self, self)
|
@body.call(self, self)
|
||||||
elsif @body.is_a?(String)
|
elsif @body.is_a?(String)
|
||||||
@body.each_line(&callback)
|
callback.call(@body)
|
||||||
else
|
else
|
||||||
@body.each(&callback)
|
@body.each(&callback)
|
||||||
end
|
end
|
||||||
|
@ -162,7 +176,8 @@ module ActionController # :nodoc:
|
||||||
end
|
end
|
||||||
|
|
||||||
def write(str)
|
def write(str)
|
||||||
@writer.call str.to_s
|
str = str.to_s
|
||||||
|
@writer.call str
|
||||||
str
|
str
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -186,7 +201,7 @@ module ActionController # :nodoc:
|
||||||
|
|
||||||
if request && request.etag_matches?(etag)
|
if request && request.etag_matches?(etag)
|
||||||
self.status = '304 Not Modified'
|
self.status = '304 Not Modified'
|
||||||
self.body = ''
|
self.body = []
|
||||||
end
|
end
|
||||||
|
|
||||||
set_conditional_cache_control!
|
set_conditional_cache_control!
|
||||||
|
@ -195,7 +210,7 @@ module ActionController # :nodoc:
|
||||||
|
|
||||||
def nonempty_ok_response?
|
def nonempty_ok_response?
|
||||||
ok = !status || status.to_s[0..2] == '200'
|
ok = !status || status.to_s[0..2] == '200'
|
||||||
ok && body.is_a?(String) && !body.empty?
|
ok && !body_parts.respond_to?(:call) && body_parts.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_conditional_cache_control!
|
def set_conditional_cache_control!
|
||||||
|
@ -216,8 +231,8 @@ module ActionController # :nodoc:
|
||||||
headers.delete('Content-Length')
|
headers.delete('Content-Length')
|
||||||
elsif length = headers['Content-Length']
|
elsif length = headers['Content-Length']
|
||||||
headers['Content-Length'] = length.to_s
|
headers['Content-Length'] = length.to_s
|
||||||
elsif !body.respond_to?(:call) && (!status || status.to_s[0..2] != '304')
|
elsif !body_parts.respond_to?(:call) && (!status || status.to_s[0..2] != '304')
|
||||||
headers["Content-Length"] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
headers["Content-Length"] = Rack::Utils.bytesize(body).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -258,11 +258,11 @@ module ActionController #:nodoc:
|
||||||
|
|
||||||
# Returns binary content (downloadable file), converted to a String
|
# Returns binary content (downloadable file), converted to a String
|
||||||
def binary_content
|
def binary_content
|
||||||
raise "Response body is not a Proc: #{body.inspect}" unless body.kind_of?(Proc)
|
raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc)
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
|
||||||
sio = StringIO.new
|
sio = StringIO.new
|
||||||
body.call(self, sio)
|
body_parts.call(self, sio)
|
||||||
|
|
||||||
sio.rewind
|
sio.rewind
|
||||||
sio.read
|
sio.read
|
||||||
|
|
|
@ -258,7 +258,7 @@ class RackResponseTest < BaseRackTest
|
||||||
}, headers)
|
}, headers)
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
body.each { |part| parts << part }
|
body.each { |part| parts << part.to_s }
|
||||||
assert_equal ["0", "1", "2", "3", "4"], parts
|
assert_equal ["0", "1", "2", "3", "4"], parts
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,12 +44,12 @@ class SendFileTest < ActionController::TestCase
|
||||||
response = nil
|
response = nil
|
||||||
assert_nothing_raised { response = process('file') }
|
assert_nothing_raised { response = process('file') }
|
||||||
assert_not_nil response
|
assert_not_nil response
|
||||||
assert_kind_of Proc, response.body
|
assert_kind_of Proc, response.body_parts
|
||||||
|
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
output = StringIO.new
|
output = StringIO.new
|
||||||
output.binmode
|
output.binmode
|
||||||
assert_nothing_raised { response.body.call(response, output) }
|
assert_nothing_raised { response.body_parts.call(response, output) }
|
||||||
assert_equal file_data, output.string
|
assert_equal file_data, output.string
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue