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:
parent
76d75f4240
commit
356787fce8
4 changed files with 93 additions and 3 deletions
|
@ -187,7 +187,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def performed?
|
||||
!!response_body
|
||||
response_body || (response && response.committed?)
|
||||
end
|
||||
|
||||
def dispatch(name, request) #:nodoc:
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
30
actionpack/test/controller/streaming_test.rb
Normal file
30
actionpack/test/controller/streaming_test.rb
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue