event_machine: prevent double close of client socket
[rainbows.git] / lib / rainbows / response.rb
blob36ecbe2aacb29c3397e3abe7531b01b01b30df61
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     range_class = body_class = klass
38     case Rainbows::Const::RACK_DEFAULTS['rainbows.model']
39     when :WriterThreadSpawn
40       body_class = Rainbows::WriterThreadSpawn::MySocket
41       range_class = Rainbows::HttpServer
42     when :EventMachine, :NeverBlock, :Revactor
43       range_class = nil # :<
44     end
45     return if body_class.included_modules.include?(Body)
46     body_class.__send__(:include, Body)
47     sf = IO.respond_to?(:copy_stream) || IO.method_defined?(:sendfile_nonblock)
48     if range_class
49       range_class.__send__(:include, sf ? Range : NoRange)
50     end
51   end
53   module NoRange
54     # dummy method if we can't send range responses
55     def make_range!(env, status, headers)
56     end
57   end
58 end