summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-06-29 05:27:18 -0700
committerEric Wong <normalperson@yhbt.net>2009-06-29 17:48:11 -0700
commit4f05fb1a3b44f8eab1a9dda26d5b115f33a149cd (patch)
treee497aa94d7559f2825b97b19fdee076ab79b635c
parent1e10654f81e74c4d11ab538b16dcc1b7bd36cb7f (diff)
The default is false because some applications were not
written to handle partial reads (even though IO#read allows
it, not just IO#readpartial).
-rw-r--r--lib/unicorn/configurator.rb29
-rw-r--r--lib/unicorn/http_request.rb5
-rw-r--r--test/unit/test_configurator.rb4
3 files changed, 31 insertions, 7 deletions
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index a432f64..99a3c04 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -44,6 +44,7 @@ module Unicorn
       :preload_app => false,
       :stderr_path => nil,
       :stdout_path => nil,
+      :stream_input => false,
     }
 
     attr_reader :config_file #:nodoc:
@@ -64,8 +65,12 @@ module Unicorn
 
     def commit!(server, options = {}) #:nodoc:
       skip = options[:skip] || []
+      stream_input = @set.delete(:stream_input)
+      unless stream_input.nil?
+        Unicorn::HttpRequest::DEFAULTS[Const::STREAM_INPUT] = stream_input
+      end
       @set.each do |key, value|
-        (Symbol === value && value == :unset) and next
+        value == :unset and next
         skip.include?(key) and next
         setter = "#{key}="
         if server.respond_to?(setter)
@@ -249,6 +254,28 @@ module Unicorn
       end
     end
 
+    # Allow applications to stream input as it is being read from the
+    # network directly to the application.  Enabling this can allow
+    # real-time processing of request bodies as it is being sent by
+    # the client, useful for things like upload progress notification
+    # and tunneling arbitrary stream protocols via bidirectional chunked
+    # transfer encoding.
+    # This may not work with all applications because some broken
+    # applications assume env['rack.input'].read(size) always returns
+    # the requested amount of data.  This causes env['rack.input']#read
+    # to provide IO#readpartial semantics instead.  Some applications
+    # may also fully receive an input and never attempt to process it,
+    # causing clients confusion when they receive a response after
+    # only a partial request has been sent.
+    def stream_input(bool)
+      case bool
+      when TrueClass, FalseClass
+        @set[:stream_input] = bool
+      else
+        raise ArgumentError, "stream_input=#{bool.inspect} not a boolean"
+      end
+    end
+
     # Allow redirecting $stderr to a given path.  Unlike doing this from
     # the shell, this allows the unicorn process to know the path its
     # writing to and rotate the file if it is used for logging.  The
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index e25517b..b1cd8ed 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -17,11 +17,6 @@ module Unicorn
       "rack.version" => [1, 0].freeze,
       "SCRIPT_NAME" => "".freeze,
 
-      # some applications (like Echo) may want to change this to true
-      # We disable streaming by default since some (arguably broken)
-      # applications may not ever read the entire body and be confused
-      # when it receives a response after nothing has been sent to it.
-      Const::STREAM_INPUT => false,
       # this is not in the Rack spec, but some apps may rely on it
       "SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}".freeze
     }
diff --git a/test/unit/test_configurator.rb b/test/unit/test_configurator.rb
index 98f2db6..f836647 100644
--- a/test/unit/test_configurator.rb
+++ b/test/unit/test_configurator.rb
@@ -1,6 +1,6 @@
 require 'test/unit'
 require 'tempfile'
-require 'unicorn/configurator'
+require 'unicorn'
 
 class TestConfigurator < Test::Unit::TestCase
 
@@ -53,6 +53,7 @@ class TestConfigurator < Test::Unit::TestCase
     cfg = Unicorn::Configurator.new(:use_defaults => true)
     assert_nothing_raised { cfg.commit!(self) }
     Unicorn::Configurator::DEFAULTS.each do |key,value|
+      next if key == :stream_input
       assert_equal value, instance_variable_get("@#{key.to_s}")
     end
   end
@@ -64,6 +65,7 @@ class TestConfigurator < Test::Unit::TestCase
     @logger = nil
     Unicorn::Configurator::DEFAULTS.each do |key,value|
       next if skip.include?(key)
+      next if key == :stream_input
       assert_equal value, instance_variable_get("@#{key.to_s}")
     end
     assert_nil @logger