about summary refs log tree commit homepage
path: root/lib/rainbows/base.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-06-28 08:06:32 +0000
committerEric Wong <normalperson@yhbt.net>2010-06-28 08:57:26 +0000
commit8175a52c67fb9dfc9c04a7b0597b680699f43deb (patch)
tree9c50e69b27c271929082aad63d0f1f7e9a4d28fa /lib/rainbows/base.rb
parent86e9c7013308d77def5fe41b52a35dea60c7361c (diff)
downloadrainbows-8175a52c67fb9dfc9c04a7b0597b680699f43deb.tar.gz
This still needs work and lots of cleanup, but the basics are
there.  The sendfile 1.0.0 RubyGem is now safe to use under MRI
1.8, and is superior to current (1.9.2-preview3) versions of
IO.copy_stream for static files in that it supports more
platforms and doesn't truncate large files on 32-bit platforms.
Diffstat (limited to 'lib/rainbows/base.rb')
-rw-r--r--lib/rainbows/base.rb51
1 files changed, 41 insertions, 10 deletions
diff --git a/lib/rainbows/base.rb b/lib/rainbows/base.rb
index 2627719..24924cb 100644
--- a/lib/rainbows/base.rb
+++ b/lib/rainbows/base.rb
@@ -39,25 +39,56 @@ module Rainbows::Base
     logger.info "Rainbows! #@use worker_connections=#@worker_connections"
   end
 
+  # TODO: move write_body_* stuff out of Base
+  def write_body_each(client, body)
+    body.each { |chunk| client.write(chunk) }
+    ensure
+      body.respond_to?(:close) and body.close
+  end
+
+  # The sendfile 1.0.0 RubyGem includes IO#sendfile and
+  # IO#sendfile_nonblock, previous versions didn't have
+  # IO#sendfile_nonblock, and IO#sendfile in previous versions
+  # could other threads under 1.8 with large files
+  #
+  # IO#sendfile currently (June 2010) beats 1.9 IO.copy_stream with
+  # non-Linux support and large files on 32-bit.  We still fall back to
+  # IO.copy_stream (if available) if we're dealing with DevFdResponse
+  # objects, though.
+  if IO.method_defined?(:sendfile_nonblock)
+    def write_body_path(client, body)
+      file = Rainbows.body_to_io(body)
+      file.stat.file? ? client.sendfile(file, 0) :
+                        write_body_stream(client, file)
+    end
+  end
+
   if IO.respond_to?(:copy_stream)
-    def write_body(client, body)
-      if body.respond_to?(:to_path)
+    unless method_defined?(:write_body_path)
+      def write_body_path(client, body)
         IO.copy_stream(Rainbows.body_to_io(body), client)
-      else
-        body.each { |chunk| client.write(chunk) }
       end
-      ensure
-        body.respond_to?(:close) and body.close
+    end
+
+    def write_body_stream(client, body)
+      IO.copy_stream(body, client)
     end
   else
+    alias write_body_stream write_body_each
+  end
+
+  if method_defined?(:write_body_path)
     def write_body(client, body)
-      body.each { |chunk| client.write(chunk) }
-      ensure
-        body.respond_to?(:close) and body.close
+      body.respond_to?(:to_path) ?
+        write_body_path(client, body) :
+        write_body_each(client, body)
     end
+  else
+    alias write_body write_body_each
   end
 
-  module_function :write_body
+  module_function :write_body, :write_body_each, :write_body_stream
+  method_defined?(:write_body_path) and module_function(:write_body_path)
 
   def wait_headers_readable(client)
     IO.select([client], nil, nil, G.kato)