From 5facf207004a805d0b0836a6605bb02ab5ac77da Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 23 Apr 2009 21:20:03 -0700 Subject: http_response: minor performance gains 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. --- lib/unicorn/const.rb | 3 +++ lib/unicorn/http_response.rb | 14 ++++++++------ test/unit/test_response.rb | 2 +- 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 -- cgit v1.2.3-24-ge0c7