puma 5.6.9-java → 6.6.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +465 -18
- data/README.md +152 -42
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +12 -4
- data/docs/java_options.md +54 -0
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +4 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +2 -2
- data/docs/stats.md +8 -3
- data/docs/systemd.md +13 -7
- 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 +27 -17
- 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 +137 -19
- data/ext/puma_http11/org/jruby/puma/Http11.java +31 -10
- 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 +21 -10
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +60 -55
- data/lib/puma/cli.rb +22 -20
- data/lib/puma/client.rb +93 -30
- data/lib/puma/cluster/worker.rb +27 -17
- data/lib/puma/cluster/worker_handle.rb +8 -6
- data/lib/puma/cluster.rb +121 -47
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +101 -65
- data/lib/puma/const.rb +141 -93
- data/lib/puma/control_cli.rb +19 -15
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +521 -88
- data/lib/puma/error_logger.rb +22 -13
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +0 -15
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +121 -181
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +27 -12
- data/lib/puma/minissl.rb +105 -11
- data/lib/puma/null_io.rb +42 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- 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 +368 -169
- data/lib/puma/runner.rb +65 -22
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +161 -102
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +3 -6
- data/lib/puma/thread_pool.rb +71 -21
- data/lib/puma/util.rb +1 -12
- data/lib/puma.rb +9 -10
- data/lib/rack/handler/puma.rb +116 -86
- data/tools/Dockerfile +2 -2
- metadata +17 -12
- 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/binder.rb
CHANGED
@@ -3,24 +3,15 @@
|
|
3
3
|
require 'uri'
|
4
4
|
require 'socket'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require_relative 'const'
|
7
|
+
require_relative 'util'
|
8
|
+
require_relative 'configuration'
|
9
9
|
|
10
10
|
module Puma
|
11
11
|
|
12
12
|
if HAS_SSL
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Odd bug in 'pure Ruby' nio4r version 2.5.2, which installs with Ruby 2.3.
|
17
|
-
# NIO doesn't create any OpenSSL objects, but it rescues an OpenSSL error.
|
18
|
-
# The bug was that it did not require openssl.
|
19
|
-
# @todo remove when Ruby 2.3 support is dropped
|
20
|
-
#
|
21
|
-
if windows? && RbConfig::CONFIG['ruby_version'] == '2.3.0'
|
22
|
-
require 'openssl'
|
23
|
-
end
|
13
|
+
require_relative 'minissl'
|
14
|
+
require_relative 'minissl/context_builder'
|
24
15
|
end
|
25
16
|
|
26
17
|
class Binder
|
@@ -28,22 +19,23 @@ module Puma
|
|
28
19
|
|
29
20
|
RACK_VERSION = [1,6].freeze
|
30
21
|
|
31
|
-
def initialize(
|
32
|
-
@
|
22
|
+
def initialize(log_writer, conf = Configuration.new, env: ENV)
|
23
|
+
@log_writer = log_writer
|
33
24
|
@conf = conf
|
34
25
|
@listeners = []
|
35
26
|
@inherited_fds = {}
|
36
27
|
@activated_sockets = {}
|
37
28
|
@unix_paths = []
|
29
|
+
@env = env
|
38
30
|
|
39
31
|
@proto_env = {
|
40
32
|
"rack.version".freeze => RACK_VERSION,
|
41
|
-
"rack.errors".freeze =>
|
33
|
+
"rack.errors".freeze => log_writer.stderr,
|
42
34
|
"rack.multithread".freeze => conf.options[:max_threads] > 1,
|
43
35
|
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
44
36
|
"rack.run_once".freeze => false,
|
45
37
|
RACK_URL_SCHEME => conf.options[:rack_url_scheme],
|
46
|
-
"SCRIPT_NAME".freeze =>
|
38
|
+
"SCRIPT_NAME".freeze => env['SCRIPT_NAME'] || "",
|
47
39
|
|
48
40
|
# I'd like to set a default CONTENT_TYPE here but some things
|
49
41
|
# depend on their not being a default set and inferring
|
@@ -51,14 +43,12 @@ module Puma
|
|
51
43
|
# infer properly.
|
52
44
|
|
53
45
|
"QUERY_STRING".freeze => "",
|
54
|
-
SERVER_PROTOCOL => HTTP_11,
|
55
46
|
SERVER_SOFTWARE => PUMA_SERVER_STRING,
|
56
47
|
GATEWAY_INTERFACE => CGI_VER
|
57
48
|
}
|
58
49
|
|
59
50
|
@envs = {}
|
60
51
|
@ios = []
|
61
|
-
localhost_authority
|
62
52
|
end
|
63
53
|
|
64
54
|
attr_reader :ios
|
@@ -80,7 +70,7 @@ module Puma
|
|
80
70
|
# @!attribute [r] connected_ports
|
81
71
|
# @version 5.0.0
|
82
72
|
def connected_ports
|
83
|
-
ios.map { |io| io.addr[1] }.uniq
|
73
|
+
t = ios.map { |io| io.addr[1] }; t.uniq!; t
|
84
74
|
end
|
85
75
|
|
86
76
|
# @version 5.0.0
|
@@ -98,7 +88,7 @@ module Puma
|
|
98
88
|
# @version 5.0.0
|
99
89
|
#
|
100
90
|
def create_activated_fds(env_hash)
|
101
|
-
@
|
91
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{@env['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
102
92
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
103
93
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
104
94
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
@@ -106,11 +96,11 @@ module Puma
|
|
106
96
|
[:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
|
107
97
|
rescue ArgumentError # Try to parse as a port/ip
|
108
98
|
port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
|
109
|
-
addr = "[#{addr}]" if addr
|
99
|
+
addr = "[#{addr}]" if addr&.include? ':'
|
110
100
|
[:tcp, addr, port]
|
111
101
|
end
|
112
102
|
@activated_sockets[key] = sock
|
113
|
-
@
|
103
|
+
@log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
|
114
104
|
end
|
115
105
|
["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
|
116
106
|
end
|
@@ -152,29 +142,37 @@ module Puma
|
|
152
142
|
end
|
153
143
|
end
|
154
144
|
|
155
|
-
def
|
145
|
+
def before_parse(&block)
|
146
|
+
@before_parse ||= []
|
147
|
+
@before_parse << block if block
|
148
|
+
@before_parse
|
149
|
+
end
|
150
|
+
|
151
|
+
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
152
|
+
before_parse.each(&:call)
|
153
|
+
log_writer ||= @log_writer
|
156
154
|
binds.each do |str|
|
157
155
|
uri = URI.parse str
|
158
156
|
case uri.scheme
|
159
157
|
when "tcp"
|
160
158
|
if fd = @inherited_fds.delete(str)
|
161
159
|
io = inherit_tcp_listener uri.host, uri.port, fd
|
162
|
-
|
160
|
+
log_writer.log "* Inherited #{str}"
|
163
161
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
164
162
|
io = inherit_tcp_listener uri.host, uri.port, sock
|
165
|
-
|
163
|
+
log_writer.log "* Activated #{str}"
|
166
164
|
else
|
167
165
|
ios_len = @ios.length
|
168
166
|
params = Util.parse_query uri.query
|
169
167
|
|
170
|
-
|
168
|
+
low_latency = params.key?('low_latency') && params['low_latency'] != 'false'
|
171
169
|
backlog = params.fetch('backlog', 1024).to_i
|
172
170
|
|
173
|
-
io = add_tcp_listener uri.host, uri.port,
|
171
|
+
io = add_tcp_listener uri.host, uri.port, low_latency, backlog
|
174
172
|
|
175
173
|
@ios[ios_len..-1].each do |i|
|
176
174
|
addr = loc_addr_str i
|
177
|
-
|
175
|
+
log_writer.log "* #{log_msg} on http://#{addr}"
|
178
176
|
end
|
179
177
|
end
|
180
178
|
|
@@ -191,12 +189,12 @@ module Puma
|
|
191
189
|
if fd = @inherited_fds.delete(str)
|
192
190
|
@unix_paths << path unless abstract || File.exist?(path)
|
193
191
|
io = inherit_unix_listener path, fd
|
194
|
-
|
192
|
+
log_writer.log "* Inherited #{str}"
|
195
193
|
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
196
|
-
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
194
|
+
!abstract && @activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
197
195
|
@unix_paths << path unless abstract || File.exist?(path)
|
198
196
|
io = inherit_unix_listener path, sock
|
199
|
-
|
197
|
+
log_writer.log "* Activated #{str}"
|
200
198
|
else
|
201
199
|
umask = nil
|
202
200
|
mode = nil
|
@@ -220,11 +218,12 @@ module Puma
|
|
220
218
|
|
221
219
|
@unix_paths << path unless abstract || File.exist?(path)
|
222
220
|
io = add_unix_listener path, umask, mode, backlog
|
223
|
-
|
221
|
+
log_writer.log "* #{log_msg} on #{str}"
|
224
222
|
end
|
225
223
|
|
226
224
|
@listeners << [str, io]
|
227
225
|
when "ssl"
|
226
|
+
cert_key = %w[cert key]
|
228
227
|
|
229
228
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
230
229
|
|
@@ -233,49 +232,51 @@ module Puma
|
|
233
232
|
# If key and certs are not defined and localhost gem is required.
|
234
233
|
# localhost gem will be used for self signed
|
235
234
|
# Load localhost authority if not loaded.
|
236
|
-
|
235
|
+
# Ruby 3 `values_at` accepts an array, earlier do not
|
236
|
+
if params.values_at(*cert_key).all? { |v| v.to_s.empty? }
|
237
237
|
ctx = localhost_authority && localhost_authority_context
|
238
238
|
end
|
239
239
|
|
240
240
|
ctx ||=
|
241
241
|
begin
|
242
242
|
# Extract cert_pem and key_pem from options[:store] if present
|
243
|
-
|
244
|
-
if params[v]
|
243
|
+
cert_key.each do |v|
|
244
|
+
if params[v]&.start_with?('store:')
|
245
245
|
index = Integer(params.delete(v).split('store:').last)
|
246
246
|
params["#{v}_pem"] = @conf.options[:store][index]
|
247
247
|
end
|
248
248
|
end
|
249
|
-
MiniSSL::ContextBuilder.new(params, @
|
249
|
+
MiniSSL::ContextBuilder.new(params, @log_writer).context
|
250
250
|
end
|
251
251
|
|
252
252
|
if fd = @inherited_fds.delete(str)
|
253
|
-
|
253
|
+
log_writer.log "* Inherited #{str}"
|
254
254
|
io = inherit_ssl_listener fd, ctx
|
255
255
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
256
256
|
io = inherit_ssl_listener sock, ctx
|
257
|
-
|
257
|
+
log_writer.log "* Activated #{str}"
|
258
258
|
else
|
259
259
|
ios_len = @ios.length
|
260
260
|
backlog = params.fetch('backlog', 1024).to_i
|
261
|
-
|
261
|
+
low_latency = params['low_latency'] != 'false'
|
262
|
+
io = add_ssl_listener uri.host, uri.port, ctx, low_latency, backlog
|
262
263
|
|
263
264
|
@ios[ios_len..-1].each do |i|
|
264
265
|
addr = loc_addr_str i
|
265
|
-
|
266
|
+
log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
|
266
267
|
end
|
267
268
|
end
|
268
269
|
|
269
270
|
@listeners << [str, io] if io
|
270
271
|
else
|
271
|
-
|
272
|
+
log_writer.error "Invalid URI: #{str}"
|
272
273
|
end
|
273
274
|
end
|
274
275
|
|
275
276
|
# If we inherited fds but didn't use them (because of a
|
276
277
|
# configuration change), then be sure to close them.
|
277
278
|
@inherited_fds.each do |str, fd|
|
278
|
-
|
279
|
+
log_writer.log "* Closing unused inherited connection: #{str}"
|
279
280
|
|
280
281
|
begin
|
281
282
|
IO.for_fd(fd).close
|
@@ -295,7 +296,7 @@ module Puma
|
|
295
296
|
fds = @ios.map(&:to_i)
|
296
297
|
@activated_sockets.each do |key, sock|
|
297
298
|
next if fds.include? sock.to_i
|
298
|
-
|
299
|
+
log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
|
299
300
|
begin
|
300
301
|
sock.close
|
301
302
|
rescue SystemCallError
|
@@ -319,7 +320,7 @@ module Puma
|
|
319
320
|
local_certificates_path = File.expand_path("~/.localhost")
|
320
321
|
[File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
|
321
322
|
end
|
322
|
-
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @
|
323
|
+
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context
|
323
324
|
end
|
324
325
|
|
325
326
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -337,7 +338,7 @@ module Puma
|
|
337
338
|
return
|
338
339
|
end
|
339
340
|
|
340
|
-
host = host[1..-2] if host
|
341
|
+
host = host[1..-2] if host&.start_with? '['
|
341
342
|
tcp_server = TCPServer.new(host, port)
|
342
343
|
|
343
344
|
if optimize_for_latency
|
@@ -371,7 +372,7 @@ module Puma
|
|
371
372
|
return
|
372
373
|
end
|
373
374
|
|
374
|
-
host = host[1..-2] if host
|
375
|
+
host = host[1..-2] if host&.start_with? '['
|
375
376
|
s = TCPServer.new(host, port)
|
376
377
|
if optimize_for_latency
|
377
378
|
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
@@ -457,11 +458,14 @@ module Puma
|
|
457
458
|
|
458
459
|
def close_listeners
|
459
460
|
@listeners.each do |l, io|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
461
|
+
begin
|
462
|
+
io.close unless io.closed?
|
463
|
+
uri = URI.parse l
|
464
|
+
next unless uri.scheme == 'unix'
|
465
|
+
unix_path = "#{uri.host}#{uri.path}"
|
466
|
+
File.unlink unix_path if @unix_paths.include?(unix_path) && File.exist?(unix_path)
|
467
|
+
rescue Errno::EBADF
|
468
|
+
end
|
465
469
|
end
|
466
470
|
end
|
467
471
|
|
@@ -482,9 +486,10 @@ module Puma
|
|
482
486
|
|
483
487
|
# @!attribute [r] loopback_addresses
|
484
488
|
def loopback_addresses
|
485
|
-
Socket.ip_address_list.select do |addrinfo|
|
489
|
+
t = Socket.ip_address_list.select do |addrinfo|
|
486
490
|
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
487
|
-
end
|
491
|
+
end
|
492
|
+
t.map! { |addrinfo| addrinfo.ip_address }; t.uniq!; t
|
488
493
|
end
|
489
494
|
|
490
495
|
def loc_addr_str(io)
|
data/lib/puma/cli.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'uri'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require_relative '../puma'
|
7
|
+
require_relative 'configuration'
|
8
|
+
require_relative 'launcher'
|
9
|
+
require_relative 'const'
|
10
|
+
require_relative 'log_writer'
|
11
11
|
|
12
12
|
module Puma
|
13
13
|
class << self
|
@@ -21,19 +21,13 @@ module Puma
|
|
21
21
|
# Handles invoke a Puma::Server in a command line style.
|
22
22
|
#
|
23
23
|
class CLI
|
24
|
-
# @deprecated 6.0.0
|
25
|
-
KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
|
26
|
-
|
27
24
|
# Create a new CLI object using +argv+ as the command line
|
28
25
|
# arguments.
|
29
26
|
#
|
30
|
-
|
31
|
-
# this object will report status on.
|
32
|
-
#
|
33
|
-
def initialize(argv, events=Events.stdio)
|
27
|
+
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new, env: ENV)
|
34
28
|
@debug = false
|
35
29
|
@argv = argv.dup
|
36
|
-
|
30
|
+
@log_writer = log_writer
|
37
31
|
@events = events
|
38
32
|
|
39
33
|
@conf = nil
|
@@ -45,7 +39,7 @@ module Puma
|
|
45
39
|
@control_url = nil
|
46
40
|
@control_options = {}
|
47
41
|
|
48
|
-
setup_options
|
42
|
+
setup_options env
|
49
43
|
|
50
44
|
begin
|
51
45
|
@parser.parse! @argv
|
@@ -69,7 +63,7 @@ module Puma
|
|
69
63
|
end
|
70
64
|
end
|
71
65
|
|
72
|
-
@launcher = Puma::Launcher.new(@conf, :
|
66
|
+
@launcher = Puma::Launcher.new(@conf, env: ENV, log_writer: @log_writer, events: @events, argv: argv)
|
73
67
|
end
|
74
68
|
|
75
69
|
attr_reader :launcher
|
@@ -83,7 +77,7 @@ module Puma
|
|
83
77
|
|
84
78
|
private
|
85
79
|
def unsupported(str)
|
86
|
-
@
|
80
|
+
@log_writer.error(str)
|
87
81
|
raise UnsupportedOption
|
88
82
|
end
|
89
83
|
|
@@ -98,8 +92,8 @@ module Puma
|
|
98
92
|
# Build the OptionParser object to handle the available options.
|
99
93
|
#
|
100
94
|
|
101
|
-
def setup_options
|
102
|
-
@conf = Configuration.new do |user_config, file_config|
|
95
|
+
def setup_options(env = ENV)
|
96
|
+
@conf = Configuration.new({}, {events: @events}, env) do |user_config, file_config|
|
103
97
|
@parser = OptionParser.new do |o|
|
104
98
|
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
105
99
|
user_config.bind arg
|
@@ -150,15 +144,23 @@ module Puma
|
|
150
144
|
$LOAD_PATH.unshift(*arg.split(':'))
|
151
145
|
end
|
152
146
|
|
147
|
+
o.on "--idle-timeout SECONDS", "Number of seconds until the next request before automatic shutdown" do |arg|
|
148
|
+
user_config.idle_timeout arg
|
149
|
+
end
|
150
|
+
|
153
151
|
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
154
152
|
"Use -b for more advanced options" do |arg|
|
155
|
-
user_config.bind "tcp://#{Configuration::
|
153
|
+
user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
|
156
154
|
end
|
157
155
|
|
158
156
|
o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
|
159
157
|
user_config.pidfile arg
|
160
158
|
end
|
161
159
|
|
160
|
+
o.on "--plugin PLUGIN", "Load the given PLUGIN. Can be used multiple times to load multiple plugins." do |arg|
|
161
|
+
user_config.plugin arg
|
162
|
+
end
|
163
|
+
|
162
164
|
o.on "--preload", "Preload the app. Cluster mode only" do
|
163
165
|
user_config.preload_app!
|
164
166
|
end
|
@@ -186,7 +188,7 @@ module Puma
|
|
186
188
|
end
|
187
189
|
|
188
190
|
o.on "-s", "--silent", "Do not log prompt messages other than errors" do
|
189
|
-
@
|
191
|
+
@log_writer = LogWriter.new(NullIO.new, $stderr)
|
190
192
|
end
|
191
193
|
|
192
194
|
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|