puma 4.3.12 → 6.0.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 +1618 -521
- data/LICENSE +23 -20
- data/README.md +130 -42
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +63 -26
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +60 -69
- data/docs/fork_worker.md +31 -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 +2 -2
- data/docs/plugins.md +15 -15
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +46 -23
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +85 -128
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +49 -12
- data/ext/puma_http11/http11_parser.c +46 -48
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +3 -3
- data/ext/puma_http11/http11_parser.rl +3 -3
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +250 -93
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +4 -6
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
- data/ext/puma_http11/puma_http11.c +46 -57
- data/lib/puma/app/status.rb +52 -38
- data/lib/puma/binder.rb +232 -119
- data/lib/puma/cli.rb +33 -33
- data/lib/puma/client.rb +129 -88
- data/lib/puma/cluster/worker.rb +175 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +224 -231
- data/lib/puma/commonlogger.rb +2 -2
- data/lib/puma/configuration.rb +112 -87
- data/lib/puma/const.rb +86 -91
- data/lib/puma/control_cli.rb +99 -79
- data/lib/puma/detect.rb +31 -2
- data/lib/puma/dsl.rb +426 -110
- data/lib/puma/error_logger.rb +112 -0
- data/lib/puma/events.rb +16 -115
- data/lib/puma/io_buffer.rb +44 -2
- data/lib/puma/jruby_restart.rb +2 -59
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +170 -148
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +35 -19
- data/lib/puma/minissl.rb +213 -55
- data/lib/puma/null_io.rb +18 -1
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +3 -12
- data/lib/puma/rack/builder.rb +5 -9
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +85 -369
- data/lib/puma/request.rb +644 -0
- data/lib/puma/runner.rb +86 -76
- data/lib/puma/server.rb +306 -793
- data/lib/puma/single.rb +18 -74
- data/lib/puma/state_file.rb +45 -8
- data/lib/puma/systemd.rb +47 -0
- data/lib/puma/thread_pool.rb +136 -68
- data/lib/puma/util.rb +21 -4
- data/lib/puma.rb +54 -7
- data/lib/rack/handler/puma.rb +11 -12
- data/tools/{docker/Dockerfile → Dockerfile} +1 -1
- metadata +31 -23
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/accept_nonblock.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -41
- 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
@@ -1,12 +1,9 @@
|
|
1
1
|
module Puma
|
2
2
|
module MiniSSL
|
3
3
|
class ContextBuilder
|
4
|
-
def initialize(params,
|
5
|
-
require 'puma/minissl'
|
6
|
-
MiniSSL.check
|
7
|
-
|
4
|
+
def initialize(params, log_writer)
|
8
5
|
@params = params
|
9
|
-
@
|
6
|
+
@log_writer = log_writer
|
10
7
|
end
|
11
8
|
|
12
9
|
def context
|
@@ -14,42 +11,55 @@ module Puma
|
|
14
11
|
|
15
12
|
if defined?(JRUBY_VERSION)
|
16
13
|
unless params['keystore']
|
17
|
-
|
14
|
+
log_writer.error "Please specify the Java keystore via 'keystore='"
|
18
15
|
end
|
19
16
|
|
20
17
|
ctx.keystore = params['keystore']
|
21
18
|
|
22
19
|
unless params['keystore-pass']
|
23
|
-
|
20
|
+
log_writer.error "Please specify the Java keystore password via 'keystore-pass='"
|
24
21
|
end
|
25
22
|
|
26
23
|
ctx.keystore_pass = params['keystore-pass']
|
27
|
-
ctx.
|
24
|
+
ctx.keystore_type = params['keystore-type']
|
25
|
+
|
26
|
+
if truststore = params['truststore']
|
27
|
+
ctx.truststore = truststore.eql?('default') ? :default : truststore
|
28
|
+
ctx.truststore_pass = params['truststore-pass']
|
29
|
+
ctx.truststore_type = params['truststore-type']
|
30
|
+
end
|
31
|
+
|
32
|
+
ctx.cipher_suites = params['cipher_suites'] || params['ssl_cipher_list']
|
33
|
+
ctx.protocols = params['protocols'] if params['protocols']
|
28
34
|
else
|
29
|
-
|
30
|
-
|
35
|
+
if params['key'].nil? && params['key_pem'].nil?
|
36
|
+
log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
|
31
37
|
end
|
32
38
|
|
33
|
-
ctx.key = params['key']
|
39
|
+
ctx.key = params['key'] if params['key']
|
40
|
+
ctx.key_pem = params['key_pem'] if params['key_pem']
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
if params['cert'].nil? && params['cert_pem'].nil?
|
43
|
+
log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
|
37
44
|
end
|
38
45
|
|
39
|
-
ctx.cert = params['cert']
|
46
|
+
ctx.cert = params['cert'] if params['cert']
|
47
|
+
ctx.cert_pem = params['cert_pem'] if params['cert_pem']
|
40
48
|
|
41
49
|
if ['peer', 'force_peer'].include?(params['verify_mode'])
|
42
50
|
unless params['ca']
|
43
|
-
|
51
|
+
log_writer.error "Please specify the SSL ca via 'ca='"
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
47
55
|
ctx.ca = params['ca'] if params['ca']
|
48
56
|
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
|
57
|
+
|
58
|
+
ctx.reuse = params['reuse'] if params['reuse']
|
49
59
|
end
|
50
60
|
|
51
|
-
ctx.no_tlsv1
|
52
|
-
ctx.no_tlsv1_1 =
|
61
|
+
ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
|
62
|
+
ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
|
53
63
|
|
54
64
|
if params['verify_mode']
|
55
65
|
ctx.verify_mode = case params['verify_mode']
|
@@ -60,17 +70,23 @@ module Puma
|
|
60
70
|
when "none"
|
61
71
|
MiniSSL::VERIFY_NONE
|
62
72
|
else
|
63
|
-
|
73
|
+
log_writer.error "Please specify a valid verify_mode="
|
64
74
|
MiniSSL::VERIFY_NONE
|
65
75
|
end
|
66
76
|
end
|
67
77
|
|
78
|
+
if params['verification_flags']
|
79
|
+
ctx.verification_flags = params['verification_flags'].split(',').
|
80
|
+
map { |flag| MiniSSL::VERIFICATION_FLAGS.fetch(flag) }.
|
81
|
+
inject { |sum, flag| sum ? sum | flag : flag }
|
82
|
+
end
|
83
|
+
|
68
84
|
ctx
|
69
85
|
end
|
70
86
|
|
71
87
|
private
|
72
88
|
|
73
|
-
attr_reader :params, :
|
89
|
+
attr_reader :params, :log_writer
|
74
90
|
end
|
75
91
|
end
|
76
92
|
end
|
data/lib/puma/minissl.rb
CHANGED
@@ -1,19 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
begin
|
4
|
-
require 'io/wait'
|
4
|
+
require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
|
5
5
|
rescue LoadError
|
6
6
|
end
|
7
7
|
|
8
|
+
# need for Puma::MiniSSL::OPENSSL constants used in `HAS_TLS1_3`
|
9
|
+
# use require, see https://github.com/puma/puma/pull/2381
|
10
|
+
require 'puma/puma_http11'
|
11
|
+
|
8
12
|
module Puma
|
9
13
|
module MiniSSL
|
14
|
+
# Define constant at runtime, as it's easy to determine at built time,
|
15
|
+
# but Puma could (it shouldn't) be loaded with an older OpenSSL version
|
16
|
+
# @version 5.0.0
|
17
|
+
HAS_TLS1_3 = IS_JRUBY ||
|
18
|
+
((OPENSSL_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) != -1 &&
|
19
|
+
(OPENSSL_LIBRARY_VERSION[/ \d+\.\d+\.\d+/].split('.').map(&:to_i) <=> [1,1,1]) !=-1)
|
20
|
+
|
10
21
|
class Socket
|
11
22
|
def initialize(socket, engine)
|
12
23
|
@socket = socket
|
13
24
|
@engine = engine
|
14
25
|
@peercert = nil
|
26
|
+
@reuse = nil
|
15
27
|
end
|
16
28
|
|
29
|
+
# @!attribute [r] to_io
|
17
30
|
def to_io
|
18
31
|
@socket
|
19
32
|
end
|
@@ -22,6 +35,27 @@ module Puma
|
|
22
35
|
@socket.closed?
|
23
36
|
end
|
24
37
|
|
38
|
+
# Returns a two element array,
|
39
|
+
# first is protocol version (SSL_get_version),
|
40
|
+
# second is 'handshake' state (SSL_state_string)
|
41
|
+
#
|
42
|
+
# Used for dropping tcp connections to ssl.
|
43
|
+
# See OpenSSL ssl/ssl_stat.c SSL_state_string for info
|
44
|
+
# @!attribute [r] ssl_version_state
|
45
|
+
# @version 5.0.0
|
46
|
+
#
|
47
|
+
def ssl_version_state
|
48
|
+
IS_JRUBY ? [nil, nil] : @engine.ssl_vers_st
|
49
|
+
end
|
50
|
+
|
51
|
+
# Used to check the handshake status, in particular when a TCP connection
|
52
|
+
# is made with TLSv1.3 as an available protocol
|
53
|
+
# @version 5.0.0
|
54
|
+
def bad_tlsv1_3?
|
55
|
+
HAS_TLS1_3 && ssl_version_state == ['TLSv1.3', 'SSLERR']
|
56
|
+
end
|
57
|
+
private :bad_tlsv1_3?
|
58
|
+
|
25
59
|
def readpartial(size)
|
26
60
|
while true
|
27
61
|
output = @engine.read
|
@@ -67,6 +101,7 @@ module Puma
|
|
67
101
|
# ourselves.
|
68
102
|
raise IO::EAGAINWaitReadable
|
69
103
|
elsif data.nil?
|
104
|
+
raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
|
70
105
|
return nil
|
71
106
|
end
|
72
107
|
|
@@ -84,22 +119,23 @@ module Puma
|
|
84
119
|
def write(data)
|
85
120
|
return 0 if data.empty?
|
86
121
|
|
87
|
-
|
122
|
+
data_size = data.bytesize
|
123
|
+
need = data_size
|
88
124
|
|
89
125
|
while true
|
90
126
|
wrote = @engine.write data
|
91
|
-
enc = @engine.extract
|
92
127
|
|
93
|
-
|
94
|
-
|
95
|
-
|
128
|
+
enc_wr = +''
|
129
|
+
while (enc = @engine.extract)
|
130
|
+
enc_wr << enc
|
96
131
|
end
|
132
|
+
@socket.write enc_wr unless enc_wr.empty?
|
97
133
|
|
98
134
|
need -= wrote
|
99
135
|
|
100
|
-
return
|
136
|
+
return data_size if need == 0
|
101
137
|
|
102
|
-
data = data
|
138
|
+
data = data.byteslice(wrote..-1)
|
103
139
|
end
|
104
140
|
end
|
105
141
|
|
@@ -107,14 +143,18 @@ module Puma
|
|
107
143
|
alias_method :<<, :write
|
108
144
|
|
109
145
|
# This is a temporary fix to deal with websockets code using
|
110
|
-
# write_nonblock.
|
146
|
+
# write_nonblock.
|
147
|
+
|
148
|
+
# The problem with implementing it properly
|
111
149
|
# is that it means we'd have to have the ability to rewind
|
112
150
|
# an engine because after we write+extract, the socket
|
113
151
|
# write_nonblock call might raise an exception and later
|
114
152
|
# code would pass the same data in, but the engine would think
|
115
|
-
# it had already written the data in.
|
116
|
-
#
|
117
|
-
#
|
153
|
+
# it had already written the data in.
|
154
|
+
#
|
155
|
+
# So for the time being (and since write blocking is quite rare),
|
156
|
+
# go ahead and actually block in write_nonblock.
|
157
|
+
#
|
118
158
|
def write_nonblock(data, *_)
|
119
159
|
write data
|
120
160
|
end
|
@@ -123,39 +163,27 @@ module Puma
|
|
123
163
|
@socket.flush
|
124
164
|
end
|
125
165
|
|
126
|
-
def read_and_drop(timeout = 1)
|
127
|
-
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
128
|
-
return :eof unless read_nonblock(1024)
|
129
|
-
:drop
|
130
|
-
rescue Errno::EAGAIN
|
131
|
-
# do nothing
|
132
|
-
:eagain
|
133
|
-
end
|
134
|
-
|
135
|
-
def should_drop_bytes?
|
136
|
-
@engine.init? || !@engine.shutdown
|
137
|
-
end
|
138
|
-
|
139
166
|
def close
|
140
167
|
begin
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
return if [:timeout, :eof].include?(read_and_drop(1))
|
168
|
+
unless @engine.shutdown
|
169
|
+
while alert_data = @engine.extract
|
170
|
+
@socket.write alert_data
|
171
|
+
end
|
146
172
|
end
|
147
173
|
rescue IOError, SystemCallError
|
148
|
-
|
174
|
+
Puma::Util.purge_interrupt_queue
|
149
175
|
# nothing
|
150
176
|
ensure
|
151
177
|
@socket.close
|
152
178
|
end
|
153
179
|
end
|
154
180
|
|
181
|
+
# @!attribute [r] peeraddr
|
155
182
|
def peeraddr
|
156
183
|
@socket.peeraddr
|
157
184
|
end
|
158
185
|
|
186
|
+
# @!attribute [r] peercert
|
159
187
|
def peercert
|
160
188
|
return @peercert if @peercert
|
161
189
|
|
@@ -166,12 +194,9 @@ module Puma
|
|
166
194
|
end
|
167
195
|
end
|
168
196
|
|
169
|
-
if
|
170
|
-
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
def self.check; end
|
197
|
+
if IS_JRUBY
|
198
|
+
OPENSSL_NO_SSL3 = false
|
199
|
+
OPENSSL_NO_TLS1 = false
|
175
200
|
end
|
176
201
|
|
177
202
|
class Context
|
@@ -181,21 +206,72 @@ module Puma
|
|
181
206
|
def initialize
|
182
207
|
@no_tlsv1 = false
|
183
208
|
@no_tlsv1_1 = false
|
209
|
+
@key = nil
|
210
|
+
@cert = nil
|
211
|
+
@key_pem = nil
|
212
|
+
@cert_pem = nil
|
213
|
+
@reuse = nil
|
214
|
+
@reuse_cache_size = nil
|
215
|
+
@reuse_timeout = nil
|
184
216
|
end
|
185
217
|
|
186
|
-
|
218
|
+
def check_file(file, desc)
|
219
|
+
raise ArgumentError, "#{desc} file '#{file}' does not exist" unless File.exist? file
|
220
|
+
raise ArgumentError, "#{desc} file '#{file}' is not readable" unless File.readable? file
|
221
|
+
end
|
222
|
+
|
223
|
+
if IS_JRUBY
|
187
224
|
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
188
225
|
attr_reader :keystore
|
226
|
+
attr_reader :keystore_type
|
189
227
|
attr_accessor :keystore_pass
|
190
|
-
|
228
|
+
attr_reader :truststore
|
229
|
+
attr_reader :truststore_type
|
230
|
+
attr_accessor :truststore_pass
|
231
|
+
attr_reader :cipher_suites
|
232
|
+
attr_reader :protocols
|
191
233
|
|
192
234
|
def keystore=(keystore)
|
193
|
-
|
235
|
+
check_file keystore, 'Keystore'
|
194
236
|
@keystore = keystore
|
195
237
|
end
|
196
238
|
|
239
|
+
def truststore=(truststore)
|
240
|
+
# NOTE: historically truststore was assumed the same as keystore, this is kept for backwards
|
241
|
+
# compatibility, to rely on JVM's trust defaults we allow setting `truststore = :default`
|
242
|
+
unless truststore.eql?(:default)
|
243
|
+
raise ArgumentError, "No such truststore file '#{truststore}'" unless File.exist?(truststore)
|
244
|
+
end
|
245
|
+
@truststore = truststore
|
246
|
+
end
|
247
|
+
|
248
|
+
def keystore_type=(type)
|
249
|
+
raise ArgumentError, "Invalid keystore type: #{type.inspect}" unless ['pkcs12', 'jks', nil].include?(type)
|
250
|
+
@keystore_type = type
|
251
|
+
end
|
252
|
+
|
253
|
+
def truststore_type=(type)
|
254
|
+
raise ArgumentError, "Invalid truststore type: #{type.inspect}" unless ['pkcs12', 'jks', nil].include?(type)
|
255
|
+
@truststore_type = type
|
256
|
+
end
|
257
|
+
|
258
|
+
def cipher_suites=(list)
|
259
|
+
list = list.split(',').map(&:strip) if list.is_a?(String)
|
260
|
+
@cipher_suites = list
|
261
|
+
end
|
262
|
+
|
263
|
+
# aliases for backwards compatibility
|
264
|
+
alias_method :ssl_cipher_list, :cipher_suites
|
265
|
+
alias_method :ssl_cipher_list=, :cipher_suites=
|
266
|
+
|
267
|
+
def protocols=(list)
|
268
|
+
list = list.split(',').map(&:strip) if list.is_a?(String)
|
269
|
+
@protocols = list
|
270
|
+
end
|
271
|
+
|
197
272
|
def check
|
198
273
|
raise "Keystore not configured" unless @keystore
|
274
|
+
# @truststore defaults to @keystore due backwards compatibility
|
199
275
|
end
|
200
276
|
|
201
277
|
else
|
@@ -203,38 +279,84 @@ module Puma
|
|
203
279
|
attr_reader :key
|
204
280
|
attr_reader :cert
|
205
281
|
attr_reader :ca
|
282
|
+
attr_reader :cert_pem
|
283
|
+
attr_reader :key_pem
|
206
284
|
attr_accessor :ssl_cipher_filter
|
285
|
+
attr_accessor :verification_flags
|
286
|
+
|
287
|
+
attr_reader :reuse, :reuse_cache_size, :reuse_timeout
|
207
288
|
|
208
289
|
def key=(key)
|
209
|
-
|
290
|
+
check_file key, 'Key'
|
210
291
|
@key = key
|
211
292
|
end
|
212
293
|
|
213
294
|
def cert=(cert)
|
214
|
-
|
295
|
+
check_file cert, 'Cert'
|
215
296
|
@cert = cert
|
216
297
|
end
|
217
298
|
|
218
299
|
def ca=(ca)
|
219
|
-
|
300
|
+
check_file ca, 'ca'
|
220
301
|
@ca = ca
|
221
302
|
end
|
222
303
|
|
304
|
+
def cert_pem=(cert_pem)
|
305
|
+
raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String
|
306
|
+
@cert_pem = cert_pem
|
307
|
+
end
|
308
|
+
|
309
|
+
def key_pem=(key_pem)
|
310
|
+
raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String
|
311
|
+
@key_pem = key_pem
|
312
|
+
end
|
313
|
+
|
223
314
|
def check
|
224
|
-
raise "Key not configured"
|
225
|
-
raise "Cert not configured"
|
315
|
+
raise "Key not configured" if @key.nil? && @key_pem.nil?
|
316
|
+
raise "Cert not configured" if @cert.nil? && @cert_pem.nil?
|
317
|
+
end
|
318
|
+
|
319
|
+
# Controls session reuse. Allowed values are as follows:
|
320
|
+
# * 'off' - matches the behavior of Puma 5.6 and earlier. This is included
|
321
|
+
# in case reuse 'on' is made the default in future Puma versions.
|
322
|
+
# * 'dflt' - sets session reuse on, with OpenSSL default cache size of
|
323
|
+
# 20k and default timeout of 300 seconds.
|
324
|
+
# * 's,t' - where s and t are integer strings, for size and timeout.
|
325
|
+
# * 's' - where s is an integer strings for size.
|
326
|
+
# * ',t' - where t is an integer strings for timeout.
|
327
|
+
#
|
328
|
+
def reuse=(reuse_str)
|
329
|
+
case reuse_str
|
330
|
+
when 'off'
|
331
|
+
@reuse = nil
|
332
|
+
when 'dflt'
|
333
|
+
@reuse = true
|
334
|
+
when /\A\d+\z/
|
335
|
+
@reuse = true
|
336
|
+
@reuse_cache_size = reuse_str.to_i
|
337
|
+
when /\A\d+,\d+\z/
|
338
|
+
@reuse = true
|
339
|
+
size, time = reuse_str.split ','
|
340
|
+
@reuse_cache_size = size.to_i
|
341
|
+
@reuse_timeout = time.to_i
|
342
|
+
when /\A,\d+\z/
|
343
|
+
@reuse = true
|
344
|
+
@reuse_timeout = reuse_str.delete(',').to_i
|
345
|
+
end
|
226
346
|
end
|
227
347
|
end
|
228
348
|
|
229
349
|
# disables TLSv1
|
350
|
+
# @!attribute [w] no_tlsv1=
|
230
351
|
def no_tlsv1=(tlsv1)
|
231
|
-
raise ArgumentError, "Invalid value of no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1)
|
352
|
+
raise ArgumentError, "Invalid value of no_tlsv1=" unless ['true', 'false', true, false].include?(tlsv1)
|
232
353
|
@no_tlsv1 = tlsv1
|
233
354
|
end
|
234
355
|
|
235
356
|
# disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
|
357
|
+
# @!attribute [w] no_tlsv1_1=
|
236
358
|
def no_tlsv1_1=(tlsv1_1)
|
237
|
-
raise ArgumentError, "Invalid value of
|
359
|
+
raise ArgumentError, "Invalid value of no_tlsv1_1=" unless ['true', 'false', true, false].include?(tlsv1_1)
|
238
360
|
@no_tlsv1_1 = tlsv1_1
|
239
361
|
end
|
240
362
|
|
@@ -244,35 +366,71 @@ module Puma
|
|
244
366
|
VERIFY_PEER = 1
|
245
367
|
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
246
368
|
|
369
|
+
# https://github.com/openssl/openssl/blob/master/include/openssl/x509_vfy.h.in
|
370
|
+
# /* Certificate verify flags */
|
371
|
+
VERIFICATION_FLAGS = {
|
372
|
+
"USE_CHECK_TIME" => 0x2,
|
373
|
+
"CRL_CHECK" => 0x4,
|
374
|
+
"CRL_CHECK_ALL" => 0x8,
|
375
|
+
"IGNORE_CRITICAL" => 0x10,
|
376
|
+
"X509_STRICT" => 0x20,
|
377
|
+
"ALLOW_PROXY_CERTS" => 0x40,
|
378
|
+
"POLICY_CHECK" => 0x80,
|
379
|
+
"EXPLICIT_POLICY" => 0x100,
|
380
|
+
"INHIBIT_ANY" => 0x200,
|
381
|
+
"INHIBIT_MAP" => 0x400,
|
382
|
+
"NOTIFY_POLICY" => 0x800,
|
383
|
+
"EXTENDED_CRL_SUPPORT" => 0x1000,
|
384
|
+
"USE_DELTAS" => 0x2000,
|
385
|
+
"CHECK_SS_SIGNATURE" => 0x4000,
|
386
|
+
"TRUSTED_FIRST" => 0x8000,
|
387
|
+
"SUITEB_128_LOS_ONLY" => 0x10000,
|
388
|
+
"SUITEB_192_LOS" => 0x20000,
|
389
|
+
"SUITEB_128_LOS" => 0x30000,
|
390
|
+
"PARTIAL_CHAIN" => 0x80000,
|
391
|
+
"NO_ALT_CHAINS" => 0x100000,
|
392
|
+
"NO_CHECK_TIME" => 0x200000
|
393
|
+
}.freeze
|
394
|
+
|
247
395
|
class Server
|
248
396
|
def initialize(socket, ctx)
|
249
397
|
@socket = socket
|
250
398
|
@ctx = ctx
|
251
|
-
|
252
|
-
|
253
|
-
def to_io
|
254
|
-
@socket
|
399
|
+
@eng_ctx = IS_JRUBY ? @ctx : SSLContext.new(ctx)
|
255
400
|
end
|
256
401
|
|
257
402
|
def accept
|
258
403
|
@ctx.check
|
259
404
|
io = @socket.accept
|
260
|
-
engine = Engine.server @
|
261
|
-
|
405
|
+
engine = Engine.server @eng_ctx
|
262
406
|
Socket.new io, engine
|
263
407
|
end
|
264
408
|
|
265
409
|
def accept_nonblock
|
266
410
|
@ctx.check
|
267
411
|
io = @socket.accept_nonblock
|
268
|
-
engine = Engine.server @
|
269
|
-
|
412
|
+
engine = Engine.server @eng_ctx
|
270
413
|
Socket.new io, engine
|
271
414
|
end
|
272
415
|
|
416
|
+
# @!attribute [r] to_io
|
417
|
+
def to_io
|
418
|
+
@socket
|
419
|
+
end
|
420
|
+
|
421
|
+
# @!attribute [r] addr
|
422
|
+
# @version 5.0.0
|
423
|
+
def addr
|
424
|
+
@socket.addr
|
425
|
+
end
|
426
|
+
|
273
427
|
def close
|
274
428
|
@socket.close unless @socket.closed? # closed? call is for Windows
|
275
429
|
end
|
430
|
+
|
431
|
+
def closed?
|
432
|
+
@socket.closed?
|
433
|
+
end
|
276
434
|
end
|
277
435
|
end
|
278
436
|
end
|
data/lib/puma/null_io.rb
CHANGED
@@ -9,13 +9,17 @@ module Puma
|
|
9
9
|
nil
|
10
10
|
end
|
11
11
|
|
12
|
+
def string
|
13
|
+
""
|
14
|
+
end
|
15
|
+
|
12
16
|
def each
|
13
17
|
end
|
14
18
|
|
15
19
|
# Mimics IO#read with no data.
|
16
20
|
#
|
17
21
|
def read(count = nil, _buffer = nil)
|
18
|
-
|
22
|
+
count && count > 0 ? nil : ""
|
19
23
|
end
|
20
24
|
|
21
25
|
def rewind
|
@@ -32,6 +36,10 @@ module Puma
|
|
32
36
|
true
|
33
37
|
end
|
34
38
|
|
39
|
+
def sync
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
35
43
|
def sync=(v)
|
36
44
|
end
|
37
45
|
|
@@ -40,5 +48,14 @@ module Puma
|
|
40
48
|
|
41
49
|
def write(*ary)
|
42
50
|
end
|
51
|
+
|
52
|
+
def flush
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# This is used as singleton class, so can't have state.
|
57
|
+
def closed?
|
58
|
+
false
|
59
|
+
end
|
43
60
|
end
|
44
61
|
end
|
data/lib/puma/plugin.rb
CHANGED
@@ -10,7 +10,7 @@ module Puma
|
|
10
10
|
|
11
11
|
def create(name)
|
12
12
|
if cls = Plugins.find(name)
|
13
|
-
plugin = cls.new
|
13
|
+
plugin = cls.new
|
14
14
|
@instances << plugin
|
15
15
|
return plugin
|
16
16
|
end
|
@@ -64,7 +64,7 @@ module Puma
|
|
64
64
|
def fire_background
|
65
65
|
@background.each_with_index do |b, i|
|
66
66
|
Thread.new do
|
67
|
-
Puma.set_thread_name "
|
67
|
+
Puma.set_thread_name "plgn bg #{i}"
|
68
68
|
b.call
|
69
69
|
end
|
70
70
|
end
|
@@ -91,7 +91,7 @@ module Puma
|
|
91
91
|
path = ary.first[CALLER_FILE]
|
92
92
|
|
93
93
|
m = %r!puma/plugin/([^/]*)\.rb$!.match(path)
|
94
|
-
|
94
|
+
m[1]
|
95
95
|
end
|
96
96
|
|
97
97
|
def self.create(&blk)
|
@@ -104,17 +104,8 @@ module Puma
|
|
104
104
|
Plugins.register name, cls
|
105
105
|
end
|
106
106
|
|
107
|
-
def initialize(loader)
|
108
|
-
@loader = loader
|
109
|
-
end
|
110
|
-
|
111
107
|
def in_background(&blk)
|
112
108
|
Plugins.add_background blk
|
113
109
|
end
|
114
|
-
|
115
|
-
def workers_supported?
|
116
|
-
return false if Puma.jruby? || Puma.windows?
|
117
|
-
true
|
118
|
-
end
|
119
110
|
end
|
120
111
|
end
|
data/lib/puma/rack/builder.rb
CHANGED
@@ -67,10 +67,6 @@ module Puma::Rack
|
|
67
67
|
options[:environment] = e
|
68
68
|
}
|
69
69
|
|
70
|
-
opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
|
71
|
-
options[:daemonize] = d ? true : false
|
72
|
-
}
|
73
|
-
|
74
70
|
opts.on("-P", "--pid FILE", "file to store PID") { |f|
|
75
71
|
options[:pid] = ::File.expand_path(f)
|
76
72
|
}
|
@@ -106,13 +102,13 @@ module Puma::Rack
|
|
106
102
|
begin
|
107
103
|
info = []
|
108
104
|
server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
|
109
|
-
if server
|
105
|
+
if server&.respond_to?(:valid_options)
|
110
106
|
info << ""
|
111
107
|
info << "Server-specific options for #{server.name}:"
|
112
108
|
|
113
109
|
has_options = false
|
114
110
|
server.valid_options.each do |name, description|
|
115
|
-
next if
|
111
|
+
next if /^(Host|Port)[^a-zA-Z]/.match? name.to_s # ignore handler's host and port options, we do our own.
|
116
112
|
|
117
113
|
info << " -O %-21s %s" % [name, description]
|
118
114
|
has_options = true
|
@@ -169,7 +165,7 @@ module Puma::Rack
|
|
169
165
|
require config
|
170
166
|
app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
171
167
|
end
|
172
|
-
|
168
|
+
[app, options]
|
173
169
|
end
|
174
170
|
|
175
171
|
def self.new_from_string(builder_script, file="(rackup)")
|
@@ -280,7 +276,7 @@ module Puma::Rack
|
|
280
276
|
app = @map ? generate_map(@run, @map) : @run
|
281
277
|
fail "missing run or map statement" unless app
|
282
278
|
app = @use.reverse.inject(app) { |a,e| e[a] }
|
283
|
-
@warmup
|
279
|
+
@warmup&.call app
|
284
280
|
app
|
285
281
|
end
|
286
282
|
|
@@ -291,7 +287,7 @@ module Puma::Rack
|
|
291
287
|
private
|
292
288
|
|
293
289
|
def generate_map(default_app, mapping)
|
294
|
-
|
290
|
+
require_relative 'urlmap'
|
295
291
|
|
296
292
|
mapped = default_app ? {'/' => default_app} : {}
|
297
293
|
mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b).to_app }
|