about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2014-02-04 03:41:15 +0000
committerEric Wong <normalperson@yhbt.net>2014-02-04 03:41:15 +0000
commit648c9a67bf397c22b82496a03c4b2b2a8ae8dd1f (patch)
treeea2089a1ec7d1165231513067f6dce2eaecae79e
parent0fca33cc0eea24f5b6c0e8d172d59802300b7345 (diff)
downloadyahns-648c9a67bf397c22b82496a03c4b2b2a8ae8dd1f.tar.gz
If Content-Length is known, try to save some bandwidth by
corking the headers until the body is sendable.  This allows
us to avoid sending an extra packet for small HTTP responses.

This allows high-performance websites like YHBT.net to be served
faster!
-rw-r--r--lib/yahns/http_response.rb21
-rw-r--r--test/server_helper.rb5
-rw-r--r--yahns.gemspec2
3 files changed, 26 insertions, 2 deletions
diff --git a/lib/yahns/http_response.rb b/lib/yahns/http_response.rb
index 65ecdff..e257feb 100644
--- a/lib/yahns/http_response.rb
+++ b/lib/yahns/http_response.rb
@@ -32,6 +32,20 @@ module Yahns::HttpResponse # :nodoc:
   R100_CCC = "100 Continue\r\n\r\nHTTP/1.1 "
   HTTP_EXPECT = "HTTP_EXPECT"
 
+  # no point in using one without the other, these have been in Linux
+  # for ages
+  if Socket.const_defined?(:MSG_MORE) && Socket.const_defined?(:MSG_DONTWAIT)
+    MSG_MORE = Socket::MSG_MORE
+    MSG_DONTWAIT = Socket::MSG_DONTWAIT
+  else
+    MSG_MORE = 0
+    MSG_DONTWAIT = 0
+
+    def kgio_syssend(buf, flags)
+      kgio_trywrite(buf)
+    end
+  end
+
   def response_start
     @response_start_sent ? Z : RESPONSE_START
   end
@@ -117,6 +131,7 @@ module Yahns::HttpResponse # :nodoc:
     count = hijack = nil
     k = self.class
     alive = @hs.next? && k.persistent_connections
+    flags = MSG_DONTWAIT
 
     if @hs.headers?
       buf = "#{response_start}#{status}\r\nDate: #{httpdate}\r\n"
@@ -133,6 +148,9 @@ module Yahns::HttpResponse # :nodoc:
         when %r{\AConnection\z}i
           # allow Rack apps to tell us they want to drop the client
           alive = false if value =~ /\bclose\b/i
+        when %r{\AContent-Length\z}i
+          flags |= MSG_MORE
+          buf << kv_str(key, value)
         when "rack.hijack"
           hijack = value
           body = nil # ensure we do not close body
@@ -141,10 +159,11 @@ module Yahns::HttpResponse # :nodoc:
         end
       end
       buf << (alive ? CONN_KA : CONN_CLOSE)
-      case rv = kgio_trywrite(buf)
+      case rv = kgio_syssend(buf, flags)
       when nil # all done, likely
         break
       when String
+        flags = MSG_DONTWAIT
         buf = rv # hope the skb grows
       when :wait_writable, :wait_readable
         if k.output_buffering
diff --git a/test/server_helper.rb b/test/server_helper.rb
index d4b8f98..a92a2da 100644
--- a/test/server_helper.rb
+++ b/test/server_helper.rb
@@ -100,4 +100,9 @@ module TrywriteBlocked
     return :wait_writable if $_tw_block_on.include?($_tw_blocked += 1)
     super
   end
+
+  def kgio_syssend(*args)
+    return :wait_writable if $_tw_block_on.include?($_tw_blocked += 1)
+    super
+  end
 end
diff --git a/yahns.gemspec b/yahns.gemspec
index 200230f..26b68b2 100644
--- a/yahns.gemspec
+++ b/yahns.gemspec
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
   s.email = %q{yahns@yhbt.net}
   s.executables = manifest.grep(%r{\Abin/}).map { |s| s.sub(%r{\Abin/}, "") }
   s.files = manifest
-  s.add_dependency(%q<kgio>, '~> 2.8')
+  s.add_dependency(%q<kgio>, '~> 2.9')
   s.add_dependency(%q<sleepy_penguin>, '~> 3.2')
   s.add_dependency(%q<sendfile>, '~> 1.2.1')
   s.add_dependency(%q<unicorn>, '~> 4.6', '>= 4.6.3')