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

adding a buffered stream to the response object

This commit is contained in:
Aaron Patterson 2012-07-29 15:51:21 -07:00
parent 76d75f4240
commit 356787fce8
4 changed files with 93 additions and 3 deletions

View file

@ -187,7 +187,7 @@ module ActionController
end
def performed?
!!response_body
response_body || (response && response.committed?)
end
def dispatch(name, request) #:nodoc:

View file

@ -65,6 +65,36 @@ module ActionDispatch # :nodoc:
include ActionDispatch::Http::Cache::Response
include MonitorMixin
class Buffer # :nodoc:
def initialize(response, buf)
@response = response
@buf = buf
@closed = false
end
def write(string)
raise IOError, "closed stream" if closed?
@response.commit!
@buf.push string
end
def each(&block)
@buf.each(&block)
end
def close
@response.commit!
@closed = true
end
def closed?
@closed
end
end
attr_reader :stream
def initialize(status = 200, header = {}, body = [])
super()
@ -76,6 +106,8 @@ module ActionDispatch # :nodoc:
@committed = false
@content_type = nil
@charset = nil
@stream = build_buffer self, @body
if content_type = self[CONTENT_TYPE]
type, charset = content_type.split(/;\s*charset=/)
@ -102,7 +134,7 @@ module ActionDispatch # :nodoc:
end
def committed?
synchronize { @committed }
@committed
end
def status=(status)
@ -151,7 +183,7 @@ module ActionDispatch # :nodoc:
def body=(body)
@blank = true if body == EMPTY
@body = body.respond_to?(:each) ? body : [body]
@body = munge_body_object(body)
end
def body_parts
@ -214,6 +246,14 @@ module ActionDispatch # :nodoc:
private
def build_buffer(response, body)
Buffer.new response, body
end
def munge_body_object(body)
body.respond_to?(:each) ? body : [body]
end
def assign_default_content_type_and_charset!
return if headers[CONTENT_TYPE].present?

View file

@ -0,0 +1,30 @@
require 'abstract_unit'
module ActionController
class StreamingResponseTest < ActionController::TestCase
class TestController < ActionController::Base
def self.controller_path
'test'
end
def basic_stream
%w{ hello world }.each do |word|
response.stream.write word
response.stream.write "\n"
end
response.stream.close
end
end
tests TestController
def test_write_to_stream
get :basic_stream
assert_equal "hello\nworld\n", @response.body
end
def test_write_after_close
@response.stream
end
end
end

View file

@ -14,6 +14,26 @@ class ResponseTest < ActiveSupport::TestCase
assert t.join(0.5)
end
def test_stream_close
@response.stream.close
assert @response.stream.closed?
end
def test_stream_write
@response.stream.write "foo"
@response.stream.close
assert_equal "foo", @response.body
end
def test_write_after_close
@response.stream.close
e = assert_raises(IOError) do
@response.stream.write "omg"
end
assert_equal "closed stream", e.message
end
def test_response_body_encoding
body = ["hello".encode('utf-8')]
response = ActionDispatch::Response.new 200, {}, body