123456789_123456789_123456789_123456789_123456789_

Class: WEBrick::HTTPServer

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: WEBrick::GenericServer
Defined in: lib/webrick/httpserver.rb

Overview

An HTTP Server

Class Method Summary

GenericServer - Inherited

.new

Creates a new generic server from config.

Instance Attribute Summary

GenericServer - Inherited

#config

The server configuration.

#listeners

Sockets listening for connections.

#logger

The server logger.

#status

The server status.

#tokens

Tokens control the number of outstanding clients.

Instance Method Summary

GenericServer - Inherited

#[]

Retrieves key from the configuration.

#run

You must subclass GenericServer and implement #run which accepts a TCP client socket.

#shutdown

Shuts down the server and all listening sockets.

#start

Starts the server and runs the block for each connection.

#stop

Stops the server from accepting new connections.

Constructor Details

.new(config = {}, default = Config::HTTP) ⇒ HTTPServer

Creates a new HTTP server according to config

An HTTP server uses the following attributes:

:AccessLog

An array of access logs. See 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

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 44

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

Instance Method Details

#access_log(config, req, res)

Logs req and res in the access logs. config is used for the server name.

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 218

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

#do_OPTIONS(req, res)

The default OPTIONS request handler says GET, HEAD, POST and OPTIONS requests are allowed.

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 145

def do_OPTIONS(req, res)
  res["allow"] = "GET,HEAD,POST,OPTIONS"
end

#lookup_server(req)

Finds the appropriate virtual host to handle req

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 205

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

#mount(dir, servlet, *options)

Mounts servlet on dir passing options to the servlet at creation time

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 153

def mount(dir, servlet, *options)
  @logger.debug(sprintf("%s is mounted on %s.", servlet.inspect, dir))
  @mount_tab[dir] = [ servlet, options ]
end

#mount_proc(dir, proc = nil, &block)

Mounts proc or block on dir and calls it with a HTTPRequest and HTTPResponse

Raises:

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 162

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

#run(sock)

Processes requests on sock

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 67

def run(sock)
  while true
    res = HTTPResponse.new(@config)
    req = HTTPRequest.new(@config)
    server = self
    begin
      timeout = @config[:RequestTimeout]
      while timeout > 0
        break if IO.select([sock], nil, nil, 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

#search_servlet(path)

Finds a servlet for path

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 180

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

#service(req, res)

Services req and fills in res

Raises:

  • (HTTPStatus::NotFound)
[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 123

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

#umount(dir)

Alias for #unmount.

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 175

alias umount unmount

#unmount(dir) Also known as: #umount

Unmounts dir

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 171

def unmount(dir)
  @logger.debug(sprintf("unmount %s.", dir))
  @mount_tab.delete(dir)
end

#virtual_host(server)

Adds server as a virtual host.

[ GitHub ]

  
# File 'lib/webrick/httpserver.rb', line 191

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