class Puma::Server

The HTTP Server itself. Serves out a single Rack app.

Attributes

app[RW]
auto_trim_time[RW]
events[R]
max_threads[RW]
min_threads[RW]
persistent_timeout[RW]
thread[R]

Public Class Methods

new(app, events=Events::DEFAULT) click to toggle source

Create a server for the rack app app.

events is an object which will be called when certain error events occur to be handled. See Puma::Events for the list of current methods to implement.

#run returns a thread that you can join on to wait for the server to do it’s work.

# File lib/puma/server.rb, line 40
def initialize(app, events=Events::DEFAULT)
  @app = app
  @events = events

  @check, @notify = IO.pipe
  @ios = [@check]

  @status = :stop

  @min_threads = 0
  @max_threads = 16
  @auto_trim_time = 1

  @thread = nil
  @thread_pool = nil

  @persistent_timeout = PERSISTENT_TIMEOUT
  @persistent_check, @persistent_wakeup = IO.pipe

  @first_data_timeout = FIRST_DATA_TIMEOUT

  @unix_paths = []

  @proto_env = {
    "rack.version".freeze => Rack::VERSION,
    "rack.errors".freeze => events.stderr,
    "rack.multithread".freeze => true,
    "rack.multiprocess".freeze => false,
    "rack.run_once".freeze => false,
    "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",

    # Rack blows up if this is an empty string, and Rack::Lint
    # blows up if it's nil. So 'text/plain' seems like the most
    # sensible default value.
    "CONTENT_TYPE".freeze => "text/plain",

    "QUERY_STRING".freeze => "",
    SERVER_PROTOCOL => HTTP_11,
    SERVER_SOFTWARE => PUMA_VERSION,
    GATEWAY_INTERFACE => CGI_VER
  }

  @envs = {}

  ENV['RACK_ENV'] ||= "development"
end

Public Instance Methods

add_ssl_listener(host, port, ctx, optimize_for_latency=true, backlog=1024) click to toggle source
# File lib/puma/server.rb, line 133
def add_ssl_listener(host, port, ctx, optimize_for_latency=true, backlog=1024)
  s = TCPServer.new(host, port)
  if optimize_for_latency
    s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
  end
  s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
  s.listen backlog

  ssl = OpenSSL::SSL::SSLServer.new(s, ctx)
  env = @proto_env.dup
  env[HTTPS_KEY] = HTTPS
  @envs[ssl] = env

  @ios << ssl
  s
end
add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024) click to toggle source

Tell the server to listen on host host, port port. If optimize_for_latency is true (the default) then clients connecting will be optimized for latency over throughput.

backlog indicates how many unaccepted connections the kernel should allow to accumulate before returning connection refused.

# File lib/puma/server.rb, line 116
def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
  s = TCPServer.new(host, port)
  if optimize_for_latency
    s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
  end
  s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
  s.listen backlog
  @ios << s
  s
end
add_unix_listener(path, umask=nil) click to toggle source

Tell the server to listen on path as a UNIX domain socket.

# File lib/puma/server.rb, line 158
def add_unix_listener(path, umask=nil)
  @unix_paths << path

  # Let anyone connect by default
  umask ||= 0

  begin
    old_mask = File.umask(umask)
    s = UNIXServer.new(path)
    @ios << s
  ensure
    File.umask old_mask
  end

  s
end
backlog() click to toggle source
# File lib/puma/server.rb, line 184
def backlog
  @thread_pool and @thread_pool.backlog
end
cork_socket(socket) click to toggle source

6 == Socket::IPPROTO_TCP 3 == TCP_CORK 1/0 == turn on/off

# File lib/puma/server.rb, line 94
def cork_socket(socket)
  socket.setsockopt(6, 3, 1) if socket.kind_of? TCPSocket
end
handle_servers() click to toggle source
# File lib/puma/server.rb, line 239
def handle_servers
  begin
    check = @check
    sockets = @ios
    pool = @thread_pool

    while @status == :run
      begin
        ios = IO.select sockets
        ios.first.each do |sock|
          if sock == check
            break if handle_check
          else
            c = Client.new sock.accept, @envs.fetch(sock, @proto_env)
            pool << c
          end
        end
      rescue Errno::ECONNABORTED
        # client closed the socket even before accept
        client.close rescue nil
      rescue Object => e
        @events.unknown_error self, e, "Listen loop"
      end
    end

    @reactor.clear! if @status == :restart

    @reactor.shutdown
    graceful_shutdown if @status == :stop
  ensure
    unless @status == :restart
      @ios.each { |i| i.close }
      @unix_paths.each { |i| File.unlink i }
    end
  end
end
inherit_tcp_listener(host, port, fd) click to toggle source
# File lib/puma/server.rb, line 127
def inherit_tcp_listener(host, port, fd)
  s = TCPServer.for_fd(fd)
  @ios << s
  s
end
inherit_unix_listener(path, fd) click to toggle source
# File lib/puma/server.rb, line 175
def inherit_unix_listener(path, fd)
  @unix_paths << path

  s = UNIXServer.for_fd fd
  @ios << s

  s
end
inherited_ssl_listener(fd, ctx) click to toggle source
# File lib/puma/server.rb, line 150
def inherited_ssl_listener(fd, ctx)
  s = TCPServer.for_fd(fd)
  @ios << OpenSSL::SSL::SSLServer.new(s, ctx)
  s
end
run(background=true) click to toggle source

Runs the server.

If background is true (the default) then a thread is spun up in the background to handle requests. Otherwise requests are handled synchronously.

# File lib/puma/server.rb, line 198
def run(background=true)
  BasicSocket.do_not_reverse_lookup = true

  @status = :run

  @thread_pool = ThreadPool.new(@min_threads, @max_threads) do |client|
    process_now = false

    begin
      process_now = client.eagerly_finish
    rescue HttpParserError => e
      client.close
      @events.parse_error self, client.env, e
    rescue IOError
      client.close
    else
      if process_now
        process_client client
      else
        client.set_timeout @first_data_timeout
        @reactor.add client
      end
    end
  end

  @reactor = Reactor.new self, @thread_pool

  @reactor.run_in_thread

  if @auto_trim_time
    @thread_pool.auto_trim!(@auto_trim_time)
  end

  if background
    @thread = Thread.new { handle_servers }
    return @thread
  else
    handle_servers
  end
end
running() click to toggle source
# File lib/puma/server.rb, line 188
def running
  @thread_pool and @thread_pool.spawned
end
uncork_socket(socket) click to toggle source
# File lib/puma/server.rb, line 98
def uncork_socket(socket)
  socket.setsockopt(6, 3, 0) if socket.kind_of? TCPSocket
end