123456789_123456789_123456789_123456789_123456789_

Class: WEBrick::GenericServer

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Inherits: Object
Defined in: lib/webrick/ssl.rb,
lib/webrick/server.rb

Class Method Summary

Instance Attribute Summary

  • #config readonly

    The server configuration.

  • #listeners readonly

    Sockets listening for connections.

  • #logger readonly

    The server logger.

  • #status readonly

    The server status.

  • #tokens readonly

    Tokens control the number of outstanding clients.

Instance Method Summary

  • #[](key)

    Retrieves key from the configuration.

  • #run(sock)

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

  • #shutdown

    Shuts down the server and all listening sockets.

  • #start(&block)

    Starts the server and runs the block for each connection.

  • #stop

    Stops the server from accepting new connections.

Constructor Details

.new(config = {}, default = Config::General) ⇒ GenericServer

Creates a new generic server from #config. The default configuration comes from default.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 95

def initialize(config={}, default=Config::General)
  @config = default.dup.update(config)
  @status = :Stop
  @config[:Logger] ||= Log::new
  @logger = @config[:Logger]

  @tokens = SizedQueue.new(@config[:MaxClients])
  @config[:MaxClients].times{ @tokens.push(nil) }

  webrickv = WEBrick::VERSION
  rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
  @logger.info("WEBrick #{webrickv}")
  @logger.info("ruby #{rubyv}")

  @listeners = []
  @shutdown_pipe = nil
  unless @config[:DoNotListen]
    if @config[:Listen]
      warn(":Listen option is deprecated; use GenericServer#listen")
    end
    listen(@config[:BindAddress], @config[:Port])
    if @config[:Port] == 0
      @config[:Port] = @listeners[0].addr[1]
    end
  end
end

Instance Attribute Details

#config (readonly)

The server configuration

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 73

attr_reader :config

#listeners (readonly)

Sockets listening for connections.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 89

attr_reader :listeners

#logger (readonly)

The server logger. This is independent from the HTTP access log.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 78

attr_reader :logger

#status (readonly)

The server status. One of :Stop, :Running or :Shutdown

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 68

attr_reader :status

#tokens (readonly)

Tokens control the number of outstanding clients. The :MaxClients configuration sets this.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 84

attr_reader :tokens

Instance Method Details

#[](key)

Retrieves key from the configuration

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 125

def [](key)
  @config[key]
end

#run(sock)

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

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 248

def run(sock)
  @logger.fatal "run() must be provided by user."
end

#shutdown

Shuts down the server and all listening sockets. New listeners must be provided to restart the server.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 238

def shutdown
  stop

  alarm_shutdown_pipe {|f| f.close}
end

#start(&block)

Starts the server and runs the block for each connection. This method does not return until the server is stopped from a signal handler or another thread using #stop or #shutdown.

If the block raises a subclass of StandardError the exception is logged and ignored. If an IOError or Errno::EBADF exception is raised the exception is ignored. If an Exception subclass is raised the exception is logged and re-raised which stops the server.

To completely shut down a server call #shutdown from ensure:

server = WEBrick::GenericServer.new
# or WEBrick::HTTPServer.new

begin
  server.start
ensure
  server.shutdown
end

Raises:

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 158

def start(&block)
  raise ServerError, "already started." if @status != :Stop
  server_type = @config[:ServerType] || SimpleServer

  setup_shutdown_pipe

  server_type.start{
    @logger.info \
      "#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
    call_callback(:StartCallback)

    shutdown_pipe = @shutdown_pipe

    thgroup = ThreadGroup.new
    @status = :Running
    begin
      while @status == :Running
        begin
          sp = shutdown_pipe[0]
          if svrs = IO.select([sp, *@listeners], nil, nil, 2.0)
            if svrs[0].include? sp
              # swallow shutdown pipe
              buf = String.new
              nil while String ===
                        sp.read_nonblock([sp.nread, 8].max, buf, exception: false)
              break
            end
            svrs[0].each{|svr|
              @tokens.pop          # blocks while no token is there.
              if sock = accept_client(svr)
                unless config[:DoNotReverseLookup].nil?
                  sock.do_not_reverse_lookup = !!config[:DoNotReverseLookup]
                end
                th = start_thread(sock, &block)
                th[:WEBrickThread] = true
                thgroup.add(th)
              else
                @tokens.push(nil)
              end
            }
          end
        rescue Errno::EBADF, Errno::ENOTSOCK, IOError => ex
          # if the listening socket was closed in GenericServer#shutdown,
          # IO::select raise it.
        rescue StandardError => ex
          msg = "#{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
          @logger.error msg
        rescue Exception => ex
          @logger.fatal ex
          raise
        end
      end
    ensure
      cleanup_shutdown_pipe(shutdown_pipe)
      cleanup_listener
      @status = :Shutdown
      @logger.info "going to shutdown ..."
      thgroup.list.each{|th| th.join if th[:WEBrickThread] }
      call_callback(:StopCallback)
      @logger.info "#{self.class}#start done."
      @status = :Stop
    end
  }
end

#stop

Stops the server from accepting new connections.

[ GitHub ]

  
# File 'lib/webrick/server.rb', line 226

def stop
  if @status == :Running
    @status = :Shutdown
  end

  alarm_shutdown_pipe {|f| f.write_nonblock("\0")}
end