Class: WEBrick::GenericServer

Inherits:
Object
  • Object
show all
Defined in:
lib/webrick/ssl.rb,
lib/webrick/server.rb

Overview

Base TCP server class. You must subclass GenericServer and provide a #run method.

Direct Known Subclasses

HTTPServer

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = {}, default = Config::General) ⇒ GenericServer

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


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/webrick/server.rb', line 94

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 = []
  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

#configObject (readonly)

The server configuration


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

def config
  @config
end

#listenersObject (readonly)

Sockets listening for connections.


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

def listeners
  @listeners
end

#loggerObject (readonly)

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


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

def logger
  @logger
end

#statusObject (readonly)

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


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

def status
  @status
end

#tokensObject (readonly)

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


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

def tokens
  @tokens
end

Instance Method Details

#[](key) ⇒ Object

Retrieves key from the configuration


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

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

#listen(address, port) ⇒ Object

Adds listeners from address and port to the server. See WEBrick::Utils::create_listeners for details.


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/webrick/ssl.rb', line 151

def listen(address, port) # :nodoc:
  listeners = Utils::create_listeners(address, port, @logger)
  if @config[:SSLEnable]
    unless ssl_context
      @ssl_context = setup_ssl_context(@config)
      @logger.info("\n" + @config[:SSLCertificate].to_text)
    end
    listeners.collect!{|svr|
      ssvr = ::OpenSSL::SSL::SSLServer.new(svr, ssl_context)
      ssvr.start_immediately = @config[:SSLStartImmediately]
      ssvr
    }
  end
  @listeners += listeners
end

#run(sock) ⇒ Object

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


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

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

#setup_ssl_context(config) ⇒ Object

Sets up an SSL context for config


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/webrick/ssl.rb', line 170

def setup_ssl_context(config) # :nodoc:
  unless config[:SSLCertificate]
    cn = config[:SSLCertName]
    comment = config[:SSLCertComment]
    cert, key = Utils::create_self_signed_cert(1024, cn, comment)
    config[:SSLCertificate] = cert
    config[:SSLPrivateKey] = key
  end
  ctx = OpenSSL::SSL::SSLContext.new
  ctx.key = config[:SSLPrivateKey]
  ctx.cert = config[:SSLCertificate]
  ctx.client_ca = config[:SSLClientCA]
  ctx.extra_chain_cert = config[:SSLExtraChainCert]
  ctx.ca_file = config[:SSLCACertificateFile]
  ctx.ca_path = config[:SSLCACertificatePath]
  ctx.cert_store = config[:SSLCertificateStore]
  ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
  ctx.verify_mode = config[:SSLVerifyClient]
  ctx.verify_depth = config[:SSLVerifyDepth]
  ctx.verify_callback = config[:SSLVerifyCallback]
  ctx.timeout = config[:SSLTimeout]
  ctx.options = config[:SSLOptions]
  ctx
end

#shutdownObject

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


219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/webrick/server.rb', line 219

def shutdown
  stop
  @listeners.each{|s|
    if @logger.debug?
      addr = s.addr
      @logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
    end
    begin
      s.shutdown
    rescue Errno::ENOTCONN
      # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
      # call #close instead of #shutdown.
      # (ignore @config[:ShutdownSocketWithoutClose])
      s.close
    else
      unless @config[:ShutdownSocketWithoutClose]
        s.close
      end
    end
  }
  @listeners.clear
end

#ssl_contextObject

SSL context for the server when run in SSL mode


142
143
144
# File 'lib/webrick/ssl.rb', line 142

def ssl_context # :nodoc:
  @ssl_context ||= nil
end

#start(&block) ⇒ Object

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:


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/webrick/server.rb', line 156

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

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

    thgroup = ThreadGroup.new
    @status = :Running
    begin
      while @status == :Running
        begin
          if svrs = IO.select(@listeners, nil, nil, 2.0)
            svrs[0].each{|svr|
              @tokens.pop          # blocks while no token is there.
              if sock = accept_client(svr)
                sock.do_not_reverse_lookup = config[:DoNotReverseLookup]
                th = start_thread(sock, &block)
                th[:WEBrickThread] = true
                thgroup.add(th)
              else
                @tokens.push(nil)
              end
            }
          end
        rescue Errno::EBADF, 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
      @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

#stopObject

Stops the server from accepting new connections.


209
210
211
212
213
# File 'lib/webrick/server.rb', line 209

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