diff options
Diffstat (limited to 'lib/webrick/httpserver.rb')
| -rw-r--r-- | lib/webrick/httpserver.rb | 124 |
1 files changed, 104 insertions, 20 deletions
diff --git a/lib/webrick/httpserver.rb b/lib/webrick/httpserver.rb index 9edb0018f8..e85d059319 100644 --- a/lib/webrick/httpserver.rb +++ b/lib/webrick/httpserver.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: false # # httpserver.rb -- HTTPServer Class # @@ -8,20 +9,42 @@ # # $IPR: httpserver.rb,v 1.63 2002/10/01 17:16:32 gotoyuzo Exp $ -require 'webrick/server' -require 'webrick/httputils' -require 'webrick/httpstatus' -require 'webrick/httprequest' -require 'webrick/httpresponse' -require 'webrick/httpservlet' -require 'webrick/accesslog' +require 'io/wait' +require_relative 'server' +require_relative 'httputils' +require_relative 'httpstatus' +require_relative 'httprequest' +require_relative 'httpresponse' +require_relative 'httpservlet' +require_relative 'accesslog' module WEBrick class HTTPServerError < ServerError; end + ## + # An HTTP Server + class HTTPServer < ::WEBrick::GenericServer + ## + # 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 + def initialize(config={}, default=Config::HTTP) - super + super(config, default) @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @mount_tab = MountTable.new @@ -36,30 +59,38 @@ module WEBrick [ $stderr, AccessLog::REFERER_LOG_FORMAT ] ] end - + @virtual_hosts = Array.new end + ## + # Processes requests on +sock+ + def run(sock) - while true - res = HTTPResponse.new(@config) - req = HTTPRequest.new(@config) + while true + req = create_request(@config) + res = create_response(@config) server = self begin timeout = @config[:RequestTimeout] while timeout > 0 - break if IO.select([sock], nil, nil, 0.5) - timeout = 0 if @status != :Running + break if sock.to_io.wait_readable(0.5) + break if @status != :Running timeout -= 0.5 end - raise HTTPStatus::EOFError if timeout <= 0 || sock.eof? + 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] || server[:RequestHandler] + 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) @@ -75,7 +106,9 @@ module WEBrick res.set_error(ex, true) ensure if req.request_line - req.fixup() + if req.keep_alive? && res.keep_alive? + req.fixup() + end res.send_response(sock) server.access_log(@config, req, res) end @@ -86,6 +119,9 @@ module WEBrick end end + ## + # Services +req+ and fills in +res+ + def service(req, res) if req.unparsed_uri == "*" if req.request_method == "OPTIONS" @@ -104,27 +140,45 @@ module WEBrick si.service(req, res) end + ## + # The default OPTIONS request handler says GET, HEAD, POST and OPTIONS + # requests are allowed. + def do_OPTIONS(req, res) res["allow"] = "GET,HEAD,POST,OPTIONS" end + ## + # Mounts +servlet+ on +dir+ passing +options+ to the servlet at creation + # time + def mount(dir, servlet, *options) @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir)) @mount_tab[dir] = [ servlet, options ] end + ## + # Mounts +proc+ or +block+ on +dir+ and calls it with a + # WEBrick::HTTPRequest and WEBrick::HTTPResponse + 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 + ## + # Unmounts +dir+ + def unmount(dir) @logger.debug(sprintf("unmount %s.", dir)) @mount_tab.delete(dir) end alias umount unmount + ## + # Finds a servlet for +path+ + def search_servlet(path) script_name, path_info = @mount_tab.scan(path) servlet, options = @mount_tab[script_name] @@ -133,6 +187,9 @@ module WEBrick end end + ## + # Adds +server+ as a virtual host. + def virtual_host(server) @virtual_hosts << server @virtual_hosts = @virtual_hosts.sort_by{|s| @@ -144,6 +201,9 @@ module WEBrick } end + ## + # Finds the appropriate virtual host to handle +req+ + def lookup_server(req) @virtual_hosts.find{|s| (s[:BindAddress].nil? || req.addr[3] == s[:BindAddress]) && @@ -153,6 +213,10 @@ module WEBrick } end + ## + # Logs +req+ and +res+ in the access logs. +config+ is used for the + # server name. + def access_log(config, req, res) param = AccessLog::setup_params(config, req, res) @config[:AccessLog].each{|logger, fmt| @@ -160,7 +224,27 @@ module WEBrick } end - class MountTable + ## + # Creates the HTTPRequest used when handling the HTTP + # request. Can be overridden by subclasses. + def create_request(with_webrick_config) + HTTPRequest.new(with_webrick_config) + end + + ## + # Creates the HTTPResponse used when handling the HTTP + # request. Can be overridden by subclasses. + def create_response(with_webrick_config) + HTTPResponse.new(with_webrick_config) + end + + ## + # Mount table for the path a servlet is mounted on in the directory space + # of the server. Users of WEBrick can only access this indirectly via + # WEBrick::HTTPServer#mount, WEBrick::HTTPServer#unmount and + # WEBrick::HTTPServer#search_servlet + + class MountTable # :nodoc: def initialize @tab = Hash.new compile @@ -197,12 +281,12 @@ module WEBrick k.sort! k.reverse! k.collect!{|path| Regexp.escape(path) } - @scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)") + @scanner = Regexp.new("\\A(" + k.join("|") +")(?=/|\\z)") end def normalize(dir) ret = dir ? dir.dup : "" - ret.sub!(%r|/+$|, "") + ret.sub!(%r|/+\z|, "") ret end end |
