puma 5.0.0-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 +1190 -574
- data/README.md +28 -20
- data/bin/puma-wild +3 -9
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +5 -6
- data/docs/fork_worker.md +2 -0
- data/docs/jungle/README.md +0 -4
- data/docs/jungle/rc.d/puma +2 -2
- data/docs/nginx.md +1 -1
- data/docs/restart.md +46 -23
- data/docs/systemd.md +25 -3
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +4 -5
- data/ext/puma_http11/http11_parser.c +64 -64
- data/ext/puma_http11/mini_ssl.c +39 -37
- data/ext/puma_http11/puma_http11.c +25 -12
- data/lib/puma.rb +7 -4
- data/lib/puma/app/status.rb +44 -46
- data/lib/puma/binder.rb +48 -1
- data/lib/puma/cli.rb +4 -0
- data/lib/puma/client.rb +31 -80
- data/lib/puma/cluster.rb +39 -202
- data/lib/puma/cluster/worker.rb +176 -0
- data/lib/puma/cluster/worker_handle.rb +86 -0
- data/lib/puma/configuration.rb +20 -8
- 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/error_logger.rb +2 -2
- data/lib/puma/events.rb +21 -3
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +61 -12
- data/lib/puma/minissl.rb +8 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/reactor.rb +79 -373
- data/lib/puma/request.rb +451 -0
- data/lib/puma/runner.rb +15 -21
- data/lib/puma/server.rb +193 -508
- data/lib/puma/single.rb +3 -2
- data/lib/puma/state_file.rb +5 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +22 -2
- data/lib/puma/util.rb +12 -0
- metadata +9 -6
- data/docs/jungle/upstart/README.md +0 -61
- data/docs/jungle/upstart/puma-manager.conf +0 -31
- data/docs/jungle/upstart/puma.conf +0 -69
- data/lib/puma/accept_nonblock.rb +0 -29
@@ -0,0 +1,176 @@
|
|
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
|
+
server = @server ||= start_server
|
58
|
+
restart_server = Queue.new << true << false
|
59
|
+
|
60
|
+
fork_worker = @options[:fork_worker] && index == 0
|
61
|
+
|
62
|
+
if fork_worker
|
63
|
+
restart_server.clear
|
64
|
+
worker_pids = []
|
65
|
+
Signal.trap "SIGCHLD" do
|
66
|
+
wakeup! if worker_pids.reject! do |p|
|
67
|
+
Process.wait(p, Process::WNOHANG) rescue true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Thread.new do
|
72
|
+
Puma.set_thread_name "worker fork pipe"
|
73
|
+
while (idx = @fork_pipe.gets)
|
74
|
+
idx = idx.to_i
|
75
|
+
if idx == -1 # stop server
|
76
|
+
if restart_server.length > 0
|
77
|
+
restart_server.clear
|
78
|
+
server.begin_restart(true)
|
79
|
+
@launcher.config.run_hooks :before_refork, nil, @launcher.events
|
80
|
+
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
81
|
+
end
|
82
|
+
elsif idx == 0 # restart server
|
83
|
+
restart_server << true << false
|
84
|
+
else # fork worker
|
85
|
+
worker_pids << pid = spawn_worker(idx)
|
86
|
+
@worker_write << "f#{pid}:#{idx}\n" rescue nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Signal.trap "SIGTERM" do
|
93
|
+
@worker_write << "e#{Process.pid}\n" rescue nil
|
94
|
+
restart_server.clear
|
95
|
+
server.stop
|
96
|
+
restart_server << false
|
97
|
+
end
|
98
|
+
|
99
|
+
begin
|
100
|
+
@worker_write << "b#{Process.pid}:#{index}\n"
|
101
|
+
rescue SystemCallError, IOError
|
102
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
103
|
+
STDERR.puts "Master seems to have exited, exiting."
|
104
|
+
return
|
105
|
+
end
|
106
|
+
|
107
|
+
while restart_server.pop
|
108
|
+
server_thread = server.run
|
109
|
+
stat_thread ||= Thread.new(@worker_write) do |io|
|
110
|
+
Puma.set_thread_name "stat payload"
|
111
|
+
base_payload = "p#{Process.pid}"
|
112
|
+
|
113
|
+
while true
|
114
|
+
begin
|
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
|
122
|
+
rescue IOError
|
123
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
124
|
+
break
|
125
|
+
end
|
126
|
+
sleep Const::WORKER_CHECK_INTERVAL
|
127
|
+
end
|
128
|
+
end
|
129
|
+
server_thread.join
|
130
|
+
end
|
131
|
+
|
132
|
+
# Invoke any worker shutdown hooks so they can prevent the worker
|
133
|
+
# exiting until any background operations are completed
|
134
|
+
@launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
|
135
|
+
ensure
|
136
|
+
@worker_write << "t#{Process.pid}\n" rescue nil
|
137
|
+
@worker_write.close
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def spawn_worker(idx)
|
143
|
+
@launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
|
144
|
+
|
145
|
+
pid = fork do
|
146
|
+
new_worker = Worker.new index: idx,
|
147
|
+
master: master,
|
148
|
+
launcher: @launcher,
|
149
|
+
pipes: { check_pipe: @check_pipe,
|
150
|
+
worker_write: @worker_write },
|
151
|
+
server: @server
|
152
|
+
new_worker.run
|
153
|
+
end
|
154
|
+
|
155
|
+
if !pid
|
156
|
+
log "! Complete inability to spawn new workers detected"
|
157
|
+
log "! Seppuku is the only choice."
|
158
|
+
exit! 1
|
159
|
+
end
|
160
|
+
|
161
|
+
@launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
|
162
|
+
pid
|
163
|
+
end
|
164
|
+
|
165
|
+
def wakeup!
|
166
|
+
return unless @wakeup
|
167
|
+
|
168
|
+
begin
|
169
|
+
@wakeup.write "!" unless @wakeup.closed?
|
170
|
+
rescue SystemCallError, IOError
|
171
|
+
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,86 @@
|
|
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 boot!
|
35
|
+
@last_checkin = Time.now
|
36
|
+
@stage = :booted
|
37
|
+
end
|
38
|
+
|
39
|
+
def term?
|
40
|
+
@term
|
41
|
+
end
|
42
|
+
|
43
|
+
def ping!(status)
|
44
|
+
@last_checkin = Time.now
|
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
|
50
|
+
end
|
51
|
+
|
52
|
+
# @see Puma::Cluster#check_workers
|
53
|
+
# @version 5.0.0
|
54
|
+
def ping_timeout
|
55
|
+
@last_checkin +
|
56
|
+
(booted? ?
|
57
|
+
@options[:worker_timeout] :
|
58
|
+
@options[:worker_boot_timeout]
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def term
|
63
|
+
begin
|
64
|
+
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
65
|
+
@signal = "KILL"
|
66
|
+
else
|
67
|
+
@term ||= true
|
68
|
+
@first_term_sent ||= Time.now
|
69
|
+
end
|
70
|
+
Process.kill @signal, @pid if @pid
|
71
|
+
rescue Errno::ESRCH
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def kill
|
76
|
+
@signal = 'KILL'
|
77
|
+
term
|
78
|
+
end
|
79
|
+
|
80
|
+
def hup
|
81
|
+
Process.kill "HUP", @pid
|
82
|
+
rescue Errno::ESRCH
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
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.
|
@@ -108,16 +114,17 @@ module Puma
|
|
108
114
|
#
|
109
115
|
# It also handles loading plugins.
|
110
116
|
#
|
111
|
-
#
|
117
|
+
# [Note:]
|
118
|
+
# `:port` and `:host` are not valid keys. By the time they make it to the
|
112
119
|
# configuration options they are expected to be incorporated into a `:binds` key.
|
113
120
|
# Under the hood the DSL maps `port` and `host` calls to `:binds`
|
114
121
|
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
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
|
121
128
|
#
|
122
129
|
# It is expected that `load` is called on the configuration instance after setting
|
123
130
|
# config. This method expands any values in `config_file` and puts them into the
|
@@ -197,7 +204,8 @@ module Puma
|
|
197
204
|
:logger => STDOUT,
|
198
205
|
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
199
206
|
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
200
|
-
:raise_exception_on_sigterm => true
|
207
|
+
:raise_exception_on_sigterm => true,
|
208
|
+
:max_fast_inline => Const::MAX_FAST_INLINE
|
201
209
|
}
|
202
210
|
end
|
203
211
|
|
@@ -288,6 +296,10 @@ module Puma
|
|
288
296
|
end
|
289
297
|
end
|
290
298
|
|
299
|
+
def final_options
|
300
|
+
@options.final_options
|
301
|
+
end
|
302
|
+
|
291
303
|
def self.temp_path
|
292
304
|
require 'tmpdir'
|
293
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.
|
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
|