class Thin::Server

The uterly famous Thin HTTP server. It listen for incoming request through a given backend and forward all request to app.

TCP server

Create a new TCP server on bound to host:port by specifiying host and port as the first 2 arguments.

Thin::Server.start('0.0.0.0', 3000, app)

UNIX domain server

Create a new UNIX domain socket bound to socket file by specifiying a filename as the first argument. Eg.: /tmp/thin.sock. If the first argument contains a / it will be assumed to be a UNIX socket.

Thin::Server.start('/tmp/thin.sock', app)

Using a custom backend

You can implement your own way to connect the server to its client by creating your own Backend class and pass it as the :backend option.

Thin::Server.start('galaxy://faraway', 1345, app, :backend => Thin::Backends::MyFancyBackend)

Rack application (app)

All requests will be processed through app that must be a valid Rack adapter. A valid Rack adapter (application) must respond to call(env#Hash) and return an array of [status, headers, body].

Building an app in place

If a block is passed, a Rack::Builder instance will be passed to build the app. So you can do cool stuff like this:

Thin::Server.start('0.0.0.0', 3000) do
  use Rack::CommonLogger
  use Rack::ShowExceptions
  map "/lobster" do
    use Rack::Lint
    run Rack::Lobster.new
  end
end

Controlling with signals

Signals are processed at one second intervals. Disable signals by passing :signals => false.

Constants

DEFAULT_HOST
DEFAULT_MAXIMUM_CONNECTIONS
DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
DEFAULT_PORT
DEFAULT_TIMEOUT

Default values

Attributes

app[RW]

Application (Rack adapter) called with the request that produces the response.

backend[RW]

Backend handling the connections to the clients.

tag[RW]

A tag that will show in the process listing

Public Class Methods

new(*args, &block) click to toggle source
# File lib/thin/server.rb, line 100
def initialize(*args, &block)
  host, port, options = DEFAULT_HOST, DEFAULT_PORT, {}
  
  # Guess each parameter by its type so they can be
  # received in any order.
  args.each do |arg|
    case arg
    when Fixnum, /^\d+$/ then port    = arg.to_i
    when String          then host    = arg
    when Hash            then options = arg
    else
      @app = arg if arg.respond_to?(:call)
    end
  end
  
  # Set tag if needed
  self.tag = options[:tag]

  # Try to intelligently select which backend to use.
  @backend = select_backend(host, port, options)
  
  load_cgi_multipart_eof_fix
  
  @backend.server = self
  
  # Set defaults
  @backend.maximum_connections            = DEFAULT_MAXIMUM_CONNECTIONS
  @backend.maximum_persistent_connections = DEFAULT_MAXIMUM_PERSISTENT_CONNECTIONS
  @backend.timeout                        = DEFAULT_TIMEOUT
  
  # Allow using Rack builder as a block
  @app = Rack::Builder.new(&block).to_app if block
  
  # If in debug mode, wrap in logger adapter
  @app = Rack::CommonLogger.new(@app) if Logging.debug?
  
  @setup_signals = options[:signals] != false
end
start(*args, &block) click to toggle source

Lil' shortcut to turn this:

Server.new(...).start

into this:

Server.start(...)
# File lib/thin/server.rb, line 147
def self.start(*args, &block)
  new(*args, &block).start!
end

Public Instance Methods

config() click to toggle source

Configure the server

The process might need to have superuser privilege to configure server with optimal options.

# File lib/thin/server.rb, line 211
def config
  @backend.config
end
name() click to toggle source

Name of the server and type of backend used. This is also the name of the process in which Thin is running as a daemon.

# File lib/thin/server.rb, line 217
def name
  "thin server (#{@backend})" + (tag ? " [#{tag}]" : "")
end
Also aliased as: to_s
reopen_log() click to toggle source

Reopen log file.

Reopen the log file and redirect STDOUT and STDERR to it.

# File lib/thin/server.rb, line 201
def reopen_log
  return unless log_file
  file = File.expand_path(log_file)
  log_info "Reopening log file: #{file}"
  Daemonize.redirect_io(file)
end
running?() click to toggle source

Return true if the server is running and ready to receive requests. Note that the server might still be running and return false when shuting down and waiting for active connections to complete.

# File lib/thin/server.rb, line 225
def running?
  @backend.running?
end
start() click to toggle source

Start the server and listen for connections.

# File lib/thin/server.rb, line 152
def start
  raise ArgumentError, 'app required' unless @app
  
  log_info  "Thin web server (v#{VERSION::STRING} codename #{VERSION::CODENAME})"
  log_debug "Debugging ON"
  trace     "Tracing ON"
  
  log_info "Maximum connections set to #{@backend.maximum_connections}"
  log_info "Listening on #{@backend}, CTRL+C to stop"

  @backend.start { setup_signals if @setup_signals }
end
Also aliased as: start!
start!()
Alias for: start
stop() click to toggle source

Gracefull shutdown

Stops the server after processing all current connections. As soon as this method is called, the server stops accepting new requests and wait for all current connections to finish. Calling twice is the equivalent of calling stop!.

# File lib/thin/server.rb, line 171
def stop
  if running?
    @backend.stop
    unless @backend.empty?
      log_info "Waiting for #{@backend.size} connection(s) to finish, "                    "can take up to #{timeout} sec, CTRL+C to stop now"
    end
  else
    stop!
  end
end
stop!() click to toggle source

Force shutdown

Stops the server closing all current connections right away. This doesn't wait for connection to finish their work and send data. All current requests will be dropped.

# File lib/thin/server.rb, line 187
def stop!
  if @backend.started_reactor?
    log_info "Stopping ..."
  else
    log_info "Stopping Thin ..."
    log_info "Thin was started inside an existing EventMachine.run block."
    log_info "Call `EventMachine.stop` to stop the reactor and quit the process."
  end

  @backend.stop!
end
to_s()
Alias for: name

Protected Instance Methods

handle_signals() click to toggle source
# File lib/thin/server.rb, line 247
def handle_signals
  case @signal_queue.shift
  when 'INT'
    stop!
  when 'TERM', 'QUIT'
    stop
  when 'HUP'
    restart
  when 'USR1'
    reopen_log
  end
  EM.next_tick { handle_signals } unless @signal_queue.empty?
end
load_cgi_multipart_eof_fix() click to toggle source

Taken from Mongrel cgi_multipart_eof_fix Ruby 1.8.5 has a security bug in cgi.rb, we need to patch it.

# File lib/thin/server.rb, line 277
def load_cgi_multipart_eof_fix
  version = RUBY_VERSION.split('.').map { |i| i.to_i }
  
  if version[0] <= 1 && version[1] <= 8 && version[2] <= 5 && RUBY_PLATFORM !~ /java/
    begin
      require 'cgi_multipart_eof_fix'
    rescue LoadError
      log_error "Ruby 1.8.5 is not secure please install cgi_multipart_eof_fix:"
      log_error "gem install cgi_multipart_eof_fix"
    end
  end
end
select_backend(host, port, options) click to toggle source
# File lib/thin/server.rb, line 261
def select_backend(host, port, options)
  case
  when options.has_key?(:backend)
    raise ArgumentError, ":backend must be a class" unless options[:backend].is_a?(Class)
    options[:backend].new(host, port, options)
  when options.has_key?(:swiftiply)
    Backends::SwiftiplyClient.new(host, port, options)
  when host.include?('/')
    Backends::UnixServer.new(host)
  else
    Backends::TcpServer.new(host, port)
  end
end
setup_signals() click to toggle source
# File lib/thin/server.rb, line 230
def setup_signals
  # Queue up signals so they are processed in non-trap context
  # using a EM timer.
  @signal_queue ||= []

  %w( INT TERM ).each do |signal|
    trap(signal) { @signal_queue.push signal }
  end
  # *nix only signals
  %w( QUIT HUP USR1 ).each do |signal|
    trap(signal) { @signal_queue.push signal }
  end unless Thin.win?

  # Signals are processed at one second intervals.
  @signal_timer ||= EM.add_periodic_timer(1) { handle_signals }
end