ed-precompiled_puma 7.0.4

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