puma 5.5.2 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +336 -3
- data/README.md +61 -16
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +4 -4
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/nginx.md +1 -1
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -2
- 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 +28 -14
- 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 +135 -23
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
- data/ext/puma_http11/puma_http11.c +18 -10
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +62 -51
- data/lib/puma/cli.rb +19 -20
- data/lib/puma/client.rb +108 -26
- data/lib/puma/cluster/worker.rb +23 -16
- data/lib/puma/cluster/worker_handle.rb +8 -1
- data/lib/puma/cluster.rb +62 -41
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +76 -55
- data/lib/puma/const.rb +133 -97
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +12 -2
- data/lib/puma/dsl.rb +270 -55
- 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 +114 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +30 -16
- data/lib/puma/minissl.rb +126 -17
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +1 -1
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -161
- data/lib/puma/runner.rb +55 -22
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +91 -94
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +39 -7
- data/lib/puma/thread_pool.rb +25 -21
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +1 -1
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
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
|