1 # -*- encoding: binary -*-
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
12 # freeze headers we may set as hash keys for a small speedup
13 CONNECTION = "Connection".freeze
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
26 # avoiding blank, key-only cookies with /\n+/
27 rv << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join('')
29 rv << "#{key}: #{value}\r\n"
35 # called after forking
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 # :<
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)
49 range_class.__send__(:include, sf ? Range : NoRange)
54 # dummy method if we can't send range responses
55 def make_range!(env, status, headers)