about summary refs log tree commit homepage
path: root/lib/unicorn/http_response.rb
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-09-27 17:27:01 -0700
committerEric Wong <normalperson@yhbt.net>2009-09-27 17:27:01 -0700
commit32d5db4f499dbbe3e9026969eee66592800dd725 (patch)
tree338d4165bbd14374bfd9cccbb70cb8d36b8eccf7 /lib/unicorn/http_response.rb
parent8e1f0620e567cd676902e4ed34edb042f28ec3b0 (diff)
downloadunicorn-32d5db4f499dbbe3e9026969eee66592800dd725.tar.gz
We don't need the Z constant anymore and inlining the header
writing gives a small overall performance improvement in
microbenchmarks.  This also makes this method reentrant and
thread-safe for Rainbows as well.
Diffstat (limited to 'lib/unicorn/http_response.rb')
-rw-r--r--lib/unicorn/http_response.rb54
1 files changed, 26 insertions, 28 deletions
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb
index f226ef3..92d4d6d 100644
--- a/lib/unicorn/http_response.rb
+++ b/lib/unicorn/http_response.rb
@@ -33,39 +33,37 @@ module Unicorn
     # Connection: and Date: headers no matter what (if anything) our
     # Rack application sent us.
     SKIP = { 'connection' => true, 'date' => true, 'status' => true }
-    OUT = [] # :nodoc
 
-    def self.write_header(socket, status, headers)
-      status = CODES[status.to_i] || status
-      OUT.clear
+    # writes the rack_response to socket as an HTTP response
+    def self.write(socket, rack_response, have_header = true)
+      status, headers, body = rack_response
 
-      # 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}\r\n" }
-        else
-          OUT << "#{key}: #{value}\r\n"
-        end
-      end
+      if have_header
+        status = CODES[status.to_i] || status
+        out = []
 
-      # Rack should enforce Content-Length or chunked transfer encoding,
-      # so don't worry or care about them.
-      # Date is required by HTTP/1.1 as long as our clock can be trusted.
-      # Some broken clients require a "Status" header so we accomodate them
-      socket.write("HTTP/1.1 #{status}\r\n" \
-                   "Date: #{Time.now.httpdate}\r\n" \
-                   "Status: #{status}\r\n" \
-                   "Connection: close\r\n" \
-                   "#{OUT.join(Z)}\r\n")
+        # 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/
+            out.concat(value.split(/\n/).map! { |v| "#{key}: #{v}\r\n" })
+          else
+            out << "#{key}: #{value}\r\n"
+          end
+        end
 
-    end
+        # Rack should enforce Content-Length or chunked transfer encoding,
+        # so don't worry or care about them.
+        # Date is required by HTTP/1.1 as long as our clock can be trusted.
+        # Some broken clients require a "Status" header so we accomodate them
+        socket.write("HTTP/1.1 #{status}\r\n" \
+                     "Date: #{Time.now.httpdate}\r\n" \
+                     "Status: #{status}\r\n" \
+                     "Connection: close\r\n" \
+                     "#{out.join('')}\r\n")
+      end
 
-    # writes the rack_response to socket as an HTTP response
-    def self.write(socket, rack_response, have_header = true)
-      status, headers, body = rack_response
-      write_header(socket, status, headers) if have_header
       body.each { |chunk| socket.write(chunk) }
       socket.close # flushes and uncorks the socket immediately
       ensure