about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-06-10 22:08:04 +0000
committerEric Wong <normalperson@yhbt.net>2011-06-10 22:09:18 +0000
commit1468604be898d17c2cf2da519dccd493c58f4282 (patch)
treeca754932852f0e8f1ccdf3ac64f491d6c81d5fa2
parent1aa7eb6608d04a21d1143e7ac09e5219a1208123 (diff)
Do not assume middlewares/applications are stupid and blindly
add chunking to responses (we have precedence set by
Rack::Chunked).
-rw-r--r--lib/rainbows/dev_fd_response.rb9
-rw-r--r--lib/rainbows/ev_core.rb17
-rw-r--r--t/async-response-no-autochunk.ru30
3 files changed, 40 insertions, 16 deletions
diff --git a/lib/rainbows/dev_fd_response.rb b/lib/rainbows/dev_fd_response.rb
index eaa4af4..edc39af 100644
--- a/lib/rainbows/dev_fd_response.rb
+++ b/lib/rainbows/dev_fd_response.rb
@@ -19,7 +19,6 @@ class Rainbows::DevFdResponse < Struct.new(:app)
   Transfer_Encoding = "Transfer-Encoding".freeze
   Rainbows_autochunk = "rainbows.autochunk".freeze
   Rainbows_model = "rainbows.model"
-  HTTP_1_0 = "HTTP/1.0"
   HTTP_VERSION = "HTTP_VERSION"
   Chunked = "chunked"
 
@@ -55,8 +54,12 @@ class Rainbows::DevFdResponse < Struct.new(:app)
       headers.delete(Transfer_Encoding)
     elsif st.pipe? || st.socket? # epoll-able things
       unless headers.include?(Content_Length)
-        if env[Rainbows_autochunk] && HTTP_1_0 != env[HTTP_VERSION]
-          headers[Transfer_Encoding] = Chunked
+        if env[Rainbows_autochunk]
+          case env[HTTP_VERSION]
+          when "HTTP/1.0", nil
+          else
+            headers[Transfer_Encoding] = Chunked
+          end
         else
           env[Rainbows_autochunk] = false
         end
diff --git a/lib/rainbows/ev_core.rb b/lib/rainbows/ev_core.rb
index 29e0e81..46feaff 100644
--- a/lib/rainbows/ev_core.rb
+++ b/lib/rainbows/ev_core.rb
@@ -10,6 +10,7 @@ module Rainbows::EvCore
   RBUF = ""
   Z = "".freeze
   Rainbows.config!(self, :client_header_buffer_size)
+  HTTP_VERSION = "HTTP_VERSION"
 
   # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
   ASYNC_CALLBACK = "async.callback".freeze
@@ -54,13 +55,23 @@ module Rainbows::EvCore
   def stream_response_headers(status, headers, alive)
     headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
     if headers.include?(Content_Length)
-      rv = false
+      write_headers(status, headers, alive)
+      return false
+    end
+
+    case @env[HTTP_VERSION]
+    when "HTTP/1.0" # disable HTTP/1.0 keepalive to stream
+      write_headers(status, headers, false)
+      @hp.clear
+      false
+    when nil # "HTTP/0.9"
+      false
     else
       rv = !!(headers[Transfer_Encoding] =~ %r{\Achunked\z}i)
       rv = false unless @env["rainbows.autochunk"]
+      write_headers(status, headers, alive)
+      rv
     end
-    write_headers(status, headers, alive)
-    rv
   end
 
   def prepare_request_body
diff --git a/t/async-response-no-autochunk.ru b/t/async-response-no-autochunk.ru
index 1eda553..9fbe77f 100644
--- a/t/async-response-no-autochunk.ru
+++ b/t/async-response-no-autochunk.ru
@@ -1,6 +1,6 @@
 use Rack::Chunked
 use Rainbows::DevFdResponse
-script = <<-EOF
+script_chunked = <<-EOF
 for i in 0 1 2 3 4 5 6 7 8 9
 do
         printf '1\r\n%s\r\n' $i
@@ -9,15 +9,25 @@ done
 printf '0\r\n\r\n'
 EOF
 
+script_identity = <<-EOF
+for i in 0 1 2 3 4 5 6 7 8 9
+do
+        printf $i
+        sleep 1
+done
+EOF
+
 run lambda { |env|
   env['rainbows.autochunk'] = false
-  io = IO.popen(script, 'rb')
-  [
-    200,
-    {
-      'Content-Type' => 'text/plain',
-      'Transfer-Encoding' => 'chunked',
-    },
-    io
-  ].freeze
+  headers = { 'Content-Type' => 'text/plain' }
+
+  script = case env["HTTP_VERSION"]
+  when nil, "HTTP/1.0"
+    script_identity
+  else
+    headers['Transfer-Encoding'] = 'chunked'
+    script_chunked
+  end
+
+  [ 200, headers, IO.popen(script, 'rb') ].freeze
 }