summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-04-23 21:20:03 -0700
committerEric Wong <normalperson@yhbt.net>2009-04-23 21:20:03 -0700
commit5facf207004a805d0b0836a6605bb02ab5ac77da (patch)
treefc85ce61c9aa545381a61ba9f003ff91bc9d3e02
parenta9fa99940cd6d6f8572f83d6489d402c09b0cf93 (diff)
Avoid creating garbage every time we lookup the status code
along with the message.  Also, we can use global const arrays
for a little extra performance because we only write one-at-a
time

Looking at MRI 1.8, Array#join with an empty string argument is
slightly better because it skips an append for every iteration.
-rw-r--r--lib/unicorn/const.rb3
-rw-r--r--lib/unicorn/http_response.rb14
-rw-r--r--test/unit/test_response.rb2
3 files changed, 12 insertions, 7 deletions
diff --git a/lib/unicorn/const.rb b/lib/unicorn/const.rb
index c05d333..c31b8e3 100644
--- a/lib/unicorn/const.rb
+++ b/lib/unicorn/const.rb
@@ -42,6 +42,9 @@ module Unicorn
     503  => 'Service Unavailable',
     504  => 'Gateway Time-out',
     505  => 'HTTP Version not supported'
+  }.inject({}) { |hash,(code,msg)|
+      hash[code] = "#{code} #{msg}"
+      hash
   }
 
   # Frequently used constants when constructing requests or responses.  Many times
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb
index 658184b..5480b5d 100644
--- a/lib/unicorn/http_response.rb
+++ b/lib/unicorn/http_response.rb
@@ -25,22 +25,23 @@ module Unicorn
     # Connection: and Date: headers no matter what (if anything) our
     # Rack application sent us.
     SKIP = { 'connection' => true, 'date' => true, 'status' => true }.freeze
-    CONNECTION_CLOSE = "Connection: close".freeze #:nodoc
+    EMPTY = ''.freeze # :nodoc
+    OUT = [] # :nodoc
 
     # writes the rack_response to socket as an HTTP response
     def self.write(socket, rack_response)
       status, headers, body = rack_response
-      status = "#{status} #{HTTP_STATUS_CODES[status]}"
-      out = [ CONNECTION_CLOSE ]
+      status = HTTP_STATUS_CODES[status]
+      OUT.clear
 
       # Don't bother enforcing duplicate supression, it's a Hash most of
       # the time anyways so just hope our app knows what it's doing
       headers.each do |key, value|
         next if SKIP.include?(key.downcase)
         if value =~ /\n/
-          value.split(/\n/).each { |v| out << "#{key}: #{v}" }
+          value.split(/\n/).each { |v| OUT << "#{key}: #{v}\r\n" }
         else
-          out << "#{key}: #{value}"
+          OUT << "#{key}: #{value}\r\n"
         end
       end
 
@@ -52,7 +53,8 @@ module Unicorn
                    "HTTP/1.1 #{status}\r\n" \
                    "Date: #{Time.now.httpdate}\r\n" \
                    "Status: #{status}\r\n" \
-                   "#{out.join("\r\n")}\r\n\r\n")
+                   "Connection: close\r\n" \
+                   "#{OUT.join(EMPTY)}\r\n")
       body.each { |chunk| socket_write(socket, chunk) }
       socket.close # uncorks the socket immediately
       ensure
diff --git a/test/unit/test_response.rb b/test/unit/test_response.rb
index 1d47c57..3cb0a41 100644
--- a/test/unit/test_response.rb
+++ b/test/unit/test_response.rb
@@ -43,7 +43,7 @@ class ResponseTest < Test::Unit::TestCase
     HttpResponse.write(io, [code, {}, []])
     assert io.closed?
     lines = io.string.split(/\r\n/)
-    assert_match(/.* #{HTTP_STATUS_CODES[code]}$/, lines.first,
+    assert_match(/.* Bad Request$/, lines.first,
                  "wrong default reason phrase")
   end