An HTTP Server
Creates a new HTTP server according to config
An HTTP server uses the following attributes:
An array of access logs.  See WEBrick::AccessLog
Local address for the server to bind to
Root path to serve files from
Options for the default HTTPServlet::FileHandler
The HTTP version of this server
Port to listen on
Called with a request and response before each request is serviced.
Maximum time to wait between requests
Array of alternate names for this server for virtual hosting
Name for this server for virtual hosting
 
               # File 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
             
            Logs req and res in the access logs.  config is used for the server name.
 
               # File 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
             
            The default OPTIONS request handler says GET, HEAD, POST and OPTIONS requests are allowed.
 
               # File webrick/httpserver.rb, line 147
def do_OPTIONS(req, res)
  res["allow"] = "GET,HEAD,POST,OPTIONS"
end
             
            Finds the appropriate virtual host to handle req
 
               # File 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
             
            Mounts servlet on dir passing options to the servlet at creation time
 
               # File 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 proc or block on dir and calls it with a WEBrick::HTTPRequest and WEBrick::HTTPResponse
 
               # File 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
             
            Processes requests on sock
 
               # File webrick/httpserver.rb, line 69
def run(sock)
  while true
    res = HTTPResponse.new(@config)
    req = HTTPRequest.new(@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
             
            Finds a servlet for path
 
               # File 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
             
            Services req and fills in res
 
               # File 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
             
            ServerNameIndication callback
 
               # File 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
             
            Unmounts dir
 
               # File webrick/httpserver.rb, line 173
def unmount(dir)
  @logger.debug(sprintf("unmount %s.", dir))
  @mount_tab.delete(dir)
end
             
            Adds server as a virtual host.
 
               # File 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