writer_thread_spawn: factor out Client.quit
[rainbows.git] / lib / rainbows / response.rb
blob8be417756d5d46b5a140cb5239a0da3f4f0e9f1c
1 # -*- encoding: binary -*-
2 # :enddoc:
3 require 'time' # for Time#httpdate
5 module Rainbows::Response
6   autoload :Body, 'rainbows/response/body'
7   autoload :Range, 'rainbows/response/range'
9   CODES = Unicorn::HttpResponse::CODES
10   CRLF = "\r\n"
12   # freeze headers we may set as hash keys for a small speedup
13   CONNECTION = "Connection".freeze
14   CLOSE = "close"
15   KEEP_ALIVE = "keep-alive"
16   HH = Rack::Utils::HeaderHash
18   def response_header(status, headers)
19     status = CODES[status.to_i] || status
20     rv = "HTTP/1.1 #{status}\r\n" \
21          "Date: #{Time.now.httpdate}\r\n" \
22          "Status: #{status}\r\n"
23     headers.each do |key, value|
24       next if %r{\A(?:X-Rainbows-|Date\z|Status\z)}i =~ key
25       if value =~ /\n/
26         # avoiding blank, key-only cookies with /\n+/
27         rv << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join('')
28       else
29         rv << "#{key}: #{value}\r\n"
30       end
31     end
32     rv << CRLF
33   end
35   # called after forking
36   def self.setup(klass)
37     Rainbows::G.kato == 0 and KEEP_ALIVE.replace(CLOSE)
38     range_class = body_class = klass
39     case Rainbows::Const::RACK_DEFAULTS['rainbows.model']
40     when :WriterThreadSpawn
41       body_class = Rainbows::WriterThreadSpawn::Client
42       range_class = Rainbows::HttpServer
43     when :EventMachine, :NeverBlock
44       range_class = nil # :<
45     end
46     return if body_class.included_modules.include?(Body)
47     body_class.__send__(:include, Body)
48     sf = IO.respond_to?(:copy_stream) || IO.method_defined?(:sendfile_nonblock)
49     if range_class
50       range_class.__send__(:include, sf ? Range : NoRange)
51     end
52   end
54   module NoRange
55     # dummy method if we can't send range responses
56     def make_range!(env, status, headers)
57     end
58   end
59 end