From 1468604be898d17c2cf2da519dccd493c58f4282 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 10 Jun 2011 22:08:04 +0000 Subject: ev_core: do not autochunk HTTP/1.0 (and 0.9) responses Do not assume middlewares/applications are stupid and blindly add chunking to responses (we have precedence set by Rack::Chunked). --- lib/rainbows/dev_fd_response.rb | 9 ++++++--- lib/rainbows/ev_core.rb | 17 ++++++++++++++--- t/async-response-no-autochunk.ru | 30 ++++++++++++++++++++---------- 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 } -- cgit v1.2.3-24-ge0c7