puma 4.0.0 → 4.1.1
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 +60 -4
- data/README.md +63 -26
- data/ext/puma_http11/extconf.rb +8 -0
- data/ext/puma_http11/mini_ssl.c +62 -8
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +4 -0
- data/lib/puma.rb +2 -0
- data/lib/puma/accept_nonblock.rb +7 -1
- data/lib/puma/app/status.rb +4 -0
- data/lib/puma/binder.rb +3 -1
- data/lib/puma/client.rb +22 -6
- data/lib/puma/cluster.rb +34 -36
- data/lib/puma/configuration.rb +2 -2
- data/lib/puma/const.rb +5 -2
- data/lib/puma/control_cli.rb +0 -2
- data/lib/puma/dsl.rb +244 -80
- data/lib/puma/events.rb +4 -1
- data/lib/puma/launcher.rb +5 -3
- data/lib/puma/minissl.rb +25 -19
- data/lib/puma/plugin/tmp_restart.rb +2 -0
- data/lib/puma/rack/builder.rb +2 -0
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +1 -1
- data/lib/puma/runner.rb +1 -0
- data/lib/puma/server.rb +19 -12
- data/lib/puma/single.rb +1 -1
- data/lib/rack/handler/puma.rb +3 -1
- data/tools/jungle/init.d/puma +1 -1
- metadata +2 -2
@@ -166,6 +166,10 @@ public class MiniSSL extends RubyObject {
|
|
166
166
|
protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
|
167
167
|
}
|
168
168
|
|
169
|
+
if(miniSSLContext.callMethod(threadContext, "no_tlsv1_1").isTrue()) {
|
170
|
+
protocols = new String[] { "TLSv1.2" };
|
171
|
+
}
|
172
|
+
|
169
173
|
engine.setEnabledProtocols(protocols);
|
170
174
|
engine.setUseClientMode(false);
|
171
175
|
|
data/lib/puma.rb
CHANGED
data/lib/puma/accept_nonblock.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'openssl'
|
2
4
|
|
3
5
|
module OpenSSL
|
@@ -13,7 +15,11 @@ module OpenSSL
|
|
13
15
|
ssl.accept if @start_immediately
|
14
16
|
ssl
|
15
17
|
rescue SSLError => ex
|
16
|
-
|
18
|
+
if ssl
|
19
|
+
ssl.close
|
20
|
+
else
|
21
|
+
sock.close
|
22
|
+
end
|
17
23
|
raise ex
|
18
24
|
end
|
19
25
|
end
|
data/lib/puma/app/status.rb
CHANGED
data/lib/puma/binder.rb
CHANGED
@@ -53,7 +53,8 @@ module Puma
|
|
53
53
|
@unix_paths.each do |i|
|
54
54
|
# Errno::ENOENT is intermittently raised
|
55
55
|
begin
|
56
|
-
|
56
|
+
unix_socket = UNIXSocket.new i
|
57
|
+
unix_socket.close
|
57
58
|
rescue Errno::ENOENT
|
58
59
|
end
|
59
60
|
end
|
@@ -194,6 +195,7 @@ module Puma
|
|
194
195
|
end
|
195
196
|
|
196
197
|
ctx.no_tlsv1 = true if params['no_tlsv1'] == 'true'
|
198
|
+
ctx.no_tlsv1_1 = true if params['no_tlsv1_1'] == 'true'
|
197
199
|
|
198
200
|
if params['verify_mode']
|
199
201
|
ctx.verify_mode = case params['verify_mode']
|
data/lib/puma/client.rb
CHANGED
@@ -68,6 +68,8 @@ module Puma
|
|
68
68
|
@remote_addr_header = nil
|
69
69
|
|
70
70
|
@body_remain = 0
|
71
|
+
|
72
|
+
@in_last_chunk = false
|
71
73
|
end
|
72
74
|
|
73
75
|
attr_reader :env, :to_io, :body, :io, :timeout_at, :ready, :hijacked,
|
@@ -108,6 +110,7 @@ module Puma
|
|
108
110
|
@ready = false
|
109
111
|
@body_remain = 0
|
110
112
|
@peerip = nil
|
113
|
+
@in_last_chunk = false
|
111
114
|
|
112
115
|
if @buffer
|
113
116
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
@@ -166,7 +169,7 @@ module Puma
|
|
166
169
|
chunk = chunk[@partial_part_left..-1]
|
167
170
|
@partial_part_left = 0
|
168
171
|
else
|
169
|
-
@body << chunk
|
172
|
+
@body << chunk if @partial_part_left > 2 # don't include the last \r\n
|
170
173
|
@partial_part_left -= chunk.size
|
171
174
|
return false
|
172
175
|
end
|
@@ -184,12 +187,20 @@ module Puma
|
|
184
187
|
if line.end_with?("\r\n")
|
185
188
|
len = line.strip.to_i(16)
|
186
189
|
if len == 0
|
190
|
+
@in_last_chunk = true
|
187
191
|
@body.rewind
|
188
192
|
rest = io.read
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
+
last_crlf_size = "\r\n".bytesize
|
194
|
+
if rest.bytesize < last_crlf_size
|
195
|
+
@buffer = nil
|
196
|
+
@partial_part_left = last_crlf_size - rest.bytesize
|
197
|
+
return false
|
198
|
+
else
|
199
|
+
@buffer = rest[last_crlf_size..-1]
|
200
|
+
@buffer = nil if @buffer.empty?
|
201
|
+
set_ready
|
202
|
+
return true
|
203
|
+
end
|
193
204
|
end
|
194
205
|
|
195
206
|
len += 2
|
@@ -219,7 +230,12 @@ module Puma
|
|
219
230
|
end
|
220
231
|
end
|
221
232
|
|
222
|
-
|
233
|
+
if @in_last_chunk
|
234
|
+
set_ready
|
235
|
+
true
|
236
|
+
else
|
237
|
+
false
|
238
|
+
end
|
223
239
|
end
|
224
240
|
|
225
241
|
def read_chunked_body
|
data/lib/puma/cluster.rb
CHANGED
@@ -35,34 +35,10 @@ module Puma
|
|
35
35
|
@workers.each { |x| x.term }
|
36
36
|
|
37
37
|
begin
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
rescue Errno::ECHILD
|
43
|
-
# child is already terminated
|
44
|
-
end
|
45
|
-
end
|
46
|
-
else
|
47
|
-
# below code is for a bug in Ruby 2.6+, above waitpid call hangs
|
48
|
-
t_st = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
49
|
-
pids = @workers.map(&:pid)
|
50
|
-
loop do
|
51
|
-
pids.reject! do |w_pid|
|
52
|
-
begin
|
53
|
-
if Process.waitpid(w_pid, Process::WNOHANG)
|
54
|
-
log " worker status: #{$?}"
|
55
|
-
true
|
56
|
-
end
|
57
|
-
rescue Errno::ECHILD
|
58
|
-
true # child is already terminated
|
59
|
-
end
|
60
|
-
end
|
61
|
-
break if pids.empty?
|
62
|
-
sleep 0.5
|
63
|
-
end
|
64
|
-
t_end = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
65
|
-
log format(" worker shutdown time: %6.2f", t_end - t_st)
|
38
|
+
loop do
|
39
|
+
wait_workers
|
40
|
+
break if @workers.empty?
|
41
|
+
sleep 0.2
|
66
42
|
end
|
67
43
|
rescue Interrupt
|
68
44
|
log "! Cancelled waiting for workers"
|
@@ -95,12 +71,14 @@ module Puma
|
|
95
71
|
@signal = "TERM"
|
96
72
|
@options = options
|
97
73
|
@first_term_sent = nil
|
74
|
+
@started_at = Time.now
|
98
75
|
@last_checkin = Time.now
|
99
76
|
@last_status = '{}'
|
100
77
|
@dead = false
|
78
|
+
@term = false
|
101
79
|
end
|
102
80
|
|
103
|
-
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status
|
81
|
+
attr_reader :index, :pid, :phase, :signal, :last_checkin, :last_status, :started_at
|
104
82
|
|
105
83
|
def booted?
|
106
84
|
@stage == :booted
|
@@ -119,6 +97,10 @@ module Puma
|
|
119
97
|
@dead = true
|
120
98
|
end
|
121
99
|
|
100
|
+
def term?
|
101
|
+
@term
|
102
|
+
end
|
103
|
+
|
122
104
|
def ping!(status)
|
123
105
|
@last_checkin = Time.now
|
124
106
|
@last_status = status
|
@@ -133,9 +115,9 @@ module Puma
|
|
133
115
|
if @first_term_sent && (Time.now - @first_term_sent) > @options[:worker_shutdown_timeout]
|
134
116
|
@signal = "KILL"
|
135
117
|
else
|
118
|
+
@term ||= true
|
136
119
|
@first_term_sent ||= Time.now
|
137
120
|
end
|
138
|
-
|
139
121
|
Process.kill @signal, @pid
|
140
122
|
rescue Errno::ESRCH
|
141
123
|
end
|
@@ -226,10 +208,7 @@ module Puma
|
|
226
208
|
# during this loop by giving the kernel time to kill them.
|
227
209
|
sleep 1 if any
|
228
210
|
|
229
|
-
|
230
|
-
|
231
|
-
@workers.reject!(&:dead?)
|
232
|
-
|
211
|
+
wait_workers
|
233
212
|
cull_workers
|
234
213
|
spawn_workers
|
235
214
|
|
@@ -376,8 +355,8 @@ module Puma
|
|
376
355
|
def stats
|
377
356
|
old_worker_count = @workers.count { |w| w.phase != @phase }
|
378
357
|
booted_worker_count = @workers.count { |w| w.booted? }
|
379
|
-
worker_status = '[' + @workers.map { |w| %Q!{ "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
|
380
|
-
%Q!{ "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
|
358
|
+
worker_status = '[' + @workers.map { |w| %Q!{ "started_at": "#{w.started_at.utc.iso8601}", "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
|
359
|
+
%Q!{ "started_at": "#{@started_at.utc.iso8601}", "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
|
381
360
|
end
|
382
361
|
|
383
362
|
def preload?
|
@@ -551,5 +530,24 @@ module Puma
|
|
551
530
|
@wakeup.close
|
552
531
|
end
|
553
532
|
end
|
533
|
+
|
534
|
+
private
|
535
|
+
|
536
|
+
# loops thru @workers, removing workers that exited, and calling
|
537
|
+
# `#term` if needed
|
538
|
+
def wait_workers
|
539
|
+
@workers.reject! do |w|
|
540
|
+
begin
|
541
|
+
if Process.wait(w.pid, Process::WNOHANG)
|
542
|
+
true
|
543
|
+
else
|
544
|
+
w.term if w.term?
|
545
|
+
nil
|
546
|
+
end
|
547
|
+
rescue Errno::ECHILD
|
548
|
+
true # child is already terminated
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
554
552
|
end
|
555
553
|
end
|
data/lib/puma/configuration.rb
CHANGED
@@ -20,7 +20,7 @@ module Puma
|
|
20
20
|
# In this class any "user" specified options take precedence over any
|
21
21
|
# "file" specified options, take precedence over any "default" options.
|
22
22
|
#
|
23
|
-
# User input is
|
23
|
+
# User input is preferred over "defaults":
|
24
24
|
# user_options = { foo: "bar" }
|
25
25
|
# default_options = { foo: "zoo" }
|
26
26
|
# options = UserFileDefaultOptions.new(user_options, default_options)
|
@@ -32,7 +32,7 @@ module Puma
|
|
32
32
|
# puts options.all_of(:foo)
|
33
33
|
# # => ["bar", "zoo"]
|
34
34
|
#
|
35
|
-
# A "file" option can be set. This config will be
|
35
|
+
# A "file" option can be set. This config will be preferred over "default" options
|
36
36
|
# but will defer to any available "user" specified options.
|
37
37
|
#
|
38
38
|
# user_options = { foo: "bar" }
|
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 = "4.
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "4.1.1".freeze
|
104
|
+
CODE_NAME = "Fourth and One".freeze
|
105
105
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
106
106
|
|
107
107
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
@@ -160,6 +160,9 @@ module Puma
|
|
160
160
|
LINE_END = "\r\n".freeze
|
161
161
|
REMOTE_ADDR = "REMOTE_ADDR".freeze
|
162
162
|
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
|
163
|
+
HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
|
164
|
+
HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
|
165
|
+
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
|
163
166
|
|
164
167
|
SERVER_NAME = "SERVER_NAME".freeze
|
165
168
|
SERVER_PORT = "SERVER_PORT".freeze
|
data/lib/puma/control_cli.rb
CHANGED
@@ -101,7 +101,6 @@ module Puma
|
|
101
101
|
|
102
102
|
rescue => e
|
103
103
|
@stdout.puts e.message
|
104
|
-
@stdout.puts e.backtrace
|
105
104
|
exit 1
|
106
105
|
end
|
107
106
|
|
@@ -244,7 +243,6 @@ module Puma
|
|
244
243
|
|
245
244
|
rescue => e
|
246
245
|
message e.message
|
247
|
-
message e.backtrace
|
248
246
|
exit 1
|
249
247
|
end
|
250
248
|
|
data/lib/puma/dsl.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'puma/const'
|
4
4
|
|
5
5
|
module Puma
|
6
|
-
# The methods that are available for use inside the
|
6
|
+
# The methods that are available for use inside the configuration file.
|
7
7
|
# These same methods are used in Puma cli and the rack handler
|
8
8
|
# internally.
|
9
9
|
#
|
@@ -28,7 +28,8 @@ module Puma
|
|
28
28
|
# puts config.options[:binds]
|
29
29
|
# # => "tcp://127.0.0.1:3002"
|
30
30
|
#
|
31
|
-
#
|
31
|
+
# You can also find many examples being used by the test suite in
|
32
|
+
# +test/config+.
|
32
33
|
class DSL
|
33
34
|
include ConfigDefault
|
34
35
|
|
@@ -81,9 +82,22 @@ module Puma
|
|
81
82
|
@plugins << @config.load_plugin(name)
|
82
83
|
end
|
83
84
|
|
84
|
-
# Use
|
85
|
-
# be the
|
85
|
+
# Use an object or block as the rack application. This allows the
|
86
|
+
# configuration file to be the application itself.
|
86
87
|
#
|
88
|
+
# @example
|
89
|
+
# app do |env|
|
90
|
+
# body = 'Hello, World!'
|
91
|
+
#
|
92
|
+
# [
|
93
|
+
# 200,
|
94
|
+
# {
|
95
|
+
# 'Content-Type' => 'text/plain',
|
96
|
+
# 'Content-Length' => body.length.to_s
|
97
|
+
# },
|
98
|
+
# [body]
|
99
|
+
# ]
|
100
|
+
# end
|
87
101
|
def app(obj=nil, &block)
|
88
102
|
obj ||= block
|
89
103
|
|
@@ -92,9 +106,20 @@ module Puma
|
|
92
106
|
@options[:app] = obj
|
93
107
|
end
|
94
108
|
|
95
|
-
# Start the Puma control rack
|
96
|
-
# with to control the main server.
|
109
|
+
# Start the Puma control rack application on +url+. This application can
|
110
|
+
# be communicated with to control the main server. Additionally, you can
|
111
|
+
# provide an authentication token, so all requests to the control server
|
112
|
+
# will need to include that token as a query parameter. This allows for
|
113
|
+
# simple authentication.
|
114
|
+
#
|
115
|
+
# Check out {Puma::App::Status} to see what the app has available.
|
97
116
|
#
|
117
|
+
# @example
|
118
|
+
# activate_control_app 'unix:///var/run/pumactl.sock'
|
119
|
+
# @example
|
120
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
121
|
+
# @example
|
122
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
98
123
|
def activate_control_app(url="auto", opts={})
|
99
124
|
if url == "auto"
|
100
125
|
path = Configuration.temp_path
|
@@ -127,22 +152,29 @@ module Puma
|
|
127
152
|
@options[:config_files] << file
|
128
153
|
end
|
129
154
|
|
130
|
-
#
|
131
|
-
# protocols.
|
155
|
+
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
156
|
+
# accepted protocols. Multiple urls can be bound to, calling `bind` does
|
157
|
+
# not overwrite previous bindings.
|
132
158
|
#
|
133
|
-
#
|
159
|
+
# The default is "tcp://0.0.0.0:9292".
|
134
160
|
#
|
135
|
-
#
|
136
|
-
# bind('unix:///var/run/puma.sock?backlog=2048')
|
161
|
+
# You can use query parameters within the url to specify options:
|
137
162
|
#
|
138
|
-
#
|
139
|
-
#
|
163
|
+
# - Set the socket backlog depth with +backlog+, default is 1024.
|
164
|
+
# - Set up an SSL certificate with +key+ & +cert+.
|
165
|
+
# - Set whether to optimize for low latency instead of throughput with
|
166
|
+
# +low_latency+, default is to optimize for low latency. This is done
|
167
|
+
# via +Socket::TCP_NODELAY+.
|
168
|
+
# - Set socket permissions with +umask+.
|
140
169
|
#
|
141
|
-
# @example
|
142
|
-
# bind
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
170
|
+
# @example Backlog depth
|
171
|
+
# bind 'unix:///var/run/puma.sock?backlog=512'
|
172
|
+
# @example SSL cert
|
173
|
+
# bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
|
174
|
+
# @example Disable optimization for low latency
|
175
|
+
# bind 'tcp://0.0.0.0:9292?low_latency=false'
|
176
|
+
# @example Socket permissions
|
177
|
+
# bind 'unix:///var/run/puma.sock?umask=0111'
|
146
178
|
def bind(url)
|
147
179
|
@options[:binds] ||= []
|
148
180
|
@options[:binds] << url
|
@@ -154,33 +186,40 @@ module Puma
|
|
154
186
|
|
155
187
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
156
188
|
#
|
189
|
+
# @example
|
190
|
+
# port 9292
|
157
191
|
def port(port, host=nil)
|
158
192
|
host ||= default_host
|
159
193
|
bind "tcp://#{host}:#{port}"
|
160
194
|
end
|
161
195
|
|
162
|
-
# Define how long persistent connections can be idle before
|
163
|
-
# them
|
164
|
-
#
|
196
|
+
# Define how long persistent connections can be idle before Puma closes
|
197
|
+
# them.
|
165
198
|
def persistent_timeout(seconds)
|
166
199
|
@options[:persistent_timeout] = Integer(seconds)
|
167
200
|
end
|
168
201
|
|
169
|
-
# Define how long the tcp socket stays open, if no data has been received
|
170
|
-
#
|
202
|
+
# Define how long the tcp socket stays open, if no data has been received.
|
171
203
|
def first_data_timeout(seconds)
|
172
204
|
@options[:first_data_timeout] = Integer(seconds)
|
173
205
|
end
|
174
206
|
|
175
207
|
# Work around leaky apps that leave garbage in Thread locals
|
176
|
-
# across requests
|
177
|
-
#
|
208
|
+
# across requests.
|
178
209
|
def clean_thread_locals(which=true)
|
179
210
|
@options[:clean_thread_locals] = which
|
180
211
|
end
|
181
212
|
|
182
|
-
# Daemonize the server into the background.
|
183
|
-
# this
|
213
|
+
# Daemonize the server into the background. It's highly recommended to
|
214
|
+
# use this in combination with +pidfile+ and +stdout_redirect+.
|
215
|
+
#
|
216
|
+
# The default is "false".
|
217
|
+
#
|
218
|
+
# @example
|
219
|
+
# daemonize
|
220
|
+
#
|
221
|
+
# @example
|
222
|
+
# daemonize false
|
184
223
|
def daemonize(which=true)
|
185
224
|
@options[:daemon] = which
|
186
225
|
end
|
@@ -193,7 +232,13 @@ module Puma
|
|
193
232
|
@options[:drain_on_shutdown] = which
|
194
233
|
end
|
195
234
|
|
196
|
-
# Set the environment in which the
|
235
|
+
# Set the environment in which the rack's app will run. The value must be
|
236
|
+
# a string.
|
237
|
+
#
|
238
|
+
# The default is "development".
|
239
|
+
#
|
240
|
+
# @example
|
241
|
+
# environment 'production'
|
197
242
|
def environment(environment)
|
198
243
|
@options[:environment] = environment
|
199
244
|
end
|
@@ -219,30 +264,41 @@ module Puma
|
|
219
264
|
end
|
220
265
|
|
221
266
|
# Code to run before doing a restart. This code should
|
222
|
-
# close
|
267
|
+
# close log files, database connections, etc.
|
223
268
|
#
|
224
269
|
# This can be called multiple times to add code each time.
|
225
270
|
#
|
271
|
+
# @example
|
272
|
+
# on_restart do
|
273
|
+
# puts 'On restart...'
|
274
|
+
# end
|
226
275
|
def on_restart(&block)
|
227
276
|
@options[:on_restart] ||= []
|
228
277
|
@options[:on_restart] << block
|
229
278
|
end
|
230
279
|
|
231
|
-
# Command to use to restart
|
232
|
-
# load
|
233
|
-
# to
|
280
|
+
# Command to use to restart Puma. This should be just how to
|
281
|
+
# load Puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
|
282
|
+
# to Puma, as those are the same as the original process.
|
234
283
|
#
|
284
|
+
# @example
|
285
|
+
# restart_command '/u/app/lolcat/bin/restart_puma'
|
235
286
|
def restart_command(cmd)
|
236
287
|
@options[:restart_cmd] = cmd.to_s
|
237
288
|
end
|
238
289
|
|
239
|
-
# Store the pid of the server in the file at
|
290
|
+
# Store the pid of the server in the file at "path".
|
291
|
+
#
|
292
|
+
# @example
|
293
|
+
# pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
|
240
294
|
def pidfile(path)
|
241
295
|
@options[:pidfile] = path.to_s
|
242
296
|
end
|
243
297
|
|
244
|
-
# Disable request logging.
|
298
|
+
# Disable request logging, if this isn't used it'll be enabled by default.
|
245
299
|
#
|
300
|
+
# @example
|
301
|
+
# quiet
|
246
302
|
def quiet(which=true)
|
247
303
|
@options[:log_requests] = !which
|
248
304
|
end
|
@@ -261,6 +317,10 @@ module Puma
|
|
261
317
|
|
262
318
|
# Load +path+ as a rackup file.
|
263
319
|
#
|
320
|
+
# The default is "config.ru".
|
321
|
+
#
|
322
|
+
# @example
|
323
|
+
# rackup '/u/apps/lolcat/config.ru'
|
264
324
|
def rackup(path)
|
265
325
|
@options[:rackup] = path.to_s
|
266
326
|
end
|
@@ -275,16 +335,32 @@ module Puma
|
|
275
335
|
@options[:early_hints] = answer
|
276
336
|
end
|
277
337
|
|
278
|
-
# Redirect STDOUT and STDERR to files specified.
|
338
|
+
# Redirect STDOUT and STDERR to files specified. The +append+ parameter
|
339
|
+
# specifies whether the output is appended, the default is +false+.
|
340
|
+
#
|
341
|
+
# @example
|
342
|
+
# stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr'
|
343
|
+
# @example
|
344
|
+
# stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr', true
|
279
345
|
def stdout_redirect(stdout=nil, stderr=nil, append=false)
|
280
346
|
@options[:redirect_stdout] = stdout
|
281
347
|
@options[:redirect_stderr] = stderr
|
282
348
|
@options[:redirect_append] = append
|
283
349
|
end
|
284
350
|
|
351
|
+
def log_formatter(&block)
|
352
|
+
@options[:log_formatter] = block
|
353
|
+
end
|
354
|
+
|
285
355
|
# Configure +min+ to be the minimum number of threads to use to answer
|
286
356
|
# requests and +max+ the maximum.
|
287
357
|
#
|
358
|
+
# The default is "0, 16".
|
359
|
+
#
|
360
|
+
# @example
|
361
|
+
# threads 0, 16
|
362
|
+
# @example
|
363
|
+
# threads 5, 5
|
288
364
|
def threads(min, max)
|
289
365
|
min = Integer(min)
|
290
366
|
max = Integer(max)
|
@@ -300,84 +376,135 @@ module Puma
|
|
300
376
|
@options[:max_threads] = max
|
301
377
|
end
|
302
378
|
|
379
|
+
# Instead of "bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'" you
|
380
|
+
# can also use the "ssl_bind" option.
|
381
|
+
#
|
382
|
+
# @example
|
383
|
+
# ssl_bind '127.0.0.1', '9292', {
|
384
|
+
# cert: path_to_cert,
|
385
|
+
# key: path_to_key,
|
386
|
+
# ssl_cipher_filter: cipher_filter, # optional
|
387
|
+
# verify_mode: verify_mode, # default 'none'
|
388
|
+
# }
|
389
|
+
# @example For JRuby additional keys are required: keystore & keystore_pass.
|
390
|
+
# ssl_bind '127.0.0.1', '9292', {
|
391
|
+
# cert: path_to_cert,
|
392
|
+
# key: path_to_key,
|
393
|
+
# ssl_cipher_filter: cipher_filter, # optional
|
394
|
+
# verify_mode: verify_mode, # default 'none'
|
395
|
+
# keystore: path_to_keystore,
|
396
|
+
# keystore_pass: password
|
397
|
+
# }
|
303
398
|
def ssl_bind(host, port, opts)
|
304
399
|
verify = opts.fetch(:verify_mode, 'none')
|
305
400
|
no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
|
401
|
+
no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
|
306
402
|
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
307
403
|
|
308
404
|
if defined?(JRUBY_VERSION)
|
309
405
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
310
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}#{ca_additions}"
|
406
|
+
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
311
407
|
else
|
312
408
|
ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
|
313
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}#{ca_additions}"
|
409
|
+
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
314
410
|
end
|
315
411
|
end
|
316
412
|
|
317
413
|
# Use +path+ as the file to store the server info state. This is
|
318
|
-
# used by pumactl to query and control the server.
|
414
|
+
# used by +pumactl+ to query and control the server.
|
319
415
|
#
|
416
|
+
# @example
|
417
|
+
# state_path '/u/apps/lolcat/tmp/pids/puma.state'
|
320
418
|
def state_path(path)
|
321
419
|
@options[:state] = path.to_s
|
322
420
|
end
|
323
421
|
|
324
|
-
#
|
422
|
+
# How many worker processes to run. Typically this is set to
|
423
|
+
# to the number of available cores.
|
325
424
|
#
|
425
|
+
# The default is 0.
|
426
|
+
#
|
427
|
+
# @note Cluster mode only.
|
326
428
|
def workers(count)
|
327
429
|
@options[:workers] = count.to_i
|
328
430
|
end
|
329
431
|
|
330
|
-
#
|
432
|
+
# Code to run immediately before master process
|
331
433
|
# forks workers (once on boot). These hooks can block if necessary
|
332
|
-
# to wait for background operations unknown to
|
434
|
+
# to wait for background operations unknown to Puma to finish before
|
333
435
|
# the process terminates.
|
334
|
-
# This can be used to close any connections to remote servers (database,
|
335
|
-
# that were opened when preloading the code
|
436
|
+
# This can be used to close any connections to remote servers (database,
|
437
|
+
# Redis, ...) that were opened when preloading the code.
|
336
438
|
#
|
337
|
-
# This can be called multiple times to add hooks.
|
439
|
+
# This can be called multiple times to add several hooks.
|
338
440
|
#
|
441
|
+
# @note Cluster mode only.
|
442
|
+
# @example
|
443
|
+
# before_fork do
|
444
|
+
# puts "Starting workers..."
|
445
|
+
# end
|
339
446
|
def before_fork(&block)
|
340
447
|
@options[:before_fork] ||= []
|
341
448
|
@options[:before_fork] << block
|
342
449
|
end
|
343
450
|
|
344
|
-
#
|
451
|
+
# Code to run in a worker when it boots to setup
|
345
452
|
# the process before booting the app.
|
346
453
|
#
|
347
|
-
# This can be called multiple times to add hooks.
|
454
|
+
# This can be called multiple times to add several hooks.
|
348
455
|
#
|
456
|
+
# @note Cluster mode only.
|
457
|
+
# @example
|
458
|
+
# on_worker_fork do
|
459
|
+
# puts 'Before worker fork...'
|
460
|
+
# end
|
349
461
|
def on_worker_boot(&block)
|
350
462
|
@options[:before_worker_boot] ||= []
|
351
463
|
@options[:before_worker_boot] << block
|
352
464
|
end
|
353
465
|
|
354
|
-
#
|
466
|
+
# Code to run immediately before a worker shuts
|
355
467
|
# down (after it has finished processing HTTP requests). These hooks
|
356
468
|
# can block if necessary to wait for background operations unknown
|
357
|
-
# to
|
469
|
+
# to Puma to finish before the process terminates.
|
358
470
|
#
|
359
|
-
# This can be called multiple times to add hooks.
|
471
|
+
# This can be called multiple times to add several hooks.
|
360
472
|
#
|
473
|
+
# @note Cluster mode only.
|
474
|
+
# @example
|
475
|
+
# on_worker_shutdown do
|
476
|
+
# puts 'On worker shutdown...'
|
477
|
+
# end
|
361
478
|
def on_worker_shutdown(&block)
|
362
479
|
@options[:before_worker_shutdown] ||= []
|
363
480
|
@options[:before_worker_shutdown] << block
|
364
481
|
end
|
365
482
|
|
366
|
-
#
|
367
|
-
#
|
483
|
+
# Code to run in the master right before a worker is started. The worker's
|
484
|
+
# index is passed as an argument.
|
368
485
|
#
|
369
|
-
# This can be called multiple times to add hooks.
|
486
|
+
# This can be called multiple times to add several hooks.
|
370
487
|
#
|
488
|
+
# @note Cluster mode only.
|
489
|
+
# @example
|
490
|
+
# on_worker_fork do
|
491
|
+
# puts 'Before worker fork...'
|
492
|
+
# end
|
371
493
|
def on_worker_fork(&block)
|
372
494
|
@options[:before_worker_fork] ||= []
|
373
495
|
@options[:before_worker_fork] << block
|
374
496
|
end
|
375
497
|
|
376
|
-
#
|
377
|
-
#
|
498
|
+
# Code to run in the master after a worker has been started. The worker's
|
499
|
+
# index is passed as an argument.
|
378
500
|
#
|
379
|
-
# This
|
501
|
+
# This is called everytime a worker is to be started.
|
380
502
|
#
|
503
|
+
# @note Cluster mode only.
|
504
|
+
# @example
|
505
|
+
# after_worker_fork do
|
506
|
+
# puts 'After worker fork...'
|
507
|
+
# end
|
381
508
|
def after_worker_fork(&block)
|
382
509
|
@options[:after_worker_fork] ||= []
|
383
510
|
@options[:after_worker_fork] = block
|
@@ -393,14 +520,18 @@ module Puma
|
|
393
520
|
# This hook is useful for running out-of-band garbage collection
|
394
521
|
# or scheduling asynchronous tasks to execute after a response.
|
395
522
|
#
|
396
|
-
# This can be called multiple times to add hooks.
|
397
|
-
#
|
523
|
+
# This can be called multiple times to add several hooks.
|
398
524
|
def out_of_band(&block)
|
399
525
|
@options[:out_of_band] ||= []
|
400
526
|
@options[:out_of_band] << block
|
401
527
|
end
|
402
528
|
|
403
529
|
# The directory to operate out of.
|
530
|
+
#
|
531
|
+
# The default is the current directory.
|
532
|
+
#
|
533
|
+
# @example
|
534
|
+
# directory '/u/apps/lolcat'
|
404
535
|
def directory(dir)
|
405
536
|
@options[:directory] = dir.to_s
|
406
537
|
end
|
@@ -411,22 +542,28 @@ module Puma
|
|
411
542
|
directory dir
|
412
543
|
end
|
413
544
|
|
414
|
-
# Run the app as a raw TCP app instead of an HTTP rack app
|
545
|
+
# Run the app as a raw TCP app instead of an HTTP rack app.
|
415
546
|
def tcp_mode
|
416
547
|
@options[:mode] = :tcp
|
417
548
|
end
|
418
549
|
|
419
|
-
#
|
420
|
-
#
|
421
|
-
# with using the phased restart feature, you can't use both.
|
550
|
+
# Preload the application before starting the workers; this conflicts with
|
551
|
+
# phased restart feature. This is off by default.
|
422
552
|
#
|
553
|
+
# @note Cluster mode only.
|
554
|
+
# @example
|
555
|
+
# preload_app!
|
423
556
|
def preload_app!(answer=true)
|
424
557
|
@options[:preload_app] = answer
|
425
558
|
end
|
426
559
|
|
427
|
-
# Use +obj+ or +block+ as the low level error handler. This allows
|
428
|
-
# change the default error on the server.
|
560
|
+
# Use +obj+ or +block+ as the low level error handler. This allows the
|
561
|
+
# configuration file to change the default error on the server.
|
429
562
|
#
|
563
|
+
# @example
|
564
|
+
# lowlevel_error_handler do |err|
|
565
|
+
# [200, {}, ["error page"]]
|
566
|
+
# end
|
430
567
|
def lowlevel_error_handler(obj=nil, &block)
|
431
568
|
obj ||= block
|
432
569
|
raise "Provide either a #call'able or a block" unless obj
|
@@ -436,38 +573,57 @@ module Puma
|
|
436
573
|
# This option is used to allow your app and its gems to be
|
437
574
|
# properly reloaded when not using preload.
|
438
575
|
#
|
439
|
-
# When set, if
|
576
|
+
# When set, if Puma detects that it's been invoked in the
|
440
577
|
# context of Bundler, it will cleanup the environment and
|
441
578
|
# re-run itself outside the Bundler environment, but directly
|
442
579
|
# using the files that Bundler has setup.
|
443
580
|
#
|
444
|
-
# This means that
|
581
|
+
# This means that Puma is now decoupled from your Bundler
|
445
582
|
# context and when each worker loads, it will be loading a
|
446
583
|
# new Bundler context and thus can float around as the release
|
447
584
|
# dictates.
|
585
|
+
#
|
586
|
+
# @note This is incompatible with +preload_app!+.
|
448
587
|
def prune_bundler(answer=true)
|
449
588
|
@options[:prune_bundler] = answer
|
450
589
|
end
|
451
590
|
|
452
|
-
#
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
591
|
+
# By default, Puma will raise SignalException when SIGTERM is received. In
|
592
|
+
# environments where SIGTERM is something expected, you can suppress these
|
593
|
+
# with this option.
|
594
|
+
#
|
595
|
+
# This can be useful for example in Kubernetes, where rolling restart is
|
596
|
+
# guaranteed usually on infrastructure level.
|
456
597
|
#
|
457
|
-
#
|
598
|
+
# @example
|
599
|
+
# raise_exception_on_sigterm false
|
458
600
|
def raise_exception_on_sigterm(answer=true)
|
459
601
|
@options[:raise_exception_on_sigterm] = answer
|
460
602
|
end
|
461
603
|
|
462
|
-
# Additional text to display in process listing
|
604
|
+
# Additional text to display in process listing.
|
605
|
+
#
|
606
|
+
# If you do not specify a tag, Puma will infer it. If you do not want Puma
|
607
|
+
# to add a tag, use an empty string.
|
608
|
+
#
|
609
|
+
# @example
|
610
|
+
# tag 'app name'
|
611
|
+
# @example
|
612
|
+
# tag ''
|
463
613
|
def tag(string)
|
464
614
|
@options[:tag] = string.to_s
|
465
615
|
end
|
466
616
|
|
467
|
-
#
|
468
|
-
#
|
469
|
-
#
|
470
|
-
#
|
617
|
+
# Verifies that all workers have checked in to the master process within
|
618
|
+
# the given timeout. If not the worker process will be restarted. This is
|
619
|
+
# not a request timeout, it is to protect against a hung or dead process.
|
620
|
+
# Setting this value will not protect against slow requests.
|
621
|
+
#
|
622
|
+
# The minimum value is 6 seconds, the default value is 60 seconds.
|
623
|
+
#
|
624
|
+
# @note Cluster mode only.
|
625
|
+
# @example
|
626
|
+
# worker_timeout 60
|
471
627
|
def worker_timeout(timeout)
|
472
628
|
timeout = Integer(timeout)
|
473
629
|
min = Const::WORKER_CHECK_INTERVAL
|
@@ -476,15 +632,23 @@ module Puma
|
|
476
632
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
477
633
|
end
|
478
634
|
|
479
|
-
@options[:worker_timeout] =
|
635
|
+
@options[:worker_timeout] = timeout
|
480
636
|
end
|
481
637
|
|
482
|
-
#
|
638
|
+
# Change the default worker timeout for booting.
|
639
|
+
#
|
640
|
+
# If unspecified, this defaults to the value of worker_timeout.
|
641
|
+
#
|
642
|
+
# @note Cluster mode only.
|
643
|
+
# @example:
|
644
|
+
# worker_boot_timeout 60
|
483
645
|
def worker_boot_timeout(timeout)
|
484
646
|
@options[:worker_boot_timeout] = Integer(timeout)
|
485
647
|
end
|
486
648
|
|
487
|
-
#
|
649
|
+
# Set the timeout for worker shutdown
|
650
|
+
#
|
651
|
+
# @note Cluster mode only.
|
488
652
|
def worker_shutdown_timeout(timeout)
|
489
653
|
@options[:worker_shutdown_timeout] = Integer(timeout)
|
490
654
|
end
|
@@ -501,7 +665,7 @@ module Puma
|
|
501
665
|
# Note that setting this to false disables HTTP keepalive and
|
502
666
|
# slow clients will occupy a handler thread while the request
|
503
667
|
# is being sent. A reverse proxy, such as nginx, can handle
|
504
|
-
# slow clients and queue requests before they reach
|
668
|
+
# slow clients and queue requests before they reach Puma.
|
505
669
|
def queue_requests(answer=true)
|
506
670
|
@options[:queue_requests] = answer
|
507
671
|
end
|
@@ -530,7 +694,7 @@ module Puma
|
|
530
694
|
# is used, allowing headers such as X-Forwarded-For
|
531
695
|
# to be used as well.
|
532
696
|
# * Any string - this allows you to hardcode remote address to any value
|
533
|
-
# you wish. Because
|
697
|
+
# you wish. Because Puma never uses this field anyway, it's
|
534
698
|
# format is entirely in your hands.
|
535
699
|
def set_remote_address(val=:socket)
|
536
700
|
case val
|