puma 4.3.5 → 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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1639 -519
  3. data/LICENSE +23 -20
  4. data/README.md +130 -42
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +63 -26
  7. data/docs/compile_options.md +55 -0
  8. data/docs/deployment.md +60 -69
  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 +15 -15
  20. data/docs/rails_dev_mode.md +28 -0
  21. data/docs/restart.md +46 -23
  22. data/docs/signals.md +13 -11
  23. data/docs/stats.md +142 -0
  24. data/docs/systemd.md +85 -128
  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 -4
  28. data/ext/puma_http11/ext_help.h +1 -1
  29. data/ext/puma_http11/extconf.rb +56 -11
  30. data/ext/puma_http11/http11_parser.c +69 -58
  31. data/ext/puma_http11/http11_parser.h +2 -2
  32. data/ext/puma_http11/http11_parser.java.rl +3 -3
  33. data/ext/puma_http11/http11_parser.rl +3 -3
  34. data/ext/puma_http11/http11_parser_common.rl +3 -3
  35. data/ext/puma_http11/mini_ssl.c +322 -130
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +6 -6
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +52 -52
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +241 -96
  40. data/ext/puma_http11/puma_http11.c +47 -57
  41. data/lib/puma/app/status.rb +53 -37
  42. data/lib/puma/binder.rb +232 -119
  43. data/lib/puma/cli.rb +33 -33
  44. data/lib/puma/client.rb +197 -101
  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 +224 -229
  48. data/lib/puma/commonlogger.rb +2 -2
  49. data/lib/puma/configuration.rb +112 -87
  50. data/lib/puma/const.rb +30 -25
  51. data/lib/puma/control_cli.rb +99 -79
  52. data/lib/puma/detect.rb +31 -2
  53. data/lib/puma/dsl.rb +426 -110
  54. data/lib/puma/error_logger.rb +112 -0
  55. data/lib/puma/events.rb +16 -115
  56. data/lib/puma/io_buffer.rb +44 -2
  57. data/lib/puma/jruby_restart.rb +2 -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 +170 -148
  61. data/lib/puma/log_writer.rb +137 -0
  62. data/lib/puma/minissl/context_builder.rb +35 -19
  63. data/lib/puma/minissl.rb +213 -55
  64. data/lib/puma/null_io.rb +18 -1
  65. data/lib/puma/plugin/tmp_restart.rb +1 -1
  66. data/lib/puma/plugin.rb +3 -12
  67. data/lib/puma/rack/builder.rb +5 -9
  68. data/lib/puma/rack/urlmap.rb +0 -0
  69. data/lib/puma/rack_default.rb +1 -1
  70. data/lib/puma/reactor.rb +85 -369
  71. data/lib/puma/request.rb +644 -0
  72. data/lib/puma/runner.rb +83 -77
  73. data/lib/puma/server.rb +303 -773
  74. data/lib/puma/single.rb +18 -74
  75. data/lib/puma/state_file.rb +45 -8
  76. data/lib/puma/systemd.rb +47 -0
  77. data/lib/puma/thread_pool.rb +136 -68
  78. data/lib/puma/util.rb +21 -4
  79. data/lib/puma.rb +54 -5
  80. data/lib/rack/handler/puma.rb +11 -12
  81. data/tools/{docker/Dockerfile → Dockerfile} +1 -1
  82. data/tools/trickletest.rb +0 -0
  83. metadata +36 -28
  84. data/docs/tcp_mode.md +0 -96
  85. data/ext/puma_http11/io_buffer.c +0 -155
  86. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  87. data/lib/puma/accept_nonblock.rb +0 -29
  88. data/lib/puma/tcp_logger.rb +0 -41
  89. data/tools/jungle/README.md +0 -19
  90. data/tools/jungle/init.d/README.md +0 -61
  91. data/tools/jungle/init.d/puma +0 -421
  92. data/tools/jungle/init.d/run-puma +0 -18
  93. data/tools/jungle/upstart/README.md +0 -61
  94. data/tools/jungle/upstart/puma-manager.conf +0 -31
  95. 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, events)
5
- require 'puma/minissl'
6
- MiniSSL.check
7
-
4
+ def initialize(params, log_writer)
8
5
  @params = params
9
- @events = events
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
- events.error "Please specify the Java keystore via 'keystore='"
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
- events.error "Please specify the Java keystore password via 'keystore-pass='"
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.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
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
- unless params['key']
30
- events.error "Please specify the SSL key via 'key='"
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
- unless params['cert']
36
- events.error "Please specify the SSL cert via 'cert='"
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
- events.error "Please specify the SSL ca via 'ca='"
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 = true if params['no_tlsv1'] == 'true'
52
- ctx.no_tlsv1_1 = true if params['no_tlsv1_1'] == 'true'
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
- events.error "Please specify a valid verify_mode="
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, :events
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
- need = data.bytesize
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
- while enc
94
- @socket.write enc
95
- enc = @engine.extract
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 data.bytesize if need == 0
136
+ return data_size if need == 0
101
137
 
102
- data = data[wrote..-1]
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. The problem with implementing it properly
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. So for the time being
116
- # (and since write blocking is quite rare), go ahead and actually
117
- # 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
+ #
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
- # Read any drop any partially initialized sockets and any received bytes during shutdown.
142
- # Don't let this socket hold this loop forever.
143
- # If it can't send more packets within 1s, then give up.
144
- while should_drop_bytes?
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
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
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 defined?(JRUBY_VERSION)
170
- class SSLError < StandardError
171
- # Define this for jruby even though it isn't used.
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
- if defined?(JRUBY_VERSION)
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
- attr_accessor :ssl_cipher_list
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
- raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
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
- raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
290
+ check_file key, 'Key'
210
291
  @key = key
211
292
  end
212
293
 
213
294
  def cert=(cert)
214
- raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
295
+ check_file cert, 'Cert'
215
296
  @cert = cert
216
297
  end
217
298
 
218
299
  def ca=(ca)
219
- raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
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" unless @key
225
- 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
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 no_tlsv1" unless ['true', 'false', true, false].include?(tlsv1_1)
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
- end
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 @ctx
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 @ctx
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
- (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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/plugin'
3
+ require_relative '../plugin'
4
4
 
5
5
  Puma::Plugin.create do
6
6
  def start(launcher)
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(Plugin)
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 "plugin background #{i}"
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
- return m[1]
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
@@ -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 && server.respond_to?(:valid_options)
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 name.to_s =~ /^(Host|Port)[^a-zA-Z]/ # ignore handler's host and port options, we do our own.
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
- return app, options
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.call(app) if @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
- require 'puma/rack/urlmap'
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 }
File without changes