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.

Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1717 -432
  3. data/LICENSE +23 -20
  4. data/README.md +190 -64
  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/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +66 -0
  18. data/docs/nginx.md +2 -2
  19. data/docs/plugins.md +22 -12
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +47 -22
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +95 -120
  25. data/docs/testing_benchmarks_local_files.md +150 -0
  26. data/docs/testing_test_rackup_ci_files.md +36 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +61 -3
  30. data/ext/puma_http11/http11_parser.c +106 -118
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +22 -38
  33. data/ext/puma_http11/http11_parser.rl +6 -4
  34. data/ext/puma_http11/http11_parser_common.rl +6 -6
  35. data/ext/puma_http11/mini_ssl.c +376 -93
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +250 -88
  40. data/ext/puma_http11/puma_http11.c +49 -57
  41. data/lib/puma/app/status.rb +71 -49
  42. data/lib/puma/binder.rb +243 -148
  43. data/lib/puma/cli.rb +50 -36
  44. data/lib/puma/client.rb +373 -233
  45. data/lib/puma/cluster/worker.rb +175 -0
  46. data/lib/puma/cluster/worker_handle.rb +97 -0
  47. data/lib/puma/cluster.rb +268 -235
  48. data/lib/puma/commonlogger.rb +4 -2
  49. data/lib/puma/configuration.rb +116 -88
  50. data/lib/puma/const.rb +49 -30
  51. data/lib/puma/control_cli.rb +123 -76
  52. data/lib/puma/detect.rb +33 -2
  53. data/lib/puma/dsl.rb +685 -135
  54. data/lib/puma/error_logger.rb +112 -0
  55. data/lib/puma/events.rb +17 -111
  56. data/lib/puma/io_buffer.rb +44 -5
  57. data/lib/puma/jruby_restart.rb +4 -59
  58. data/lib/puma/json_serialization.rb +96 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  60. data/lib/puma/launcher.rb +196 -130
  61. data/lib/puma/log_writer.rb +137 -0
  62. data/lib/puma/minissl/context_builder.rb +92 -0
  63. data/lib/puma/minissl.rb +249 -69
  64. data/lib/puma/null_io.rb +20 -1
  65. data/lib/puma/plugin/tmp_restart.rb +3 -1
  66. data/lib/puma/plugin.rb +9 -13
  67. data/lib/puma/rack/builder.rb +8 -9
  68. data/lib/puma/rack/urlmap.rb +2 -0
  69. data/lib/puma/rack_default.rb +3 -1
  70. data/lib/puma/reactor.rb +90 -187
  71. data/lib/puma/request.rb +644 -0
  72. data/lib/puma/runner.rb +94 -71
  73. data/lib/puma/server.rb +337 -715
  74. data/lib/puma/single.rb +27 -72
  75. data/lib/puma/state_file.rb +46 -7
  76. data/lib/puma/systemd.rb +47 -0
  77. data/lib/puma/thread_pool.rb +184 -93
  78. data/lib/puma/util.rb +23 -10
  79. data/lib/puma.rb +60 -3
  80. data/lib/rack/handler/puma.rb +17 -15
  81. data/tools/Dockerfile +16 -0
  82. data/tools/trickletest.rb +0 -1
  83. metadata +53 -33
  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 -23
  88. data/lib/puma/daemon_ext.rb +0 -31
  89. data/lib/puma/delegation.rb +0 -11
  90. data/lib/puma/java_io_buffer.rb +0 -45
  91. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  92. data/lib/puma/tcp_logger.rb +0 -39
  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
@@ -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
- rescue LoadError
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
- begin
56
- data = @socket.read_nonblock(size, exception: false)
57
- if data == :wait_readable || data == :wait_writable
58
- if @socket.to_io.respond_to?(data)
59
- @socket.to_io.__send__(data)
60
- elsif data == :wait_readable
61
- IO.select([@socket.to_io])
62
- else
63
- IO.select(nil, [@socket.to_io])
64
- end
65
- elsif !data
66
- return nil
67
- else
68
- break
69
- end
70
- end while true
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
- need = data.bytesize
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
- while enc
93
- @socket.write enc
94
- enc = @engine.extract
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 data.bytesize if need == 0
136
+ return data_size if need == 0
100
137
 
101
- data = data[wrote..-1]
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. The problem with implementing it properly
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. So for the time being
115
- # (and since write blocking is quite rare), go ahead and actually
116
- # block in write_nonblock.
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
- # Read any drop any partially initialized sockets and any received bytes during shutdown.
141
- # Don't let this socket hold this loop forever.
142
- # If it can't send more packets within 1s, then give up.
143
- while should_drop_bytes?
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
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
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 defined?(JRUBY_VERSION)
169
- class SSLError < StandardError
170
- # Define this for jruby even though it isn't used.
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 defined?(JRUBY_VERSION)
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
- raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
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
- raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
290
+ check_file key, 'Key'
201
291
  @key = key
202
292
  end
203
293
 
204
294
  def cert=(cert)
205
- raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
295
+ check_file cert, 'Cert'
206
296
  @cert = cert
207
297
  end
208
298
 
209
299
  def ca=(ca)
210
- raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
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" unless @key
216
- raise "Cert not configured" unless @cert
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
- end
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 @ctx
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 @ctx
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
- (count && count > 0) ? nil : ""
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
@@ -1,4 +1,6 @@
1
- require 'puma/plugin'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../plugin'
2
4
 
3
5
  Puma::Plugin.create do
4
6
  def start(launcher)
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(Plugin)
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.each do |b|
64
- Thread.new(&b)
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
- return m[1]
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