An HTTP Server
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 46
def initialize(config={}, default=Config::HTTP)
super(config, default)
@http_version = HTTPVersion::convert(@config[:HTTPVersion])
@mount_tab = MountTable.new
if @config[:DocumentRoot]
mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot],
@config[:DocumentRootOptions])
end
unless @config[:AccessLog]
@config[:AccessLog] = [
[ $stderr, AccessLog::COMMON_LOG_FORMAT ],
[ $stderr, AccessLog::REFERER_LOG_FORMAT ]
]
end
@virtual_hosts = Array.new
end
Creates a new HTTP server according to config
An HTTP server uses the following attributes:
- :AccessLog
-
An array of access logs. See
WEBrick::AccessLog
- :BindAddress
-
Local address for the server to bind to
- :DocumentRoot
-
Root path to serve files from
- :DocumentRootOptions
-
Options for the default
HTTPServlet::FileHandler
- :HTTPVersion
-
The HTTP version of this server
- :Port
-
Port to listen on
- :RequestCallback
-
Called with a request and response before each request is serviced.
- :RequestTimeout
-
Maximum time to wait between requests
- :ServerAlias
-
Array
of alternate names for this server for virtual hosting - :ServerName
-
Name for this server for virtual hosting
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 220
def access_log(config, req, res)
param = AccessLog::setup_params(config, req, res)
@config[:AccessLog].each{|logger, fmt|
logger << AccessLog::format(fmt+"\n", param)
}
end
Logs req
and res
in the access logs. config
is used for the server name.
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 230
def create_request(with_webrick_config)
HTTPRequest.new(with_webrick_config)
end
Creates the HTTPRequest
used when handling the HTTP request. Can be overridden by subclasses.
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 237
def create_response(with_webrick_config)
HTTPResponse.new(with_webrick_config)
end
Creates the HTTPResponse
used when handling the HTTP request. Can be overridden by subclasses.
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 147
def do_OPTIONS(req, res)
res["allow"] = "GET,HEAD,POST,OPTIONS"
end
The default OPTIONS request handler says GET, HEAD, POST and OPTIONS requests are allowed.
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 207
def lookup_server(req)
@virtual_hosts.find{|s|
(s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) &&
(s[:Port].nil? || req.port == s[:Port]) &&
((s[:ServerName].nil? || req.host == s[:ServerName]) ||
(!s[:ServerAlias].nil? && s[:ServerAlias].find{|h| h === req.host}))
}
end
Finds the appropriate virtual host to handle req
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 155
def mount(dir, servlet, *options)
@logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir))
@mount_tab[dir] = [ servlet, options ]
end
Mounts servlet
on dir
passing options
to the servlet at creation time
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 164
def mount_proc(dir, proc=nil, &block)
proc ||= block
raise HTTPServerError, "must pass a proc or block" unless proc
mount(dir, HTTPServlet::ProcHandler.new(proc))
end
Mounts proc
or block
on dir
and calls it with a WEBrick::HTTPRequest
and WEBrick::HTTPResponse
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 69
def run(sock)
while true
req = create_request(@config)
res = create_response(@config)
server = self
begin
timeout = @config[:RequestTimeout]
while timeout > 0
break if sock.to_io.wait_readable(0.5)
break if @status != :Running
timeout -= 0.5
end
raise HTTPStatus::EOFError if timeout <= 0 || @status != :Running
raise HTTPStatus::EOFError if sock.eof?
req.parse(sock)
res.request_method = req.request_method
res.request_uri = req.request_uri
res.request_http_version = req.http_version
res.keep_alive = req.keep_alive?
server = lookup_server(req) || self
if callback = server[:RequestCallback]
callback.call(req, res)
elsif callback = server[:RequestHandler]
msg = ":RequestHandler is deprecated, please use :RequestCallback"
@logger.warn(msg)
callback.call(req, res)
end
server.service(req, res)
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
res.set_error(ex)
rescue HTTPStatus::Error => ex
@logger.error(ex.message)
res.set_error(ex)
rescue HTTPStatus::Status => ex
res.status = ex.code
rescue StandardError => ex
@logger.error(ex)
res.set_error(ex, true)
ensure
if req.request_line
if req.keep_alive? && res.keep_alive?
req.fixup()
end
res.send_response(sock)
server.access_log(@config, req, res)
end
end
break if @http_version < "1.1"
break unless req.keep_alive?
break unless res.keep_alive?
end
end
Processes requests on sock
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 182
def search_servlet(path)
script_name, path_info = @mount_tab.scan(path)
servlet, options = @mount_tab[script_name]
if servlet
[ servlet, options, script_name, path_info ]
end
end
Finds a servlet for path
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 125
def service(req, res)
if req.unparsed_uri == "*"
if req.request_method == "OPTIONS"
do_OPTIONS(req, res)
raise HTTPStatus::OK
end
raise HTTPStatus::NotFound, "`#{req.unparsed_uri}' not found."
end
servlet, options, script_name, path_info = search_servlet(req.path)
raise HTTPStatus::NotFound, "`#{req.path}' not found." unless servlet
req.script_name = script_name
req.path_info = path_info
si = servlet.get_instance(self, *options)
@logger.debug(format("%s is invoked.", si.class.name))
si.service(req, res)
end
Services req
and fills in res
# File tmp/rubies/ruby-2.7.6/lib/webrick/https.rb, line 129
def ssl_servername_callback(sslsocket, hostname = nil)
req = SNIRequest.new(sslsocket, hostname)
server = lookup_server(req)
server ? server.ssl_context : nil
end
ServerNameIndication callback
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 173
def unmount(dir)
@logger.debug(sprintf("unmount %s.", dir))
@mount_tab.delete(dir)
end
Unmounts dir
# File tmp/rubies/ruby-2.7.6/lib/webrick/httpserver.rb, line 193
def virtual_host(server)
@virtual_hosts << server
@virtual_hosts = @virtual_hosts.sort_by{|s|
num = 0
num -= 4 if s[:BindAddress]
num -= 2 if s[:Port]
num -= 1 if s[:ServerName]
num
}
end
Adds server
as a virtual host.