# -*- encoding: binary -*-
# :enddoc:
require 'time' # for Time#httpdate

module Rainbows::Response
  autoload :Body, 'rainbows/response/body'
  autoload :Range, 'rainbows/response/range'

  CODES = Unicorn::HttpResponse::CODES
  CRLF = "\r\n"

  # freeze headers we may set as hash keys for a small speedup
  CONNECTION = "Connection".freeze
  CLOSE = "close"
  KEEP_ALIVE = "keep-alive"
  HH = Rack::Utils::HeaderHash

  def response_header(status, headers)
    status = CODES[status.to_i] || status
    rv = "HTTP/1.1 #{status}\r\n" \
         "Date: #{Time.now.httpdate}\r\n" \
         "Status: #{status}\r\n"
    headers.each do |key, value|
      next if %r{\A(?:X-Rainbows-|Date\z|Status\z)}i =~ key
      if value =~ /\n/
        # avoiding blank, key-only cookies with /\n+/
        rv << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join('')
      else
        rv << "#{key}: #{value}\r\n"
      end
    end
    rv << CRLF
  end

  # called after forking
  def self.setup(klass)
    Rainbows::G.kato == 0 and KEEP_ALIVE.replace(CLOSE)
    range_class = body_class = klass
    case Rainbows::Const::RACK_DEFAULTS['rainbows.model']
    when :WriterThreadSpawn
      body_class = Rainbows::WriterThreadSpawn::MySocket
      range_class = Rainbows::HttpServer
    when :EventMachine, :NeverBlock
      range_class = nil # :<
    end
    return if body_class.included_modules.include?(Body)
    body_class.__send__(:include, Body)
    sf = IO.respond_to?(:copy_stream) || IO.method_defined?(:sendfile_nonblock)
    if range_class
      range_class.__send__(:include, sf ? Range : NoRange)
    end
  end

  module NoRange
    # dummy method if we can't send range responses
    def make_range!(env, status, headers)
    end
  end
end
