Skip to content

Commit 6a30a96

Browse files
committed
Merge branch 'master' of git://github.com/rails/rails
2 parents dcbacb1 + 6ed42eb commit 6a30a96

File tree

10 files changed

+118
-26
lines changed

10 files changed

+118
-26
lines changed

actionpack/lib/action_controller/base.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,7 @@ def render(options = nil, extra_options = {}, &block) #:doc:
984984
# of sending it as the response body to the browser.
985985
def render_to_string(options = nil, &block) #:doc:
986986
render(options, &block)
987+
response.body
987988
ensure
988989
response.content_type = nil
989990
erase_render_results
@@ -1020,7 +1021,7 @@ def head(*args)
10201021

10211022
# Clears the rendered results, allowing for another render to be performed.
10221023
def erase_render_results #:nodoc:
1023-
response.body = nil
1024+
response.body = []
10241025
@performed_render = false
10251026
end
10261027

@@ -1247,13 +1248,12 @@ def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
12471248
response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
12481249

12491250
if append_response
1250-
response.body ||= ''
1251-
response.body << text.to_s
1251+
response.body_parts << text.to_s
12521252
else
12531253
response.body = case text
1254-
when Proc then text
1255-
when nil then " " # Safari doesn't pass the headers of the return if the response is zero length
1256-
else text.to_s
1254+
when Proc then text
1255+
when nil then [" "] # Safari doesn't pass the headers of the return if the response is zero length
1256+
else [text.to_s]
12571257
end
12581258
end
12591259
end

actionpack/lib/action_controller/integration.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,13 @@ def process(method, path, parameters = nil, headers = nil)
332332
@cookies[name] = value
333333
end
334334

335-
@body = ""
336335
if body.is_a?(String)
337-
@body << body
336+
@body_parts = [body]
337+
@body = body
338338
else
339-
body.each { |part| @body << part }
339+
@body_parts = []
340+
body.each { |part| @body_parts << part.to_s }
341+
@body = @body_parts.join
340342
end
341343

342344
if @controller = ActionController::Base.last_instantiation
@@ -349,7 +351,7 @@ def process(method, path, parameters = nil, headers = nil)
349351
@response = Response.new
350352
@response.status = status.to_s
351353
@response.headers.replace(@headers)
352-
@response.body = @body
354+
@response.body = @body_parts
353355
end
354356

355357
# Decorate the response with the standard behavior of the

actionpack/lib/action_controller/response.rb

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,28 @@ class Response < Rack::Response
4040
delegate :default_charset, :to => 'ActionController::Base'
4141

4242
def initialize
43-
@status = 200
43+
super
4444
@header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS)
45+
@session, @assigns = [], []
46+
end
4547

46-
@writer = lambda { |x| @body << x }
47-
@block = nil
48+
def body
49+
str = ''
50+
each { |part| str << part.to_s }
51+
str
52+
end
4853

49-
@body = "",
50-
@session, @assigns = [], []
54+
def body=(body)
55+
@body =
56+
if body.is_a?(String)
57+
[body]
58+
else
59+
body
60+
end
61+
end
62+
63+
def body_parts
64+
@body
5165
end
5266

5367
def location; headers['Location'] end
@@ -152,7 +166,7 @@ def each(&callback)
152166
@writer = lambda { |x| callback.call(x) }
153167
@body.call(self, self)
154168
elsif @body.is_a?(String)
155-
@body.each_line(&callback)
169+
callback.call(@body)
156170
else
157171
@body.each(&callback)
158172
end
@@ -162,7 +176,8 @@ def each(&callback)
162176
end
163177

164178
def write(str)
165-
@writer.call str.to_s
179+
str = str.to_s
180+
@writer.call str
166181
str
167182
end
168183

@@ -186,7 +201,7 @@ def handle_conditional_get!
186201

187202
if request && request.etag_matches?(etag)
188203
self.status = '304 Not Modified'
189-
self.body = ''
204+
self.body = []
190205
end
191206

192207
set_conditional_cache_control!
@@ -195,7 +210,11 @@ def handle_conditional_get!
195210

196211
def nonempty_ok_response?
197212
ok = !status || status.to_s[0..2] == '200'
198-
ok && body.is_a?(String) && !body.empty?
213+
ok && string_body?
214+
end
215+
216+
def string_body?
217+
!body_parts.respond_to?(:call) && body_parts.any? && body_parts.all? { |part| part.is_a?(String) }
199218
end
200219

