diff options
author | Eric Wong <normalperson@yhbt.net> | 2010-06-28 04:45:16 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2010-06-28 05:03:29 +0000 |
commit | 5769f313793ca84100f089b1911f2e22d0a31e9d (patch) | |
tree | 91acceeb65e5ec8baa60a33efc2ebae24af6669c | |
parent | cf63db66bca9acfd3416ab8fc8a7fd4f07927342 (diff) | |
download | unicorn-5769f313793ca84100f089b1911f2e22d0a31e9d.tar.gz |
This affects Rainbows!, but Rainbows! is still using the Unicorn 1.x branch. While we're at it, avoid redeclaring the "Unicorn" module, it makes documentation noisier.
-rw-r--r-- | lib/unicorn/http_response.rb | 115 |
1 files changed, 55 insertions, 60 deletions
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb index 96e484b..6f1cd48 100644 --- a/lib/unicorn/http_response.rb +++ b/lib/unicorn/http_response.rb @@ -1,75 +1,70 @@ # -*- encoding: binary -*- - require 'time' -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.write(socket, [ status, headers, body ]) - # - # 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 - # performance due to how it has to be handled and how unclear the - # standard is. To fix this the HttpResponse always gives a - # "Connection: close" header which forces the client to close right - # away. The bonus for this is that it gives a pretty nice speed boost - # to most clients since they can close their connection immediately. - - class HttpResponse +# 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.write(socket, [ status, headers, body ]) +# +# 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 +# performance due to how it has to be handled and how unclear the +# standard is. To fix this the HttpResponse always gives a +# "Connection: close" header which forces the client to close right +# away. The bonus for this is that it gives a pretty nice speed boost +# to most clients since they can close their connection immediately. +module Unicorn::HttpResponse - # Every standard HTTP code mapped to the appropriate message. - CODES = Rack::Utils::HTTP_STATUS_CODES.inject({}) { |hash,(code,msg)| - hash[code] = "#{code} #{msg}" - hash - } + # Every standard HTTP code mapped to the appropriate message. + CODES = Rack::Utils::HTTP_STATUS_CODES.inject({}) { |hash,(code,msg)| + hash[code] = "#{code} #{msg}" + hash + } - # Rack does not set/require a Date: header. We always override the - # Connection: and Date: headers no matter what (if anything) our - # Rack application sent us. - SKIP = { 'connection' => true, 'date' => true, 'status' => true } + # Rack does not set/require a Date: header. We always override the + # Connection: and Date: headers no matter what (if anything) our + # Rack application sent us. + SKIP = { 'connection' => true, 'date' => true, 'status' => true } - # writes the rack_response to socket as an HTTP response - def self.write(socket, rack_response, have_header = true) - status, headers, body = rack_response + # writes the rack_response to socket as an HTTP response + def self.write(socket, rack_response, have_header = true) + status, headers, body = rack_response - if have_header - status = CODES[status.to_i] || status - out = [] + if have_header + status = CODES[status.to_i] || status + out = [] - # 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/ - # avoiding blank, key-only cookies with /\n+/ - out.concat(value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }) - else - out << "#{key}: #{value}\r\n" - end + # 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/ + # avoiding blank, key-only cookies with /\n+/ + out.concat(value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }) + else + out << "#{key}: #{value}\r\n" 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 - body.each { |chunk| socket.write(chunk) } - socket.close # flushes and uncorks the socket immediately - ensure - body.respond_to?(:close) and body.close + # 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 + body.each { |chunk| socket.write(chunk) } + socket.close # flushes and uncorks the socket immediately + ensure + body.respond_to?(:close) and body.close end end |