diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-09-27 17:27:01 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-09-27 17:27:01 -0700 |
commit | 32d5db4f499dbbe3e9026969eee66592800dd725 (patch) | |
tree | 338d4165bbd14374bfd9cccbb70cb8d36b8eccf7 /lib/unicorn/http_response.rb | |
parent | 8e1f0620e567cd676902e4ed34edb042f28ec3b0 (diff) | |
download | unicorn-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.rb | 54 |
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 |