aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2011-04-18 08:52:29 +0200
committerJosé Valim <jose.valim@gmail.com>2011-04-18 08:55:41 +0200
commit389d15ef139e50696b274f2d61dd309ba2632877 (patch)
tree333341059cbf9227979873345c0cb09338ec45ca /actionpack
parent7a152ab0127877eea6f2cef8ff6d1975a3fc16d4 (diff)
downloadrails-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.
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_controller.rb1
-rw-r--r--actionpack/lib/action_controller/base.rb1
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb57
-rw-r--r--actionpack/lib/action_view/context.rb1
-rw-r--r--actionpack/test/controller/new_base/render_streaming_test.rb62
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