puma 5.6.8 → 6.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +332 -16
- data/README.md +79 -29
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/restart.md +1 -0
- data/docs/systemd.md +3 -6
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +16 -9
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +127 -19
- data/ext/puma_http11/org/jruby/puma/Http11.java +5 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +50 -53
- data/lib/puma/cli.rb +16 -18
- data/lib/puma/client.rb +59 -19
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +102 -40
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +77 -59
- data/lib/puma/const.rb +137 -92
- data/lib/puma/control_cli.rb +15 -11
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +250 -56
- data/lib/puma/error_logger.rb +18 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +102 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +26 -12
- data/lib/puma/minissl.rb +104 -11
- data/lib/puma/null_io.rb +16 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +380 -172
- data/lib/puma/runner.rb +56 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +137 -89
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +3 -6
- data/lib/puma/thread_pool.rb +57 -19
- data/lib/puma/util.rb +0 -11
- data/lib/puma.rb +9 -10
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +2 -2
- metadata +11 -7
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
- data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/events.rb
CHANGED
@@ -1,52 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "puma/null_io"
|
4
|
-
require 'puma/error_logger'
|
5
|
-
require 'stringio'
|
6
|
-
|
7
3
|
module Puma
|
8
|
-
# The default implement of an event sink object used by Server
|
9
|
-
# for when certain kinds of events occur in the life of the server.
|
10
|
-
#
|
11
|
-
# The methods available are the events that the Server fires.
|
12
|
-
#
|
13
|
-
class Events
|
14
|
-
class DefaultFormatter
|
15
|
-
def call(str)
|
16
|
-
str
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class PidFormatter
|
21
|
-
def call(str)
|
22
|
-
"[#{$$}] #{str}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Create an Events object that prints to +stdout+ and +stderr+.
|
27
|
-
#
|
28
|
-
def initialize(stdout, stderr)
|
29
|
-
@formatter = DefaultFormatter.new
|
30
|
-
@stdout = stdout
|
31
|
-
@stderr = stderr
|
32
4
|
|
33
|
-
|
34
|
-
|
5
|
+
# This is an event sink used by `Puma::Server` to handle
|
6
|
+
# lifecycle events such as :on_booted, :on_restart, and :on_stopped.
|
7
|
+
# Using `Puma::DSL` it is possible to register callback hooks
|
8
|
+
# for each event type.
|
9
|
+
class Events
|
35
10
|
|
11
|
+
def initialize
|
36
12
|
@hooks = Hash.new { |h,k| h[k] = [] }
|
37
13
|
end
|
38
14
|
|
39
|
-
attr_reader :stdout, :stderr
|
40
|
-
attr_accessor :formatter
|
41
|
-
|
42
15
|
# Fire callbacks for the named hook
|
43
|
-
#
|
44
16
|
def fire(hook, *args)
|
45
17
|
@hooks[hook].each { |t| t.call(*args) }
|
46
18
|
end
|
47
19
|
|
48
20
|
# Register a callback for a given hook
|
49
|
-
#
|
50
21
|
def register(hook, obj=nil, &blk)
|
51
22
|
if obj and blk
|
52
23
|
raise "Specify either an object or a block, not both"
|
@@ -59,79 +30,6 @@ module Puma
|
|
59
30
|
h
|
60
31
|
end
|
61
32
|
|
62
|
-
# Write +str+ to +@stdout+
|
63
|
-
#
|
64
|
-
def log(str)
|
65
|
-
@stdout.puts format(str) if @stdout.respond_to? :puts
|
66
|
-
|
67
|
-
@stdout.flush unless @stdout.sync
|
68
|
-
rescue Errno::EPIPE
|
69
|
-
end
|
70
|
-
|
71
|
-
def write(str)
|
72
|
-
@stdout.write format(str)
|
73
|
-
end
|
74
|
-
|
75
|
-
def debug(str)
|
76
|
-
log("% #{str}") if @debug
|
77
|
-
end
|
78
|
-
|
79
|
-
# Write +str+ to +@stderr+
|
80
|
-
#
|
81
|
-
def error(str)
|
82
|
-
@error_logger.info(text: format("ERROR: #{str}"))
|
83
|
-
exit 1
|
84
|
-
end
|
85
|
-
|
86
|
-
def format(str)
|
87
|
-
formatter.call(str)
|
88
|
-
end
|
89
|
-
|
90
|
-
# An HTTP connection error has occurred.
|
91
|
-
# +error+ a connection exception, +req+ the request,
|
92
|
-
# and +text+ additional info
|
93
|
-
# @version 5.0.0
|
94
|
-
#
|
95
|
-
def connection_error(error, req, text="HTTP connection error")
|
96
|
-
@error_logger.info(error: error, req: req, text: text)
|
97
|
-
end
|
98
|
-
|
99
|
-
# An HTTP parse error has occurred.
|
100
|
-
# +error+ a parsing exception,
|
101
|
-
# and +req+ the request.
|
102
|
-
#
|
103
|
-
def parse_error(error, req)
|
104
|
-
@error_logger.info(error: error, req: req, text: 'HTTP parse error, malformed request')
|
105
|
-
end
|
106
|
-
|
107
|
-
# An SSL error has occurred.
|
108
|
-
# @param error <Puma::MiniSSL::SSLError>
|
109
|
-
# @param ssl_socket <Puma::MiniSSL::Socket>
|
110
|
-
#
|
111
|
-
def ssl_error(error, ssl_socket)
|
112
|
-
peeraddr = ssl_socket.peeraddr.last rescue "<unknown>"
|
113
|
-
peercert = ssl_socket.peercert
|
114
|
-
subject = peercert ? peercert.subject : nil
|
115
|
-
@error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}")
|
116
|
-
end
|
117
|
-
|
118
|
-
# An unknown error has occurred.
|
119
|
-
# +error+ an exception object, +req+ the request,
|
120
|
-
# and +text+ additional info
|
121
|
-
#
|
122
|
-
def unknown_error(error, req=nil, text="Unknown error")
|
123
|
-
@error_logger.info(error: error, req: req, text: text)
|
124
|
-
end
|
125
|
-
|
126
|
-
# Log occurred error debug dump.
|
127
|
-
# +error+ an exception object, +req+ the request,
|
128
|
-
# and +text+ additional info
|
129
|
-
# @version 5.0.0
|
130
|
-
#
|
131
|
-
def debug_error(error, req=nil, text="")
|
132
|
-
@error_logger.debug(error: error, req: req, text: text)
|
133
|
-
end
|
134
|
-
|
135
33
|
def on_booted(&block)
|
136
34
|
register(:on_booted, &block)
|
137
35
|
end
|
@@ -155,23 +53,5 @@ module Puma
|
|
155
53
|
def fire_on_stopped!
|
156
54
|
fire(:on_stopped)
|
157
55
|
end
|
158
|
-
|
159
|
-
DEFAULT = new(STDOUT, STDERR)
|
160
|
-
|
161
|
-
# Returns an Events object which writes its status to 2 StringIO
|
162
|
-
# objects.
|
163
|
-
#
|
164
|
-
def self.strings
|
165
|
-
Events.new StringIO.new, StringIO.new
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.stdio
|
169
|
-
Events.new $stdout, $stderr
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.null
|
173
|
-
n = NullIO.new
|
174
|
-
Events.new n, n
|
175
|
-
end
|
176
56
|
end
|
177
57
|
end
|
data/lib/puma/io_buffer.rb
CHANGED
@@ -1,11 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'stringio'
|
4
|
+
|
3
5
|
module Puma
|
4
|
-
class IOBuffer <
|
5
|
-
def
|
6
|
-
|
6
|
+
class IOBuffer < StringIO
|
7
|
+
def initialize
|
8
|
+
super.binmode
|
9
|
+
end
|
10
|
+
|
11
|
+
def empty?
|
12
|
+
length.zero?
|
7
13
|
end
|
8
14
|
|
9
|
-
|
15
|
+
def reset
|
16
|
+
truncate 0
|
17
|
+
rewind
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
rewind
|
22
|
+
read
|
23
|
+
end
|
24
|
+
|
25
|
+
# Read & Reset - returns contents and resets
|
26
|
+
# @return [String] StringIO contents
|
27
|
+
def read_and_reset
|
28
|
+
rewind
|
29
|
+
str = read
|
30
|
+
truncate 0
|
31
|
+
rewind
|
32
|
+
str
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :clear, :reset
|
36
|
+
|
37
|
+
# before Ruby 2.5, `write` would only take one argument
|
38
|
+
if RUBY_VERSION >= '2.5' && RUBY_ENGINE != 'truffleruby'
|
39
|
+
alias_method :append, :write
|
40
|
+
else
|
41
|
+
def append(*strs)
|
42
|
+
strs.each { |str| write str }
|
43
|
+
end
|
44
|
+
end
|
10
45
|
end
|
11
46
|
end
|
data/lib/puma/jruby_restart.rb
CHANGED
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
class Launcher
|
5
|
+
|
6
|
+
# This class is used to pickup Gemfile changes during
|
7
|
+
# application restarts.
|
8
|
+
class BundlePruner
|
9
|
+
|
10
|
+
def initialize(original_argv, extra_runtime_dependencies, log_writer)
|
11
|
+
@original_argv = Array(original_argv)
|
12
|
+
@extra_runtime_dependencies = Array(extra_runtime_dependencies)
|
13
|
+
@log_writer = log_writer
|
14
|
+
end
|
15
|
+
|
16
|
+
def prune
|
17
|
+
return if ENV['PUMA_BUNDLER_PRUNED']
|
18
|
+
return unless defined?(Bundler)
|
19
|
+
|
20
|
+
require_rubygems_min_version!
|
21
|
+
|
22
|
+
unless puma_wild_path
|
23
|
+
log "! Unable to prune Bundler environment, continuing"
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
dirs = paths_to_require_after_prune
|
28
|
+
|
29
|
+
log '* Pruning Bundler environment'
|
30
|
+
home = ENV['GEM_HOME']
|
31
|
+
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
32
|
+
bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
|
33
|
+
|
34
|
+
with_unbundled_env do
|
35
|
+
ENV['GEM_HOME'] = home
|
36
|
+
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
37
|
+
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
38
|
+
ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
|
39
|
+
args = [Gem.ruby, puma_wild_path, '-I', dirs.join(':')] + @original_argv
|
40
|
+
# Ruby 2.0+ defaults to true which breaks socket activation
|
41
|
+
args += [{:close_others => false}]
|
42
|
+
Kernel.exec(*args)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def require_rubygems_min_version!
|
49
|
+
min_version = Gem::Version.new('2.2')
|
50
|
+
|
51
|
+
return if min_version <= Gem::Version.new(Gem::VERSION)
|
52
|
+
|
53
|
+
raise "prune_bundler is not supported on your version of RubyGems. " \
|
54
|
+
"You must have RubyGems #{min_version}+ to use this feature."
|
55
|
+
end
|
56
|
+
|
57
|
+
def puma_wild_path
|
58
|
+
puma_lib_dir = puma_require_paths.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
|
59
|
+
File.expand_path(File.join(puma_lib_dir, '../bin/puma-wild'))
|
60
|
+
end
|
61
|
+
|
62
|
+
def with_unbundled_env
|
63
|
+
bundler_ver = Gem::Version.new(Bundler::VERSION)
|
64
|
+
if bundler_ver < Gem::Version.new('2.1.0')
|
65
|
+
Bundler.with_clean_env { yield }
|
66
|
+
else
|
67
|
+
Bundler.with_unbundled_env { yield }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def paths_to_require_after_prune
|
72
|
+
puma_require_paths + extra_runtime_deps_paths
|
73
|
+
end
|
74
|
+
|
75
|
+
def extra_runtime_deps_paths
|
76
|
+
t = @extra_runtime_dependencies.map do |dep_name|
|
77
|
+
if (spec = spec_for_gem(dep_name))
|
78
|
+
require_paths_for_gem(spec)
|
79
|
+
else
|
80
|
+
log "* Could not load extra dependency: #{dep_name}"
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
end
|
84
|
+
t.flatten!; t.compact!; t
|
85
|
+
end
|
86
|
+
|
87
|
+
def puma_require_paths
|
88
|
+
require_paths_for_gem(spec_for_gem('puma'))
|
89
|
+
end
|
90
|
+
|
91
|
+
def spec_for_gem(gem_name)
|
92
|
+
Bundler.rubygems.loaded_specs(gem_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
def require_paths_for_gem(gem_spec)
|
96
|
+
gem_spec.full_require_paths
|
97
|
+
end
|
98
|
+
|
99
|
+
def log(str)
|
100
|
+
@log_writer.log(str)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|