puma 5.3.2 → 5.6.2
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 +143 -8
- data/LICENSE +0 -0
- data/README.md +47 -6
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +49 -16
- data/docs/compile_options.md +4 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +0 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +0 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +6 -6
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +64 -67
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +28 -5
- data/ext/puma_http11/http11_parser.c +23 -10
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +0 -0
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +69 -9
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +49 -47
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
- data/ext/puma_http11/puma_http11.c +1 -1
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +50 -5
- data/lib/puma/cli.rb +14 -4
- data/lib/puma/client.rb +50 -9
- data/lib/puma/cluster/worker.rb +8 -18
- data/lib/puma/cluster/worker_handle.rb +4 -0
- data/lib/puma/cluster.rb +30 -24
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +4 -1
- data/lib/puma/const.rb +4 -5
- data/lib/puma/control_cli.rb +1 -1
- data/lib/puma/detect.rb +8 -2
- data/lib/puma/dsl.rb +105 -11
- data/lib/puma/error_logger.rb +0 -0
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +0 -0
- data/lib/puma/jruby_restart.rb +0 -0
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher.rb +4 -1
- data/lib/puma/minissl/context_builder.rb +8 -6
- data/lib/puma/minissl.rb +24 -23
- data/lib/puma/null_io.rb +0 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/queue_close.rb +0 -0
- data/lib/puma/rack/builder.rb +1 -1
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +0 -0
- data/lib/puma/reactor.rb +0 -0
- data/lib/puma/request.rb +14 -9
- data/lib/puma/runner.rb +22 -8
- data/lib/puma/server.rb +32 -29
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +41 -7
- data/lib/puma/systemd.rb +0 -0
- data/lib/puma/thread_pool.rb +7 -5
- data/lib/puma/util.rb +8 -1
- data/lib/puma.rb +2 -2
- data/lib/rack/handler/puma.rb +0 -0
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +7 -7
@@ -17,7 +17,7 @@ module Puma
|
|
17
17
|
# be particularly full-featured or fast. It just has to handle the few places
|
18
18
|
# where Puma relies on JSON serialization internally.
|
19
19
|
|
20
|
-
module
|
20
|
+
module JSONSerialization
|
21
21
|
QUOTE = /"/
|
22
22
|
BACKSLASH = /\\/
|
23
23
|
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
data/lib/puma/launcher.rb
CHANGED
@@ -15,6 +15,7 @@ module Puma
|
|
15
15
|
# It is responsible for either launching a cluster of Puma workers or a single
|
16
16
|
# puma server.
|
17
17
|
class Launcher
|
18
|
+
# @deprecated 6.0.0
|
18
19
|
KEYS_NOT_TO_PERSIST_IN_STATE = [
|
19
20
|
:logger, :lowlevel_error_handler,
|
20
21
|
:before_worker_shutdown, :before_worker_boot, :before_worker_fork,
|
@@ -73,7 +74,7 @@ module Puma
|
|
73
74
|
|
74
75
|
generate_restart_data
|
75
76
|
|
76
|
-
if clustered? && !
|
77
|
+
if clustered? && !Puma.forkable?
|
77
78
|
unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
|
78
79
|
end
|
79
80
|
|
@@ -319,10 +320,12 @@ module Puma
|
|
319
320
|
log '* Pruning Bundler environment'
|
320
321
|
home = ENV['GEM_HOME']
|
321
322
|
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
323
|
+
bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
|
322
324
|
with_unbundled_env do
|
323
325
|
ENV['GEM_HOME'] = home
|
324
326
|
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
325
327
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
328
|
+
ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
|
326
329
|
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
|
327
330
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
328
331
|
args += [{:close_others => false}]
|
@@ -23,17 +23,19 @@ module Puma
|
|
23
23
|
ctx.keystore_pass = params['keystore-pass']
|
24
24
|
ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
|
25
25
|
else
|
26
|
-
|
27
|
-
events.error "Please specify the SSL key via 'key='"
|
26
|
+
if params['key'].nil? && params['key_pem'].nil?
|
27
|
+
events.error "Please specify the SSL key via 'key=' or 'key_pem='"
|
28
28
|
end
|
29
29
|
|
30
|
-
ctx.key = params['key']
|
30
|
+
ctx.key = params['key'] if params['key']
|
31
|
+
ctx.key_pem = params['key_pem'] if params['key_pem']
|
31
32
|
|
32
|
-
|
33
|
-
events.error "Please specify the SSL cert via 'cert='"
|
33
|
+
if params['cert'].nil? && params['cert_pem'].nil?
|
34
|
+
events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
|
34
35
|
end
|
35
36
|
|
36
|
-
ctx.cert = params['cert']
|
37
|
+
ctx.cert = params['cert'] if params['cert']
|
38
|
+
ctx.cert_pem = params['cert_pem'] if params['cert_pem']
|
37
39
|
|
38
40
|
if ['peer', 'force_peer'].include?(params['verify_mode'])
|
39
41
|
unless params['ca']
|
data/lib/puma/minissl.rb
CHANGED
@@ -161,30 +161,15 @@ module Puma
|
|
161
161
|
@socket.flush
|
162
162
|
end
|
163
163
|
|
164
|
-
def read_and_drop(timeout = 1)
|
165
|
-
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
166
|
-
case @socket.read_nonblock(1024, exception: false)
|
167
|
-
when nil
|
168
|
-
:eof
|
169
|
-
when :wait_readable
|
170
|
-
:eagain
|
171
|
-
else
|
172
|
-
:drop
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def should_drop_bytes?
|
177
|
-
@engine.init? || !@engine.shutdown
|
178
|
-
end
|
179
|
-
|
180
164
|
def close
|
181
165
|
begin
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
166
|
+
unless @engine.shutdown
|
167
|
+
while alert_data = @engine.extract
|
168
|
+
@socket.write alert_data
|
169
|
+
end
|
170
|
+
end
|
186
171
|
rescue IOError, SystemCallError
|
187
|
-
|
172
|
+
Puma::Util.purge_interrupt_queue
|
188
173
|
# nothing
|
189
174
|
ensure
|
190
175
|
@socket.close
|
@@ -223,6 +208,10 @@ module Puma
|
|
223
208
|
def initialize
|
224
209
|
@no_tlsv1 = false
|
225
210
|
@no_tlsv1_1 = false
|
211
|
+
@key = nil
|
212
|
+
@cert = nil
|
213
|
+
@key_pem = nil
|
214
|
+
@cert_pem = nil
|
226
215
|
end
|
227
216
|
|
228
217
|
if IS_JRUBY
|
@@ -245,6 +234,8 @@ module Puma
|
|
245
234
|
attr_reader :key
|
246
235
|
attr_reader :cert
|
247
236
|
attr_reader :ca
|
237
|
+
attr_reader :cert_pem
|
238
|
+
attr_reader :key_pem
|
248
239
|
attr_accessor :ssl_cipher_filter
|
249
240
|
attr_accessor :verification_flags
|
250
241
|
|
@@ -263,9 +254,19 @@ module Puma
|
|
263
254
|
@ca = ca
|
264
255
|
end
|
265
256
|
|
257
|
+
def cert_pem=(cert_pem)
|
258
|
+
raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String
|
259
|
+
@cert_pem = cert_pem
|
260
|
+
end
|
261
|
+
|
262
|
+
def key_pem=(key_pem)
|
263
|
+
raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String
|
264
|
+
@key_pem = key_pem
|
265
|
+
end
|
266
|
+
|
266
267
|
def check
|
267
|
-
raise "Key not configured"
|
268
|
-
raise "Cert not configured"
|
268
|
+
raise "Key not configured" if @key.nil? && @key_pem.nil?
|
269
|
+
raise "Cert not configured" if @cert.nil? && @cert_pem.nil?
|
269
270
|
end
|
270
271
|
end
|
271
272
|
|
data/lib/puma/null_io.rb
CHANGED
File without changes
|
File without changes
|
data/lib/puma/plugin.rb
CHANGED
@@ -64,7 +64,7 @@ module Puma
|
|
64
64
|
def fire_background
|
65
65
|
@background.each_with_index do |b, i|
|
66
66
|
Thread.new do
|
67
|
-
Puma.set_thread_name "
|
67
|
+
Puma.set_thread_name "plgn bg #{i}"
|
68
68
|
b.call
|
69
69
|
end
|
70
70
|
end
|
@@ -91,7 +91,7 @@ module Puma
|
|
91
91
|
path = ary.first[CALLER_FILE]
|
92
92
|
|
93
93
|
m = %r!puma/plugin/([^/]*)\.rb$!.match(path)
|
94
|
-
|
94
|
+
m[1]
|
95
95
|
end
|
96
96
|
|
97
97
|
def self.create(&blk)
|
data/lib/puma/queue_close.rb
CHANGED
File without changes
|
data/lib/puma/rack/builder.rb
CHANGED
data/lib/puma/rack/urlmap.rb
CHANGED
File without changes
|
data/lib/puma/rack_default.rb
CHANGED
File without changes
|
data/lib/puma/reactor.rb
CHANGED
File without changes
|
data/lib/puma/request.rb
CHANGED
@@ -51,7 +51,7 @@ module Puma
|
|
51
51
|
head = env[REQUEST_METHOD] == HEAD
|
52
52
|
|
53
53
|
env[RACK_INPUT] = body
|
54
|
-
env[RACK_URL_SCHEME]
|
54
|
+
env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
|
55
55
|
|
56
56
|
if @early_hints
|
57
57
|
env[EARLY_HINTS] = lambda { |headers|
|
@@ -167,16 +167,21 @@ module Puma
|
|
167
167
|
end
|
168
168
|
|
169
169
|
ensure
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
170
|
+
begin
|
171
|
+
uncork_socket io
|
172
|
+
|
173
|
+
body.close
|
174
|
+
client.tempfile.unlink if client.tempfile
|
175
|
+
ensure
|
176
|
+
# Whatever happens, we MUST call `close` on the response body.
|
177
|
+
# Otherwise Rack::BodyProxy callbacks may not fire and lead to various state leaks
|
178
|
+
res_body.close if res_body.respond_to? :close
|
179
|
+
end
|
175
180
|
|
176
181
|
after_reply.each { |o| o.call }
|
177
182
|
end
|
178
183
|
|
179
|
-
|
184
|
+
res_info[:keep_alive]
|
180
185
|
end
|
181
186
|
|
182
187
|
# @param env [Hash] see Puma::Client#env, from request
|
@@ -201,7 +206,7 @@ module Puma
|
|
201
206
|
begin
|
202
207
|
n = io.syswrite str
|
203
208
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
204
|
-
|
209
|
+
unless io.wait_writable WRITE_TIMEOUT
|
205
210
|
raise ConnectionError, "Socket timeout writing data"
|
206
211
|
end
|
207
212
|
|
@@ -419,7 +424,7 @@ module Puma
|
|
419
424
|
# of concurrent connections exceeds the size of the threadpool.
|
420
425
|
res_info[:keep_alive] &&= requests < @max_fast_inline ||
|
421
426
|
@thread_pool.busy_threads < @max_threads ||
|
422
|
-
!
|
427
|
+
!client.listener.to_io.wait_readable(0)
|
423
428
|
|
424
429
|
res_info[:response_hijack] = nil
|
425
430
|
|
data/lib/puma/runner.rb
CHANGED
@@ -15,6 +15,16 @@ module Puma
|
|
15
15
|
@app = nil
|
16
16
|
@control = nil
|
17
17
|
@started_at = Time.now
|
18
|
+
@wakeup = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def wakeup!
|
22
|
+
return unless @wakeup
|
23
|
+
|
24
|
+
@wakeup.write "!" unless @wakeup.closed?
|
25
|
+
|
26
|
+
rescue SystemCallError, IOError
|
27
|
+
Puma::Util.purge_interrupt_queue
|
18
28
|
end
|
19
29
|
|
20
30
|
def development?
|
@@ -59,7 +69,7 @@ module Puma
|
|
59
69
|
|
60
70
|
control.binder.parse [str], self, 'Starting control server'
|
61
71
|
|
62
|
-
control.run thread_name: '
|
72
|
+
control.run thread_name: 'ctl'
|
63
73
|
@control = control
|
64
74
|
end
|
65
75
|
|
@@ -84,12 +94,13 @@ module Puma
|
|
84
94
|
def output_header(mode)
|
85
95
|
min_t = @options[:min_threads]
|
86
96
|
max_t = @options[:max_threads]
|
97
|
+
environment = @options[:environment]
|
87
98
|
|
88
99
|
log "Puma starting in #{mode} mode..."
|
89
100
|
log "* Puma version: #{Puma::Const::PUMA_VERSION} (#{ruby_engine}) (\"#{Puma::Const::CODE_NAME}\")"
|
90
101
|
log "* Min threads: #{min_t}"
|
91
102
|
log "* Max threads: #{max_t}"
|
92
|
-
log "* Environment: #{
|
103
|
+
log "* Environment: #{environment}"
|
93
104
|
|
94
105
|
if mode == "cluster"
|
95
106
|
log "* Master PID: #{Process.pid}"
|
@@ -108,9 +119,7 @@ module Puma
|
|
108
119
|
append = @options[:redirect_append]
|
109
120
|
|
110
121
|
if stdout
|
111
|
-
|
112
|
-
raise "Cannot redirect STDOUT to #{stdout}"
|
113
|
-
end
|
122
|
+
ensure_output_directory_exists(stdout, 'STDOUT')
|
114
123
|
|
115
124
|
STDOUT.reopen stdout, (append ? "a" : "w")
|
116
125
|
STDOUT.puts "=== puma startup: #{Time.now} ==="
|
@@ -118,9 +127,7 @@ module Puma
|
|
118
127
|
end
|
119
128
|
|
120
129
|
if stderr
|
121
|
-
|
122
|
-
raise "Cannot redirect STDERR to #{stderr}"
|
123
|
-
end
|
130
|
+
ensure_output_directory_exists(stderr, 'STDERR')
|
124
131
|
|
125
132
|
STDERR.reopen stderr, (append ? "a" : "w")
|
126
133
|
STDERR.puts "=== puma startup: #{Time.now} ==="
|
@@ -159,5 +166,12 @@ module Puma
|
|
159
166
|
server.inherit_binder @launcher.binder
|
160
167
|
server
|
161
168
|
end
|
169
|
+
|
170
|
+
private
|
171
|
+
def ensure_output_directory_exists(path, io_name)
|
172
|
+
unless Dir.exist?(File.dirname(path))
|
173
|
+
raise "Cannot redirect #{io_name} to #{path}"
|
174
|
+
end
|
175
|
+
end
|
162
176
|
end
|
163
177
|
end
|
data/lib/puma/server.rb
CHANGED
@@ -14,6 +14,7 @@ require 'puma/io_buffer'
|
|
14
14
|
require 'puma/request'
|
15
15
|
|
16
16
|
require 'socket'
|
17
|
+
require 'io/wait'
|
17
18
|
require 'forwardable'
|
18
19
|
|
19
20
|
module Puma
|
@@ -145,7 +146,7 @@ module Puma
|
|
145
146
|
begin
|
146
147
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 1) if skt.kind_of? TCPSocket
|
147
148
|
rescue IOError, SystemCallError
|
148
|
-
|
149
|
+
Puma::Util.purge_interrupt_queue
|
149
150
|
end
|
150
151
|
end
|
151
152
|
|
@@ -154,7 +155,7 @@ module Puma
|
|
154
155
|
begin
|
155
156
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 0) if skt.kind_of? TCPSocket
|
156
157
|
rescue IOError, SystemCallError
|
157
|
-
|
158
|
+
Puma::Util.purge_interrupt_queue
|
158
159
|
end
|
159
160
|
end
|
160
161
|
else
|
@@ -175,7 +176,7 @@ module Puma
|
|
175
176
|
begin
|
176
177
|
tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
|
177
178
|
rescue IOError, SystemCallError
|
178
|
-
|
179
|
+
Puma::Util.purge_interrupt_queue
|
179
180
|
@precheck_closing = false
|
180
181
|
false
|
181
182
|
else
|
@@ -219,7 +220,7 @@ module Puma
|
|
219
220
|
# up in the background to handle requests. Otherwise requests
|
220
221
|
# are handled synchronously.
|
221
222
|
#
|
222
|
-
def run(background=true, thread_name: '
|
223
|
+
def run(background=true, thread_name: 'srv')
|
223
224
|
BasicSocket.do_not_reverse_lookup = true
|
224
225
|
|
225
226
|
@events.fire :state, :booting
|
@@ -227,6 +228,7 @@ module Puma
|
|
227
228
|
@status = :run
|
228
229
|
|
229
230
|
@thread_pool = ThreadPool.new(
|
231
|
+
thread_name,
|
230
232
|
@min_threads,
|
231
233
|
@max_threads,
|
232
234
|
::Puma::IOBuffer,
|
@@ -313,14 +315,15 @@ module Puma
|
|
313
315
|
queue_requests = @queue_requests
|
314
316
|
drain = @options[:drain_on_shutdown] ? 0 : nil
|
315
317
|
|
316
|
-
|
317
|
-
remote_addr_header = nil
|
318
|
-
|
319
|
-
case @options[:remote_address]
|
318
|
+
addr_send_name, addr_value = case @options[:remote_address]
|
320
319
|
when :value
|
321
|
-
|
320
|
+
[:peerip=, @options[:remote_address_value]]
|
322
321
|
when :header
|
323
|
-
remote_addr_header
|
322
|
+
[:remote_addr_header=, @options[:remote_address_header]]
|
323
|
+
when :proxy_protocol
|
324
|
+
[:expect_proxy_proto=, @options[:remote_address_proxy_protocol]]
|
325
|
+
else
|
326
|
+
[nil, nil]
|
324
327
|
end
|
325
328
|
|
326
329
|
while @status == :run || (drain && shutting_down?)
|
@@ -340,17 +343,16 @@ module Puma
|
|
340
343
|
next
|
341
344
|
end
|
342
345
|
drain += 1 if shutting_down?
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
elsif remote_addr_header
|
348
|
-
client.remote_addr_header = remote_addr_header
|
349
|
-
end
|
350
|
-
pool << client
|
346
|
+
pool << Client.new(io, @binder.env(sock)).tap { |c|
|
347
|
+
c.listener = sock
|
348
|
+
c.send(addr_send_name, addr_value) if addr_value
|
349
|
+
}
|
351
350
|
end
|
352
351
|
end
|
353
|
-
rescue
|
352
|
+
rescue IOError, Errno::EBADF
|
353
|
+
# In the case that any of the sockets are unexpectedly close.
|
354
|
+
raise
|
355
|
+
rescue StandardError => e
|
354
356
|
@events.unknown_error e, nil, "Listen loop"
|
355
357
|
end
|
356
358
|
end
|
@@ -366,13 +368,14 @@ module Puma
|
|
366
368
|
rescue Exception => e
|
367
369
|
@events.unknown_error e, nil, "Exception handling servers"
|
368
370
|
ensure
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
371
|
+
# RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
|
372
|
+
# Errno::EBADF is infrequently raised
|
373
|
+
[@check, @notify].each do |io|
|
374
|
+
begin
|
375
|
+
io.close unless io.closed?
|
376
|
+
rescue Errno::EBADF, RuntimeError
|
377
|
+
end
|
374
378
|
end
|
375
|
-
@notify.close
|
376
379
|
@notify = nil
|
377
380
|
@check = nil
|
378
381
|
end
|
@@ -396,7 +399,7 @@ module Puma
|
|
396
399
|
return true
|
397
400
|
end
|
398
401
|
|
399
|
-
|
402
|
+
false
|
400
403
|
end
|
401
404
|
|
402
405
|
# Given a connection on +client+, handle the incoming requests,
|
@@ -482,7 +485,7 @@ module Puma
|
|
482
485
|
begin
|
483
486
|
client.close if close_socket
|
484
487
|
rescue IOError, SystemCallError
|
485
|
-
|
488
|
+
Puma::Util.purge_interrupt_queue
|
486
489
|
# Already closed
|
487
490
|
rescue StandardError => e
|
488
491
|
@events.unknown_error e, nil, "Client"
|
@@ -574,11 +577,11 @@ module Puma
|
|
574
577
|
@notify << message
|
575
578
|
rescue IOError, NoMethodError, Errno::EPIPE
|
576
579
|
# The server, in another thread, is shutting down
|
577
|
-
|
580
|
+
Puma::Util.purge_interrupt_queue
|
578
581
|
rescue RuntimeError => e
|
579
582
|
# Temporary workaround for https://bugs.ruby-lang.org/issues/13239
|
580
583
|
if e.message.include?('IOError')
|
581
|
-
|
584
|
+
Puma::Util.purge_interrupt_queue
|
582
585
|
else
|
583
586
|
raise e
|
584
587
|
end
|
data/lib/puma/single.rb
CHANGED
File without changes
|
data/lib/puma/state_file.rb
CHANGED
@@ -1,15 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'yaml'
|
4
|
-
|
5
3
|
module Puma
|
4
|
+
|
5
|
+
# Puma::Launcher uses StateFile to write a yaml file for use with Puma::ControlCLI.
|
6
|
+
#
|
7
|
+
# In previous versions of Puma, YAML was used to read/write the state file.
|
8
|
+
# Since Puma is similar to Bundler/RubyGems in that it may load before one's app
|
9
|
+
# does, minimizing the dependencies that may be shared with the app is desired.
|
10
|
+
#
|
11
|
+
# At present, it only works with numeric and string values. It is still a valid
|
12
|
+
# yaml file, and the CI tests parse it with Psych.
|
13
|
+
#
|
6
14
|
class StateFile
|
15
|
+
|
16
|
+
ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
|
17
|
+
|
18
|
+
# @deprecated 6.0.0
|
19
|
+
FIELDS = ALLOWED_FIELDS
|
20
|
+
|
7
21
|
def initialize
|
8
22
|
@options = {}
|
9
23
|
end
|
10
24
|
|
11
25
|
def save(path, permission = nil)
|
12
|
-
contents =
|
26
|
+
contents = "---\n".dup
|
27
|
+
@options.each do |k,v|
|
28
|
+
next unless ALLOWED_FIELDS.include? k
|
29
|
+
case v
|
30
|
+
when Numeric
|
31
|
+
contents << "#{k}: #{v}\n"
|
32
|
+
when String
|
33
|
+
next if v.strip.empty?
|
34
|
+
contents << (k == 'running_from' || v.to_s.include?(' ') ?
|
35
|
+
"#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
|
36
|
+
end
|
37
|
+
end
|
13
38
|
if permission
|
14
39
|
File.write path, contents, mode: 'wb:UTF-8'
|
15
40
|
else
|
@@ -18,12 +43,21 @@ module Puma
|
|
18
43
|
end
|
19
44
|
|
20
45
|
def load(path)
|
21
|
-
|
46
|
+
File.read(path).lines.each do |line|
|
47
|
+
next if line.start_with? '#'
|
48
|
+
k,v = line.split ':', 2
|
49
|
+
next unless v && ALLOWED_FIELDS.include?(k)
|
50
|
+
v = v.strip
|
51
|
+
@options[k] =
|
52
|
+
case v
|
53
|
+
when /\A\d+\z/ then v.to_i
|
54
|
+
when /\A\d+\.\d+\z/ then v.to_f
|
55
|
+
else v.gsub(/\A"|"\z/, '')
|
56
|
+
end
|
57
|
+
end
|
22
58
|
end
|
23
59
|
|
24
|
-
|
25
|
-
|
26
|
-
FIELDS.each do |f|
|
60
|
+
ALLOWED_FIELDS.each do |f|
|
27
61
|
define_method f do
|
28
62
|
@options[f]
|
29
63
|
end
|
data/lib/puma/systemd.rb
CHANGED
File without changes
|
data/lib/puma/thread_pool.rb
CHANGED
@@ -29,7 +29,7 @@ module Puma
|
|
29
29
|
# The block passed is the work that will be performed in each
|
30
30
|
# thread.
|
31
31
|
#
|
32
|
-
def initialize(min, max, *extra, &block)
|
32
|
+
def initialize(name, min, max, *extra, &block)
|
33
33
|
@not_empty = ConditionVariable.new
|
34
34
|
@not_full = ConditionVariable.new
|
35
35
|
@mutex = Mutex.new
|
@@ -39,6 +39,7 @@ module Puma
|
|
39
39
|
@spawned = 0
|
40
40
|
@waiting = 0
|
41
41
|
|
42
|
+
@name = name
|
42
43
|
@min = Integer(min)
|
43
44
|
@max = Integer(max)
|
44
45
|
@block = block
|
@@ -71,7 +72,7 @@ module Puma
|
|
71
72
|
attr_accessor :out_of_band_hook # @version 5.0.0
|
72
73
|
|
73
74
|
def self.clean_thread_locals
|
74
|
-
Thread.current.keys.each do |key| # rubocop: disable
|
75
|
+
Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
|
75
76
|
Thread.current[key] = nil unless key == :__recursive_key__
|
76
77
|
end
|
77
78
|
end
|
@@ -101,7 +102,7 @@ module Puma
|
|
101
102
|
@spawned += 1
|
102
103
|
|
103
104
|
th = Thread.new(@spawned) do |spawned|
|
104
|
-
Puma.set_thread_name '
|
105
|
+
Puma.set_thread_name '%s tp %03i' % [@name, spawned]
|
105
106
|
todo = @todo
|
106
107
|
block = @block
|
107
108
|
mutex = @mutex
|
@@ -119,6 +120,7 @@ module Puma
|
|
119
120
|
@trim_requested -= 1
|
120
121
|
@spawned -= 1
|
121
122
|
@workers.delete th
|
123
|
+
not_full.signal
|
122
124
|
Thread.exit
|
123
125
|
end
|
124
126
|
|
@@ -318,12 +320,12 @@ module Puma
|
|
318
320
|
end
|
319
321
|
|
320
322
|
def auto_trim!(timeout=30)
|
321
|
-
@auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
|
323
|
+
@auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
|
322
324
|
@auto_trim.start!
|
323
325
|
end
|
324
326
|
|
325
327
|
def auto_reap!(timeout=5)
|
326
|
-
@reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
|
328
|
+
@reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
|
327
329
|
@reaper.start!
|
328
330
|
end
|
329
331
|
|
data/lib/puma/util.rb
CHANGED
@@ -10,6 +10,13 @@ module Puma
|
|
10
10
|
IO.pipe
|
11
11
|
end
|
12
12
|
|
13
|
+
# An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
|
14
|
+
# which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
|
15
|
+
# Additional context: https://github.com/puma/puma/pull/1345
|
16
|
+
def purge_interrupt_queue
|
17
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
18
|
+
end
|
19
|
+
|
13
20
|
# Unescapes a URI escaped string with +encoding+. +encoding+ will be the
|
14
21
|
# target encoding of the string returned, and it defaults to UTF-8
|
15
22
|
if defined?(::Encoding)
|
@@ -61,7 +68,7 @@ module Puma
|
|
61
68
|
end
|
62
69
|
end
|
63
70
|
|
64
|
-
|
71
|
+
params
|
65
72
|
end
|
66
73
|
|
67
74
|
# A case-insensitive Hash that preserves the original case of a
|
data/lib/puma.rb
CHANGED
@@ -12,7 +12,7 @@ require 'thread'
|
|
12
12
|
|
13
13
|
require 'puma/puma_http11'
|
14
14
|
require 'puma/detect'
|
15
|
-
require 'puma/
|
15
|
+
require 'puma/json_serialization'
|
16
16
|
|
17
17
|
module Puma
|
18
18
|
autoload :Const, 'puma/const'
|
@@ -60,7 +60,7 @@ module Puma
|
|
60
60
|
|
61
61
|
# @!attribute [rw] stats_object
|
62
62
|
def self.stats
|
63
|
-
Puma::
|
63
|
+
Puma::JSONSerialization.generate @get_stats.stats
|
64
64
|
end
|
65
65
|
|
66
66
|
# @!attribute [r] stats_hash
|
data/lib/rack/handler/puma.rb
CHANGED
File without changes
|
data/tools/Dockerfile
CHANGED
data/tools/trickletest.rb
CHANGED
File without changes
|