puma 5.3.2 → 5.6.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +143 -8
- data/LICENSE +0 -0
- data/README.md +47 -6
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +49 -16
- data/docs/compile_options.md +4 -2
- data/docs/deployment.md +53 -67
- data/docs/fork_worker.md +0 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +0 -0
- data/docs/nginx.md +0 -0
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +2 -3
- data/docs/restart.md +6 -6
- data/docs/signals.md +11 -10
- data/docs/stats.md +8 -8
- data/docs/systemd.md +64 -67
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +28 -5
- data/ext/puma_http11/http11_parser.c +23 -10
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +0 -0
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +69 -9
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +49 -47
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +28 -43
- data/ext/puma_http11/puma_http11.c +1 -1
- data/lib/puma/app/status.rb +4 -4
- data/lib/puma/binder.rb +50 -5
- data/lib/puma/cli.rb +14 -4
- data/lib/puma/client.rb +50 -9
- data/lib/puma/cluster/worker.rb +8 -18
- data/lib/puma/cluster/worker_handle.rb +4 -0
- data/lib/puma/cluster.rb +30 -24
- data/lib/puma/commonlogger.rb +0 -0
- data/lib/puma/configuration.rb +4 -1
- data/lib/puma/const.rb +4 -5
- data/lib/puma/control_cli.rb +1 -1
- data/lib/puma/detect.rb +8 -2
- data/lib/puma/dsl.rb +105 -11
- data/lib/puma/error_logger.rb +0 -0
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +0 -0
- data/lib/puma/jruby_restart.rb +0 -0
- data/lib/puma/{json.rb → json_serialization.rb} +1 -1
- data/lib/puma/launcher.rb +4 -1
- data/lib/puma/minissl/context_builder.rb +8 -6
- data/lib/puma/minissl.rb +24 -23
- data/lib/puma/null_io.rb +0 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +2 -2
- data/lib/puma/queue_close.rb +0 -0
- data/lib/puma/rack/builder.rb +1 -1
- data/lib/puma/rack/urlmap.rb +0 -0
- data/lib/puma/rack_default.rb +0 -0
- data/lib/puma/reactor.rb +0 -0
- data/lib/puma/request.rb +14 -9
- data/lib/puma/runner.rb +22 -8
- data/lib/puma/server.rb +32 -29
- data/lib/puma/single.rb +0 -0
- data/lib/puma/state_file.rb +41 -7
- data/lib/puma/systemd.rb +0 -0
- data/lib/puma/thread_pool.rb +7 -5
- data/lib/puma/util.rb +8 -1
- data/lib/puma.rb +2 -2
- data/lib/rack/handler/puma.rb +0 -0
- data/tools/Dockerfile +1 -1
- data/tools/trickletest.rb +0 -0
- metadata +7 -7
data/lib/puma/cli.rb
CHANGED
@@ -11,16 +11,17 @@ require 'puma/events'
|
|
11
11
|
|
12
12
|
module Puma
|
13
13
|
class << self
|
14
|
-
# The CLI exports
|
15
|
-
# apps to pick it up. An app
|
16
|
-
#
|
17
|
-
#
|
14
|
+
# The CLI exports a Puma::Configuration instance here to allow
|
15
|
+
# apps to pick it up. An app must load this object conditionally
|
16
|
+
# because it is not set if the app is launched via any mechanism
|
17
|
+
# other than the CLI class.
|
18
18
|
attr_accessor :cli_config
|
19
19
|
end
|
20
20
|
|
21
21
|
# Handles invoke a Puma::Server in a command line style.
|
22
22
|
#
|
23
23
|
class CLI
|
24
|
+
# @deprecated 6.0.0
|
24
25
|
KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
|
25
26
|
|
26
27
|
# Create a new CLI object using +argv+ as the command line
|
@@ -112,6 +113,11 @@ module Puma
|
|
112
113
|
file_config.load arg
|
113
114
|
end
|
114
115
|
|
116
|
+
# Identical to supplying --config "-", but more semantic
|
117
|
+
o.on "--no-config", "Prevent Puma from searching for a config file" do |arg|
|
118
|
+
file_config.load "-"
|
119
|
+
end
|
120
|
+
|
115
121
|
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
116
122
|
configure_control_url(arg)
|
117
123
|
end
|
@@ -179,6 +185,10 @@ module Puma
|
|
179
185
|
user_config.restart_command cmd
|
180
186
|
end
|
181
187
|
|
188
|
+
o.on "-s", "--silent", "Do not log prompt messages other than errors" do
|
189
|
+
@events = Events.new NullIO.new, $stderr
|
190
|
+
end
|
191
|
+
|
182
192
|
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|
183
193
|
user_config.state_path arg
|
184
194
|
end
|
data/lib/puma/client.rb
CHANGED
@@ -56,6 +56,7 @@ module Puma
|
|
56
56
|
@parser = HttpParser.new
|
57
57
|
@parsed_bytes = 0
|
58
58
|
@read_header = true
|
59
|
+
@read_proxy = false
|
59
60
|
@ready = false
|
60
61
|
|
61
62
|
@body = nil
|
@@ -71,6 +72,7 @@ module Puma
|
|
71
72
|
@peerip = nil
|
72
73
|
@listener = nil
|
73
74
|
@remote_addr_header = nil
|
75
|
+
@expect_proxy_proto = false
|
74
76
|
|
75
77
|
@body_remain = 0
|
76
78
|
|
@@ -106,7 +108,7 @@ module Puma
|
|
106
108
|
|
107
109
|
# @!attribute [r] in_data_phase
|
108
110
|
def in_data_phase
|
109
|
-
|
111
|
+
!(@read_header || @read_proxy)
|
110
112
|
end
|
111
113
|
|
112
114
|
def set_timeout(val)
|
@@ -121,6 +123,7 @@ module Puma
|
|
121
123
|
def reset(fast_check=true)
|
122
124
|
@parser.reset
|
123
125
|
@read_header = true
|
126
|
+
@read_proxy = !!@expect_proxy_proto
|
124
127
|
@env = @proto_env.dup
|
125
128
|
@body = nil
|
126
129
|
@tempfile = nil
|
@@ -131,6 +134,8 @@ module Puma
|
|
131
134
|
@in_last_chunk = false
|
132
135
|
|
133
136
|
if @buffer
|
137
|
+
return false unless try_to_parse_proxy_protocol
|
138
|
+
|
134
139
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
135
140
|
|
136
141
|
if @parser.finished?
|
@@ -143,8 +148,7 @@ module Puma
|
|
143
148
|
return false
|
144
149
|
else
|
145
150
|
begin
|
146
|
-
if fast_check &&
|
147
|
-
IO.select([@to_io], nil, nil, FAST_TRACK_KA_TIMEOUT)
|
151
|
+
if fast_check && @to_io.wait_readable(FAST_TRACK_KA_TIMEOUT)
|
148
152
|
return try_to_finish
|
149
153
|
end
|
150
154
|
rescue IOError
|
@@ -157,13 +161,37 @@ module Puma
|
|
157
161
|
def close
|
158
162
|
begin
|
159
163
|
@io.close
|
160
|
-
rescue IOError
|
161
|
-
|
164
|
+
rescue IOError, Errno::EBADF
|
165
|
+
Puma::Util.purge_interrupt_queue
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# If necessary, read the PROXY protocol from the buffer. Returns
|
170
|
+
# false if more data is needed.
|
171
|
+
def try_to_parse_proxy_protocol
|
172
|
+
if @read_proxy
|
173
|
+
if @expect_proxy_proto == :v1
|
174
|
+
if @buffer.include? "\r\n"
|
175
|
+
if md = PROXY_PROTOCOL_V1_REGEX.match(@buffer)
|
176
|
+
if md[1]
|
177
|
+
@peerip = md[1].split(" ")[0]
|
178
|
+
end
|
179
|
+
@buffer = md.post_match
|
180
|
+
end
|
181
|
+
# if the buffer has a \r\n but doesn't have a PROXY protocol
|
182
|
+
# request, this is just HTTP from a non-PROXY client; move on
|
183
|
+
@read_proxy = false
|
184
|
+
return @buffer.size > 0
|
185
|
+
else
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
end
|
162
189
|
end
|
190
|
+
true
|
163
191
|
end
|
164
192
|
|
165
193
|
def try_to_finish
|
166
|
-
return read_body
|
194
|
+
return read_body if in_data_phase
|
167
195
|
|
168
196
|
begin
|
169
197
|
data = @io.read_nonblock(CHUNK_SIZE)
|
@@ -188,6 +216,8 @@ module Puma
|
|
188
216
|
@buffer = data
|
189
217
|
end
|
190
218
|
|
219
|
+
return false unless try_to_parse_proxy_protocol
|
220
|
+
|
191
221
|
@parsed_bytes = @parser.execute(@env, @buffer, @parsed_bytes)
|
192
222
|
|
193
223
|
if @parser.finished?
|
@@ -202,13 +232,13 @@ module Puma
|
|
202
232
|
|
203
233
|
def eagerly_finish
|
204
234
|
return true if @ready
|
205
|
-
return false unless
|
235
|
+
return false unless @to_io.wait_readable(0)
|
206
236
|
try_to_finish
|
207
237
|
end
|
208
238
|
|
209
239
|
def finish(timeout)
|
210
240
|
return if @ready
|
211
|
-
|
241
|
+
@to_io.wait_readable(timeout) || timeout! until try_to_finish
|
212
242
|
end
|
213
243
|
|
214
244
|
def timeout!
|
@@ -244,6 +274,17 @@ module Puma
|
|
244
274
|
@parsed_bytes == 0
|
245
275
|
end
|
246
276
|
|
277
|
+
def expect_proxy_proto=(val)
|
278
|
+
if val
|
279
|
+
if @read_header
|
280
|
+
@read_proxy = true
|
281
|
+
end
|
282
|
+
else
|
283
|
+
@read_proxy = false
|
284
|
+
end
|
285
|
+
@expect_proxy_proto = val
|
286
|
+
end
|
287
|
+
|
247
288
|
private
|
248
289
|
|
249
290
|
def setup_body
|
@@ -309,7 +350,7 @@ module Puma
|
|
309
350
|
|
310
351
|
@body_remain = remain
|
311
352
|
|
312
|
-
|
353
|
+
false
|
313
354
|
end
|
314
355
|
|
315
356
|
def read_body
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -33,9 +33,9 @@ module Puma
|
|
33
33
|
Signal.trap "SIGINT", "IGNORE"
|
34
34
|
Signal.trap "SIGCHLD", "DEFAULT"
|
35
35
|
|
36
|
-
|
37
|
-
Puma.set_thread_name "
|
38
|
-
|
36
|
+
Thread.new do
|
37
|
+
Puma.set_thread_name "wrkr check"
|
38
|
+
@check_pipe.wait_readable
|
39
39
|
log "! Detected parent died, dying"
|
40
40
|
exit! 1
|
41
41
|
end
|
@@ -76,7 +76,7 @@ module Puma
|
|
76
76
|
end
|
77
77
|
|
78
78
|
Thread.new do
|
79
|
-
Puma.set_thread_name "
|
79
|
+
Puma.set_thread_name "wrkr fork"
|
80
80
|
while (idx = @fork_pipe.gets)
|
81
81
|
idx = idx.to_i
|
82
82
|
if idx == -1 # stop server
|
@@ -106,7 +106,7 @@ module Puma
|
|
106
106
|
begin
|
107
107
|
@worker_write << "b#{Process.pid}:#{index}\n"
|
108
108
|
rescue SystemCallError, IOError
|
109
|
-
|
109
|
+
Puma::Util.purge_interrupt_queue
|
110
110
|
STDERR.puts "Master seems to have exited, exiting."
|
111
111
|
return
|
112
112
|
end
|
@@ -114,7 +114,7 @@ module Puma
|
|
114
114
|
while restart_server.pop
|
115
115
|
server_thread = server.run
|
116
116
|
stat_thread ||= Thread.new(@worker_write) do |io|
|
117
|
-
Puma.set_thread_name "stat
|
117
|
+
Puma.set_thread_name "stat pld"
|
118
118
|
base_payload = "p#{Process.pid}"
|
119
119
|
|
120
120
|
while true
|
@@ -127,10 +127,10 @@ module Puma
|
|
127
127
|
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r}, "pool_capacity":#{t}, "max_threads": #{m}, "requests_count": #{rc} }\n!
|
128
128
|
io << payload
|
129
129
|
rescue IOError
|
130
|
-
|
130
|
+
Puma::Util.purge_interrupt_queue
|
131
131
|
break
|
132
132
|
end
|
133
|
-
sleep
|
133
|
+
sleep @options[:worker_check_interval]
|
134
134
|
end
|
135
135
|
end
|
136
136
|
server_thread.join
|
@@ -168,16 +168,6 @@ module Puma
|
|
168
168
|
@launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
|
169
169
|
pid
|
170
170
|
end
|
171
|
-
|
172
|
-
def wakeup!
|
173
|
-
return unless @wakeup
|
174
|
-
|
175
|
-
begin
|
176
|
-
@wakeup.write "!" unless @wakeup.closed?
|
177
|
-
rescue SystemCallError, IOError
|
178
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
179
|
-
end
|
180
|
-
end
|
181
171
|
end
|
182
172
|
end
|
183
173
|
end
|
data/lib/puma/cluster.rb
CHANGED
@@ -108,24 +108,42 @@ module Puma
|
|
108
108
|
def cull_workers
|
109
109
|
diff = @workers.size - @options[:workers]
|
110
110
|
return if diff < 1
|
111
|
+
debug "Culling #{diff} workers"
|
111
112
|
|
112
|
-
|
113
|
+
workers = workers_to_cull(diff)
|
114
|
+
debug "Workers to cull: #{workers.inspect}"
|
113
115
|
|
114
|
-
|
115
|
-
debug "Workers to cull: #{workers_to_cull.inspect}"
|
116
|
-
|
117
|
-
workers_to_cull.each do |worker|
|
116
|
+
workers.each do |worker|
|
118
117
|
log "- Worker #{worker.index} (PID: #{worker.pid}) terminating"
|
119
118
|
worker.term
|
120
119
|
end
|
121
120
|
end
|
122
121
|
|
122
|
+
def workers_to_cull(diff)
|
123
|
+
workers = @workers.sort_by(&:started_at)
|
124
|
+
|
125
|
+
# In fork_worker mode, worker 0 acts as our master process.
|
126
|
+
# We should avoid culling it to preserve copy-on-write memory gains.
|
127
|
+
workers.reject! { |w| w.index == 0 } if @options[:fork_worker]
|
128
|
+
|
129
|
+
workers[cull_start_index(diff), diff]
|
130
|
+
end
|
131
|
+
|
132
|
+
def cull_start_index(diff)
|
133
|
+
case @options[:worker_culling_strategy]
|
134
|
+
when :oldest
|
135
|
+
0
|
136
|
+
else # :youngest
|
137
|
+
-diff
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
123
141
|
# @!attribute [r] next_worker_index
|
124
142
|
def next_worker_index
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
143
|
+
occupied_positions = @workers.map(&:index)
|
144
|
+
idx = 0
|
145
|
+
idx += 1 until !occupied_positions.include?(idx)
|
146
|
+
idx
|
129
147
|
end
|
130
148
|
|
131
149
|
def all_workers_booted?
|
@@ -135,7 +153,7 @@ module Puma
|
|
135
153
|
def check_workers
|
136
154
|
return if @next_check >= Time.now
|
137
155
|
|
138
|
-
@next_check = Time.now +
|
156
|
+
@next_check = Time.now + @options[:worker_check_interval]
|
139
157
|
|
140
158
|
timeout_workers
|
141
159
|
wait_workers
|
@@ -164,16 +182,6 @@ module Puma
|
|
164
182
|
].compact.min
|
165
183
|
end
|
166
184
|
|
167
|
-
def wakeup!
|
168
|
-
return unless @wakeup
|
169
|
-
|
170
|
-
begin
|
171
|
-
@wakeup.write "!" unless @wakeup.closed?
|
172
|
-
rescue SystemCallError, IOError
|
173
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
185
|
def worker(index, master)
|
178
186
|
@workers = []
|
179
187
|
|
@@ -426,9 +434,7 @@ module Puma
|
|
426
434
|
|
427
435
|
check_workers
|
428
436
|
|
429
|
-
|
430
|
-
|
431
|
-
if res
|
437
|
+
if read.wait_readable([0, @next_check - Time.now].max)
|
432
438
|
req = read.read_nonblock(1)
|
433
439
|
|
434
440
|
@next_check = Time.now if req == "!"
|
@@ -452,7 +458,7 @@ module Puma
|
|
452
458
|
workers_not_booted -= 1
|
453
459
|
when "e"
|
454
460
|
# external term, see worker method, Signal.trap "SIGTERM"
|
455
|
-
w.
|
461
|
+
w.term!
|
456
462
|
when "t"
|
457
463
|
w.term unless w.term?
|
458
464
|
when "p"
|
data/lib/puma/commonlogger.rb
CHANGED
File without changes
|
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
|
@@ -195,12 +196,14 @@ module Puma
|
|
195
196
|
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
196
197
|
:silence_single_worker_warning => false,
|
197
198
|
:mode => :http,
|
199
|
+
:worker_check_interval => DefaultWorkerCheckInterval,
|
198
200
|
:worker_timeout => DefaultWorkerTimeout,
|
199
201
|
:worker_boot_timeout => DefaultWorkerTimeout,
|
200
202
|
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
203
|
+
:worker_culling_strategy => :youngest,
|
201
204
|
:remote_address => :socket,
|
202
205
|
:tag => method(:infer_tag),
|
203
|
-
:environment => -> { ENV['RACK_ENV'] || ENV['RAILS_ENV'] ||
|
206
|
+
:environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
|
204
207
|
:rackup => DefaultRackup,
|
205
208
|
:logger => STDOUT,
|
206
209
|
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
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.6.2".freeze
|
104
|
+
CODE_NAME = "Birdie's Version".freeze
|
105
105
|
|
106
106
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
107
107
|
|
@@ -235,9 +235,6 @@ module Puma
|
|
235
235
|
|
236
236
|
EARLY_HINTS = "rack.early_hints".freeze
|
237
237
|
|
238
|
-
# Minimum interval to checks worker health
|
239
|
-
WORKER_CHECK_INTERVAL = 5
|
240
|
-
|
241
238
|
# Illegal character in the key or value of response header
|
242
239
|
DQUOTE = "\"".freeze
|
243
240
|
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
@@ -247,5 +244,7 @@ module Puma
|
|
247
244
|
|
248
245
|
# Banned keys of response header
|
249
246
|
BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
|
247
|
+
|
248
|
+
PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
|
250
249
|
end
|
251
250
|
end
|
data/lib/puma/control_cli.rb
CHANGED
data/lib/puma/detect.rb
CHANGED
@@ -10,8 +10,10 @@ module Puma
|
|
10
10
|
|
11
11
|
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
IS_OSX = RUBY_PLATFORM.include? 'darwin'
|
14
|
+
|
15
|
+
IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
|
16
|
+
IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
|
15
17
|
|
16
18
|
# @version 5.2.0
|
17
19
|
IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
|
@@ -20,6 +22,10 @@ module Puma
|
|
20
22
|
IS_JRUBY
|
21
23
|
end
|
22
24
|
|
25
|
+
def self.osx?
|
26
|
+
IS_OSX
|
27
|
+
end
|
28
|
+
|
23
29
|
def self.windows?
|
24
30
|
IS_WINDOWS
|
25
31
|
end
|
data/lib/puma/dsl.rb
CHANGED
@@ -48,6 +48,8 @@ module Puma
|
|
48
48
|
|
49
49
|
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
50
50
|
|
51
|
+
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
|
52
|
+
|
51
53
|
if defined?(JRUBY_VERSION)
|
52
54
|
ssl_cipher_list = opts[:ssl_cipher_list] ?
|
53
55
|
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
|
@@ -55,7 +57,7 @@ module Puma
|
|
55
57
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
56
58
|
|
57
59
|
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
|
58
|
-
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
60
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
|
59
61
|
else
|
60
62
|
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
61
63
|
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
@@ -64,7 +66,7 @@ module Puma
|
|
64
66
|
"&verification_flags=#{Array(ary).join ','}" : nil
|
65
67
|
|
66
68
|
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
|
67
|
-
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}"
|
69
|
+
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
@@ -191,7 +193,7 @@ module Puma
|
|
191
193
|
end
|
192
194
|
|
193
195
|
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
194
|
-
# accepted protocols. Multiple urls can be bound to, calling
|
196
|
+
# accepted protocols. Multiple urls can be bound to, calling +bind+ does
|
195
197
|
# not overwrite previous bindings.
|
196
198
|
#
|
197
199
|
# The default is "tcp://0.0.0.0:9292".
|
@@ -381,6 +383,13 @@ module Puma
|
|
381
383
|
@options[:rackup] ||= path.to_s
|
382
384
|
end
|
383
385
|
|
386
|
+
# Allows setting `env['rack.url_scheme']`.
|
387
|
+
# Only necessary if X-Forwarded-Proto is not being set by your proxy
|
388
|
+
# Normal values are 'http' or 'https'.
|
389
|
+
def rack_url_scheme(scheme=nil)
|
390
|
+
@options[:rack_url_scheme] = scheme
|
391
|
+
end
|
392
|
+
|
384
393
|
def early_hints(answer=true)
|
385
394
|
@options[:early_hints] = answer
|
386
395
|
end
|
@@ -429,8 +438,15 @@ module Puma
|
|
429
438
|
@options[:max_threads] = max
|
430
439
|
end
|
431
440
|
|
432
|
-
# Instead of
|
433
|
-
#
|
441
|
+
# Instead of using +bind+ and manually constructing a URI like:
|
442
|
+
#
|
443
|
+
# bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'
|
444
|
+
#
|
445
|
+
# you can use the this method.
|
446
|
+
#
|
447
|
+
# When binding on localhost you don't need to specify +cert+ and +key+,
|
448
|
+
# Puma will assume you are using the +localhost+ gem and try to load the
|
449
|
+
# appropriate files.
|
434
450
|
#
|
435
451
|
# @example
|
436
452
|
# ssl_bind '127.0.0.1', '9292', {
|
@@ -440,14 +456,25 @@ module Puma
|
|
440
456
|
# verify_mode: verify_mode, # default 'none'
|
441
457
|
# verification_flags: flags, # optional, not supported by JRuby
|
442
458
|
# }
|
443
|
-
#
|
459
|
+
#
|
460
|
+
# @example Using self-signed certificate with the +localhost+ gem:
|
461
|
+
# ssl_bind '127.0.0.1', '9292'
|
462
|
+
#
|
463
|
+
# @example Alternatively, you can provide +cert_pem+ and +key_pem+:
|
464
|
+
# ssl_bind '127.0.0.1', '9292', {
|
465
|
+
# cert_pem: File.read(path_to_cert),
|
466
|
+
# key_pem: File.read(path_to_key),
|
467
|
+
# }
|
468
|
+
#
|
469
|
+
# @example For JRuby, two keys are required: +keystore+ & +keystore_pass+
|
444
470
|
# ssl_bind '127.0.0.1', '9292', {
|
445
471
|
# keystore: path_to_keystore,
|
446
472
|
# keystore_pass: password,
|
447
473
|
# ssl_cipher_list: cipher_list, # optional
|
448
474
|
# verify_mode: verify_mode # default 'none'
|
449
475
|
# }
|
450
|
-
def ssl_bind(host, port, opts)
|
476
|
+
def ssl_bind(host, port, opts = {})
|
477
|
+
add_pem_values_to_options_store(opts)
|
451
478
|
bind self.class.ssl_bind_str(host, port, opts)
|
452
479
|
end
|
453
480
|
|
@@ -578,7 +605,7 @@ module Puma
|
|
578
605
|
# end
|
579
606
|
def after_worker_fork(&block)
|
580
607
|
@options[:after_worker_fork] ||= []
|
581
|
-
@options[:after_worker_fork]
|
608
|
+
@options[:after_worker_fork] << block
|
582
609
|
end
|
583
610
|
|
584
611
|
alias_method :after_worker_boot, :after_worker_fork
|
@@ -720,6 +747,19 @@ module Puma
|
|
720
747
|
@options[:tag] = string.to_s
|
721
748
|
end
|
722
749
|
|
750
|
+
# Change the default interval for checking workers.
|
751
|
+
#
|
752
|
+
# The default value is 5 seconds.
|
753
|
+
#
|
754
|
+
# @note Cluster mode only.
|
755
|
+
# @example
|
756
|
+
# worker_check_interval 5
|
757
|
+
# @see Puma::Cluster#check_workers
|
758
|
+
#
|
759
|
+
def worker_check_interval(interval)
|
760
|
+
@options[:worker_check_interval] = Integer(interval)
|
761
|
+
end
|
762
|
+
|
723
763
|
# Verifies that all workers have checked in to the master process within
|
724
764
|
# the given timeout. If not the worker process will be restarted. This is
|
725
765
|
# not a request timeout, it is to protect against a hung or dead process.
|
@@ -734,7 +774,7 @@ module Puma
|
|
734
774
|
#
|
735
775
|
def worker_timeout(timeout)
|
736
776
|
timeout = Integer(timeout)
|
737
|
-
min =
|
777
|
+
min = @options.fetch(:worker_check_interval, Puma::ConfigDefault::DefaultWorkerCheckInterval)
|
738
778
|
|
739
779
|
if timeout <= min
|
740
780
|
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
@@ -766,6 +806,30 @@ module Puma
|
|
766
806
|
@options[:worker_shutdown_timeout] = Integer(timeout)
|
767
807
|
end
|
768
808
|
|
809
|
+
# Set the strategy for worker culling.
|
810
|
+
#
|
811
|
+
# There are two possible values:
|
812
|
+
#
|
813
|
+
# 1. **:youngest** - the youngest workers (i.e. the workers that were
|
814
|
+
# the most recently started) will be culled.
|
815
|
+
# 2. **:oldest** - the oldest workers (i.e. the workers that were started
|
816
|
+
# the longest time ago) will be culled.
|
817
|
+
#
|
818
|
+
# @note Cluster mode only.
|
819
|
+
# @example
|
820
|
+
# worker_culling_strategy :oldest
|
821
|
+
# @see Puma::Cluster#cull_workers
|
822
|
+
#
|
823
|
+
def worker_culling_strategy(strategy)
|
824
|
+
stategy = strategy.to_sym
|
825
|
+
|
826
|
+
if ![:youngest, :oldest].include?(strategy)
|
827
|
+
raise "Invalid value for worker_culling_strategy - #{stategy}"
|
828
|
+
end
|
829
|
+
|
830
|
+
@options[:worker_culling_strategy] = strategy
|
831
|
+
end
|
832
|
+
|
769
833
|
# When set to true (the default), workers accept all requests
|
770
834
|
# and queue them before passing them to the handlers.
|
771
835
|
# When set to false, each worker process accepts exactly as
|
@@ -811,7 +875,7 @@ module Puma
|
|
811
875
|
# a kernel syscall is required which for very fast rack handlers
|
812
876
|
# slows down the handling significantly.
|
813
877
|
#
|
814
|
-
# There are
|
878
|
+
# There are 5 possible values:
|
815
879
|
#
|
816
880
|
# 1. **:socket** (the default) - read the peername from the socket using the
|
817
881
|
# syscall. This is the normal behavior.
|
@@ -821,7 +885,10 @@ module Puma
|
|
821
885
|
# `set_remote_address header: "X-Real-IP"`.
|
822
886
|
# Only the first word (as separated by spaces or comma) is used, allowing
|
823
887
|
# headers such as X-Forwarded-For to be used as well.
|
824
|
-
# 4.
|
888
|
+
# 4. **proxy_protocol: :v1**- set the remote address to the value read from the
|
889
|
+
# HAproxy PROXY protocol, version 1. If the request does not have the PROXY
|
890
|
+
# protocol attached to it, will fall back to :socket
|
891
|
+
# 5. **\<Any string\>** - this allows you to hardcode remote address to any value
|
825
892
|
# you wish. Because Puma never uses this field anyway, it's format is
|
826
893
|
# entirely in your hands.
|
827
894
|
#
|
@@ -839,6 +906,13 @@ module Puma
|
|
839
906
|
if hdr = val[:header]
|
840
907
|
@options[:remote_address] = :header
|
841
908
|
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
909
|
+
elsif protocol_version = val[:proxy_protocol]
|
910
|
+
@options[:remote_address] = :proxy_protocol
|
911
|
+
protocol_version = protocol_version.downcase.to_sym
|
912
|
+
unless [:v1].include?(protocol_version)
|
913
|
+
raise "Invalid value for proxy_protocol - #{protocol_version.inspect}"
|
914
|
+
end
|
915
|
+
@options[:remote_address_proxy_protocol] = protocol_version
|
842
916
|
else
|
843
917
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
844
918
|
end
|
@@ -910,5 +984,25 @@ module Puma
|
|
910
984
|
def mutate_stdout_and_stderr_to_sync_on_write(enabled=true)
|
911
985
|
@options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled
|
912
986
|
end
|
987
|
+
|
988
|
+
private
|
989
|
+
|
990
|
+
# To avoid adding cert_pem and key_pem as URI params, we store them on the
|
991
|
+
# options[:store] from where Puma binder knows how to find and extract them.
|
992
|
+
def add_pem_values_to_options_store(opts)
|
993
|
+
return if defined?(JRUBY_VERSION)
|
994
|
+
|
995
|
+
@options[:store] ||= []
|
996
|
+
|
997
|
+
# Store cert_pem and key_pem to options[:store] if present
|
998
|
+
[:cert, :key].each do |v|
|
999
|
+
opt_key = :"#{v}_pem"
|
1000
|
+
if opts[opt_key]
|
1001
|
+
index = @options[:store].length
|
1002
|
+
@options[:store] << opts[opt_key]
|
1003
|
+
opts[v] = "store:#{index}"
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
end
|
913
1007
|
end
|
914
1008
|
end
|
data/lib/puma/error_logger.rb
CHANGED
File without changes
|
data/lib/puma/events.rb
CHANGED
File without changes
|
data/lib/puma/io_buffer.rb
CHANGED
File without changes
|
data/lib/puma/jruby_restart.rb
CHANGED
File without changes
|