WEBrick

Apache 使うほど本格的な開発でなかったり,実運用前の開発用としてサーバが欲しい場合,WEBrick がすごく便利ですね.

Servlet だから取っ付きやすいし.

require 'webrick'
include WEBrick

$DOC_ROOT = Dir.pwd

class WbServlet < HTTPServlet::AbstractServlet
  def do_GET(req, res)
    res.content_type = 'text/plain;charset=UTF-8'
    res.body = "orz... (path=#{req.path})"
  end
end

server = HTTPServer.new(
  :Port => 8001,
  :DocumentRoot => $DOC_ROOT
)
server.mount('/wb', WbServlet)

['INT', 'TERM'].each {|s|
  Signal.trap(s) { server.shutdown }
}

server.start

http://localhost:8001/wb にアクセス.

コード

  • /usr/lib/ruby/1.8/webrick/server.rb
    • GenericServer#start(&block)
      • GenericServer#start_thread(sock, &block)
        • block ? block.call(sock) : GenericServer#run(sock) ← HttpServer#run(sock)
  • /usr/lib/ruby/1.8/webrick/httpserver.rb
  • /usr/lib/ruby/1.8/webrick/httpservlet.rb
    • *.rhtml に対して ERBHandler が割り当てられている
  • /usr/lib/ruby/1.8/webrick/httpservlet/abstract.rb
  • /usr/lib/ruby/1.8/webrick/httpservlet/filehandler.rb

呼び出し階層 (2009/04/16 追記)

GenericServer#start(&block)
    SimpleServer.start {...}      # 内部で yield してるので server_type.start {...} のブロックが実行される
        # ブロックの中で...
        GenericServer#start_thread(sock, &block)
            Thread.start {...}    # sock.close はこのブロック内で呼ばれる
                # ブロックの中で...
                HTTPServer#run(sock)
                    while true
                        ...
                        server = lookup_server(req)
                        server.service(req, res)    # HTTPServer#service → (2) へ
                        # http_version == 1.1 で
                        # req.keep_alive? == true かつ res.keep_alive? == true なら
                        # ループし続ける
                    end

→ (2) 続き
HTTPServer#service(req, res)
    si = servlet.get_instance(server, options)    # AbstractServlet#get_instance
        # 内部では self.new してる
    si.service(req, res)    # AbstractServlet#service(req, res)
        # 内部で do_GET 等を呼び出している