From b1315983056f91467b336aeb426759debc006a4e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Jun 2010 02:14:58 +0000 Subject: centralize body => IO conversion logic Since EventMachine and Rev shared the same logic for optimizing and avoiding extra file opens for IO/File-ish response bodies, so centralize that. For Ruby 1.9 users, we've also enabled this logic so ThreadPool, ThreadSpawn, WriterThreadPool, and WriterThreadSpawn can take advantage of Rainbows::DevFdResponse-generated bodies while proxying sockets. --- lib/rainbows.rb | 15 +++++++++++++++ lib/rainbows/base.rb | 3 +-- lib/rainbows/event_machine.rb | 9 +++------ lib/rainbows/rev/deferred_response.rb | 7 +------ 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/rainbows.rb b/lib/rainbows.rb index e186549..5aae746 100644 --- a/lib/rainbows.rb +++ b/lib/rainbows.rb @@ -156,6 +156,21 @@ module Rainbows # :startdoc: autoload :Fiber, 'rainbows/fiber' # core class + # to_io is not part of the Rack spec, but make an exception here + # since we can conserve path lookups and file descriptors + # \Rainbows! will never get here without checking for the existence + # of body.to_path first. + def self.body_to_io(body) + if body.respond_to?(:to_io) + body.to_io + else + # try to take advantage of Rainbows::DevFdResponse, calling File.open + # is a last resort + path = body.to_path + path =~ %r{\A/dev/fd/(\d+)\z} ? IO.new($1.to_i) : File.open(path, 'rb') + end + end + end # inject the Rainbows! method into Unicorn::Configurator diff --git a/lib/rainbows/base.rb b/lib/rainbows/base.rb index a773722..8e5031f 100644 --- a/lib/rainbows/base.rb +++ b/lib/rainbows/base.rb @@ -33,8 +33,7 @@ module Rainbows if IO.respond_to?(:copy_stream) def write_body(client, body) if body.respond_to?(:to_path) - io = body.respond_to?(:to_io) ? body.to_io : body.to_path - IO.copy_stream(io, client) + IO.copy_stream(Rainbows.body_to_io(body), client) else body.each { |chunk| client.write(chunk) } end diff --git a/lib/rainbows/event_machine.rb b/lib/rainbows/event_machine.rb index b19bdec..12d9e5e 100644 --- a/lib/rainbows/event_machine.rb +++ b/lib/rainbows/event_machine.rb @@ -112,18 +112,15 @@ module Rainbows end headers = Rack::Utils::HeaderHash.new(response[1]) - path = body.to_path - io = body.to_io if body.respond_to?(:to_io) - io ||= IO.new($1.to_i) if path =~ %r{\A/dev/fd/(\d+)\z} - io ||= File.open(path, 'rb') # could be a named pipe - + io = Rainbows.body_to_io(body) st = io.stat + if st.file? headers.delete('Transfer-Encoding') headers['Content-Length'] ||= st.size.to_s response = [ response.first, headers.to_hash, [] ] HttpResponse.write(self, response, out) - stream = stream_file_data(path) + stream = stream_file_data(body.to_path) stream.callback { quit } unless alive elsif st.socket? || st.pipe? do_chunk = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i) diff --git a/lib/rainbows/rev/deferred_response.rb b/lib/rainbows/rev/deferred_response.rb index dd7a229..62a308c 100644 --- a/lib/rainbows/rev/deferred_response.rb +++ b/lib/rainbows/rev/deferred_response.rb @@ -17,12 +17,7 @@ module Rainbows return HttpResponse.write(client, response, out) headers = HH.new(headers) - - # to_io is not part of the Rack spec, but make an exception - # here since we can't get here without checking to_path first - io = body.to_io if body.respond_to?(:to_io) - io ||= ::IO.new($1.to_i) if body.to_path =~ %r{\A/dev/fd/(\d+)\z} - io ||= File.open(body.to_path, 'rb') + io = Rainbows.body_to_io(body) st = io.stat if st.socket? || st.pipe? -- cgit v1.2.3-24-ge0c7