class SnowmanIO::WebServer::ConnectionHandler

Constants

CONTENT_LENGTH_HEADER

Compile the regex once

NO_PREFIX_HEADERS

Those headers must not start with 'HTTP_'.

Public Class Methods

new(connection, app) click to toggle source

include Celluloid

# File lib/snowman-io/web_server.rb, line 11
def initialize(connection, app)
  @connection = connection
  @app = app
  # async.run
  run
rescue Reel::SocketError
  @connection.close
end

Public Instance Methods

run() click to toggle source
# File lib/snowman-io/web_server.rb, line 20
def run
  @connection.each_request do |request|
    # TODO: support websockets
    if request.websocket?
      request.respond :bad_request, "WebSockets not supported"
    else
      route_request request
    end
  end
end

Protected Instance Methods

convert_headers(headers) click to toggle source
# File lib/snowman-io/web_server.rb, line 68
def convert_headers(headers)
  Hash[headers.map { |key, value|
    header = key.upcase.gsub('-','_')

    if NO_PREFIX_HEADERS.member?(header)
      [header, value]
    else
      ['HTTP_' + header, value]
    end
  }]
end
route_request(request) click to toggle source
# File lib/snowman-io/web_server.rb, line 36
def route_request(request)
  options = {
    :method       => request.method,
    :input        => request.body.to_s,
    "REMOTE_ADDR" => request.remote_addr
  }.merge(convert_headers(request.headers))

  status, headers, body = @app.call ::Rack::MockRequest.env_for(request.url, options)

  if body.respond_to? :each
    # If Content-Length was specified we can send the response all at once
    if headers.keys.detect { |h| h =~ CONTENT_LENGTH_HEADER }
      # Can't use collect here because Rack::BodyProxy/Rack::Lint isn't a real Enumerable
      full_body = ''
      body.each { |b| full_body << b }
      request.respond status_symbol(status), headers, full_body
    else
      request.respond status_symbol(status), headers.merge(:transfer_encoding => :chunked)
      body.each { |chunk| request << chunk }
      request.finish_response
    end
  else
    SnowmanIO.logger.error("don't know how to render: #{body.inspect}")
    request.respond :internal_server_error, "An error occurred processing your request"
  end

  body.close if body.respond_to? :close
end
status_symbol(status) click to toggle source
# File lib/snowman-io/web_server.rb, line 80
def status_symbol(status)
  if status.is_a?(Fixnum)
    Http::Response::STATUS_CODES[status].downcase.gsub(/\s|-/, '_').to_sym
  else
    status.to_sym
  end
end