2013-02-05 01:31:40 -05:00
|
|
|
require 'puma/util'
|
2015-07-17 16:00:55 -04:00
|
|
|
require 'puma/minissl'
|
2013-02-05 01:31:40 -05:00
|
|
|
|
2012-07-23 13:26:52 -04:00
|
|
|
module Puma
|
|
|
|
class Reactor
|
|
|
|
DefaultSleepFor = 5
|
|
|
|
|
2012-07-23 20:00:53 -04:00
|
|
|
def initialize(server, app_pool)
|
|
|
|
@server = server
|
|
|
|
@events = server.events
|
2012-07-23 13:26:52 -04:00
|
|
|
@app_pool = app_pool
|
|
|
|
|
|
|
|
@mutex = Mutex.new
|
2013-02-05 01:31:40 -05:00
|
|
|
@ready, @trigger = Puma::Util.pipe
|
2012-07-23 13:26:52 -04:00
|
|
|
@input = []
|
|
|
|
@sleep_for = DefaultSleepFor
|
|
|
|
@timeouts = []
|
2012-08-27 13:56:43 -04:00
|
|
|
|
|
|
|
@sockets = [@ready]
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
|
2013-10-28 08:56:45 -04:00
|
|
|
private
|
|
|
|
|
|
|
|
def run_internal
|
2012-08-27 13:56:43 -04:00
|
|
|
sockets = @sockets
|
2012-07-23 13:26:52 -04:00
|
|
|
|
|
|
|
while true
|
2013-10-28 09:36:54 -04:00
|
|
|
begin
|
|
|
|
ready = IO.select sockets, nil, nil, @sleep_for
|
|
|
|
rescue IOError => e
|
2013-10-31 12:33:44 -04:00
|
|
|
if sockets.any? { |socket| socket.closed? }
|
2013-10-28 09:36:54 -04:00
|
|
|
STDERR.puts "Error in select: #{e.message} (#{e.class})"
|
|
|
|
STDERR.puts e.backtrace
|
2013-10-31 12:33:44 -04:00
|
|
|
sockets = sockets.reject { |socket| socket.closed? }
|
2013-10-28 09:36:54 -04:00
|
|
|
retry
|
|
|
|
else
|
|
|
|
raise
|
|
|
|
end
|
|
|
|
end
|
2012-07-23 13:26:52 -04:00
|
|
|
|
|
|
|
if ready and reads = ready[0]
|
|
|
|
reads.each do |c|
|
|
|
|
if c == @ready
|
|
|
|
@mutex.synchronize do
|
2012-08-10 13:10:30 -04:00
|
|
|
case @ready.read(1)
|
|
|
|
when "*"
|
|
|
|
sockets += @input
|
|
|
|
@input.clear
|
2012-09-02 23:33:09 -04:00
|
|
|
when "c"
|
|
|
|
sockets.delete_if do |s|
|
|
|
|
if s == @ready
|
|
|
|
false
|
|
|
|
else
|
|
|
|
s.close
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|
2012-08-10 13:10:30 -04:00
|
|
|
when "!"
|
|
|
|
return
|
|
|
|
end
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
else
|
2012-07-30 19:12:23 -04:00
|
|
|
# We have to be sure to remove it from the timeout
|
|
|
|
# list or we'll accidentally close the socket when
|
|
|
|
# it's in use!
|
|
|
|
if c.timeout_at
|
2013-03-18 19:41:59 -04:00
|
|
|
@mutex.synchronize do
|
|
|
|
@timeouts.delete c
|
|
|
|
end
|
2012-07-30 19:12:23 -04:00
|
|
|
end
|
|
|
|
|
2012-07-23 13:26:52 -04:00
|
|
|
begin
|
|
|
|
if c.try_to_finish
|
|
|
|
@app_pool << c
|
|
|
|
sockets.delete c
|
|
|
|
end
|
2012-08-11 01:41:35 -04:00
|
|
|
|
2015-01-13 23:11:26 -05:00
|
|
|
# SSL handshake failure
|
|
|
|
rescue MiniSSL::SSLError => e
|
|
|
|
ssl_socket = c.io
|
|
|
|
addr = ssl_socket.peeraddr.last
|
|
|
|
cert = ssl_socket.peercert
|
|
|
|
|
|
|
|
c.close
|
|
|
|
sockets.delete c
|
|
|
|
|
|
|
|
@events.ssl_error @server, addr, cert, e
|
|
|
|
|
2012-07-23 13:26:52 -04:00
|
|
|
# The client doesn't know HTTP well
|
|
|
|
rescue HttpParserError => e
|
2012-09-06 01:09:42 -04:00
|
|
|
c.write_400
|
2012-07-23 20:08:11 -04:00
|
|
|
c.close
|
2012-09-06 01:09:42 -04:00
|
|
|
|
2012-07-23 20:08:11 -04:00
|
|
|
sockets.delete c
|
|
|
|
|
2012-07-23 20:00:53 -04:00
|
|
|
@events.parse_error @server, c.env, e
|
2012-08-27 13:56:43 -04:00
|
|
|
rescue StandardError => e
|
2012-09-06 01:09:42 -04:00
|
|
|
c.write_500
|
2012-07-23 13:26:52 -04:00
|
|
|
c.close
|
2012-09-06 01:09:42 -04:00
|
|
|
|
2012-07-23 13:26:52 -04:00
|
|
|
sockets.delete c
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
unless @timeouts.empty?
|
2013-03-18 19:41:59 -04:00
|
|
|
@mutex.synchronize do
|
|
|
|
now = Time.now
|
2012-07-23 13:26:52 -04:00
|
|
|
|
2013-03-18 19:41:59 -04:00
|
|
|
while @timeouts.first.timeout_at < now
|
|
|
|
c = @timeouts.shift
|
2014-01-30 17:37:38 -05:00
|
|
|
c.write_408 if c.in_data_phase
|
2013-03-18 19:41:59 -04:00
|
|
|
c.close
|
2014-01-30 13:23:01 -05:00
|
|
|
sockets.delete c
|
2012-07-23 13:26:52 -04:00
|
|
|
|
2013-03-18 19:41:59 -04:00
|
|
|
break if @timeouts.empty?
|
|
|
|
end
|
2012-07-30 19:12:23 -04:00
|
|
|
|
2013-03-18 19:41:59 -04:00
|
|
|
calculate_sleep
|
|
|
|
end
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
end
|
2013-10-28 08:56:45 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
public
|
|
|
|
|
|
|
|
def run
|
|
|
|
run_internal
|
2013-02-05 01:31:40 -05:00
|
|
|
ensure
|
|
|
|
@trigger.close
|
|
|
|
@ready.close
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def run_in_thread
|
2013-10-28 09:27:30 -04:00
|
|
|
@thread = Thread.new do
|
|
|
|
begin
|
|
|
|
run_internal
|
|
|
|
rescue StandardError => e
|
|
|
|
STDERR.puts "Error in reactor loop escaped: #{e.message} (#{e.class})"
|
|
|
|
STDERR.puts e.backtrace
|
|
|
|
retry
|
|
|
|
ensure
|
|
|
|
@trigger.close
|
|
|
|
@ready.close
|
2012-08-09 19:54:55 -04:00
|
|
|
end
|
2013-10-28 09:27:30 -04:00
|
|
|
end
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
|
2012-07-30 19:12:23 -04:00
|
|
|
def calculate_sleep
|
|
|
|
if @timeouts.empty?
|
|
|
|
@sleep_for = DefaultSleepFor
|
|
|
|
else
|
|
|
|
diff = @timeouts.first.timeout_at.to_f - Time.now.to_f
|
|
|
|
|
|
|
|
if diff < 0.0
|
|
|
|
@sleep_for = 0
|
|
|
|
else
|
|
|
|
@sleep_for = diff
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-07-23 13:26:52 -04:00
|
|
|
def add(c)
|
|
|
|
@mutex.synchronize do
|
|
|
|
@input << c
|
2012-08-10 13:10:30 -04:00
|
|
|
@trigger << "*"
|
2012-07-23 13:26:52 -04:00
|
|
|
|
|
|
|
if c.timeout_at
|
|
|
|
@timeouts << c
|
|
|
|
@timeouts.sort! { |a,b| a.timeout_at <=> b.timeout_at }
|
2012-07-24 20:25:03 -04:00
|
|
|
|
2012-07-30 19:12:23 -04:00
|
|
|
calculate_sleep
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-08-10 13:10:30 -04:00
|
|
|
|
2012-09-02 23:33:09 -04:00
|
|
|
# Close all watched sockets and clear them from being watched
|
|
|
|
def clear!
|
2013-02-05 01:31:40 -05:00
|
|
|
begin
|
|
|
|
@trigger << "c"
|
|
|
|
rescue IOError
|
|
|
|
end
|
2012-09-02 23:33:09 -04:00
|
|
|
end
|
|
|
|
|
2012-08-10 13:10:30 -04:00
|
|
|
def shutdown
|
2013-02-05 01:31:40 -05:00
|
|
|
begin
|
|
|
|
@trigger << "!"
|
|
|
|
rescue IOError
|
|
|
|
end
|
|
|
|
|
2012-09-02 23:33:09 -04:00
|
|
|
@thread.join
|
2012-08-10 13:10:30 -04:00
|
|
|
end
|
2012-07-23 13:26:52 -04:00
|
|
|
end
|
|
|
|
end
|