Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
171 lines (144 sloc) 4.18 KB
require 'net/http/server/daemon'
require 'net/http/server/version'
require 'rack'
require 'rack/rewindable_input'
require 'set'
module Rack
module Handler
#
# A Rack handler for {Net::HTTP::Server}.
#
class HTTP
# The default environment settings.
DEFAULT_ENV = {
'rack.version' => Rack::VERSION,
'rack.errors' => $stderr,
'rack.multithread' => true,
'rack.multiprocess' => false,
'rack.run_once' => false,
'rack.url_scheme' => 'http',
'SERVER_SOFTWARE' => "Net::HTTP::Server/#{Net::HTTP::Server::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})",
'SCRIPT_NAME' => ''
}
# Special HTTP Headers used by Rack::Request
SPECIAL_HEADERS = Set[
'Content-Type',
'Content-Length'
]
#
# Initializes the handler.
#
# @param [#call] app
# The application the handler will be passing requests to.
#
# @param [Hash] options
# Additional options.
#
# @option options [String] :Host
# The host to bind to.
#
# @option options [Integer] :Port
# The port to listen on.
#
def initialize(app,options={})
@app = app
@options = options
@server = nil
end
#
# Creates a new handler and begins handling HTTP Requests.
#
# @see #initialize
#
def self.run(app,options={})
new(app,options).run
end
#
# Starts {Net::HTTP::Server} and begins handling HTTP Requests.
#
def run
@server = Net::HTTP::Server::Daemon.new(
:host => @options[:Host],
:port => @options[:Port],
:handler => self
)
@server.start
@server.join
end
#
# Handles an HTTP Request.
#
# @param [Hash] request
# An HTTP Request received from {Net::HTTP::Server}.
#
# @param [Net::HTTP::Server::Stream, Net::HTTP::Server::ChunkedStream] stream
# The stream that represents the body of the request.
#
# @return [Array<Integer, Hash, Array>]
# The response status, headers and body.
#
def call(request,stream)
request_uri = request[:uri]
remote_address = stream.socket.remote_address
local_address = stream.socket.local_address
env = {}
# add the default values
env.merge!(DEFAULT_ENV)
# populate
env['rack.input'] = Rack::RewindableInput.new(stream)
if request_uri[:scheme]
env['rack.url_scheme'] = request_uri[:scheme].to_s
end
env['SERVER_NAME'] = local_address.getnameinfo[0]
env['SERVER_PORT'] = local_address.ip_port.to_s
env['SERVER_PROTOCOL'] = "HTTP/#{request[:http_version]}"
env['REMOTE_ADDR'] = remote_address.ip_address
env['REMOTE_PORT'] = remote_address.ip_port.to_s
env['REQUEST_METHOD'] = request[:method].to_s
env['PATH_INFO'] = request_uri.fetch(:path,'*').to_s
env['QUERY_STRING'] = request_uri[:query].to_s
# add the headers
request[:headers].each do |name,value|
key = name.dup
key.upcase!
key.tr!('-','_')
# if the header is not special, prepend 'HTTP_'
unless SPECIAL_HEADERS.include?(name)
key.insert(0,'HTTP_')
end
env[key] = case value
when Array
value.join("\n")
else
value.to_s
end
end
@app.call(env)
end
#
# Determines if the handler is running.
#
# @return [Boolean]
# Specifies whether the handler is still running.
#
def running?
@server && !(@server.stopped?)
end
#
# Determines whether the handler was stopped.
#
# @return [Boolean]
# Specifies whether the handler was previously stopped.
#
def stopped?
@server.nil? || @server.stopped?
end
#
# Stops the handler.
#
def stop
@server.stop if @server
end
end
end
end