mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Merge branch 'master' into just-dash-w
Conflicts: lib/puma/cli.rb lib/puma/server.rb
This commit is contained in:
commit
e8d7979c36
7 changed files with 117 additions and 21 deletions
|
@ -57,7 +57,7 @@ DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
|
||||||
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
||||||
|
|
||||||
struct common_field {
|
struct common_field {
|
||||||
const signed long len;
|
const size_t len;
|
||||||
const char *name;
|
const char *name;
|
||||||
int raw;
|
int raw;
|
||||||
VALUE value;
|
VALUE value;
|
||||||
|
@ -127,7 +127,7 @@ static int common_field_cmp(const void *a, const void *b)
|
||||||
|
|
||||||
static void init_common_fields(void)
|
static void init_common_fields(void)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned i;
|
||||||
struct common_field *cf = common_http_fields;
|
struct common_field *cf = common_http_fields;
|
||||||
char tmp[256]; /* MAX_FIELD_NAME_LENGTH */
|
char tmp[256]; /* MAX_FIELD_NAME_LENGTH */
|
||||||
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN);
|
||||||
|
@ -163,7 +163,7 @@ static VALUE find_common_field_value(const char *field, size_t flen)
|
||||||
common_field_cmp);
|
common_field_cmp);
|
||||||
return found ? found->value : Qnil;
|
return found ? found->value : Qnil;
|
||||||
#else /* !HAVE_QSORT_BSEARCH */
|
#else /* !HAVE_QSORT_BSEARCH */
|
||||||
int i;
|
unsigned i;
|
||||||
struct common_field *cf = common_http_fields;
|
struct common_field *cf = common_http_fields;
|
||||||
for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
|
for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) {
|
||||||
if (cf->len == flen && !memcmp(cf->name, field, flen))
|
if (cf->len == flen && !memcmp(cf->name, field, flen))
|
||||||
|
@ -460,6 +460,7 @@ void Init_puma_http11()
|
||||||
{
|
{
|
||||||
|
|
||||||
VALUE mPuma = rb_define_module("Puma");
|
VALUE mPuma = rb_define_module("Puma");
|
||||||
|
VALUE cHttpParser = rb_define_class_under(mPuma, "HttpParser", rb_cObject);
|
||||||
|
|
||||||
DEF_GLOBAL(request_method, "REQUEST_METHOD");
|
DEF_GLOBAL(request_method, "REQUEST_METHOD");
|
||||||
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
||||||
|
@ -471,7 +472,6 @@ void Init_puma_http11()
|
||||||
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
|
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
|
||||||
rb_global_variable(&eHttpParserError);
|
rb_global_variable(&eHttpParserError);
|
||||||
|
|
||||||
VALUE cHttpParser = rb_define_class_under(mPuma, "HttpParser", rb_cObject);
|
|
||||||
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
||||||
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
rb_define_method(cHttpParser, "initialize", HttpParser_init, 0);
|
||||||
rb_define_method(cHttpParser, "reset", HttpParser_reset, 0);
|
rb_define_method(cHttpParser, "reset", HttpParser_reset, 0);
|
||||||
|
|
|
@ -5,6 +5,7 @@ require 'puma/server'
|
||||||
require 'puma/const'
|
require 'puma/const'
|
||||||
require 'puma/configuration'
|
require 'puma/configuration'
|
||||||
require 'puma/binder'
|
require 'puma/binder'
|
||||||
|
require 'puma/detect'
|
||||||
|
|
||||||
require 'rack/commonlogger'
|
require 'rack/commonlogger'
|
||||||
require 'rack/utils'
|
require 'rack/utils'
|
||||||
|
@ -13,8 +14,6 @@ module Puma
|
||||||
# Handles invoke a Puma::Server in a command line style.
|
# Handles invoke a Puma::Server in a command line style.
|
||||||
#
|
#
|
||||||
class CLI
|
class CLI
|
||||||
IS_JRUBY = defined?(JRUBY_VERSION)
|
|
||||||
|
|
||||||
# Create a new CLI object using +argv+ as the command line
|
# Create a new CLI object using +argv+ as the command line
|
||||||
# arguments.
|
# arguments.
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
class IO
|
||||||
|
# We need to use this for a jruby work around on both 1.8 and 1.9.
|
||||||
|
# So this either creates the constant (on 1.8), or harmlessly
|
||||||
|
# reopens it (on 1.9).
|
||||||
|
module WaitReadable
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'puma/detect'
|
||||||
|
|
||||||
|
if Puma::IS_JRUBY
|
||||||
|
# We have to work around some OpenSSL buffer/io-readiness bugs
|
||||||
|
# so we pull it in regardless of if the user is binding
|
||||||
|
# to an SSL socket
|
||||||
|
require 'openssl'
|
||||||
|
end
|
||||||
|
|
||||||
module Puma
|
module Puma
|
||||||
class Client
|
class Client
|
||||||
include Puma::Const
|
include Puma::Const
|
||||||
|
@ -17,10 +34,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
|
||||||
|
@ -67,6 +90,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
|
||||||
|
@ -76,6 +100,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
|
||||||
|
@ -121,11 +146,54 @@ module Puma
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def eagerly_finish
|
if IS_JRUBY
|
||||||
return true if @ready
|
def jruby_start_try_to_finish
|
||||||
return false unless IO.select([@to_io], nil, nil, 0)
|
return read_body unless @read_header
|
||||||
try_to_finish
|
|
||||||
end
|
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
|
||||||
|
return true if @ready
|
||||||
|
|
||||||
|
if @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)
|
||||||
|
try_to_finish
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
def eagerly_finish
|
||||||
|
return true if @ready
|
||||||
|
return false unless IO.select([@to_io], nil, nil, 0)
|
||||||
|
try_to_finish
|
||||||
|
end
|
||||||
|
end # IS_JRUBY
|
||||||
|
|
||||||
def read_body
|
def read_body
|
||||||
# Read an odd sized chunk so we can read even sized ones
|
# Read an odd sized chunk so we can read even sized ones
|
||||||
|
@ -144,6 +212,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
|
||||||
|
@ -153,6 +222,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
|
||||||
|
|
|
@ -33,6 +33,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
|
||||||
|
|
4
lib/puma/detect.rb
Normal file
4
lib/puma/detect.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
module Puma
|
||||||
|
IS_JRUBY = defined?(JRUBY_VERSION)
|
||||||
|
end
|
||||||
|
|
|
@ -24,9 +24,13 @@ module Puma
|
||||||
reads.each do |c|
|
reads.each do |c|
|
||||||
if c == @ready
|
if c == @ready
|
||||||
@mutex.synchronize do
|
@mutex.synchronize do
|
||||||
@ready.read(1) # drain
|
case @ready.read(1)
|
||||||
sockets += @input
|
when "*"
|
||||||
@input.clear
|
sockets += @input
|
||||||
|
@input.clear
|
||||||
|
when "!"
|
||||||
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
# We have to be sure to remove it from the timeout
|
# We have to be sure to remove it from the timeout
|
||||||
|
@ -41,6 +45,7 @@ module Puma
|
||||||
@app_pool << c
|
@app_pool << c
|
||||||
sockets.delete c
|
sockets.delete c
|
||||||
end
|
end
|
||||||
|
|
||||||
# The client doesn't know HTTP well
|
# The client doesn't know HTTP well
|
||||||
rescue HttpParserError => e
|
rescue HttpParserError => e
|
||||||
c.close
|
c.close
|
||||||
|
@ -48,7 +53,7 @@ module Puma
|
||||||
|
|
||||||
@events.parse_error @server, c.env, e
|
@events.parse_error @server, c.env, e
|
||||||
|
|
||||||
rescue EOFError
|
rescue IOError => e
|
||||||
c.close
|
c.close
|
||||||
sockets.delete c
|
sockets.delete c
|
||||||
end
|
end
|
||||||
|
@ -73,7 +78,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
|
||||||
|
@ -93,7 +106,7 @@ module Puma
|
||||||
def add(c)
|
def add(c)
|
||||||
@mutex.synchronize do
|
@mutex.synchronize do
|
||||||
@input << c
|
@input << c
|
||||||
@trigger << "!"
|
@trigger << "*"
|
||||||
|
|
||||||
if c.timeout_at
|
if c.timeout_at
|
||||||
@timeouts << c
|
@timeouts << c
|
||||||
|
@ -103,5 +116,9 @@ module Puma
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def shutdown
|
||||||
|
@trigger << "!"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,6 +60,7 @@ module Puma
|
||||||
@persistent_check, @persistent_wakeup = IO.pipe
|
@persistent_check, @persistent_wakeup = IO.pipe
|
||||||
|
|
||||||
@binder = Binder.new(events)
|
@binder = Binder.new(events)
|
||||||
|
@first_data_timeout = FIRST_DATA_TIMEOUT
|
||||||
|
|
||||||
ENV['RACK_ENV'] ||= "development"
|
ENV['RACK_ENV'] ||= "development"
|
||||||
end
|
end
|
||||||
|
@ -112,7 +113,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
|
||||||
|
@ -120,12 +120,13 @@ module Puma
|
||||||
rescue HttpParserError => e
|
rescue HttpParserError => e
|
||||||
client.close
|
client.close
|
||||||
@events.parse_error self, client.env, e
|
@events.parse_error self, client.env, e
|
||||||
rescue EOFError
|
rescue IOError
|
||||||
client.close
|
client.close
|
||||||
else
|
else
|
||||||
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
|
||||||
|
@ -163,7 +164,7 @@ module Puma
|
||||||
begin
|
begin
|
||||||
if io = sock.accept_nonblock
|
if io = sock.accept_nonblock
|
||||||
c = Client.new io, @binder.env(sock)
|
c = Client.new io, @binder.env(sock)
|
||||||
@thread_pool << c
|
pool << c
|
||||||
end
|
end
|
||||||
rescue SystemCallError => e
|
rescue SystemCallError => e
|
||||||
end
|
end
|
||||||
|
@ -177,6 +178,7 @@ module Puma
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@reactor.shutdown
|
||||||
graceful_shutdown if @status == :stop
|
graceful_shutdown if @status == :stop
|
||||||
ensure
|
ensure
|
||||||
unless @status == :restart
|
unless @status == :restart
|
||||||
|
@ -233,7 +235,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 IOError, 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
|
||||||
|
|
Loading…
Add table
Reference in a new issue