201220
def set_conditional_cache_control!
@@ -216,8 +235,8 @@ def set_content_length!
216235
headers.delete('Content-Length')
217236
elsif length = headers['Content-Length']
218237
headers['Content-Length'] = length.to_s
219-
elsif !body.respond_to?(:call) && (!status || status.to_s[0..2] != '304')
220-
headers["Content-Length"] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
238+
elsif string_body? && (!status || status.to_s[0..2] != '304')
239+
headers["Content-Length"] = Rack::Utils.bytesize(body).to_s
221240
end
222241
end
223242

actionpack/lib/action_controller/test_process.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,11 @@ def cookies
258258

259259
# Returns binary content (downloadable file), converted to a String
260260
def binary_content
261-
raise "Response body is not a Proc: #{body.inspect}" unless body.kind_of?(Proc)
261+
raise "Response body is not a Proc: #{body_parts.inspect}" unless body_parts.kind_of?(Proc)
262262
require 'stringio'
263263

264264
sio = StringIO.new
265-
body.call(self, sio)
265+
body_parts.call(self, sio)
266266

267267
sio.rewind
268268
sio.read

actionpack/lib/action_view/base.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,12 @@ def with_template(current_template)
303303
self.template = last_template
304304
end
305305

306+
def punctuate_body!(part)
307+
flush_output_buffer
308+
response.body_parts << part
309+
nil
310+
end
311+
306312
private
307313
# Evaluates the local assigns and controller ivars, pushes them to the view.
308314
def _evaluate_assigns_and_ivars #:nodoc:

actionpack/lib/action_view/helpers/capture_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ def with_output_buffer(buf = '') #:nodoc:
131131
ensure
132132
self.output_buffer = old_buffer
133133
end
134+
135+
# Add the output buffer to the response body and start a new one.
136+
def flush_output_buffer #:nodoc:
137+
if output_buffer && output_buffer != ''
138+
response.body_parts << output_buffer
139+
self.output_buffer = ''
140+
end
141+
end
134142
end
135143
end
136144
end

actionpack/test/controller/rack_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def test_streaming_block
258258
}, headers)
259259

260260
parts = []
261-
body.each { |part| parts << part }
261+
body.each { |part| parts << part.to_s }
262262
assert_equal ["0", "1", "2", "3", "4"], parts
263263
end
264264
end

actionpack/test/controller/send_file_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ def test_file_stream
4444
response = nil
4545
assert_nothing_raised { response = process('file') }
4646
assert_not_nil response
47-
assert_kind_of Proc, response.body
47+
assert_kind_of Proc, response.body_parts
4848

4949
require 'stringio'
5050
output = StringIO.new
5151
output.binmode
52-
assert_nothing_raised { response.body.call(response, output) }
52+
assert_nothing_raised { response.body_parts.call(response, output) }
5353
assert_equal file_data, output.string
5454
end
5555

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'abstract_unit'
2+
3+
class BodyPartsTest < ActionController::TestCase
4+
RENDERINGS = [Object.new, Object.new, Object.new]
5+
6+
class TestController < ActionController::Base
7+
def index
8+
RENDERINGS.each do |rendering|
9+
response.template.punctuate_body! rendering
10+
end
11+
@performed_render = true
12+
end
13+
end
14+
15+
tests TestController
16+
17+
def test_body_parts
18+
get :index
19+
assert_equal RENDERINGS, @response.body_parts
20+
assert_equal RENDERINGS.join, @response.body
21+
end
22+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require 'abstract_unit'
2+
3+
class OutputBufferTest < ActionController::TestCase
4+
class TestController < ActionController::Base
5+
def index
6+
render :text => 'foo'
7+
end
8+
end
9+
10+
tests TestController
11+
12+
def test_flush_output_buffer
13+
# Start with the default body parts
14+
get :index
15+
assert_equal ['foo'], @response.body_parts
16+
assert_nil @response.template.output_buffer
17+
18+
# Nil output buffer is skipped
19+
@response.template.flush_output_buffer
20+
assert_nil @response.template.output_buffer
21+
assert_equal ['foo'], @response.body_parts
22+
23+
# Empty output buffer is skipped
24+
@response.template.output_buffer = ''
25+
@response.template.flush_output_buffer
26+
assert_equal '', @response.template.output_buffer
27+
assert_equal ['foo'], @response.body_parts
28+
29+
# Flushing appends the output buffer to the body parts
30+
@response.template.output_buffer = 'bar'
31+
@response.template.flush_output_buffer
32+
assert_equal '', @response.template.output_buffer
33+
assert_equal ['foo', 'bar'], @response.body_parts
34+
end
35+
end

0 commit comments

Comments
 (0)