1
0
Fork 0
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:
Jeremy Kemper 2009-03-12 21:47:34 -07:00
parent c8c2b3820e
commit 91d2740595
6 changed files with 44 additions and 27 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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