puma 4.3.12 → 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 +1461 -524
- data/LICENSE +23 -20
- data/README.md +120 -36
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +63 -26
- data/docs/compile_options.md +21 -0
- data/docs/deployment.md +60 -69
- 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 +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -128
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +38 -9
- 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 +204 -86
- 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 +3 -5
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +105 -61
- data/ext/puma_http11/puma_http11.c +32 -51
- data/lib/puma/app/status.rb +47 -36
- data/lib/puma/binder.rb +225 -106
- data/lib/puma/cli.rb +24 -18
- data/lib/puma/client.rb +104 -76
- data/lib/puma/cluster/worker.rb +173 -0
- data/lib/puma/cluster/worker_handle.rb +94 -0
- data/lib/puma/cluster.rb +212 -220
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +58 -49
- data/lib/puma/const.rb +13 -6
- data/lib/puma/control_cli.rb +93 -76
- data/lib/puma/detect.rb +29 -2
- data/lib/puma/dsl.rb +364 -96
- 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_serialization.rb +96 -0
- data/lib/puma/launcher.rb +117 -46
- data/lib/puma/minissl/context_builder.rb +14 -9
- data/lib/puma/minissl.rb +128 -46
- data/lib/puma/null_io.rb +13 -1
- data/lib/puma/plugin.rb +3 -12
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/rack/builder.rb +1 -5
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +472 -0
- data/lib/puma/runner.rb +46 -61
- data/lib/puma/server.rb +290 -763
- data/lib/puma/single.rb +9 -65
- data/lib/puma/state_file.rb +47 -8
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +125 -57
- data/lib/puma/util.rb +20 -1
- data/lib/puma.rb +46 -0
- data/lib/rack/handler/puma.rb +2 -3
- data/tools/{docker/Dockerfile → Dockerfile} +1 -1
- metadata +26 -22
- 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
data/lib/puma/configuration.rb
CHANGED
@@ -11,6 +11,7 @@ module Puma
|
|
11
11
|
|
12
12
|
DefaultTCPHost = "0.0.0.0"
|
13
13
|
DefaultTCPPort = 9292
|
14
|
+
DefaultWorkerCheckInterval = 5
|
14
15
|
DefaultWorkerTimeout = 60
|
15
16
|
DefaultWorkerShutdownTimeout = 30
|
16
17
|
end
|
@@ -54,9 +55,7 @@ module Puma
|
|
54
55
|
attr_reader :user_options, :file_options, :default_options
|
55
56
|
|
56
57
|
def [](key)
|
57
|
-
|
58
|
-
return file_options[key] if file_options.key?(key)
|
59
|
-
return default_options[key] if default_options.key?(key)
|
58
|
+
fetch(key)
|
60
59
|
end
|
61
60
|
|
62
61
|
def []=(key, value)
|
@@ -64,7 +63,11 @@ module Puma
|
|
64
63
|
end
|
65
64
|
|
66
65
|
def fetch(key, default_value = nil)
|
67
|
-
|
66
|
+
return user_options[key] if user_options.key?(key)
|
67
|
+
return file_options[key] if file_options.key?(key)
|
68
|
+
return default_options[key] if default_options.key?(key)
|
69
|
+
|
70
|
+
default_value
|
68
71
|
end
|
69
72
|
|
70
73
|
def all_of(key)
|
@@ -90,6 +93,12 @@ module Puma
|
|
90
93
|
end
|
91
94
|
end
|
92
95
|
end
|
96
|
+
|
97
|
+
def final_options
|
98
|
+
default_options
|
99
|
+
.merge(file_options)
|
100
|
+
.merge(user_options)
|
101
|
+
end
|
93
102
|
end
|
94
103
|
|
95
104
|
# The main configuration class of Puma.
|
@@ -106,16 +115,17 @@ module Puma
|
|
106
115
|
#
|
107
116
|
# It also handles loading plugins.
|
108
117
|
#
|
109
|
-
#
|
118
|
+
# [Note:]
|
119
|
+
# `:port` and `:host` are not valid keys. By the time they make it to the
|
110
120
|
# configuration options they are expected to be incorporated into a `:binds` key.
|
111
121
|
# Under the hood the DSL maps `port` and `host` calls to `:binds`
|
112
122
|
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
123
|
+
# config = Configuration.new({}) do |user_config, file_config, default_config|
|
124
|
+
# user_config.port 3003
|
125
|
+
# end
|
126
|
+
# config.load
|
127
|
+
# puts config.options[:port]
|
128
|
+
# # => 3003
|
119
129
|
#
|
120
130
|
# It is expected that `load` is called on the configuration instance after setting
|
121
131
|
# config. This method expands any values in `config_file` and puts them into the
|
@@ -137,6 +147,10 @@ module Puma
|
|
137
147
|
@file_dsl = DSL.new(@options.file_options, self)
|
138
148
|
@default_dsl = DSL.new(@options.default_options, self)
|
139
149
|
|
150
|
+
if !@options[:prune_bundler]
|
151
|
+
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
152
|
+
end
|
153
|
+
|
140
154
|
if block
|
141
155
|
configure(&block)
|
142
156
|
end
|
@@ -167,27 +181,37 @@ module Puma
|
|
167
181
|
self
|
168
182
|
end
|
169
183
|
|
184
|
+
# @version 5.0.0
|
185
|
+
def default_max_threads
|
186
|
+
Puma.mri? ? 5 : 16
|
187
|
+
end
|
188
|
+
|
170
189
|
def puma_default_options
|
171
190
|
{
|
172
|
-
:min_threads => 0,
|
173
|
-
:max_threads =>
|
191
|
+
:min_threads => Integer(ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS'] || 0),
|
192
|
+
:max_threads => Integer(ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS'] || default_max_threads),
|
174
193
|
:log_requests => false,
|
175
194
|
:debug => false,
|
176
195
|
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
177
|
-
:workers => 0,
|
178
|
-
:
|
196
|
+
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
197
|
+
:silence_single_worker_warning => false,
|
179
198
|
:mode => :http,
|
199
|
+
:worker_check_interval => DefaultWorkerCheckInterval,
|
180
200
|
:worker_timeout => DefaultWorkerTimeout,
|
181
201
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
182
202
|
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
203
|
+
:worker_culling_strategy => :youngest,
|
183
204
|
:remote_address => :socket,
|
184
205
|
:tag => method(:infer_tag),
|
185
|
-
:environment => -> { ENV['RACK_ENV'] ||
|
206
|
+
:environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
|
186
207
|
:rackup => DefaultRackup,
|
187
208
|
:logger => STDOUT,
|
188
209
|
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
189
210
|
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
190
|
-
:raise_exception_on_sigterm => true
|
211
|
+
:raise_exception_on_sigterm => true,
|
212
|
+
:max_fast_inline => Const::MAX_FAST_INLINE,
|
213
|
+
:io_selector_backend => :auto,
|
214
|
+
:mutate_stdout_and_stderr_to_sync_on_write => true,
|
191
215
|
}
|
192
216
|
end
|
193
217
|
|
@@ -245,14 +269,6 @@ module Puma
|
|
245
269
|
def app
|
246
270
|
found = options[:app] || load_rackup
|
247
271
|
|
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
272
|
if @options[:log_requests]
|
257
273
|
require 'puma/commonlogger'
|
258
274
|
logger = @options[:logger]
|
@@ -275,8 +291,19 @@ module Puma
|
|
275
291
|
@plugins.create name
|
276
292
|
end
|
277
293
|
|
278
|
-
def run_hooks(key, arg)
|
279
|
-
@options.all_of(key).each
|
294
|
+
def run_hooks(key, arg, events)
|
295
|
+
@options.all_of(key).each do |b|
|
296
|
+
begin
|
297
|
+
b.call arg
|
298
|
+
rescue => e
|
299
|
+
events.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
300
|
+
events.debug e.backtrace.join("\n")
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def final_options
|
306
|
+
@options.final_options
|
280
307
|
end
|
281
308
|
|
282
309
|
def self.temp_path
|
@@ -319,6 +346,8 @@ module Puma
|
|
319
346
|
raise "Missing rackup file '#{rackup}'" unless File.exist?(rackup)
|
320
347
|
|
321
348
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
349
|
+
rack_options = rack_options || {}
|
350
|
+
|
322
351
|
@options.file_options.merge!(rack_options)
|
323
352
|
|
324
353
|
config_ru_binds = []
|
@@ -332,29 +361,9 @@ module Puma
|
|
332
361
|
end
|
333
362
|
|
334
363
|
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
|
364
|
+
require 'securerandom' unless defined?(SecureRandom)
|
356
365
|
|
357
|
-
|
366
|
+
SecureRandom.hex(16)
|
358
367
|
end
|
359
368
|
end
|
360
369
|
end
|
data/lib/puma/const.rb
CHANGED
@@ -100,8 +100,9 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "5.6.4".freeze
|
104
|
+
CODE_NAME = "Birdie's Version".freeze
|
105
|
+
|
105
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
106
107
|
|
107
108
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
@@ -177,7 +178,6 @@ module Puma
|
|
177
178
|
PORT_443 = "443".freeze
|
178
179
|
LOCALHOST = "localhost".freeze
|
179
180
|
LOCALHOST_IP = "127.0.0.1".freeze
|
180
|
-
LOCALHOST_ADDR = "127.0.0.1:0".freeze
|
181
181
|
|
182
182
|
SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
|
183
183
|
HTTP_11 = "HTTP/1.1".freeze
|
@@ -230,7 +230,6 @@ module Puma
|
|
230
230
|
COLON = ": ".freeze
|
231
231
|
|
232
232
|
NEWLINE = "\n".freeze
|
233
|
-
HTTP_INJECTION_REGEX = /[\r\n]/.freeze
|
234
233
|
|
235
234
|
HIJACK_P = "rack.hijack?".freeze
|
236
235
|
HIJACK = "rack.hijack".freeze
|
@@ -238,8 +237,16 @@ module Puma
|
|
238
237
|
|
239
238
|
EARLY_HINTS = "rack.early_hints".freeze
|
240
239
|
|
241
|
-
#
|
242
|
-
|
240
|
+
# Illegal character in the key or value of response header
|
241
|
+
DQUOTE = "\"".freeze
|
242
|
+
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
243
|
+
ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
|
244
|
+
# header values can contain HTAB?
|
245
|
+
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
246
|
+
|
247
|
+
# Banned keys of response header
|
248
|
+
BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
|
243
249
|
|
250
|
+
PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
|
244
251
|
end
|
245
252
|
end
|
data/lib/puma/control_cli.rb
CHANGED
@@ -11,7 +11,32 @@ require 'socket'
|
|
11
11
|
module Puma
|
12
12
|
class ControlCLI
|
13
13
|
|
14
|
-
|
14
|
+
# values must be string or nil
|
15
|
+
# value of `nil` means command cannot be processed via signal
|
16
|
+
# @version 5.0.3
|
17
|
+
CMD_PATH_SIG_MAP = {
|
18
|
+
'gc' => nil,
|
19
|
+
'gc-stats' => nil,
|
20
|
+
'halt' => 'SIGQUIT',
|
21
|
+
'phased-restart' => 'SIGUSR1',
|
22
|
+
'refork' => 'SIGURG',
|
23
|
+
'reload-worker-directory' => nil,
|
24
|
+
'restart' => 'SIGUSR2',
|
25
|
+
'start' => nil,
|
26
|
+
'stats' => nil,
|
27
|
+
'status' => '',
|
28
|
+
'stop' => 'SIGTERM',
|
29
|
+
'thread-backtraces' => nil
|
30
|
+
}.freeze
|
31
|
+
|
32
|
+
# @deprecated 6.0.0
|
33
|
+
COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
|
34
|
+
|
35
|
+
# commands that cannot be used in a request
|
36
|
+
NO_REQ_COMMANDS = %w{refork}.freeze
|
37
|
+
|
38
|
+
# @version 5.0.0
|
39
|
+
PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}.freeze
|
15
40
|
|
16
41
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
17
42
|
@state = nil
|
@@ -22,7 +47,7 @@ module Puma
|
|
22
47
|
@control_auth_token = nil
|
23
48
|
@config_file = nil
|
24
49
|
@command = nil
|
25
|
-
@environment = ENV['RACK_ENV']
|
50
|
+
@environment = ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
26
51
|
|
27
52
|
@argv = argv.dup
|
28
53
|
@stdout = stdout
|
@@ -30,7 +55,7 @@ module Puma
|
|
30
55
|
@cli_options = {}
|
31
56
|
|
32
57
|
opts = OptionParser.new do |o|
|
33
|
-
o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{
|
58
|
+
o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{CMD_PATH_SIG_MAP.keys.join("|")})"
|
34
59
|
|
35
60
|
o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
|
36
61
|
@state = arg
|
@@ -71,7 +96,7 @@ module Puma
|
|
71
96
|
end
|
72
97
|
|
73
98
|
o.on_tail("-V", "--version", "Show version") do
|
74
|
-
puts Const::PUMA_VERSION
|
99
|
+
@stdout.puts Const::PUMA_VERSION
|
75
100
|
exit
|
76
101
|
end
|
77
102
|
end
|
@@ -81,6 +106,15 @@ module Puma
|
|
81
106
|
|
82
107
|
@command = argv.shift
|
83
108
|
|
109
|
+
# check presence of command
|
110
|
+
unless @command
|
111
|
+
raise "Available commands: #{CMD_PATH_SIG_MAP.keys.join(", ")}"
|
112
|
+
end
|
113
|
+
|
114
|
+
unless CMD_PATH_SIG_MAP.key? @command
|
115
|
+
raise "Invalid command: #{@command}"
|
116
|
+
end
|
117
|
+
|
84
118
|
unless @config_file == '-'
|
85
119
|
environment = @environment || 'development'
|
86
120
|
|
@@ -99,16 +133,6 @@ module Puma
|
|
99
133
|
@pidfile ||= config.options[:pidfile]
|
100
134
|
end
|
101
135
|
end
|
102
|
-
|
103
|
-
# check present of command
|
104
|
-
unless @command
|
105
|
-
raise "Available commands: #{COMMANDS.join(", ")}"
|
106
|
-
end
|
107
|
-
|
108
|
-
unless COMMANDS.include? @command
|
109
|
-
raise "Invalid command: #{@command}"
|
110
|
-
end
|
111
|
-
|
112
136
|
rescue => e
|
113
137
|
@stdout.puts e.message
|
114
138
|
exit 1
|
@@ -132,7 +156,7 @@ module Puma
|
|
132
156
|
@pid = sf.pid
|
133
157
|
elsif @pidfile
|
134
158
|
# get pid from pid_file
|
135
|
-
File.
|
159
|
+
@pid = File.read(@pidfile, mode: 'rb:UTF-8').to_i
|
136
160
|
end
|
137
161
|
end
|
138
162
|
|
@@ -140,23 +164,29 @@ module Puma
|
|
140
164
|
uri = URI.parse @control_url
|
141
165
|
|
142
166
|
# create server object by scheme
|
143
|
-
server =
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
167
|
+
server =
|
168
|
+
case uri.scheme
|
169
|
+
when 'ssl'
|
170
|
+
require 'openssl'
|
171
|
+
OpenSSL::SSL::SSLSocket.new(
|
172
|
+
TCPSocket.new(uri.host, uri.port),
|
173
|
+
OpenSSL::SSL::SSLContext.new)
|
174
|
+
.tap { |ssl| ssl.sync_close = true } # default is false
|
175
|
+
.tap(&:connect)
|
176
|
+
when 'tcp'
|
177
|
+
TCPSocket.new uri.host, uri.port
|
178
|
+
when 'unix'
|
179
|
+
# check for abstract UNIXSocket
|
180
|
+
UNIXSocket.new(@control_url.start_with?('unix://@') ?
|
181
|
+
"\0#{uri.host}#{uri.path}" : "#{uri.host}#{uri.path}")
|
182
|
+
else
|
183
|
+
raise "Invalid scheme: #{uri.scheme}"
|
184
|
+
end
|
185
|
+
|
186
|
+
if @command == 'status'
|
187
|
+
message 'Puma is started'
|
188
|
+
elsif NO_REQ_COMMANDS.include? @command
|
189
|
+
raise "Invalid request command: #{@command}"
|
160
190
|
else
|
161
191
|
url = "/#{@command}"
|
162
192
|
|
@@ -164,10 +194,10 @@ module Puma
|
|
164
194
|
url = url + "?token=#{@control_auth_token}"
|
165
195
|
end
|
166
196
|
|
167
|
-
server
|
197
|
+
server.syswrite "GET #{url} HTTP/1.0\r\n\r\n"
|
168
198
|
|
169
199
|
unless data = server.read
|
170
|
-
raise
|
200
|
+
raise 'Server closed connection before responding'
|
171
201
|
end
|
172
202
|
|
173
203
|
response = data.split("\r\n")
|
@@ -176,67 +206,55 @@ module Puma
|
|
176
206
|
raise "Server sent empty response"
|
177
207
|
end
|
178
208
|
|
179
|
-
|
209
|
+
@http, @code, @message = response.first.split(' ',3)
|
180
210
|
|
181
|
-
if @code ==
|
182
|
-
raise
|
183
|
-
elsif @code ==
|
211
|
+
if @code == '403'
|
212
|
+
raise 'Unauthorized access to server (wrong auth token)'
|
213
|
+
elsif @code == '404'
|
184
214
|
raise "Command error: #{response.last}"
|
185
|
-
elsif @code !=
|
215
|
+
elsif @code != '200'
|
186
216
|
raise "Bad response from server: #{@code}"
|
187
217
|
end
|
188
218
|
|
189
219
|
message "Command #{@command} sent success"
|
190
|
-
message response.last if @command
|
220
|
+
message response.last if PRINTABLE_COMMANDS.include?(@command)
|
191
221
|
end
|
192
222
|
ensure
|
193
|
-
|
223
|
+
if server
|
224
|
+
if uri.scheme == 'ssl'
|
225
|
+
server.sysclose
|
226
|
+
else
|
227
|
+
server.close unless server.closed?
|
228
|
+
end
|
229
|
+
end
|
194
230
|
end
|
195
231
|
|
196
232
|
def send_signal
|
197
233
|
unless @pid
|
198
|
-
raise
|
234
|
+
raise 'Neither pid nor control url available'
|
199
235
|
end
|
200
236
|
|
201
237
|
begin
|
238
|
+
sig = CMD_PATH_SIG_MAP[@command]
|
202
239
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
when "halt"
|
208
|
-
Process.kill "QUIT", @pid
|
209
|
-
|
210
|
-
when "stop"
|
211
|
-
Process.kill "SIGTERM", @pid
|
212
|
-
|
213
|
-
when "stats"
|
214
|
-
puts "Stats not available via pid only"
|
215
|
-
return
|
216
|
-
|
217
|
-
when "reload-worker-directory"
|
218
|
-
puts "reload-worker-directory not available via pid only"
|
240
|
+
if sig.nil?
|
241
|
+
@stdout.puts "'#{@command}' not available via pid only"
|
242
|
+
@stdout.flush unless @stdout.sync
|
219
243
|
return
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
when "status"
|
244
|
+
elsif sig.start_with? 'SIG'
|
245
|
+
Process.kill sig, @pid
|
246
|
+
elsif @command == 'status'
|
225
247
|
begin
|
226
248
|
Process.kill 0, @pid
|
227
|
-
puts
|
249
|
+
@stdout.puts 'Puma is started'
|
250
|
+
@stdout.flush unless @stdout.sync
|
228
251
|
rescue Errno::ESRCH
|
229
|
-
raise
|
252
|
+
raise 'Puma is not running'
|
230
253
|
end
|
231
|
-
|
232
|
-
return
|
233
|
-
|
234
|
-
else
|
235
254
|
return
|
236
255
|
end
|
237
|
-
|
238
256
|
rescue SystemCallError
|
239
|
-
if @command ==
|
257
|
+
if @command == 'restart'
|
240
258
|
start
|
241
259
|
else
|
242
260
|
raise "No pid '#{@pid}' found"
|
@@ -247,14 +265,13 @@ module Puma
|
|
247
265
|
end
|
248
266
|
|
249
267
|
def run
|
250
|
-
return start if @command ==
|
251
|
-
|
268
|
+
return start if @command == 'start'
|
252
269
|
prepare_configuration
|
253
270
|
|
254
|
-
if Puma.windows?
|
271
|
+
if Puma.windows? || @control_url
|
255
272
|
send_request
|
256
273
|
else
|
257
|
-
|
274
|
+
send_signal
|
258
275
|
end
|
259
276
|
|
260
277
|
rescue => e
|
@@ -262,7 +279,7 @@ module Puma
|
|
262
279
|
exit 1
|
263
280
|
end
|
264
281
|
|
265
|
-
|
282
|
+
private
|
266
283
|
def start
|
267
284
|
require 'puma/cli'
|
268
285
|
|
data/lib/puma/detect.rb
CHANGED
@@ -1,15 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This file can be loaded independently of puma.rb, so it cannot have any code
|
4
|
+
# that assumes puma.rb is loaded.
|
5
|
+
|
6
|
+
|
3
7
|
module Puma
|
4
|
-
|
8
|
+
# @version 5.2.1
|
9
|
+
HAS_FORK = ::Process.respond_to? :fork
|
10
|
+
|
11
|
+
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
12
|
+
|
13
|
+
IS_OSX = RUBY_PLATFORM.include? 'darwin'
|
14
|
+
|
15
|
+
IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
|
16
|
+
IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
|
17
|
+
|
18
|
+
# @version 5.2.0
|
19
|
+
IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
|
5
20
|
|
6
21
|
def self.jruby?
|
7
22
|
IS_JRUBY
|
8
23
|
end
|
9
24
|
|
10
|
-
|
25
|
+
def self.osx?
|
26
|
+
IS_OSX
|
27
|
+
end
|
11
28
|
|
12
29
|
def self.windows?
|
13
30
|
IS_WINDOWS
|
14
31
|
end
|
32
|
+
|
33
|
+
# @version 5.0.0
|
34
|
+
def self.mri?
|
35
|
+
IS_MRI
|
36
|
+
end
|
37
|
+
|
38
|
+
# @version 5.0.0
|
39
|
+
def self.forkable?
|
40
|
+
HAS_FORK
|
41
|
+
end
|
15
42
|
end
|