1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Work around JRuby buffering the request inside #accept

This commit is contained in:
Evan Phoenix 2012-08-09 16:54:55 -07:00
parent 4c2f6b452a
commit 70bbef66cf
4 changed files with 76 additions and 4 deletions

View file

@ -1,3 +1,8 @@
class IO
module WaitReadable
end
end
module Puma module Puma
class Client class Client
include Puma::Const include Puma::Const
@ -17,10 +22,16 @@ module Puma
@buffer = nil @buffer = nil
@timeout_at = nil @timeout_at = nil
@requests_served = 0
end end
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready attr_reader :env, :to_io, :body, :io, :timeout_at, :ready
def inspect
"#<Puma::Client:0x#{object_id.to_s(16)} @ready=#{@ready.inspect}>"
end
def set_timeout(val) def set_timeout(val)
@timeout_at = Time.now + val @timeout_at = Time.now + val
end end
@ -65,6 +76,7 @@ module Puma
unless cl unless cl
@buffer = body.empty? ? nil : body @buffer = body.empty? ? nil : body
@body = EmptyBody @body = EmptyBody
@requests_served += 1
@ready = true @ready = true
return true return true
end end
@ -74,6 +86,7 @@ module Puma
if remain <= 0 if remain <= 0
@body = StringIO.new(body) @body = StringIO.new(body)
@buffer = nil @buffer = nil
@requests_served += 1
@ready = true @ready = true
return true return true
end end
@ -119,8 +132,43 @@ module Puma
false false
end end
def jruby_start_try_to_finish
return read_body unless @read_header
begin
data = @io.sysread_nonblock(CHUNK_SIZE)
rescue OpenSSL::SSL::SSLError => e
return false if e.kind_of? IO::WaitReadable
raise e
end
if @buffer
@buffer << data
else
@buffer = data
end
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
if @parser.finished?
return setup_body
elsif @parsed_bytes >= MAX_HEADER
raise HttpParserError,
"HEADER is longer than allowed, aborting client early."
end
false
end
def eagerly_finish def eagerly_finish
return true if @ready return true if @ready
if defined?(JRUBY_VERSION) and
defined?(OpenSSL::SSL::SSLSocket) and
@io.kind_of? OpenSSL::SSL::SSLSocket
return true if jruby_start_try_to_finish
end
return false unless IO.select([@to_io], nil, nil, 0) return false unless IO.select([@to_io], nil, nil, 0)
try_to_finish try_to_finish
end end
@ -142,6 +190,7 @@ module Puma
unless chunk unless chunk
@body.close @body.close
@buffer = nil @buffer = nil
@requests_served += 1
@ready = true @ready = true
raise EOFError raise EOFError
end end
@ -151,6 +200,7 @@ module Puma
if remain <= 0 if remain <= 0
@body.rewind @body.rewind
@buffer = nil @buffer = nil
@requests_served += 1
@ready = true @ready = true
return true return true
end end

View file

@ -31,6 +31,10 @@ module Puma
# session. # session.
PERSISTENT_TIMEOUT = 20 PERSISTENT_TIMEOUT = 20
# The default number of seconds to wait until we get the first data
# for the request
FIRST_DATA_TIMEOUT = 30
DATE = "Date".freeze DATE = "Date".freeze
SCRIPT_NAME = "SCRIPT_NAME".freeze SCRIPT_NAME = "SCRIPT_NAME".freeze

View file

@ -46,11 +46,19 @@ module Puma
c.close c.close
sockets.delete c sockets.delete c
if c.timeout_at
@timeouts.delete c
end
@events.parse_error @server, c.env, e @events.parse_error @server, c.env, e
rescue EOFError rescue EOFError => e
c.close c.close
sockets.delete c sockets.delete c
if c.timeout_at
@timeouts.delete c
end
end end
end end
end end
@ -73,7 +81,15 @@ module Puma
end end
def run_in_thread def run_in_thread
@thread = Thread.new { run } @thread = Thread.new {
begin
run
rescue Exception => e
puts "MAJOR ERROR DETECTED"
p e
puts e.backtrace
end
}
end end
def calculate_sleep def calculate_sleep

View file

@ -56,6 +56,8 @@ module Puma
@persistent_timeout = PERSISTENT_TIMEOUT @persistent_timeout = PERSISTENT_TIMEOUT
@persistent_check, @persistent_wakeup = IO.pipe @persistent_check, @persistent_wakeup = IO.pipe
@first_data_timeout = FIRST_DATA_TIMEOUT
@unix_paths = [] @unix_paths = []
@proto_env = { @proto_env = {
@ -199,7 +201,6 @@ module Puma
@status = :run @status = :run
@thread_pool = ThreadPool.new(@min_threads, @max_threads) do |client| @thread_pool = ThreadPool.new(@min_threads, @max_threads) do |client|
process_now = false process_now = false
begin begin
@ -213,6 +214,7 @@ module Puma
if process_now if process_now
process_client client process_client client
else else
client.set_timeout @first_data_timeout
@reactor.add client @reactor.add client
end end
end end
@ -315,7 +317,7 @@ module Puma
end end
# The client disconnected while we were reading data # The client disconnected while we were reading data
rescue EOFError, SystemCallError rescue EOFError, SystemCallError => e
# Swallow them. The ensure tries to close +client+ down # Swallow them. The ensure tries to close +client+ down
# The client doesn't know HTTP well # The client doesn't know HTTP well