puma 5.0.4 → 5.6.4
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 +322 -48
- data/LICENSE +0 -0
- data/README.md +95 -24
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +57 -20
- data/docs/compile_options.md +21 -0
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +2 -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 +1 -1
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +7 -7
- data/docs/signals.md +11 -10
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -66
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +42 -6
- data/ext/puma_http11/http11_parser.c +68 -57
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +1 -1
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +226 -88
- 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 +51 -51
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
- data/ext/puma_http11/puma_http11.c +9 -3
- data/lib/puma/app/status.rb +4 -7
- data/lib/puma/binder.rb +138 -49
- data/lib/puma/cli.rb +18 -4
- data/lib/puma/client.rb +113 -31
- data/lib/puma/cluster/worker.rb +22 -19
- data/lib/puma/cluster/worker_handle.rb +13 -2
- data/lib/puma/cluster.rb +75 -33
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +21 -2
- data/lib/puma/const.rb +17 -8
- data/lib/puma/control_cli.rb +76 -71
- data/lib/puma/detect.rb +19 -9
- data/lib/puma/dsl.rb +225 -31
- data/lib/puma/error_logger.rb +12 -5
- data/lib/puma/events.rb +18 -3
- data/lib/puma/io_buffer.rb +0 -0
- data/lib/puma/jruby_restart.rb +0 -0
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher.rb +56 -7
- data/lib/puma/minissl/context_builder.rb +14 -6
- data/lib/puma/minissl.rb +72 -40
- data/lib/puma/null_io.rb +12 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/queue_close.rb +7 -7
- 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 +19 -12
- data/lib/puma/request.rb +55 -21
- data/lib/puma/runner.rb +39 -13
- data/lib/puma/server.rb +78 -142
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +45 -9
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +11 -8
- data/lib/puma/util.rb +8 -1
- data/lib/puma.rb +36 -10
- data/lib/rack/handler/puma.rb +1 -0
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +15 -9
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,
|
@@ -58,6 +59,13 @@ module Puma
|
|
58
59
|
|
59
60
|
@config.load
|
60
61
|
|
62
|
+
if @config.options[:bind_to_activated_sockets]
|
63
|
+
@config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
|
64
|
+
@config.options[:binds],
|
65
|
+
@config.options[:bind_to_activated_sockets] == 'only'
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
61
69
|
@options = @config.options
|
62
70
|
@config.clamp
|
63
71
|
|
@@ -66,7 +74,7 @@ module Puma
|
|
66
74
|
|
67
75
|
generate_restart_data
|
68
76
|
|
69
|
-
if clustered? && !
|
77
|
+
if clustered? && !Puma.forkable?
|
70
78
|
unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
|
71
79
|
end
|
72
80
|
|
@@ -87,6 +95,8 @@ module Puma
|
|
87
95
|
Puma.stats_object = @runner
|
88
96
|
|
89
97
|
@status = :run
|
98
|
+
|
99
|
+
log_config if ENV['PUMA_LOG_CONFIG']
|
90
100
|
end
|
91
101
|
|
92
102
|
attr_reader :binder, :events, :config, :options, :restart_dir
|
@@ -168,6 +178,7 @@ module Puma
|
|
168
178
|
|
169
179
|
setup_signals
|
170
180
|
set_process_title
|
181
|
+
integrate_with_systemd
|
171
182
|
@runner.run
|
172
183
|
|
173
184
|
case @status
|
@@ -207,6 +218,10 @@ module Puma
|
|
207
218
|
def close_binder_listeners
|
208
219
|
@runner.close_control_listeners
|
209
220
|
@binder.close_listeners
|
221
|
+
unless @status == :restart
|
222
|
+
log "=== puma shutdown: #{Time.now} ==="
|
223
|
+
log "- Goodbye!"
|
224
|
+
end
|
210
225
|
end
|
211
226
|
|
212
227
|
# @!attribute [r] thread_status
|
@@ -229,11 +244,10 @@ module Puma
|
|
229
244
|
def write_pid
|
230
245
|
path = @options[:pidfile]
|
231
246
|
return unless path
|
232
|
-
|
233
|
-
File.
|
234
|
-
cur = Process.pid
|
247
|
+
cur_pid = Process.pid
|
248
|
+
File.write path, cur_pid, mode: 'wb:UTF-8'
|
235
249
|
at_exit do
|
236
|
-
delete_pidfile if
|
250
|
+
delete_pidfile if cur_pid == Process.pid
|
237
251
|
end
|
238
252
|
end
|
239
253
|
|
@@ -242,6 +256,7 @@ module Puma
|
|
242
256
|
end
|
243
257
|
|
244
258
|
def restart!
|
259
|
+
@events.fire_on_restart!
|
245
260
|
@config.run_hooks :on_restart, self, @events
|
246
261
|
|
247
262
|
if Puma.jruby?
|
@@ -305,10 +320,12 @@ module Puma
|
|
305
320
|
log '* Pruning Bundler environment'
|
306
321
|
home = ENV['GEM_HOME']
|
307
322
|
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
323
|
+
bundle_app_config = Bundler.original_env['BUNDLE_APP_CONFIG']
|
308
324
|
with_unbundled_env do
|
309
325
|
ENV['GEM_HOME'] = home
|
310
326
|
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
311
327
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
328
|
+
ENV["BUNDLE_APP_CONFIG"] = bundle_app_config
|
312
329
|
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
|
313
330
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
314
331
|
args += [{:close_others => false}]
|
@@ -316,6 +333,30 @@ module Puma
|
|
316
333
|
end
|
317
334
|
end
|
318
335
|
|
336
|
+
#
|
337
|
+
# Puma's systemd integration allows Puma to inform systemd:
|
338
|
+
# 1. when it has successfully started
|
339
|
+
# 2. when it is starting shutdown
|
340
|
+
# 3. periodically for a liveness check with a watchdog thread
|
341
|
+
#
|
342
|
+
|
343
|
+
def integrate_with_systemd
|
344
|
+
return unless ENV["NOTIFY_SOCKET"]
|
345
|
+
|
346
|
+
begin
|
347
|
+
require 'puma/systemd'
|
348
|
+
rescue LoadError
|
349
|
+
log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
|
350
|
+
return
|
351
|
+
end
|
352
|
+
|
353
|
+
log "* Enabling systemd notification integration"
|
354
|
+
|
355
|
+
systemd = Systemd.new(@events)
|
356
|
+
systemd.hook_events
|
357
|
+
systemd.start_watchdog
|
358
|
+
end
|
359
|
+
|
319
360
|
def spec_for_gem(gem_name)
|
320
361
|
Bundler.rubygems.loaded_specs(gem_name)
|
321
362
|
end
|
@@ -338,9 +379,8 @@ module Puma
|
|
338
379
|
end
|
339
380
|
|
340
381
|
def graceful_stop
|
382
|
+
@events.fire_on_stopped!
|
341
383
|
@runner.stop_blocked
|
342
|
-
log "=== puma shutdown: #{Time.now} ==="
|
343
|
-
log "- Goodbye!"
|
344
384
|
end
|
345
385
|
|
346
386
|
def set_process_title
|
@@ -493,5 +533,14 @@ module Puma
|
|
493
533
|
Bundler.with_unbundled_env { yield }
|
494
534
|
end
|
495
535
|
end
|
536
|
+
|
537
|
+
def log_config
|
538
|
+
log "Configuration:"
|
539
|
+
|
540
|
+
@config.final_options
|
541
|
+
.each { |config_key, value| log "- #{config_key}: #{value}" }
|
542
|
+
|
543
|
+
log "\n"
|
544
|
+
end
|
496
545
|
end
|
497
546
|
end
|
@@ -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']
|
@@ -62,6 +64,12 @@ module Puma
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
67
|
+
if params['verification_flags']
|
68
|
+
ctx.verification_flags = params['verification_flags'].split(',').
|
69
|
+
map { |flag| MiniSSL::VERIFICATION_FLAGS.fetch(flag) }.
|
70
|
+
inject { |sum, flag| sum ? sum | flag : flag }
|
71
|
+
end
|
72
|
+
|
65
73
|
ctx
|
66
74
|
end
|
67
75
|
|
data/lib/puma/minissl.rb
CHANGED
@@ -73,7 +73,6 @@ module Puma
|
|
73
73
|
|
74
74
|
def engine_read_all
|
75
75
|
output = @engine.read
|
76
|
-
raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
|
77
76
|
while output and additional_output = @engine.read
|
78
77
|
output << additional_output
|
79
78
|
end
|
@@ -100,6 +99,7 @@ module Puma
|
|
100
99
|
# ourselves.
|
101
100
|
raise IO::EAGAINWaitReadable
|
102
101
|
elsif data.nil?
|
102
|
+
raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
|
103
103
|
return nil
|
104
104
|
end
|
105
105
|
|
@@ -117,22 +117,23 @@ module Puma
|
|
117
117
|
def write(data)
|
118
118
|
return 0 if data.empty?
|
119
119
|
|
120
|
-
|
120
|
+
data_size = data.bytesize
|
121
|
+
need = data_size
|
121
122
|
|
122
123
|
while true
|
123
124
|
wrote = @engine.write data
|
124
|
-
enc = @engine.extract
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
enc_wr = ''.dup
|
127
|
+
while (enc = @engine.extract)
|
128
|
+
enc_wr << enc
|
129
129
|
end
|
130
|
+
@socket.write enc_wr unless enc_wr.empty?
|
130
131
|
|
131
132
|
need -= wrote
|
132
133
|
|
133
|
-
return
|
134
|
+
return data_size if need == 0
|
134
135
|
|
135
|
-
data = data
|
136
|
+
data = data.byteslice(wrote..-1)
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
@@ -160,30 +161,15 @@ module Puma
|
|
160
161
|
@socket.flush
|
161
162
|
end
|
162
163
|
|
163
|
-
def read_and_drop(timeout = 1)
|
164
|
-
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
165
|
-
case @socket.read_nonblock(1024, exception: false)
|
166
|
-
when nil
|
167
|
-
:eof
|
168
|
-
when :wait_readable
|
169
|
-
:eagain
|
170
|
-
else
|
171
|
-
:drop
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def should_drop_bytes?
|
176
|
-
@engine.init? || !@engine.shutdown
|
177
|
-
end
|
178
|
-
|
179
164
|
def close
|
180
165
|
begin
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
166
|
+
unless @engine.shutdown
|
167
|
+
while alert_data = @engine.extract
|
168
|
+
@socket.write alert_data
|
169
|
+
end
|
170
|
+
end
|
185
171
|
rescue IOError, SystemCallError
|
186
|
-
|
172
|
+
Puma::Util.purge_interrupt_queue
|
187
173
|
# nothing
|
188
174
|
ensure
|
189
175
|
@socket.close
|
@@ -222,6 +208,10 @@ module Puma
|
|
222
208
|
def initialize
|
223
209
|
@no_tlsv1 = false
|
224
210
|
@no_tlsv1_1 = false
|
211
|
+
@key = nil
|
212
|
+
@cert = nil
|
213
|
+
@key_pem = nil
|
214
|
+
@cert_pem = nil
|
225
215
|
end
|
226
216
|
|
227
217
|
if IS_JRUBY
|
@@ -244,7 +234,10 @@ module Puma
|
|
244
234
|
attr_reader :key
|
245
235
|
attr_reader :cert
|
246
236
|
attr_reader :ca
|
237
|
+
attr_reader :cert_pem
|
238
|
+
attr_reader :key_pem
|
247
239
|
attr_accessor :ssl_cipher_filter
|
240
|
+
attr_accessor :verification_flags
|
248
241
|
|
249
242
|
def key=(key)
|
250
243
|
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
@@ -261,9 +254,19 @@ module Puma
|
|
261
254
|
@ca = ca
|
262
255
|
end
|
263
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
|
+
|
264
267
|
def check
|
265
|
-
raise "Key not configured"
|
266
|
-
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?
|
267
270
|
end
|
268
271
|
end
|
269
272
|
|
@@ -287,33 +290,58 @@ module Puma
|
|
287
290
|
VERIFY_PEER = 1
|
288
291
|
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
289
292
|
|
293
|
+
# https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h.in
|
294
|
+
# /* Certificate verify flags */
|
295
|
+
VERIFICATION_FLAGS = {
|
296
|
+
"USE_CHECK_TIME" => 0x2,
|
297
|
+
"CRL_CHECK" => 0x4,
|
298
|
+
"CRL_CHECK_ALL" => 0x8,
|
299
|
+
"IGNORE_CRITICAL" => 0x10,
|
300
|
+
"X509_STRICT" => 0x20,
|
301
|
+
"ALLOW_PROXY_CERTS" => 0x40,
|
302
|
+
"POLICY_CHECK" => 0x80,
|
303
|
+
"EXPLICIT_POLICY" => 0x100,
|
304
|
+
"INHIBIT_ANY" => 0x200,
|
305
|
+
"INHIBIT_MAP" => 0x400,
|
306
|
+
"NOTIFY_POLICY" => 0x800,
|
307
|
+
"EXTENDED_CRL_SUPPORT" => 0x1000,
|
308
|
+
"USE_DELTAS" => 0x2000,
|
309
|
+
"CHECK_SS_SIGNATURE" => 0x4000,
|
310
|
+
"TRUSTED_FIRST" => 0x8000,
|
311
|
+
"SUITEB_128_LOS_ONLY" => 0x10000,
|
312
|
+
"SUITEB_192_LOS" => 0x20000,
|
313
|
+
"SUITEB_128_LOS" => 0x30000,
|
314
|
+
"PARTIAL_CHAIN" => 0x80000,
|
315
|
+
"NO_ALT_CHAINS" => 0x100000,
|
316
|
+
"NO_CHECK_TIME" => 0x200000
|
317
|
+
}.freeze
|
318
|
+
|
290
319
|
class Server
|
291
320
|
def initialize(socket, ctx)
|
292
321
|
@socket = socket
|
293
322
|
@ctx = ctx
|
294
|
-
|
295
|
-
|
296
|
-
# @!attribute [r] to_io
|
297
|
-
def to_io
|
298
|
-
@socket
|
323
|
+
@eng_ctx = IS_JRUBY ? @ctx : SSLContext.new(ctx)
|
299
324
|
end
|
300
325
|
|
301
326
|
def accept
|
302
327
|
@ctx.check
|
303
328
|
io = @socket.accept
|
304
|
-
engine = Engine.server @
|
305
|
-
|
329
|
+
engine = Engine.server @eng_ctx
|
306
330
|
Socket.new io, engine
|
307
331
|
end
|
308
332
|
|
309
333
|
def accept_nonblock
|
310
334
|
@ctx.check
|
311
335
|
io = @socket.accept_nonblock
|
312
|
-
engine = Engine.server @
|
313
|
-
|
336
|
+
engine = Engine.server @eng_ctx
|
314
337
|
Socket.new io, engine
|
315
338
|
end
|
316
339
|
|
340
|
+
# @!attribute [r] to_io
|
341
|
+
def to_io
|
342
|
+
@socket
|
343
|
+
end
|
344
|
+
|
317
345
|
# @!attribute [r] addr
|
318
346
|
# @version 5.0.0
|
319
347
|
def addr
|
@@ -323,6 +351,10 @@ module Puma
|
|
323
351
|
def close
|
324
352
|
@socket.close unless @socket.closed? # closed? call is for Windows
|
325
353
|
end
|
354
|
+
|
355
|
+
def closed?
|
356
|
+
@socket.closed?
|
357
|
+
end
|
326
358
|
end
|
327
359
|
end
|
328
360
|
end
|
data/lib/puma/null_io.rb
CHANGED
@@ -9,6 +9,10 @@ module Puma
|
|
9
9
|
nil
|
10
10
|
end
|
11
11
|
|
12
|
+
def string
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
12
16
|
def each
|
13
17
|
end
|
14
18
|
|
@@ -32,6 +36,10 @@ module Puma
|
|
32
36
|
true
|
33
37
|
end
|
34
38
|
|
39
|
+
def sync
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
35
43
|
def sync=(v)
|
36
44
|
end
|
37
45
|
|
@@ -40,5 +48,9 @@ module Puma
|
|
40
48
|
|
41
49
|
def write(*ary)
|
42
50
|
end
|
51
|
+
|
52
|
+
def flush
|
53
|
+
self
|
54
|
+
end
|
43
55
|
end
|
44
56
|
end
|
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
@@ -5,22 +5,22 @@ module Puma
|
|
5
5
|
# Add a simple implementation for earlier Ruby versions.
|
6
6
|
#
|
7
7
|
module QueueClose
|
8
|
-
def initialize
|
9
|
-
@closed = false
|
10
|
-
super
|
11
|
-
end
|
12
8
|
def close
|
9
|
+
num_waiting.times {push nil}
|
13
10
|
@closed = true
|
14
11
|
end
|
15
12
|
def closed?
|
16
|
-
@closed
|
13
|
+
@closed ||= false
|
17
14
|
end
|
18
15
|
def push(object)
|
19
|
-
|
20
|
-
raise ClosedQueueError if @closed
|
16
|
+
raise ClosedQueueError if closed?
|
21
17
|
super
|
22
18
|
end
|
23
19
|
alias << push
|
20
|
+
def pop(non_block=false)
|
21
|
+
return nil if !non_block && closed? && empty?
|
22
|
+
super
|
23
|
+
end
|
24
24
|
end
|
25
25
|
::Queue.prepend QueueClose
|
26
26
|
end
|
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
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'puma/queue_close' unless ::Queue.instance_methods.include? :close
|
4
4
|
|
5
5
|
module Puma
|
6
|
+
class UnsupportedBackend < StandardError; end
|
7
|
+
|
6
8
|
# Monitors a collection of IO objects, calling a block whenever
|
7
9
|
# any monitored object either receives data or times out, or when the Reactor shuts down.
|
8
10
|
#
|
@@ -18,9 +20,12 @@ module Puma
|
|
18
20
|
# Create a new Reactor to monitor IO objects added by #add.
|
19
21
|
# The provided block will be invoked when an IO has data available to read,
|
20
22
|
# its timeout elapses, or when the Reactor shuts down.
|
21
|
-
def initialize(&block)
|
23
|
+
def initialize(backend, &block)
|
22
24
|
require 'nio'
|
23
|
-
|
25
|
+
unless backend == :auto || NIO::Selector.backends.include?(backend)
|
26
|
+
raise "unsupported IO selector backend: #{backend} (available backends: #{NIO::Selector.backends.join(', ')})"
|
27
|
+
end
|
28
|
+
@selector = backend == :auto ? NIO::Selector.new : NIO::Selector.new(backend)
|
24
29
|
@input = Queue.new
|
25
30
|
@timeouts = []
|
26
31
|
@block = block
|
@@ -38,11 +43,11 @@ module Puma
|
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
41
|
-
# Add a new
|
46
|
+
# Add a new client to monitor.
|
42
47
|
# The object must respond to #timeout and #timeout_at.
|
43
48
|
# Returns false if the reactor is already shut down.
|
44
|
-
def add(
|
45
|
-
@input <<
|
49
|
+
def add(client)
|
50
|
+
@input << client
|
46
51
|
@selector.wakeup
|
47
52
|
true
|
48
53
|
rescue ClosedQueueError
|
@@ -92,17 +97,19 @@ module Puma
|
|
92
97
|
end
|
93
98
|
|
94
99
|
# Start monitoring the object.
|
95
|
-
def register(
|
96
|
-
@selector.register(
|
97
|
-
@timeouts <<
|
100
|
+
def register(client)
|
101
|
+
@selector.register(client.to_io, :r).value = client
|
102
|
+
@timeouts << client
|
103
|
+
rescue ArgumentError
|
104
|
+
# unreadable clients raise error when processed by NIO
|
98
105
|
end
|
99
106
|
|
100
107
|
# 'Wake up' a monitored object by calling the provided block.
|
101
108
|
# Stop monitoring the object if the block returns `true`.
|
102
|
-
def wakeup!(
|
103
|
-
if @block.call
|
104
|
-
@selector.deregister
|
105
|
-
@timeouts.delete
|
109
|
+
def wakeup!(client)
|
110
|
+
if @block.call client
|
111
|
+
@selector.deregister client.to_io
|
112
|
+
@timeouts.delete client
|
106
113
|
end
|
107
114
|
end
|
108
115
|
end
|