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.



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
120
# 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

#configObject (readonly)

The server configuration



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

def config
  @config
end

#listenersObject (readonly)

Sockets listening for connections.



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

def listeners
  @listeners
end

#loggerObject (readonly)

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



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

def logger
  @logger
end

#statusObject (readonly)

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



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

def status
  @status
end

#tokensObject (readonly)

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



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

def tokens
  @tokens
end

Instance Method Details

#[](key) ⇒ Object

Retrieves key from the configuration



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

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.



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

def listen(address, port) # :nodoc:
  listeners = Utils::create_listeners(address, port)
  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



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

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

#setup_ssl_context(config) ⇒ Object

Sets up an SSL context for config



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

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.



238
239
240
241
242
# File 'lib/webrick/server.rb', line 238

def shutdown
  stop

  alarm_shutdown_pipe {|f| f.close}
end

#ssl_contextObject

SSL context for the server when run in SSL mode



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

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
213
214
215
216
217
218
219
220
221
# 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

#stopObject

Stops the server from accepting new connections.



226
227
228
229
230
231
232
# File 'lib/webrick/server.rb', line 226

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

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