diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-02-06 14:52:10 -0800 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-02-09 19:50:54 -0800 |
commit | 25bbb88bcc16c1c0a10efc99472b05e9f6b45861 (patch) | |
tree | 4921a360284b9ccdda99fd9e0593160b0432649b /lib/unicorn/http_response.rb | |
parent | 33cf16e950d32db97ef03fa304eb2b73e9b3cc87 (diff) | |
download | unicorn-25bbb88bcc16c1c0a10efc99472b05e9f6b45861.tar.gz |
Just stuff what little logic we had for it into HttpResponse since Rack takes care of the rest for us. Put the HTTP_STATUS_HEADERS hash in HttpResponse since we're the only user of it. Also, change HttpResponse.send to HttpResponse.write to avoid overriding the default method.
Diffstat (limited to 'lib/unicorn/http_response.rb')
-rw-r--r-- | lib/unicorn/http_response.rb | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb index 4ffe64b..e2a4e2f 100644 --- a/lib/unicorn/http_response.rb +++ b/lib/unicorn/http_response.rb @@ -1,14 +1,13 @@ module Unicorn - # Writes a Rack response to your client using the HTTP/1.1 specification. # You use it by simply doing: # # status, headers, body = rack_app.call(env) - # HttpResponse.send(socket, [ status, headers, body ]) + # HttpResponse.write(socket, [ status, headers, body ]) # - # Most header correctness (including Content-Length) is the job of - # Rack, with the exception of the "Connection: close" and "Date" - # headers. + # Most header correctness (including Content-Length and Content-Type) + # is the job of Rack, with the exception of the "Connection: close" + # and "Date" headers. # # A design decision was made to force the client to not pipeline or # keepalive requests. HTTP/1.1 pipelining really kills the @@ -20,19 +19,36 @@ module Unicorn class HttpResponse - # we'll have one of these per-process - HEADERS = HeaderOut.new unless defined?(HEADERS) + # enforce "Connection: close" usage on all our responses + HTTP_STATUS_HEADERS = HTTP_STATUS_CODES.inject({}) do |hash, (code, text)| + hash[code] = "HTTP/1.1 #{code} #{text}\r\nConnection: close".freeze + hash + end.freeze + + # headers we allow duplicates for + ALLOWED_DUPLICATES = { + 'Set-Cookie' => true, + 'Set-Cookie2' => true, + 'Warning' => true, + 'WWW-Authenticate' => true, + }.freeze - def self.send(socket, rack_response) + def self.write(socket, rack_response) status, headers, body = rack_response - HEADERS.reset! - # Rack does not set Date, but don't worry about Content-Length, - # since Rack enforces that in Rack::Lint - HEADERS[Const::DATE] = Time.now.httpdate - HEADERS.merge!(headers) + # Rack does not set/require Date, but don't worry about Content-Length + # since Rack enforces that in Rack::Lint. + out = [ "#{Const::DATE}: #{Time.now.httpdate}\r\n" ] + sent = { Const::CONNECTION => true, Const::DATE => true } + + headers.each_pair do |key, value| + if ! sent[key] || ALLOWED_DUPLICATES[key] + sent[key] = true + out << "#{key}: #{value}\r\n" + end + end - socket.write("#{HTTP_STATUS_HEADERS[status]}#{HEADERS.to_s}\r\n") + socket.write("#{HTTP_STATUS_HEADERS[status]}\r\n#{out.join}\r\n") body.each { |chunk| socket.write(chunk) } end |