puma 3.11.4 → 6.0.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 +1717 -432
- data/LICENSE +23 -20
- data/README.md +190 -64
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +59 -21
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +69 -58
- data/docs/fork_worker.md +31 -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 +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 +22 -12
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +47 -22
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +95 -120
- 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 -2
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +61 -3
- data/ext/puma_http11/http11_parser.c +106 -118
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +22 -38
- data/ext/puma_http11/http11_parser.rl +6 -4
- data/ext/puma_http11/http11_parser_common.rl +6 -6
- data/ext/puma_http11/mini_ssl.c +376 -93
- 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 +84 -99
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +250 -88
- data/ext/puma_http11/puma_http11.c +49 -57
- data/lib/puma/app/status.rb +71 -49
- data/lib/puma/binder.rb +243 -148
- data/lib/puma/cli.rb +50 -36
- data/lib/puma/client.rb +373 -233
- data/lib/puma/cluster/worker.rb +175 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +268 -235
- data/lib/puma/commonlogger.rb +4 -2
- data/lib/puma/configuration.rb +116 -88
- data/lib/puma/const.rb +49 -30
- data/lib/puma/control_cli.rb +123 -76
- data/lib/puma/detect.rb +33 -2
- data/lib/puma/dsl.rb +685 -135
- data/lib/puma/error_logger.rb +112 -0
- data/lib/puma/events.rb +17 -111
- data/lib/puma/io_buffer.rb +44 -5
- data/lib/puma/jruby_restart.rb +4 -59
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +196 -130
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +92 -0
- data/lib/puma/minissl.rb +249 -69
- data/lib/puma/null_io.rb +20 -1
- data/lib/puma/plugin/tmp_restart.rb +3 -1
- data/lib/puma/plugin.rb +9 -13
- data/lib/puma/rack/builder.rb +8 -9
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +3 -1
- data/lib/puma/reactor.rb +90 -187
- data/lib/puma/request.rb +644 -0
- data/lib/puma/runner.rb +94 -71
- data/lib/puma/server.rb +337 -715
- data/lib/puma/single.rb +27 -72
- data/lib/puma/state_file.rb +46 -7
- data/lib/puma/systemd.rb +47 -0
- data/lib/puma/thread_pool.rb +184 -93
- data/lib/puma/util.rb +23 -10
- data/lib/puma.rb +60 -3
- data/lib/rack/handler/puma.rb +17 -15
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +53 -33
- 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
@@ -0,0 +1,92 @@
|
|
1
|
+
module Puma
|
2
|
+
module MiniSSL
|
3
|
+
class ContextBuilder
|
4
|
+
def initialize(params, log_writer)
|
5
|
+
@params = params
|
6
|
+
@log_writer = log_writer
|
7
|
+
end
|
8
|
+
|
9
|
+
def context
|
10
|
+
ctx = MiniSSL::Context.new
|
11
|
+
|
12
|
+
if defined?(JRUBY_VERSION)
|
13
|
+
unless params['keystore']
|
14
|
+
log_writer.error "Please specify the Java keystore via 'keystore='"
|
15
|
+
end
|
16
|
+
|
17
|
+
ctx.keystore = params['keystore']
|
18
|
+
|
19
|
+
unless params['keystore-pass']
|
20
|
+
log_writer.error "Please specify the Java keystore password via 'keystore-pass='"
|
21
|
+
end
|
22
|
+
|
23
|
+
ctx.keystore_pass = params['keystore-pass']
|
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']
|
34
|
+
else
|
35
|
+
if params['key'].nil? && params['key_pem'].nil?
|
36
|
+
log_writer.error "Please specify the SSL key via 'key=' or 'key_pem='"
|
37
|
+
end
|
38
|
+
|
39
|
+
ctx.key = params['key'] if params['key']
|
40
|
+
ctx.key_pem = params['key_pem'] if params['key_pem']
|
41
|
+
|
42
|
+
if params['cert'].nil? && params['cert_pem'].nil?
|
43
|
+
log_writer.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
|
44
|
+
end
|
45
|
+
|
46
|
+
ctx.cert = params['cert'] if params['cert']
|
47
|
+
ctx.cert_pem = params['cert_pem'] if params['cert_pem']
|
48
|
+
|
49
|
+
if ['peer', 'force_peer'].include?(params['verify_mode'])
|
50
|
+
unless params['ca']
|
51
|
+
log_writer.error "Please specify the SSL ca via 'ca='"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
ctx.ca = params['ca'] if params['ca']
|
56
|
+
ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
|
57
|
+
|
58
|
+
ctx.reuse = params['reuse'] if params['reuse']
|
59
|
+
end
|
60
|
+
|
61
|
+
ctx.no_tlsv1 = params['no_tlsv1'] == 'true'
|
62
|
+
ctx.no_tlsv1_1 = params['no_tlsv1_1'] == 'true'
|
63
|
+
|
64
|
+
if params['verify_mode']
|
65
|
+
ctx.verify_mode = case params['verify_mode']
|
66
|
+
when "peer"
|
67
|
+
MiniSSL::VERIFY_PEER
|
68
|
+
when "force_peer"
|
69
|
+
MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
70
|
+
when "none"
|
71
|
+
MiniSSL::VERIFY_NONE
|
72
|
+
else
|
73
|
+
log_writer.error "Please specify a valid verify_mode="
|
74
|
+
MiniSSL::VERIFY_NONE
|
75
|
+
end
|
76
|
+
end
|
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
|
+
|
84
|
+
ctx
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
attr_reader :params, :log_writer
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/puma/minissl.rb
CHANGED
@@ -1,17 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require 'io/wait'
|
3
|
-
|
4
|
+
require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
|
5
|
+
rescue LoadError
|
4
6
|
end
|
5
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
|
+
|
6
12
|
module Puma
|
7
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
|
+
|
8
21
|
class Socket
|
9
22
|
def initialize(socket, engine)
|
10
23
|
@socket = socket
|
11
24
|
@engine = engine
|
12
25
|
@peercert = nil
|
26
|
+
@reuse = nil
|
13
27
|
end
|
14
28
|
|
29
|
+
# @!attribute [r] to_io
|
15
30
|
def to_io
|
16
31
|
@socket
|
17
32
|
end
|
@@ -20,6 +35,27 @@ module Puma
|
|
20
35
|
@socket.closed?
|
21
36
|
end
|
22
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
|
+
|
23
59
|
def readpartial(size)
|
24
60
|
while true
|
25
61
|
output = @engine.read
|
@@ -52,22 +88,22 @@ module Puma
|
|
52
88
|
output = engine_read_all
|
53
89
|
return output if output
|
54
90
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
91
|
+
data = @socket.read_nonblock(size, exception: false)
|
92
|
+
if data == :wait_readable || data == :wait_writable
|
93
|
+
# It would make more sense to let @socket.read_nonblock raise
|
94
|
+
# EAGAIN if necessary but it seems like it'll misbehave on Windows.
|
95
|
+
# I don't have a Windows machine to debug this so I can't explain
|
96
|
+
# exactly whats happening in that OS. Please let me know if you
|
97
|
+
# find out!
|
98
|
+
#
|
99
|
+
# In the meantime, we can emulate the correct behavior by
|
100
|
+
# capturing :wait_readable & :wait_writable and raising EAGAIN
|
101
|
+
# ourselves.
|
102
|
+
raise IO::EAGAINWaitReadable
|
103
|
+
elsif data.nil?
|
104
|
+
raise SSLError.exception "HTTP connection?" if bad_tlsv1_3?
|
105
|
+
return nil
|
106
|
+
end
|
71
107
|
|
72
108
|
@engine.inject(data)
|
73
109
|
output = engine_read_all
|
@@ -83,22 +119,23 @@ module Puma
|
|
83
119
|
def write(data)
|
84
120
|
return 0 if data.empty?
|
85
121
|
|
86
|
-
|
122
|
+
data_size = data.bytesize
|
123
|
+
need = data_size
|
87
124
|
|
88
125
|
while true
|
89
126
|
wrote = @engine.write data
|
90
|
-
enc = @engine.extract
|
91
127
|
|
92
|
-
|
93
|
-
|
94
|
-
|
128
|
+
enc_wr = +''
|
129
|
+
while (enc = @engine.extract)
|
130
|
+
enc_wr << enc
|
95
131
|
end
|
132
|
+
@socket.write enc_wr unless enc_wr.empty?
|
96
133
|
|
97
134
|
need -= wrote
|
98
135
|
|
99
|
-
return
|
136
|
+
return data_size if need == 0
|
100
137
|
|
101
|
-
data = data
|
138
|
+
data = data.byteslice(wrote..-1)
|
102
139
|
end
|
103
140
|
end
|
104
141
|
|
@@ -106,14 +143,18 @@ module Puma
|
|
106
143
|
alias_method :<<, :write
|
107
144
|
|
108
145
|
# This is a temporary fix to deal with websockets code using
|
109
|
-
# write_nonblock.
|
146
|
+
# write_nonblock.
|
147
|
+
|
148
|
+
# The problem with implementing it properly
|
110
149
|
# is that it means we'd have to have the ability to rewind
|
111
150
|
# an engine because after we write+extract, the socket
|
112
151
|
# write_nonblock call might raise an exception and later
|
113
152
|
# code would pass the same data in, but the engine would think
|
114
|
-
# it had already written the data in.
|
115
|
-
#
|
116
|
-
#
|
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
|
+
#
|
117
158
|
def write_nonblock(data, *_)
|
118
159
|
write data
|
119
160
|
end
|
@@ -122,39 +163,27 @@ module Puma
|
|
122
163
|
@socket.flush
|
123
164
|
end
|
124
165
|
|
125
|
-
def read_and_drop(timeout = 1)
|
126
|
-
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
127
|
-
read_nonblock(1024)
|
128
|
-
:drop
|
129
|
-
rescue Errno::EAGAIN
|
130
|
-
# do nothing
|
131
|
-
:eagain
|
132
|
-
end
|
133
|
-
|
134
|
-
def should_drop_bytes?
|
135
|
-
@engine.init? || !@engine.shutdown
|
136
|
-
end
|
137
|
-
|
138
166
|
def close
|
139
167
|
begin
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
return if read_and_drop(1) == :timeout
|
168
|
+
unless @engine.shutdown
|
169
|
+
while alert_data = @engine.extract
|
170
|
+
@socket.write alert_data
|
171
|
+
end
|
145
172
|
end
|
146
173
|
rescue IOError, SystemCallError
|
147
|
-
|
174
|
+
Puma::Util.purge_interrupt_queue
|
148
175
|
# nothing
|
149
176
|
ensure
|
150
177
|
@socket.close
|
151
178
|
end
|
152
179
|
end
|
153
180
|
|
181
|
+
# @!attribute [r] peeraddr
|
154
182
|
def peeraddr
|
155
183
|
@socket.peeraddr
|
156
184
|
end
|
157
185
|
|
186
|
+
# @!attribute [r] peercert
|
158
187
|
def peercert
|
159
188
|
return @peercert if @peercert
|
160
189
|
|
@@ -165,29 +194,84 @@ module Puma
|
|
165
194
|
end
|
166
195
|
end
|
167
196
|
|
168
|
-
if
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
def self.check; end
|
197
|
+
if IS_JRUBY
|
198
|
+
OPENSSL_NO_SSL3 = false
|
199
|
+
OPENSSL_NO_TLS1 = false
|
174
200
|
end
|
175
201
|
|
176
202
|
class Context
|
177
203
|
attr_accessor :verify_mode
|
204
|
+
attr_reader :no_tlsv1, :no_tlsv1_1
|
205
|
+
|
206
|
+
def initialize
|
207
|
+
@no_tlsv1 = false
|
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
|
216
|
+
end
|
217
|
+
|
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
|
178
222
|
|
179
|
-
if
|
223
|
+
if IS_JRUBY
|
180
224
|
# jruby-specific Context properties: java uses a keystore and password pair rather than a cert/key pair
|
181
225
|
attr_reader :keystore
|
226
|
+
attr_reader :keystore_type
|
182
227
|
attr_accessor :keystore_pass
|
228
|
+
attr_reader :truststore
|
229
|
+
attr_reader :truststore_type
|
230
|
+
attr_accessor :truststore_pass
|
231
|
+
attr_reader :cipher_suites
|
232
|
+
attr_reader :protocols
|
183
233
|
|
184
234
|
def keystore=(keystore)
|
185
|
-
|
235
|
+
check_file keystore, 'Keystore'
|
186
236
|
@keystore = keystore
|
187
237
|
end
|
188
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
|
+
|
189
272
|
def check
|
190
273
|
raise "Keystore not configured" unless @keystore
|
274
|
+
# @truststore defaults to @keystore due backwards compatibility
|
191
275
|
end
|
192
276
|
|
193
277
|
else
|
@@ -195,62 +279,158 @@ module Puma
|
|
195
279
|
attr_reader :key
|
196
280
|
attr_reader :cert
|
197
281
|
attr_reader :ca
|
282
|
+
attr_reader :cert_pem
|
283
|
+
attr_reader :key_pem
|
284
|
+
attr_accessor :ssl_cipher_filter
|
285
|
+
attr_accessor :verification_flags
|
286
|
+
|
287
|
+
attr_reader :reuse, :reuse_cache_size, :reuse_timeout
|
198
288
|
|
199
289
|
def key=(key)
|
200
|
-
|
290
|
+
check_file key, 'Key'
|
201
291
|
@key = key
|
202
292
|
end
|
203
293
|
|
204
294
|
def cert=(cert)
|
205
|
-
|
295
|
+
check_file cert, 'Cert'
|
206
296
|
@cert = cert
|
207
297
|
end
|
208
298
|
|
209
299
|
def ca=(ca)
|
210
|
-
|
300
|
+
check_file ca, 'ca'
|
211
301
|
@ca = ca
|
212
302
|
end
|
213
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
|
+
|
214
314
|
def check
|
215
|
-
raise "Key not configured"
|
216
|
-
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
|
217
346
|
end
|
218
347
|
end
|
348
|
+
|
349
|
+
# disables TLSv1
|
350
|
+
# @!attribute [w] no_tlsv1=
|
351
|
+
def no_tlsv1=(tlsv1)
|
352
|
+
raise ArgumentError, "Invalid value of no_tlsv1=" unless ['true', 'false', true, false].include?(tlsv1)
|
353
|
+
@no_tlsv1 = tlsv1
|
354
|
+
end
|
355
|
+
|
356
|
+
# disables TLSv1 and TLSv1.1. Overrides `#no_tlsv1=`
|
357
|
+
# @!attribute [w] no_tlsv1_1=
|
358
|
+
def no_tlsv1_1=(tlsv1_1)
|
359
|
+
raise ArgumentError, "Invalid value of no_tlsv1_1=" unless ['true', 'false', true, false].include?(tlsv1_1)
|
360
|
+
@no_tlsv1_1 = tlsv1_1
|
361
|
+
end
|
362
|
+
|
219
363
|
end
|
220
364
|
|
221
365
|
VERIFY_NONE = 0
|
222
366
|
VERIFY_PEER = 1
|
223
367
|
VERIFY_FAIL_IF_NO_PEER_CERT = 2
|
224
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
|
+
|
225
395
|
class Server
|
226
396
|
def initialize(socket, ctx)
|
227
397
|
@socket = socket
|
228
398
|
@ctx = ctx
|
229
|
-
|
230
|
-
|
231
|
-
def to_io
|
232
|
-
@socket
|
399
|
+
@eng_ctx = IS_JRUBY ? @ctx : SSLContext.new(ctx)
|
233
400
|
end
|
234
401
|
|
235
402
|
def accept
|
236
403
|
@ctx.check
|
237
404
|
io = @socket.accept
|
238
|
-
engine = Engine.server @
|
239
|
-
|
405
|
+
engine = Engine.server @eng_ctx
|
240
406
|
Socket.new io, engine
|
241
407
|
end
|
242
408
|
|
243
409
|
def accept_nonblock
|
244
410
|
@ctx.check
|
245
411
|
io = @socket.accept_nonblock
|
246
|
-
engine = Engine.server @
|
247
|
-
|
412
|
+
engine = Engine.server @eng_ctx
|
248
413
|
Socket.new io, engine
|
249
414
|
end
|
250
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
|
+
|
251
427
|
def close
|
252
428
|
@socket.close unless @socket.closed? # closed? call is for Windows
|
253
429
|
end
|
430
|
+
|
431
|
+
def closed?
|
432
|
+
@socket.closed?
|
433
|
+
end
|
254
434
|
end
|
255
435
|
end
|
256
436
|
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,14 @@ module Puma
|
|
38
48
|
|
39
49
|
def write(*ary)
|
40
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
|
41
60
|
end
|
42
61
|
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 "plgn bg #{i}"
|
68
|
+
b.call
|
69
|
+
end
|
65
70
|
end
|
66
71
|
end
|
67
72
|
end
|
@@ -86,7 +91,7 @@ module Puma
|
|
86
91
|
path = ary.first[CALLER_FILE]
|
87
92
|
|
88
93
|
m = %r!puma/plugin/([^/]*)\.rb$!.match(path)
|
89
|
-
|
94
|
+
m[1]
|
90
95
|
end
|
91
96
|
|
92
97
|
def self.create(&blk)
|
@@ -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
|