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
119
# 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 = []
  @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

#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


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

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
166
# 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
  setup_shutdown_pipe
end

#run(sock) ⇒ Object

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


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

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

#setup_ssl_context(config) ⇒ Object

Sets up an SSL context for config


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

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.


227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/webrick/server.rb', line 227

def shutdown
  stop

  shutdown_pipe = @shutdown_pipe # another thread may modify @shutdown_pipe.
  if shutdown_pipe
    if !shutdown_pipe[1].closed?
      begin
        shutdown_pipe[1].close
      rescue IOError # closed by another thread.
      end
    end
  end
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:


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
205
206
207
208
209
210
211
212
# File 'lib/webrick/server.rb', line 158

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)

    shutdown_pipe = @shutdown_pipe

    thgroup = ThreadGroup.new
    @status = :Running
    begin
      while @status == :Running
        begin
          if svrs = IO.select([shutdown_pipe[0], *@listeners], nil, nil, 2.0)
            if svrs[0].include? shutdown_pipe[0]
              break
            end
            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, 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

#stopObject

Stops the server from accepting new connections.


217
218
219
220
221
# File 'lib/webrick/server.rb', line 217

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