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
# 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
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
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
# File lib/puma/server.rb, line 184 def backlog @thread_pool and @thread_pool.backlog end
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
# 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
# File lib/puma/server.rb, line 127 def inherit_tcp_listener(host, port, fd) s = TCPServer.for_fd(fd) @ios << s s end
# 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
# 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
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
# File lib/puma/server.rb, line 188 def running @thread_pool and @thread_pool.spawned end
# File lib/puma/server.rb, line 98 def uncork_socket(socket) socket.setsockopt(6, 3, 0) if socket.kind_of? TCPSocket end