puma 5.0.4-java → 5.1.0-java
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 +46 -46
- data/README.md +25 -17
- data/docs/compile_options.md +19 -0
- data/docs/fork_worker.md +2 -0
- data/docs/systemd.md +24 -2
- data/ext/puma_http11/extconf.rb +4 -5
- data/ext/puma_http11/http11_parser.c +64 -64
- data/ext/puma_http11/puma_http11.c +8 -2
- data/lib/puma.rb +2 -2
- data/lib/puma/app/status.rb +4 -7
- data/lib/puma/binder.rb +37 -0
- data/lib/puma/cli.rb +4 -0
- data/lib/puma/client.rb +2 -7
- data/lib/puma/cluster.rb +10 -6
- data/lib/puma/cluster/worker.rb +8 -2
- data/lib/puma/cluster/worker_handle.rb +5 -2
- data/lib/puma/configuration.rb +12 -1
- data/lib/puma/const.rb +11 -3
- data/lib/puma/control_cli.rb +71 -70
- data/lib/puma/dsl.rb +67 -19
- data/lib/puma/events.rb +16 -0
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +49 -4
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/reactor.rb +12 -10
- data/lib/puma/request.rb +19 -6
- data/lib/puma/runner.rb +11 -4
- data/lib/puma/server.rb +5 -4
- data/lib/puma/state_file.rb +5 -3
- data/lib/puma/systemd.rb +46 -0
- metadata +5 -2
@@ -40,7 +40,9 @@ static VALUE global_http_version;
|
|
40
40
|
static VALUE global_request_path;
|
41
41
|
|
42
42
|
/** Defines common length and error messages for input length validation. */
|
43
|
-
#define
|
43
|
+
#define QUOTE(s) #s
|
44
|
+
#define EXPLAND_MAX_LENGHT_VALUE(s) QUOTE(s)
|
45
|
+
#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " EXPLAND_MAX_LENGHT_VALUE(length) " allowed length (was %d)"
|
44
46
|
|
45
47
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
46
48
|
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
@@ -50,12 +52,16 @@ static VALUE global_request_path;
|
|
50
52
|
|
51
53
|
|
52
54
|
/* Defines the maximum allowed lengths for various input elements.*/
|
55
|
+
#ifndef PUMA_QUERY_STRING_MAX_LENGTH
|
56
|
+
#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
|
57
|
+
#endif
|
58
|
+
|
53
59
|
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
54
60
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
55
61
|
DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
|
56
62
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
57
63
|
DEF_MAX_LENGTH(REQUEST_PATH, 8192);
|
58
|
-
DEF_MAX_LENGTH(QUERY_STRING,
|
64
|
+
DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
59
65
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
60
66
|
|
61
67
|
struct common_field {
|
data/lib/puma.rb
CHANGED
@@ -12,6 +12,7 @@ require 'thread'
|
|
12
12
|
|
13
13
|
require 'puma/puma_http11'
|
14
14
|
require 'puma/detect'
|
15
|
+
require 'puma/json'
|
15
16
|
|
16
17
|
module Puma
|
17
18
|
autoload :Const, 'puma/const'
|
@@ -25,8 +26,7 @@ module Puma
|
|
25
26
|
|
26
27
|
# @!attribute [rw] stats_object
|
27
28
|
def self.stats
|
28
|
-
|
29
|
-
@get_stats.stats.to_json
|
29
|
+
Puma::JSON.generate @get_stats.stats
|
30
30
|
end
|
31
31
|
|
32
32
|
# @!attribute [r] stats_hash
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'puma/json'
|
2
3
|
|
3
4
|
module Puma
|
4
5
|
module App
|
@@ -22,10 +23,6 @@ module Puma
|
|
22
23
|
return rack_response(403, 'Invalid auth token', 'text/plain')
|
23
24
|
end
|
24
25
|
|
25
|
-
if env['PATH_INFO'] =~ /\/(gc-stats|stats|thread-backtraces)$/
|
26
|
-
require 'json'
|
27
|
-
end
|
28
|
-
|
29
26
|
# resp_type is processed by following case statement, return
|
30
27
|
# is a number (status) or a string used as the body of a 200 response
|
31
28
|
resp_type =
|
@@ -49,17 +46,17 @@ module Puma
|
|
49
46
|
GC.start ; 200
|
50
47
|
|
51
48
|
when 'gc-stats'
|
52
|
-
GC.stat
|
49
|
+
Puma::JSON.generate GC.stat
|
53
50
|
|
54
51
|
when 'stats'
|
55
|
-
@launcher.stats
|
52
|
+
Puma::JSON.generate @launcher.stats
|
56
53
|
|
57
54
|
when 'thread-backtraces'
|
58
55
|
backtraces = []
|
59
56
|
@launcher.thread_status do |name, backtrace|
|
60
57
|
backtraces << { name: name, backtrace: backtrace }
|
61
58
|
end
|
62
|
-
backtraces
|
59
|
+
Puma::JSON.generate backtraces
|
63
60
|
|
64
61
|
else
|
65
62
|
return rack_response(404, "Unsupported action", 'text/plain')
|
data/lib/puma/binder.rb
CHANGED
@@ -111,6 +111,43 @@ module Puma
|
|
111
111
|
["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
|
112
112
|
end
|
113
113
|
|
114
|
+
# Synthesize binds from systemd socket activation
|
115
|
+
#
|
116
|
+
# When systemd socket activation is enabled, it can be tedious to keep the
|
117
|
+
# binds in sync. This method can synthesize any binds based on the received
|
118
|
+
# activated sockets. Any existing matching binds will be respected.
|
119
|
+
#
|
120
|
+
# When only_matching is true in, all binds that do not match an activated
|
121
|
+
# socket is removed in place.
|
122
|
+
#
|
123
|
+
# It's a noop if no activated sockets were received.
|
124
|
+
def synthesize_binds_from_activated_fs(binds, only_matching)
|
125
|
+
return binds unless activated_sockets.any?
|
126
|
+
|
127
|
+
activated_binds = []
|
128
|
+
|
129
|
+
activated_sockets.keys.each do |proto, addr, port|
|
130
|
+
if port
|
131
|
+
tcp_url = "#{proto}://#{addr}:#{port}"
|
132
|
+
ssl_url = "ssl://#{addr}:#{port}"
|
133
|
+
ssl_url_prefix = "#{ssl_url}?"
|
134
|
+
|
135
|
+
existing = binds.find { |bind| bind == tcp_url || bind == ssl_url || bind.start_with?(ssl_url_prefix) }
|
136
|
+
|
137
|
+
activated_binds << (existing || tcp_url)
|
138
|
+
else
|
139
|
+
# TODO: can there be a SSL bind without a port?
|
140
|
+
activated_binds << "#{proto}://#{addr}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
if only_matching
|
145
|
+
activated_binds
|
146
|
+
else
|
147
|
+
binds | activated_binds
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
114
151
|
def parse(binds, logger, log_msg = 'Listening')
|
115
152
|
binds.each do |str|
|
116
153
|
uri = URI.parse str
|
data/lib/puma/cli.rb
CHANGED
@@ -104,6 +104,10 @@ module Puma
|
|
104
104
|
user_config.bind arg
|
105
105
|
end
|
106
106
|
|
107
|
+
o.on "--bind-to-activated-sockets [only]", "Bind to all activated sockets" do |arg|
|
108
|
+
user_config.bind_to_activated_sockets(arg || true)
|
109
|
+
end
|
110
|
+
|
107
111
|
o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
|
108
112
|
file_config.load arg
|
109
113
|
end
|
data/lib/puma/client.rb
CHANGED
@@ -239,13 +239,8 @@ module Puma
|
|
239
239
|
# @version 5.0.0
|
240
240
|
#
|
241
241
|
def can_close?
|
242
|
-
# Allow connection to close if
|
243
|
-
|
244
|
-
#
|
245
|
-
# From RFC 2616 section 8.1.4:
|
246
|
-
# Servers SHOULD always respond to at least one request per connection,
|
247
|
-
# if at all possible.
|
248
|
-
@requests_served > 0 && @parsed_bytes == 0
|
242
|
+
# Allow connection to close if we're not in the middle of parsing a request.
|
243
|
+
@parsed_bytes == 0
|
249
244
|
end
|
250
245
|
|
251
246
|
private
|
data/lib/puma/cluster.rb
CHANGED
@@ -114,7 +114,7 @@ module Puma
|
|
114
114
|
debug "Workers to cull: #{workers_to_cull.inspect}"
|
115
115
|
|
116
116
|
workers_to_cull.each do |worker|
|
117
|
-
log "- Worker #{worker.index} (
|
117
|
+
log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
|
118
118
|
worker.term
|
119
119
|
end
|
120
120
|
end
|
@@ -329,15 +329,19 @@ module Puma
|
|
329
329
|
|
330
330
|
output_header "cluster"
|
331
331
|
|
332
|
-
|
332
|
+
# This is aligned with the output from Runner, see Runner#output_header
|
333
|
+
log "* Workers: #{@options[:workers]}"
|
333
334
|
|
334
|
-
|
335
|
+
# Threads explicitly marked as fork safe will be ignored.
|
336
|
+
# Used in Rails, but may be used by anyone.
|
337
|
+
before = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
335
338
|
|
336
339
|
if preload?
|
340
|
+
log "* Restarts: (\u2714) hot (\u2716) phased"
|
337
341
|
log "* Preloading application"
|
338
342
|
load_and_bind
|
339
343
|
|
340
|
-
after = Thread.list
|
344
|
+
after = Thread.list.reject { |t| t.thread_variable_get(:fork_safe) }
|
341
345
|
|
342
346
|
if after.size > before.size
|
343
347
|
threads = (after - before)
|
@@ -351,7 +355,7 @@ module Puma
|
|
351
355
|
end
|
352
356
|
end
|
353
357
|
else
|
354
|
-
log "*
|
358
|
+
log "* Restarts: (\u2714) hot (\u2714) phased"
|
355
359
|
|
356
360
|
unless @launcher.config.app_configured?
|
357
361
|
error "No application configured, nothing to run"
|
@@ -430,7 +434,7 @@ module Puma
|
|
430
434
|
case req
|
431
435
|
when "b"
|
432
436
|
w.boot!
|
433
|
-
log "- Worker #{w.index} (
|
437
|
+
log "- Worker #{w.index} (PID: #{pid}) booted, phase: #{w.phase}"
|
434
438
|
@next_check = Time.now
|
435
439
|
when "e"
|
436
440
|
# external term, see worker method, Signal.trap "SIGTERM"
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -108,11 +108,17 @@ module Puma
|
|
108
108
|
server_thread = server.run
|
109
109
|
stat_thread ||= Thread.new(@worker_write) do |io|
|
110
110
|
Puma.set_thread_name "stat payload"
|
111
|
+
base_payload = "p#{Process.pid}"
|
111
112
|
|
112
113
|
while true
|
113
114
|
begin
|
114
|
-
|
115
|
-
|
115
|
+
b = server.backlog || 0
|
116
|
+
r = server.running || 0
|
117
|
+
t = server.pool_capacity || 0
|
118
|
+
m = server.max_threads || 0
|
119
|
+
rc = server.requests_count || 0
|
120
|
+
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
|
121
|
+
io << payload
|
116
122
|
rescue IOError
|
117
123
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
118
124
|
break
|
@@ -42,8 +42,11 @@ module Puma
|
|
42
42
|
|
43
43
|
def ping!(status)
|
44
44
|
@last_checkin = Time.now
|
45
|
-
|
46
|
-
@last_status =
|
45
|
+
captures = status.match(/{ "backlog":(?<backlog>\d*), "running":(?<running>\d*), "pool_capacity":(?<pool_capacity>\d*), "max_threads": (?<max_threads>\d*), "requests_count": (?<requests_count>\d*) }/)
|
46
|
+
@last_status = captures.names.inject({}) do |hash, key|
|
47
|
+
hash[key.to_sym] = captures[key].to_i
|
48
|
+
hash
|
49
|
+
end
|
47
50
|
end
|
48
51
|
|
49
52
|
# @see Puma::Cluster#check_workers
|
data/lib/puma/configuration.rb
CHANGED
@@ -92,6 +92,12 @@ module Puma
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
def final_options
|
97
|
+
default_options
|
98
|
+
.merge(file_options)
|
99
|
+
.merge(user_options)
|
100
|
+
end
|
95
101
|
end
|
96
102
|
|
97
103
|
# The main configuration class of Puma.
|
@@ -198,7 +204,8 @@ module Puma
|
|
198
204
|
:logger => STDOUT,
|
199
205
|
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
200
206
|
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
201
|
-
:raise_exception_on_sigterm => true
|
207
|
+
:raise_exception_on_sigterm => true,
|
208
|
+
:max_fast_inline => Const::MAX_FAST_INLINE
|
202
209
|
}
|
203
210
|
end
|
204
211
|
|
@@ -289,6 +296,10 @@ module Puma
|
|
289
296
|
end
|
290
297
|
end
|
291
298
|
|
299
|
+
def final_options
|
300
|
+
@options.final_options
|
301
|
+
end
|
302
|
+
|
292
303
|
def self.temp_path
|
293
304
|
require 'tmpdir'
|
294
305
|
|
data/lib/puma/const.rb
CHANGED
@@ -100,8 +100,8 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "5.0
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "5.1.0".freeze
|
104
|
+
CODE_NAME = "At Your Service".freeze
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
107
107
|
|
@@ -228,7 +228,6 @@ module Puma
|
|
228
228
|
COLON = ": ".freeze
|
229
229
|
|
230
230
|
NEWLINE = "\n".freeze
|
231
|
-
HTTP_INJECTION_REGEX = /[\r\n]/.freeze
|
232
231
|
|
233
232
|
HIJACK_P = "rack.hijack?".freeze
|
234
233
|
HIJACK = "rack.hijack".freeze
|
@@ -239,5 +238,14 @@ module Puma
|
|
239
238
|
# Mininum interval to checks worker health
|
240
239
|
WORKER_CHECK_INTERVAL = 5
|
241
240
|
|
241
|
+
# Illegal character in the key or value of response header
|
242
|
+
DQUOTE = "\"".freeze
|
243
|
+
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
244
|
+
ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
|
245
|
+
# header values can contain HTAB?
|
246
|
+
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
247
|
+
|
248
|
+
# Banned keys of response header
|
249
|
+
BANNED_HEADER_KEY = /rack.|status/.freeze
|
242
250
|
end
|
243
251
|
end
|
data/lib/puma/control_cli.rb
CHANGED
@@ -11,10 +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
|
15
37
|
|
16
38
|
# @version 5.0.0
|
17
|
-
PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}
|
39
|
+
PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}.freeze
|
18
40
|
|
19
41
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
20
42
|
@state = nil
|
@@ -33,7 +55,7 @@ module Puma
|
|
33
55
|
@cli_options = {}
|
34
56
|
|
35
57
|
opts = OptionParser.new do |o|
|
36
|
-
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("|")})"
|
37
59
|
|
38
60
|
o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
|
39
61
|
@state = arg
|
@@ -74,7 +96,7 @@ module Puma
|
|
74
96
|
end
|
75
97
|
|
76
98
|
o.on_tail("-V", "--version", "Show version") do
|
77
|
-
puts Const::PUMA_VERSION
|
99
|
+
@stdout.puts Const::PUMA_VERSION
|
78
100
|
exit
|
79
101
|
end
|
80
102
|
end
|
@@ -86,10 +108,10 @@ module Puma
|
|
86
108
|
|
87
109
|
# check presence of command
|
88
110
|
unless @command
|
89
|
-
raise "Available commands: #{
|
111
|
+
raise "Available commands: #{CMD_PATH_SIG_MAP.keys.join(", ")}"
|
90
112
|
end
|
91
113
|
|
92
|
-
unless
|
114
|
+
unless CMD_PATH_SIG_MAP.key? @command
|
93
115
|
raise "Invalid command: #{@command}"
|
94
116
|
end
|
95
117
|
|
@@ -134,7 +156,7 @@ module Puma
|
|
134
156
|
@pid = sf.pid
|
135
157
|
elsif @pidfile
|
136
158
|
# get pid from pid_file
|
137
|
-
File.
|
159
|
+
@pid = File.read(@pidfile, mode: 'rb:UTF-8').to_i
|
138
160
|
end
|
139
161
|
end
|
140
162
|
|
@@ -142,24 +164,27 @@ module Puma
|
|
142
164
|
uri = URI.parse @control_url
|
143
165
|
|
144
166
|
# create server object by scheme
|
145
|
-
server =
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
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
|
+
UNIXSocket.new "#{uri.host}#{uri.path}"
|
180
|
+
else
|
181
|
+
raise "Invalid scheme: #{uri.scheme}"
|
182
|
+
end
|
183
|
+
|
184
|
+
if @command == 'status'
|
185
|
+
message 'Puma is started'
|
186
|
+
elsif NO_REQ_COMMANDS.include? @command
|
187
|
+
raise "Invalid request command: #{@command}"
|
163
188
|
else
|
164
189
|
url = "/#{@command}"
|
165
190
|
|
@@ -167,10 +192,10 @@ module Puma
|
|
167
192
|
url = url + "?token=#{@control_auth_token}"
|
168
193
|
end
|
169
194
|
|
170
|
-
server
|
195
|
+
server.syswrite "GET #{url} HTTP/1.0\r\n\r\n"
|
171
196
|
|
172
197
|
unless data = server.read
|
173
|
-
raise
|
198
|
+
raise 'Server closed connection before responding'
|
174
199
|
end
|
175
200
|
|
176
201
|
response = data.split("\r\n")
|
@@ -179,13 +204,13 @@ module Puma
|
|
179
204
|
raise "Server sent empty response"
|
180
205
|
end
|
181
206
|
|
182
|
-
|
207
|
+
@http, @code, @message = response.first.split(' ',3)
|
183
208
|
|
184
|
-
if @code ==
|
185
|
-
raise
|
186
|
-
elsif @code ==
|
209
|
+
if @code == '403'
|
210
|
+
raise 'Unauthorized access to server (wrong auth token)'
|
211
|
+
elsif @code == '404'
|
187
212
|
raise "Command error: #{response.last}"
|
188
|
-
elsif @code !=
|
213
|
+
elsif @code != '200'
|
189
214
|
raise "Bad response from server: #{@code}"
|
190
215
|
end
|
191
216
|
|
@@ -194,7 +219,7 @@ module Puma
|
|
194
219
|
end
|
195
220
|
ensure
|
196
221
|
if server
|
197
|
-
if uri.scheme ==
|
222
|
+
if uri.scheme == 'ssl'
|
198
223
|
server.sysclose
|
199
224
|
else
|
200
225
|
server.close unless server.closed?
|
@@ -204,51 +229,28 @@ module Puma
|
|
204
229
|
|
205
230
|
def send_signal
|
206
231
|
unless @pid
|
207
|
-
raise
|
232
|
+
raise 'Neither pid nor control url available'
|
208
233
|
end
|
209
234
|
|
210
235
|
begin
|
236
|
+
sig = CMD_PATH_SIG_MAP[@command]
|
211
237
|
|
212
|
-
|
213
|
-
|
214
|
-
Process.kill "SIGUSR2", @pid
|
215
|
-
|
216
|
-
when "halt"
|
217
|
-
Process.kill "QUIT", @pid
|
218
|
-
|
219
|
-
when "stop"
|
220
|
-
Process.kill "SIGTERM", @pid
|
221
|
-
|
222
|
-
when "stats"
|
223
|
-
puts "Stats not available via pid only"
|
224
|
-
return
|
225
|
-
|
226
|
-
when "reload-worker-directory"
|
227
|
-
puts "reload-worker-directory not available via pid only"
|
238
|
+
if sig.nil?
|
239
|
+
@stdout.puts "'#{@command}' not available via pid only"
|
228
240
|
return
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
when "status"
|
241
|
+
elsif sig.start_with? 'SIG'
|
242
|
+
Process.kill sig, @pid
|
243
|
+
elsif @command == 'status'
|
234
244
|
begin
|
235
245
|
Process.kill 0, @pid
|
236
|
-
puts
|
246
|
+
@stdout.puts 'Puma is started'
|
237
247
|
rescue Errno::ESRCH
|
238
|
-
raise
|
248
|
+
raise 'Puma is not running'
|
239
249
|
end
|
240
|
-
|
241
|
-
return
|
242
|
-
|
243
|
-
when "refork"
|
244
|
-
Process.kill "SIGURG", @pid
|
245
|
-
|
246
|
-
else
|
247
250
|
return
|
248
251
|
end
|
249
|
-
|
250
252
|
rescue SystemCallError
|
251
|
-
if @command ==
|
253
|
+
if @command == 'restart'
|
252
254
|
start
|
253
255
|
else
|
254
256
|
raise "No pid '#{@pid}' found"
|
@@ -259,14 +261,13 @@ module Puma
|
|
259
261
|
end
|
260
262
|
|
261
263
|
def run
|
262
|
-
return start if @command ==
|
263
|
-
|
264
|
+
return start if @command == 'start'
|
264
265
|
prepare_configuration
|
265
266
|
|
266
|
-
if Puma.windows?
|
267
|
+
if Puma.windows? || @control_url
|
267
268
|
send_request
|
268
269
|
else
|
269
|
-
|
270
|
+
send_signal
|
270
271
|
end
|
271
272
|
|
272
273
|
rescue => e
|