puma 3.12.6 → 6.3.0

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.

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