puma 4.3.6 → 5.3.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 +1346 -518
- data/LICENSE +23 -20
- data/README.md +74 -31
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +24 -20
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +15 -10
- data/docs/fork_worker.md +33 -0
- data/docs/jungle/README.md +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +2 -2
- data/docs/rails_dev_mode.md +29 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +7 -6
- data/docs/stats.md +142 -0
- data/docs/systemd.md +27 -67
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +22 -8
- data/ext/puma_http11/http11_parser.c +45 -47
- 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/mini_ssl.c +211 -118
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +5 -7
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +77 -18
- data/ext/puma_http11/puma_http11.c +31 -50
- data/lib/puma.rb +46 -0
- data/lib/puma/app/status.rb +47 -36
- data/lib/puma/binder.rb +177 -103
- data/lib/puma/cli.rb +11 -15
- data/lib/puma/client.rb +73 -74
- data/lib/puma/cluster.rb +184 -198
- data/lib/puma/cluster/worker.rb +183 -0
- data/lib/puma/cluster/worker_handle.rb +90 -0
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +55 -49
- data/lib/puma/const.rb +13 -5
- data/lib/puma/control_cli.rb +93 -76
- data/lib/puma/detect.rb +24 -3
- data/lib/puma/dsl.rb +266 -92
- data/lib/puma/error_logger.rb +104 -0
- data/lib/puma/events.rb +55 -34
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +113 -45
- data/lib/puma/minissl.rb +114 -33
- data/lib/puma/minissl/context_builder.rb +6 -3
- data/lib/puma/null_io.rb +13 -1
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +467 -0
- data/lib/puma/runner.rb +29 -58
- data/lib/puma/server.rb +267 -729
- data/lib/puma/single.rb +9 -65
- data/lib/puma/state_file.rb +8 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +119 -53
- data/lib/puma/util.rb +12 -0
- data/lib/rack/handler/puma.rb +2 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- metadata +25 -21
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/accept_nonblock.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -69
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
class Cluster < Puma::Runner
|
5
|
+
# This class is instantiated by the `Puma::Cluster` and represents a single
|
6
|
+
# worker process.
|
7
|
+
#
|
8
|
+
# At the core of this class is running an instance of `Puma::Server` which
|
9
|
+
# gets created via the `start_server` method from the `Puma::Runner` class
|
10
|
+
# that this inherits from.
|
11
|
+
class Worker < Puma::Runner
|
12
|
+
attr_reader :index, :master
|
13
|
+
|
14
|
+
def initialize(index:, master:, launcher:, pipes:, server: nil)
|
15
|
+
super launcher, launcher.events
|
16
|
+
|
17
|
+
@index = index
|
18
|
+
@master = master
|
19
|
+
@launcher = launcher
|
20
|
+
@options = launcher.options
|
21
|
+
@check_pipe = pipes[:check_pipe]
|
22
|
+
@worker_write = pipes[:worker_write]
|
23
|
+
@fork_pipe = pipes[:fork_pipe]
|
24
|
+
@wakeup = pipes[:wakeup]
|
25
|
+
@server = server
|
26
|
+
end
|
27
|
+
|
28
|
+
def run
|
29
|
+
title = "puma: cluster worker #{index}: #{master}"
|
30
|
+
title += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
31
|
+
$0 = title
|
32
|
+
|
33
|
+
Signal.trap "SIGINT", "IGNORE"
|
34
|
+
Signal.trap "SIGCHLD", "DEFAULT"
|
35
|
+
|
36
|
+
Thread.new do
|
37
|
+
Puma.set_thread_name "worker check pipe"
|
38
|
+
IO.select [@check_pipe]
|
39
|
+
log "! Detected parent died, dying"
|
40
|
+
exit! 1
|
41
|
+
end
|
42
|
+
|
43
|
+
# If we're not running under a Bundler context, then
|
44
|
+
# report the info about the context we will be using
|
45
|
+
if !ENV['BUNDLE_GEMFILE']
|
46
|
+
if File.exist?("Gemfile")
|
47
|
+
log "+ Gemfile in context: #{File.expand_path("Gemfile")}"
|
48
|
+
elsif File.exist?("gems.rb")
|
49
|
+
log "+ Gemfile in context: #{File.expand_path("gems.rb")}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Invoke any worker boot hooks so they can get
|
54
|
+
# things in shape before booting the app.
|
55
|
+
@launcher.config.run_hooks :before_worker_boot, index, @launcher.events
|
56
|
+
|
57
|
+
begin
|
58
|
+
server = @server ||= start_server
|
59
|
+
rescue Exception => e
|
60
|
+
log "! Unable to start worker"
|
61
|
+
log e.backtrace[0]
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
restart_server = Queue.new << true << false
|
66
|
+
|
67
|
+
fork_worker = @options[:fork_worker] && index == 0
|
68
|
+
|
69
|
+
if fork_worker
|
70
|
+
restart_server.clear
|
71
|
+
worker_pids = []
|
72
|
+
Signal.trap "SIGCHLD" do
|
73
|
+
wakeup! if worker_pids.reject! do |p|
|
74
|
+
Process.wait(p, Process::WNOHANG) rescue true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Thread.new do
|
79
|
+
Puma.set_thread_name "worker fork pipe"
|
80
|
+
while (idx = @fork_pipe.gets)
|
81
|
+
idx = idx.to_i
|
82
|
+
if idx == -1 # stop server
|
83
|
+
if restart_server.length > 0
|
84
|
+
restart_server.clear
|
85
|
+
server.begin_restart(true)
|
86
|
+
@launcher.config.run_hooks :before_refork, nil, @launcher.events
|
87
|
+
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
88
|
+
end
|
89
|
+
elsif idx == 0 # restart server
|
90
|
+
restart_server << true << false
|
91
|
+
else # fork worker
|
92
|
+
worker_pids << pid = spawn_worker(idx)
|
93
|
+
@worker_write << "f#{pid}:#{idx}\n" rescue nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
Signal.trap "SIGTERM" do
|
100
|
+
@worker_write << "e#{Process.pid}\n" rescue nil
|
101
|
+
restart_server.clear
|
102
|
+
server.stop
|
103
|
+
restart_server << false
|
104
|
+
end
|
105
|
+
|
106
|
+
begin
|
107
|
+
@worker_write << "b#{Process.pid}:#{index}\n"
|
108
|
+
rescue SystemCallError, IOError
|
109
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
110
|
+
STDERR.puts "Master seems to have exited, exiting."
|
111
|
+
return
|
112
|
+
end
|
113
|
+
|
114
|
+
while restart_server.pop
|
115
|
+
server_thread = server.run
|
116
|
+
stat_thread ||= Thread.new(@worker_write) do |io|
|
117
|
+
Puma.set_thread_name "stat payload"
|
118
|
+
base_payload = "p#{Process.pid}"
|
119
|
+
|
120
|
+
while true
|
121
|
+
begin
|
122
|
+
b = server.backlog || 0
|
123
|
+
r = server.running || 0
|
124
|
+
t = server.pool_capacity || 0
|
125
|
+
m = server.max_threads || 0
|
126
|
+
rc = server.requests_count || 0
|
127
|
+
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
|
128
|
+
io << payload
|
129
|
+
rescue IOError
|
130
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
131
|
+
break
|
132
|
+
end
|
133
|
+
sleep Const::WORKER_CHECK_INTERVAL
|
134
|
+
end
|
135
|
+
end
|
136
|
+
server_thread.join
|
137
|
+
end
|
138
|
+
|
139
|
+
# Invoke any worker shutdown hooks so they can prevent the worker
|
140
|
+
# exiting until any background operations are completed
|
141
|
+
@launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
|
142
|
+
ensure
|
143
|
+
@worker_write << "t#{Process.pid}\n" rescue nil
|
144
|
+
@worker_write.close
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def spawn_worker(idx)
|
150
|
+
@launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
|
151
|
+
|
152
|
+
pid = fork do
|
153
|
+
new_worker = Worker.new index: idx,
|
154
|
+
master: master,
|
155
|
+
launcher: @launcher,
|
156
|
+
pipes: { check_pipe: @check_pipe,
|
157
|
+
worker_write: @worker_write },
|
158
|
+
server: @server
|
159
|
+
new_worker.run
|
160
|
+
end
|
161
|
+
|
162
|
+
if !pid
|
163
|
+
log "! Complete inability to spawn new workers detected"
|
164
|
+
log "! Seppuku is the only choice."
|
165
|
+
exit! 1
|
166
|
+
end
|
167
|
+
|
168
|
+
@launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
|
169
|
+
pid
|
170
|
+
end
|
171
|
+
|
172
|
+
def wakeup!
|
173
|
+
return unless @wakeup
|
174
|
+
|
175
|
+
begin
|
176
|
+
@wakeup.write "!" unless @wakeup.closed?
|
177
|
+
rescue SystemCallError, IOError
|
178
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Puma
|
4
|
+
class Cluster < Runner
|
5
|
+
# This class represents a worker process from the perspective of the puma
|
6
|
+
# master process. It contains information about the process and its health
|
7
|
+
# and it exposes methods to control the process via IPC. It does not
|
8
|
+
# include the actual logic executed by the worker process itself. For that,
|
9
|
+
# see Puma::Cluster::Worker.
|
10
|
+
class WorkerHandle
|
11
|
+
def initialize(idx, pid, phase, options)
|
12
|
+
@index = idx
|
13
|
+
@pid = pid
|
14
|
+
@phase = phase
|
15
|
+
@stage = :started
|
16
|
+
@signal = "TERM"
|
17
|
+
@options = options
|
18
|
+
@first_term_sent = nil
|
19
|
+
@started_at = Time.now
|
20
|
+
@last_checkin = Time.now
|
21
|
+
@last_status = {}
|
22
|
+
@term = false
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
|
26
|
+
|
27
|
+
# @version 5.0.0
|
28
|
+
attr_writer :pid, :phase
|
29
|
+
|
30
|
+
def booted?
|
31
|
+
@stage == :booted
|
32
|
+
end
|
33
|
+
|
34
|
+
def uptime
|
35
|
+
Time.now - started_at
|
36
|
+
end
|
37
|
+
|
38
|
+
def boot!
|
39
|
+
@last_checkin = Time.now
|
40
|
+
@stage = :booted
|
41
|
+
end
|
42
|
+
|
43
|
+
def term?
|
44
|
+
@term
|
45
|
+
end
|
46
|
+
|
47
|
+
def ping!(status)
|
48
|
+
@last_checkin = Time.now
|
49
|
+
captures = status.match(/{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads": (?<max_threads>\d*), "requests_count": (?<requests_count>\d*) }/)
|
50
|
+
@last_status = captures.names.inject({}) do |hash, key|
|
51
|
+
hash[key.to_sym] = captures[key].to_i
|
52
|
+
hash
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @see Puma::Cluster#check_workers
|
57
|
+
# @version 5.0.0
|
58
|
+
def ping_timeout
|
59
|
+
@last_checkin +
|
60
|
+
(booted? ?
|
61
|
+
@options[:worker_timeout] :
|
62
|
+
@options[:worker_boot_timeout]
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def term
|
67
|
+
begin
|
68
|
+
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
69
|
+
@signal = "KILL"
|
70
|
+
else
|
71
|
+
@term ||= true
|
72
|
+
@first_term_sent ||= Time.now
|
73
|
+
end
|
74
|
+
Process.kill @signal, @pid if @pid
|
75
|
+
rescue Errno::ESRCH
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def kill
|
80
|
+
@signal = 'KILL'
|
81
|
+
term
|
82
|
+
end
|
83
|
+
|
84
|
+
def hup
|
85
|
+
Process.kill "HUP", @pid
|
86
|
+
rescue Errno::ESRCH
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/puma/commonlogger.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Puma
|
4
4
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
5
5
|
# logs a line in the
|
6
|
-
# {Apache common log format}[
|
6
|
+
# {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
|
7
7
|
# to the +logger+.
|
8
8
|
#
|
9
9
|
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
@@ -16,7 +16,7 @@ module Puma
|
|
16
16
|
# (which is called without arguments in order to make the error appear for
|
17
17
|
# sure)
|
18
18
|
class CommonLogger
|
19
|
-
# Common Log Format:
|
19
|
+
# Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
|
20
20
|
#
|
21
21
|
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
22
22
|
#
|
data/lib/puma/configuration.rb
CHANGED
@@ -54,9 +54,7 @@ module Puma
|
|
54
54
|
attr_reader :user_options, :file_options, :default_options
|
55
55
|
|
56
56
|
def [](key)
|
57
|
-
|
58
|
-
return file_options[key] if file_options.key?(key)
|
59
|
-
return default_options[key] if default_options.key?(key)
|
57
|
+
fetch(key)
|
60
58
|
end
|
61
59
|
|
62
60
|
def []=(key, value)
|
@@ -64,7 +62,11 @@ module Puma
|
|
64
62
|
end
|
65
63
|
|
66
64
|
def fetch(key, default_value = nil)
|
67
|
-
|
65
|
+
return user_options[key] if user_options.key?(key)
|
66
|
+
return file_options[key] if file_options.key?(key)
|
67
|
+
return default_options[key] if default_options.key?(key)
|
68
|
+
|
69
|
+
default_value
|
68
70
|
end
|
69
71
|
|
70
72
|
def all_of(key)
|
@@ -90,6 +92,12 @@ module Puma
|
|
90
92
|
end
|
91
93
|
end
|
92
94
|
end
|
95
|
+
|
96
|
+
def final_options
|
97
|
+
default_options
|
98
|
+
.merge(file_options)
|
99
|
+
.merge(user_options)
|
100
|
+
end
|
93
101
|
end
|
94
102
|
|
95
103
|
# The main configuration class of Puma.
|
@@ -106,16 +114,17 @@ module Puma
|
|
106
114
|
#
|
107
115
|
# It also handles loading plugins.
|
108
116
|
#
|
109
|
-
#
|
117
|
+
# [Note:]
|
118
|
+
# `:port` and `:host` are not valid keys. By the time they make it to the
|
110
119
|
# configuration options they are expected to be incorporated into a `:binds` key.
|
111
120
|
# Under the hood the DSL maps `port` and `host` calls to `:binds`
|
112
121
|
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
122
|
+
# config = Configuration.new({}) do |user_config, file_config, default_config|
|
123
|
+
# user_config.port 3003
|
124
|
+
# end
|
125
|
+
# config.load
|
126
|
+
# puts config.options[:port]
|
127
|
+
# # => 3003
|
119
128
|
#
|
120
129
|
# It is expected that `load` is called on the configuration instance after setting
|
121
130
|
# config. This method expands any values in `config_file` and puts them into the
|
@@ -137,6 +146,10 @@ module Puma
|
|
137
146
|
@file_dsl = DSL.new(@options.file_options, self)
|
138
147
|
@default_dsl = DSL.new(@options.default_options, self)
|
139
148
|
|
149
|
+
if !@options[:prune_bundler]
|
150
|
+
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
151
|
+
end
|
152
|
+
|
140
153
|
if block
|
141
154
|
configure(&block)
|
142
155
|
end
|
@@ -167,27 +180,35 @@ module Puma
|
|
167
180
|
self
|
168
181
|
end
|
169
182
|
|
183
|
+
# @version 5.0.0
|
184
|
+
def default_max_threads
|
185
|
+
Puma.mri? ? 5 : 16
|
186
|
+
end
|
187
|
+
|
170
188
|
def puma_default_options
|
171
189
|
{
|
172
|
-
:min_threads => 0,
|
173
|
-
:max_threads =>
|
190
|
+
:min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
|
191
|
+
:max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
|
174
192
|
:log_requests => false,
|
175
193
|
:debug => false,
|
176
194
|
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
177
|
-
:workers => 0,
|
178
|
-
:
|
195
|
+
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
196
|
+
:silence_single_worker_warning => false,
|
179
197
|
:mode => :http,
|
180
198
|
:worker_timeout => DefaultWorkerTimeout,
|
181
199
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
182
200
|
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
183
201
|
:remote_address => :socket,
|
184
202
|
:tag => method(:infer_tag),
|
185
|
-
:environment => -> { ENV['RACK_ENV'] || "development" },
|
203
|
+
:environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] || "development" },
|
186
204
|
:rackup => DefaultRackup,
|
187
205
|
:logger => STDOUT,
|
188
206
|
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
189
207
|
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
190
|
-
:raise_exception_on_sigterm => true
|
208
|
+
:raise_exception_on_sigterm => true,
|
209
|
+
:max_fast_inline => Const::MAX_FAST_INLINE,
|
210
|
+
:io_selector_backend => :auto,
|
211
|
+
:mutate_stdout_and_stderr_to_sync_on_write => true,
|
191
212
|
}
|
192
213
|
end
|
193
214
|
|
@@ -245,14 +266,6 @@ module Puma
|
|
245
266
|
def app
|
246
267
|
found = options[:app] || load_rackup
|
247
268
|
|
248
|
-
if @options[:mode] == :tcp
|
249
|
-
require 'puma/tcp_logger'
|
250
|
-
|
251
|
-
logger = @options[:logger]
|
252
|
-
quiet = !@options[:log_requests]
|
253
|
-
return TCPLogger.new(logger, found, quiet)
|
254
|
-
end
|
255
|
-
|
256
269
|
if @options[:log_requests]
|
257
270
|
require 'puma/commonlogger'
|
258
271
|
logger = @options[:logger]
|
@@ -275,8 +288,19 @@ module Puma
|
|
275
288
|
@plugins.create name
|
276
289
|
end
|
277
290
|
|
278
|
-
def run_hooks(key, arg)
|
279
|
-
@options.all_of(key).each
|
291
|
+
def run_hooks(key, arg, events)
|
292
|
+
@options.all_of(key).each do |b|
|
293
|
+
begin
|
294
|
+
b.call arg
|
295
|
+
rescue => e
|
296
|
+
events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
297
|
+
events.debug e.backtrace.join("\n")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def final_options
|
303
|
+
@options.final_options
|
280
304
|
end
|
281
305
|
|
282
306
|
def self.temp_path
|
@@ -319,6 +343,8 @@ module Puma
|
|
319
343
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
320
344
|
|
321
345
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
346
|
+
rack_options = rack_options || {}
|
347
|
+
|
322
348
|
@options.file_options.merge!(rack_options)
|
323
349
|
|
324
350
|
config_ru_binds = []
|
@@ -332,29 +358,9 @@ module Puma
|
|
332
358
|
end
|
333
359
|
|
334
360
|
def self.random_token
|
335
|
-
|
336
|
-
require 'openssl'
|
337
|
-
rescue LoadError
|
338
|
-
end
|
339
|
-
|
340
|
-
count = 16
|
341
|
-
|
342
|
-
bytes = nil
|
343
|
-
|
344
|
-
if defined? OpenSSL::Random
|
345
|
-
bytes = OpenSSL::Random.random_bytes(count)
|
346
|
-
elsif File.exist?("/dev/urandom")
|
347
|
-
File.open('/dev/urandom') { |f| bytes = f.read(count) }
|
348
|
-
end
|
349
|
-
|
350
|
-
if bytes
|
351
|
-
token = "".dup
|
352
|
-
bytes.each_byte { |b| token << b.to_s(16) }
|
353
|
-
else
|
354
|
-
token = (0..count).to_a.map { rand(255).to_s(16) }.join
|
355
|
-
end
|
361
|
+
require 'securerandom' unless defined?(SecureRandom)
|
356
362
|
|
357
|
-
|
363
|
+
SecureRandom.hex(16)
|
358
364
|
end
|
359
365
|
end
|
360
366
|
end
|