tee_input: update documentation for Rack 1.2
[unicorn.git] / lib / unicorn / http_response.rb
blob96e484b13142854c8bdd918674beeee809c66909
1 # -*- encoding: binary -*-
3 require 'time'
5 module Unicorn
6   # Writes a Rack response to your client using the HTTP/1.1 specification.
7   # You use it by simply doing:
8   #
9   #   status, headers, body = rack_app.call(env)
10   #   HttpResponse.write(socket, [ status, headers, body ])
11   #
12   # Most header correctness (including Content-Length and Content-Type)
13   # is the job of Rack, with the exception of the "Connection: close"
14   # and "Date" headers.
15   #
16   # A design decision was made to force the client to not pipeline or
17   # keepalive requests.  HTTP/1.1 pipelining really kills the
18   # performance due to how it has to be handled and how unclear the
19   # standard is.  To fix this the HttpResponse always gives a
20   # "Connection: close" header which forces the client to close right
21   # away.  The bonus for this is that it gives a pretty nice speed boost
22   # to most clients since they can close their connection immediately.
24   class HttpResponse
26     # Every standard HTTP code mapped to the appropriate message.
27     CODES = Rack::Utils::HTTP_STATUS_CODES.inject({}) { |hash,(code,msg)|
28       hash[code] = "#{code} #{msg}"
29       hash
30     }
32     # Rack does not set/require a Date: header.  We always override the
33     # Connection: and Date: headers no matter what (if anything) our
34     # Rack application sent us.
35     SKIP = { 'connection' => true, 'date' => true, 'status' => true }
37     # writes the rack_response to socket as an HTTP response
38     def self.write(socket, rack_response, have_header = true)
39       status, headers, body = rack_response
41       if have_header
42         status = CODES[status.to_i] || status
43         out = []
45         # Don't bother enforcing duplicate supression, it's a Hash most of
46         # the time anyways so just hope our app knows what it's doing
47         headers.each do |key, value|
48           next if SKIP.include?(key.downcase)
49           if value =~ /\n/
50             # avoiding blank, key-only cookies with /\n+/
51             out.concat(value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" })
52           else
53             out << "#{key}: #{value}\r\n"
54           end
55         end
57         # Rack should enforce Content-Length or chunked transfer encoding,
58         # so don't worry or care about them.
59         # Date is required by HTTP/1.1 as long as our clock can be trusted.
60         # Some broken clients require a "Status" header so we accomodate them
61         socket.write("HTTP/1.1 #{status}\r\n" \
62                      "Date: #{Time.now.httpdate}\r\n" \
63                      "Status: #{status}\r\n" \
64                      "Connection: close\r\n" \
65                      "#{out.join('')}\r\n")
66       end
68       body.each { |chunk| socket.write(chunk) }
69       socket.close # flushes and uncorks the socket immediately
70       ensure
71         body.respond_to?(:close) and body.close
72     end
74   end
75 end