puma 3.12.0 → 5.3.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 +1413 -439
- data/LICENSE +23 -20
- data/README.md +131 -60
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +24 -19
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +38 -13
- data/docs/fork_worker.md +33 -0
- data/docs/jungle/README.md +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +20 -10
- data/docs/rails_dev_mode.md +29 -0
- data/docs/restart.md +47 -22
- data/docs/signals.md +7 -6
- data/docs/stats.md +142 -0
- data/docs/systemd.md +48 -70
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +27 -0
- data/ext/puma_http11/http11_parser.c +84 -109
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +22 -38
- data/ext/puma_http11/http11_parser.rl +4 -2
- data/ext/puma_http11/http11_parser_common.rl +3 -3
- data/ext/puma_http11/mini_ssl.c +262 -87
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +89 -106
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +92 -22
- data/ext/puma_http11/puma_http11.c +34 -50
- data/lib/puma/app/status.rb +68 -49
- data/lib/puma/binder.rb +197 -144
- data/lib/puma/cli.rb +17 -15
- data/lib/puma/client.rb +257 -226
- data/lib/puma/cluster/worker.rb +176 -0
- data/lib/puma/cluster/worker_handle.rb +90 -0
- data/lib/puma/cluster.rb +223 -212
- data/lib/puma/commonlogger.rb +4 -2
- data/lib/puma/configuration.rb +58 -51
- data/lib/puma/const.rb +41 -19
- data/lib/puma/control_cli.rb +117 -73
- data/lib/puma/detect.rb +26 -3
- data/lib/puma/dsl.rb +531 -123
- data/lib/puma/error_logger.rb +104 -0
- data/lib/puma/events.rb +57 -31
- data/lib/puma/io_buffer.rb +9 -5
- data/lib/puma/jruby_restart.rb +2 -58
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +182 -70
- data/lib/puma/minissl/context_builder.rb +79 -0
- data/lib/puma/minissl.rb +149 -48
- data/lib/puma/null_io.rb +15 -1
- data/lib/puma/plugin/tmp_restart.rb +2 -0
- data/lib/puma/plugin.rb +8 -12
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/rack/builder.rb +4 -5
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +87 -316
- data/lib/puma/request.rb +456 -0
- data/lib/puma/runner.rb +33 -52
- data/lib/puma/server.rb +288 -679
- data/lib/puma/single.rb +13 -67
- data/lib/puma/state_file.rb +10 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +131 -81
- data/lib/puma/util.rb +14 -6
- data/lib/puma.rb +54 -0
- data/lib/rack/handler/puma.rb +8 -6
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +45 -29
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- data/lib/puma/tcp_logger.rb +0 -39
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/minissl.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'io/wait'
|
3
|
-
|
5
|
+
rescue LoadError
|
4
6
|
end
|
5
7
|
|
8
|
+
# need for Puma::MiniSSL::OPENSSL constants used in `HAS_TLS1_3`
|
9
|
+
require 'puma/puma_http11'
|
10
|
+
|
6
11
|
module Puma
|
7
12
|
module MiniSSL
|
13
|
+
# Define constant at runtime, as it's easy to determine at built time,
|
14
|
+
# but Puma could (it shouldn't) be loaded with an older OpenSSL version
|
15
|
+
# @version 5.0.0
|
16
|
+
HAS_TLS1_3 = !IS_JRUBY &&
|
17
|
+
(OPENSSL_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) != -1 &&
|
18
|
+
(OPENSSL_LIBRARY_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) !=-1
|
19
|
+
|
8
20
|
class Socket
|
9
21
|
def initialize(socket, engine)
|
10
22
|
@socket = socket
|
@@ -12,6 +24,7 @@ module Puma
|
|
12
24
|
@peercert = nil
|
13
25
|
end
|
14
26
|
|
27
|
+
# @!attribute [r] to_io
|
15
28
|
def to_io
|
16
29
|
@socket
|
17
30
|
end
|
@@ -20,6 +33,27 @@ module Puma
|
|
20
33
|
@socket.closed?
|
21
34
|
end
|
22
35
|
|
36
|
+
# Returns a two element array,
|
37
|
+
# first is protocol version (SSL_get_version),
|
38
|
+
# second is 'handshake' state (SSL_state_string)
|
39
|
+
#
|
40
|
+
# Used for dropping tcp connections to ssl.
|
41
|
+
# See OpenSSL ssl/ssl_stat.c SSL_state_string for info
|
42
|
+
# @!attribute [r] ssl_version_state
|
43
|
+
# @version 5.0.0
|
44
|
+
#
|
45
|
+
def ssl_version_state
|
46
|
+
IS_JRUBY ? [nil, nil] : @engine.ssl_vers_st
|
47
|
+
end
|
48
|
+
|
49
|
+
# Used to check the handshake status, in particular when a TCP connection
|
50
|
+
# is made with TLSv1.3 as an available protocol
|
51
|
+
# @version 5.0.0
|
52
|
+
def bad_tlsv1_3?
|
53
|
+
HAS_TLS1_3 && @engine.ssl_vers_st == ['TLSv1.3', 'SSLERR']
|
54
|
+
end
|
55
|
+
private :bad_tlsv1_3?
|
56
|
+
|
23
57
|
def readpartial(size)
|
24
58
|
while true
|
25
59
|
output = @engine.read
|
@@ -52,22 +86,22 @@ module Puma
|
|
52
86
|
output = engine_read_all
|
53
87
|
return output if output
|
54
88
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
89
|
+
data = @socket.read_nonblock(size, exception: false)
|
90
|
+
if data == :wait_readable || data == :wait_writable
|
91
|
+
# It would make more sense to let @socket.read_nonblock raise
|
92
|
+
# EAGAIN if necessary but it seems like it'll misbehave on Windows.
|
93
|
+
# I don't have a Windows machine to debug this so I can't explain
|
94
|
+
# exactly whats happening in that OS. Please let me know if you
|
95
|
+
# find out!
|
96
|
+
#
|
97
|
+
# In the meantime, we can emulate the correct behavior by
|
98
|
+
# capturing :wait_readable & :wait_writable and raising EAGAIN
|
99
|
+
# ourselves.
|
100
|
+
raise IO::EAGAINWaitReadable
|
101
|
+
elsif data.nil?
|
102
|
+
raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
|
103
|
+
return nil
|
104
|
+
end
|
71
105
|
|
72
106
|
@engine.inject(data)
|
73
107
|
output = engine_read_all
|
@@ -83,22 +117,23 @@ module Puma
|
|
83
117
|
def write(data)
|
84
118
|
return 0 if data.empty?
|
85
119
|
|
86
|
-
|
120
|
+
data_size = data.bytesize
|
121
|
+
need = data_size
|
87
122
|
|
88
123
|
while true
|
89
124
|
wrote = @engine.write data
|
90
|
-
enc = @engine.extract
|
91
125
|
|
92
|
-
|
93
|
-
|
94
|
-
|
126
|
+
enc_wr = ''.dup
|
127
|
+
while (enc = @engine.extract)
|
128
|
+
enc_wr << enc
|
95
129
|
end
|
130
|
+
@socket.write enc_wr unless enc_wr.empty?
|
96
131
|
|
97
132
|
need -= wrote
|
98
133
|
|
99
|
-
return
|
134
|
+
return data_size if need == 0
|
100
135
|
|
101
|
-
data = data
|
136
|
+
data = data.byteslice(wrote..-1)
|
102
137
|
end
|
103
138
|
end
|
104
139
|
|
@@ -106,14 +141,18 @@ module Puma
|
|
106
141
|
alias_method :<<, :write
|
107
142
|
|
108
143
|
# This is a temporary fix to deal with websockets code using
|
109
|
-
# write_nonblock.
|
144
|
+
# write_nonblock.
|
145
|
+
|
146
|
+
# The problem with implementing it properly
|
110
147
|
# is that it means we'd have to have the ability to rewind
|
111
148
|
# an engine because after we write+extract, the socket
|
112
149
|
# write_nonblock call might raise an exception and later
|
113
150
|
# code would pass the same data in, but the engine would think
|
114
|
-
# it had already written the data in.
|
115
|
-
#
|
116
|
-
#
|
151
|
+
# it had already written the data in.
|
152
|
+
#
|
153
|
+
# So for the time being (and since write blocking is quite rare),
|
154
|
+
# go ahead and actually block in write_nonblock.
|
155
|
+
#
|
117
156
|
def write_nonblock(data, *_)
|
118
157
|
write data
|
119
158
|
end
|
@@ -124,11 +163,14 @@ module Puma
|
|
124
163
|
|
125
164
|
def read_and_drop(timeout = 1)
|
126
165
|
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
166
|
+
case @socket.read_nonblock(1024, exception: false)
|
167
|
+
when nil
|
168
|
+
:eof
|
169
|
+
when :wait_readable
|
170
|
+
:eagain
|
171
|
+
else
|
172
|
+
:drop
|
173
|
+
end
|
132
174
|
end
|
133
175
|
|
134
176
|
def should_drop_bytes?
|
@@ -140,9 +182,7 @@ module Puma
|
|
140
182
|
# Read any drop any partially initialized sockets and any received bytes during shutdown.
|
141
183
|
# Don't let this socket hold this loop forever.
|
142
184
|
# If it can't send more packets within 1s, then give up.
|
143
|
-
while should_drop_bytes?
|
144
|
-
return if [:timeout, :eof].include?(read_and_drop(1))
|
145
|
-
end
|
185
|
+
return if [:timeout, :eof].include?(read_and_drop(1)) while should_drop_bytes?
|
146
186
|
rescue IOError, SystemCallError
|
147
187
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
148
188
|
# nothing
|
@@ -151,10 +191,12 @@ module Puma
|
|
151
191
|
end
|
152
192
|
end
|
153
193
|
|
194
|
+
# @!attribute [r] peeraddr
|
154
195
|
def peeraddr
|
155
196
|
@socket.peeraddr
|
156
197
|
end
|
157
198
|
|
199
|
+
# @!attribute [r] peercert
|
158
200
|
def peercert
|
159
201
|
return @peercert if @peercert
|
160
202
|
|
@@ -165,18 +207,25 @@ module Puma
|
|
165
207
|
end
|
166
208
|
end
|
167
209
|
|
168
|
-
if
|
210
|
+
if IS_JRUBY
|
211
|
+
OPENSSL_NO_SSL3 = false
|
212
|
+
OPENSSL_NO_TLS1 = false
|
213
|
+
|
169
214
|
class SSLError < StandardError
|
170
215
|
# Define this for jruby even though it isn't used.
|
171
216
|
end
|
172
|
-
|
173
|
-
def self.check; end
|
174
217
|
end
|
175
218
|
|
176
219
|
class Context
|
177
220
|
attr_accessor :verify_mode
|
221
|
+
attr_reader :no_tlsv1, :no_tlsv1_1
|
222
|
+
|
223
|
+
def initialize
|
224
|
+
@no_tlsv1 = false
|
225
|
+
@no_tlsv1_1 = false
|
226
|
+
end
|
178
227
|
|
179
|
-
if
|
228
|
+
if IS_JRUBY
|
180
229
|
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
181
230
|
attr_reader :keystore
|
182
231
|
attr_accessor :keystore_pass
|
@@ -197,6 +246,7 @@ module Puma
|
|
197
246
|
attr_reader :cert
|
198
247
|
attr_reader :ca
|
199
248
|
attr_accessor :ssl_cipher_filter
|
249
|
+
attr_accessor :verification_flags
|
200
250
|
|
201
251
|
def key=(key)
|
202
252
|
raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
|
@@ -218,41 +268,92 @@ module Puma
|
|
218
268
|
raise "Cert not configured" unless @cert
|
219
269
|
end
|
220
270
|
end
|
271
|
+
|
272
|
+
# disables TLSv1
|
273
|
+
# @!attribute [w] no_tlsv1=
|
274
|
+
def no_tlsv1=(tlsv1)
|
275
|
+
raise ArgumentError, "Invalid value of no_tlsv1=" unless ['true', 'false', true, false].include?(tlsv1)
|
276
|
+
@no_tlsv1 = tlsv1
|
277
|
+
end
|
278
|
+
|
279
|
+
# disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
|
280
|
+
# @!attribute [w] no_tlsv1_1=
|
281
|
+
def no_tlsv1_1=(tlsv1_1)
|
282
|
+
raise ArgumentError, "Invalid value of no_tlsv1_1=" unless ['true', 'false', true, false].include?(tlsv1_1)
|
283
|
+
@no_tlsv1_1 = tlsv1_1
|
284
|
+
end
|
285
|
+
|
221
286
|
end
|
222
287
|
|
223
288
|
VERIFY_NONE = 0
|
224
289
|
VERIFY_PEER = 1
|
225
290
|
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
226
291
|
|
292
|
+
# https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h.in
|
293
|
+
# /* Certificate verify flags */
|
294
|
+
VERIFICATION_FLAGS = {
|
295
|
+
"USE_CHECK_TIME" => 0x2,
|
296
|
+
"CRL_CHECK" => 0x4,
|
297
|
+
"CRL_CHECK_ALL" => 0x8,
|
298
|
+
"IGNORE_CRITICAL" => 0x10,
|
299
|
+
"X509_STRICT" => 0x20,
|
300
|
+
"ALLOW_PROXY_CERTS" => 0x40,
|
301
|
+
"POLICY_CHECK" => 0x80,
|
302
|
+
"EXPLICIT_POLICY" => 0x100,
|
303
|
+
"INHIBIT_ANY" => 0x200,
|
304
|
+
"INHIBIT_MAP" => 0x400,
|
305
|
+
"NOTIFY_POLICY" => 0x800,
|
306
|
+
"EXTENDED_CRL_SUPPORT" => 0x1000,
|
307
|
+
"USE_DELTAS" => 0x2000,
|
308
|
+
"CHECK_SS_SIGNATURE" => 0x4000,
|
309
|
+
"TRUSTED_FIRST" => 0x8000,
|
310
|
+
"SUITEB_128_LOS_ONLY" => 0x10000,
|
311
|
+
"SUITEB_192_LOS" => 0x20000,
|
312
|
+
"SUITEB_128_LOS" => 0x30000,
|
313
|
+
"PARTIAL_CHAIN" => 0x80000,
|
314
|
+
"NO_ALT_CHAINS" => 0x100000,
|
315
|
+
"NO_CHECK_TIME" => 0x200000
|
316
|
+
}.freeze
|
317
|
+
|
227
318
|
class Server
|
228
319
|
def initialize(socket, ctx)
|
229
320
|
@socket = socket
|
230
321
|
@ctx = ctx
|
231
|
-
|
232
|
-
|
233
|
-
def to_io
|
234
|
-
@socket
|
322
|
+
@eng_ctx = IS_JRUBY ? @ctx : SSLContext.new(ctx)
|
235
323
|
end
|
236
324
|
|
237
325
|
def accept
|
238
326
|
@ctx.check
|
239
327
|
io = @socket.accept
|
240
|
-
engine = Engine.server @
|
241
|
-
|
328
|
+
engine = Engine.server @eng_ctx
|
242
329
|
Socket.new io, engine
|
243
330
|
end
|
244
331
|
|
245
332
|
def accept_nonblock
|
246
333
|
@ctx.check
|
247
334
|
io = @socket.accept_nonblock
|
248
|
-
engine = Engine.server @
|
249
|
-
|
335
|
+
engine = Engine.server @eng_ctx
|
250
336
|
Socket.new io, engine
|
251
337
|
end
|
252
338
|
|
339
|
+
# @!attribute [r] to_io
|
340
|
+
def to_io
|
341
|
+
@socket
|
342
|
+
end
|
343
|
+
|
344
|
+
# @!attribute [r] addr
|
345
|
+
# @version 5.0.0
|
346
|
+
def addr
|
347
|
+
@socket.addr
|
348
|
+
end
|
349
|
+
|
253
350
|
def close
|
254
351
|
@socket.close unless @socket.closed? # closed? call is for Windows
|
255
352
|
end
|
353
|
+
|
354
|
+
def closed?
|
355
|
+
@socket.closed?
|
356
|
+
end
|
256
357
|
end
|
257
358
|
end
|
258
359
|
end
|
data/lib/puma/null_io.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
# Provides an IO-like object that always appears to contain no data.
|
3
5
|
# Used as the value for rack.input when the request has no body.
|
@@ -7,13 +9,17 @@ module Puma
|
|
7
9
|
nil
|
8
10
|
end
|
9
11
|
|
12
|
+
def string
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
10
16
|
def each
|
11
17
|
end
|
12
18
|
|
13
19
|
# Mimics IO#read with no data.
|
14
20
|
#
|
15
21
|
def read(count = nil, _buffer = nil)
|
16
|
-
|
22
|
+
count && count > 0 ? nil : ""
|
17
23
|
end
|
18
24
|
|
19
25
|
def rewind
|
@@ -30,6 +36,10 @@ module Puma
|
|
30
36
|
true
|
31
37
|
end
|
32
38
|
|
39
|
+
def sync
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
33
43
|
def sync=(v)
|
34
44
|
end
|
35
45
|
|
@@ -38,5 +48,9 @@ module Puma
|
|
38
48
|
|
39
49
|
def write(*ary)
|
40
50
|
end
|
51
|
+
|
52
|
+
def flush
|
53
|
+
self
|
54
|
+
end
|
41
55
|
end
|
42
56
|
end
|
data/lib/puma/plugin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
class UnknownPlugin < RuntimeError; end
|
3
5
|
|
@@ -8,7 +10,7 @@ module Puma
|
|
8
10
|
|
9
11
|
def create(name)
|
10
12
|
if cls = Plugins.find(name)
|
11
|
-
plugin = cls.new
|
13
|
+
plugin = cls.new
|
12
14
|
@instances << plugin
|
13
15
|
return plugin
|
14
16
|
end
|
@@ -60,8 +62,11 @@ module Puma
|
|
60
62
|
end
|
61
63
|
|
62
64
|
def fire_background
|
63
|
-
@background.
|
64
|
-
Thread.new
|
65
|
+
@background.each_with_index do |b, i|
|
66
|
+
Thread.new do
|
67
|
+
Puma.set_thread_name "plugin background #{i}"
|
68
|
+
b.call
|
69
|
+
end
|
65
70
|
end
|
66
71
|
end
|
67
72
|
end
|
@@ -99,17 +104,8 @@ module Puma
|
|
99
104
|
Plugins.register name, cls
|
100
105
|
end
|
101
106
|
|
102
|
-
def initialize(loader)
|
103
|
-
@loader = loader
|
104
|
-
end
|
105
|
-
|
106
107
|
def in_background(&blk)
|
107
108
|
Plugins.add_background blk
|
108
109
|
end
|
109
|
-
|
110
|
-
def workers_supported?
|
111
|
-
return false if Puma.jruby? || Puma.windows?
|
112
|
-
true
|
113
|
-
end
|
114
110
|
end
|
115
111
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class ClosedQueueError < StandardError; end
|
2
|
+
module Puma
|
3
|
+
|
4
|
+
# Queue#close was added in Ruby 2.3.
|
5
|
+
# Add a simple implementation for earlier Ruby versions.
|
6
|
+
#
|
7
|
+
module QueueClose
|
8
|
+
def close
|
9
|
+
num_waiting.times {push nil}
|
10
|
+
@closed = true
|
11
|
+
end
|
12
|
+
def closed?
|
13
|
+
@closed ||= false
|
14
|
+
end
|
15
|
+
def push(object)
|
16
|
+
raise ClosedQueueError if closed?
|
17
|
+
super
|
18
|
+
end
|
19
|
+
alias << push
|
20
|
+
def pop(non_block=false)
|
21
|
+
return nil if !non_block && closed? && empty?
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
::Queue.prepend QueueClose
|
26
|
+
end
|
data/lib/puma/rack/builder.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Puma
|
2
4
|
end
|
3
5
|
|
@@ -65,10 +67,6 @@ module Puma::Rack
|
|
65
67
|
options[:environment] = e
|
66
68
|
}
|
67
69
|
|
68
|
-
opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
|
69
|
-
options[:daemonize] = d ? true : false
|
70
|
-
}
|
71
|
-
|
72
70
|
opts.on("-P", "--pid FILE", "file to store PID") { |f|
|
73
71
|
options[:pid] = ::File.expand_path(f)
|
74
72
|
}
|
@@ -110,7 +108,8 @@ module Puma::Rack
|
|
110
108
|
|
111
109
|
has_options = false
|
112
110
|
server.valid_options.each do |name, description|
|
113
|
-
next if name.to_s
|
111
|
+
next if name.to_s =~ /^(Host|Port)[^a-zA-Z]/ # ignore handler's host and port options, we do our own.
|
112
|
+
|
114
113
|
info << " -O %-21s %s" % [name, description]
|
115
114
|
has_options = true
|
116
115
|
end
|
data/lib/puma/rack/urlmap.rb
CHANGED