diff options
author | José Valim <jose.valim@gmail.com> | 2011-04-18 08:52:29 +0200 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2011-04-18 08:55:41 +0200 |
commit | 389d15ef139e50696b274f2d61dd309ba2632877 (patch) | |
tree | 333341059cbf9227979873345c0cb09338ec45ca | |
parent | 7a152ab0127877eea6f2cef8ff6d1975a3fc16d4 (diff) | |
download | rails-389d15ef139e50696b274f2d61dd309ba2632877.tar.gz rails-389d15ef139e50696b274f2d61dd309ba2632877.tar.bz2 rails-389d15ef139e50696b274f2d61dd309ba2632877.zip |
Body... wanna *stream* my body? Body... such a thrill my body!
Added stream as class level method to make it explicit when to stream.
Render also accepts :stream as option.
-rw-r--r-- | actionpack/lib/action_controller.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 1 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/streaming.rb | 57 | ||||
-rw-r--r-- | actionpack/lib/action_view/context.rb | 1 | ||||
-rw-r--r-- | actionpack/test/controller/new_base/render_streaming_test.rb | 62 |
5 files changed, 122 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 26e6ac770f..aab2b9dc25 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -31,6 +31,7 @@ module ActionController autoload :Rescue autoload :Responder autoload :SessionManagement + autoload :Streaming autoload :Testing autoload :UrlFor end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 53e0a4b9d1..ca0dccf575 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -199,6 +199,7 @@ module ActionController Flash, RequestForgeryProtection, ForceSSL, + Streaming, DataStreaming, RecordIdentifier, HttpAuthentication::Basic::ControllerMethods, diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb new file mode 100644 index 0000000000..adb3e94134 --- /dev/null +++ b/actionpack/lib/action_controller/metal/streaming.rb @@ -0,0 +1,57 @@ +require 'active_support/core_ext/file/path' +require 'rack/chunked' + +module ActionController #:nodoc: + # Methods for sending streaming templates back to the client. + module Streaming + extend ActiveSupport::Concern + + include AbstractController::Rendering + attr_internal :stream + + module ClassMethods + # Render streaming templates. It accepts :only, :except, :if and :unless as options + # to specify when to stream, as in ActionController filters. + def stream(options={}) + if defined?(Fiber) + before_filter :_stream_filter, options + else + raise "You cannot use streaming if Fiber is not available." + end + end + end + + protected + + # Mark following render calls as streaming. + def _stream_filter #:nodoc: + self.stream = true + end + + # Consider the stream option when normalazing options. + def _normalize_options(options) #:nodoc: + super + options[:stream] = self.stream unless options.key?(:stream) + end + + # Set proper cache control and transfer encoding when streaming + def _process_options(options) #:nodoc: + super + if options[:stream] + headers["Cache-Control"] ||= "no-cache" + headers["Transfer-Encoding"] = "chunked" + headers.delete("Content-Length") + end + end + + # Call render_to_body if we are streaming instead of usual +render+. + def _render_template(options) #:nodoc: + if options.delete(:stream) + Rack::Chunked::Body.new view_context.render_body(options) + else + super + end + end + end +end +
\ No newline at end of file diff --git a/actionpack/lib/action_view/context.rb b/actionpack/lib/action_view/context.rb index 39d88333e8..a2a64de206 100644 --- a/actionpack/lib/action_view/context.rb +++ b/actionpack/lib/action_view/context.rb @@ -2,6 +2,7 @@ module ActionView module CompiledTemplates #:nodoc: # holds compiled template code end + # = Action View Context # # Action View contexts are supplied to Action Controller to render template. diff --git a/actionpack/test/controller/new_base/render_streaming_test.rb b/actionpack/test/controller/new_base/render_streaming_test.rb new file mode 100644 index 0000000000..27ba4b1a29 --- /dev/null +++ b/actionpack/test/controller/new_base/render_streaming_test.rb @@ -0,0 +1,62 @@ +require 'abstract_unit' + +module RenderStreaming + class BasicController < ActionController::Base + self.view_paths = [ActionView::FixtureResolver.new( + "render_streaming/basic/hello_world.html.erb" => "Hello world", + "layouts/application.html.erb" => "<%= yield %>, I'm here!" + )] + + layout "application" + stream :only => :hello_world + + def hello_world + end + + def explicit + render :action => "hello_world", :stream => true + end + + def no_layout + render :action => "hello_world", :stream => true, :layout => false + end + + def explicit_cache + headers["Cache-Control"] = "private" + render :action => "hello_world", :stream => true + end + end + + class StreamingTest < Rack::TestCase + test "rendering with streaming enabled at the class level" do + get "/render_streaming/basic/hello_world" + assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n" + assert_streaming! + end + + test "rendering with streaming given to render" do + get "/render_streaming/basic/explicit" + assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n" + assert_streaming! + end + + test "rendering with streaming do not override explicit cache control given to render" do + get "/render_streaming/basic/explicit_cache" + assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n" + assert_streaming! "private" + end + + test "rendering with streaming no layout" do + get "/render_streaming/basic/no_layout" + assert_body "b\r\nHello world\r\n0\r\n\r\n" + assert_streaming! + end + + def assert_streaming!(cache="no-cache") + assert_status 200 + assert_equal nil, headers["Content-Length"] + assert_equal "chunked", headers["Transfer-Encoding"] + assert_equal cache, headers["Cache-Control"] + end + end if defined?(Fiber) +end |