puma 5.5.0 → 5.6.7

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +140 -3
  3. data/README.md +28 -6
  4. data/docs/architecture.md +49 -16
  5. data/docs/compile_options.md +4 -2
  6. data/docs/deployment.md +53 -52
  7. data/docs/plugins.md +15 -15
  8. data/docs/rails_dev_mode.md +2 -3
  9. data/docs/restart.md +6 -6
  10. data/docs/signals.md +11 -10
  11. data/docs/stats.md +8 -8
  12. data/docs/systemd.md +63 -67
  13. data/ext/puma_http11/extconf.rb +18 -7
  14. data/ext/puma_http11/http11_parser.c +23 -10
  15. data/ext/puma_http11/http11_parser_common.rl +1 -1
  16. data/ext/puma_http11/mini_ssl.c +75 -12
  17. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +49 -47
  18. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +38 -55
  19. data/ext/puma_http11/puma_http11.c +1 -1
  20. data/lib/puma/app/status.rb +3 -0
  21. data/lib/puma/binder.rb +20 -6
  22. data/lib/puma/cli.rb +9 -4
  23. data/lib/puma/client.rb +68 -18
  24. data/lib/puma/cluster/worker.rb +7 -17
  25. data/lib/puma/cluster/worker_handle.rb +4 -0
  26. data/lib/puma/cluster.rb +29 -21
  27. data/lib/puma/configuration.rb +4 -1
  28. data/lib/puma/const.rb +7 -8
  29. data/lib/puma/control_cli.rb +19 -13
  30. data/lib/puma/detect.rb +8 -2
  31. data/lib/puma/dsl.rb +91 -10
  32. data/lib/puma/launcher.rb +13 -1
  33. data/lib/puma/minissl/context_builder.rb +8 -6
  34. data/lib/puma/minissl.rb +28 -7
  35. data/lib/puma/null_io.rb +5 -0
  36. data/lib/puma/plugin.rb +1 -1
  37. data/lib/puma/request.rb +15 -6
  38. data/lib/puma/runner.rb +22 -8
  39. data/lib/puma/server.rb +29 -30
  40. data/lib/puma/state_file.rb +42 -7
  41. data/lib/puma/thread_pool.rb +2 -2
  42. data/lib/puma/util.rb +19 -3
  43. data/lib/puma.rb +5 -3
  44. data/lib/rack/version_restriction.rb +15 -0
  45. data/tools/Dockerfile +1 -1
  46. metadata +4 -3
data/lib/puma/launcher.rb CHANGED
@@ -15,6 +15,7 @@ module Puma
15
15
  # It is responsible for either launching a cluster of Puma workers or a single
16
16
  # puma server.
17
17
  class Launcher
18
+ # @deprecated 6.0.0
18
19
  KEYS_NOT_TO_PERSIST_IN_STATE = [
19
20
  :logger, :lowlevel_error_handler,
20
21
  :before_worker_shutdown, :before_worker_boot, :before_worker_fork,
@@ -73,7 +74,7 @@ module Puma
73
74
 
74
75
  generate_restart_data
75
76
 
76
- if clustered? && !Process.respond_to?(:fork)
77
+ if clustered? && !Puma.forkable?
77
78
  unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
78
79
  end
79
80
 
@@ -158,6 +159,17 @@ module Puma
158
159
  true
159
160
  end
160
161
 
162
+ # Begin a refork if supported
163
+ def refork
164
+ if clustered? && @runner.respond_to?(:fork_worker!) && @options[:fork_worker]
165
+ @runner.fork_worker!
166
+ true
167
+ else
168
+ log "* refork called but not available."
169
+ false
170
+ end
171
+ end
172
+
161
173
  # Run the server. This blocks until the server is stopped
162
174
  def run
163
175
  previous_env =
@@ -23,17 +23,19 @@ module Puma
23
23
  ctx.keystore_pass = params['keystore-pass']
24
24
  ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
25
25
  else
26
- unless params['key']
27
- events.error "Please specify the SSL key via 'key='"
26
+ if params['key'].nil? && params['key_pem'].nil?
27
+ events.error "Please specify the SSL key via 'key=' or 'key_pem='"
28
28
  end
29
29
 
30
- ctx.key = params['key']
30
+ ctx.key = params['key'] if params['key']
31
+ ctx.key_pem = params['key_pem'] if params['key_pem']
31
32
 
32
- unless params['cert']
33
- events.error "Please specify the SSL cert via 'cert='"
33
+ if params['cert'].nil? && params['cert_pem'].nil?
34
+ events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='"
34
35
  end
35
36
 
36
- ctx.cert = params['cert']
37
+ ctx.cert = params['cert'] if params['cert']
38
+ ctx.cert_pem = params['cert_pem'] if params['cert_pem']
37
39
 
38
40
  if ['peer', 'force_peer'].include?(params['verify_mode'])
39
41
  unless params['ca']
data/lib/puma/minissl.rb CHANGED
@@ -169,7 +169,7 @@ module Puma
169
169
  end
170
170
  end
171
171
  rescue IOError, SystemCallError
172
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
172
+ Puma::Util.purge_interrupt_queue
173
173
  # nothing
174
174
  ensure
175
175
  @socket.close
@@ -208,6 +208,15 @@ module Puma
208
208
  def initialize
209
209
  @no_tlsv1 = false
210
210
  @no_tlsv1_1 = false
211
+ @key = nil
212
+ @cert = nil
213
+ @key_pem = nil
214
+ @cert_pem = nil
215
+ end
216
+
217
+ def check_file(file, desc)
218
+ raise ArgumentError, "#{desc} file '#{file}' does not exist" unless File.exist? file
219
+ raise ArgumentError, "#{desc} file '#{file}' is not readable" unless File.readable? file
211
220
  end
212
221
 
213
222
  if IS_JRUBY
@@ -217,7 +226,7 @@ module Puma
217
226
  attr_accessor :ssl_cipher_list
218
227
 
219
228
  def keystore=(keystore)
220
- raise ArgumentError, "No such keystore file '#{keystore}'" unless File.exist? keystore
229
+ check_file keystore, 'Keystore'
221
230
  @keystore = keystore
222
231
  end
223
232
 
@@ -230,27 +239,39 @@ module Puma
230
239
  attr_reader :key
231
240
  attr_reader :cert
232
241
  attr_reader :ca
242
+ attr_reader :cert_pem
243
+ attr_reader :key_pem
233
244
  attr_accessor :ssl_cipher_filter
234
245
  attr_accessor :verification_flags
235
246
 
236
247
  def key=(key)
237
- raise ArgumentError, "No such key file '#{key}'" unless File.exist? key
248
+ check_file key, 'Key'
238
249
  @key = key
239
250
  end
240
251
 
241
252
  def cert=(cert)
242
- raise ArgumentError, "No such cert file '#{cert}'" unless File.exist? cert
253
+ check_file cert, 'Cert'
243
254
  @cert = cert
244
255
  end
245
256
 
246
257
  def ca=(ca)
247
- raise ArgumentError, "No such ca file '#{ca}'" unless File.exist? ca
258
+ check_file ca, 'ca'
248
259
  @ca = ca
249
260
  end
250
261
 
262
+ def cert_pem=(cert_pem)
263
+ raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String
264
+ @cert_pem = cert_pem
265
+ end
266
+
267
+ def key_pem=(key_pem)
268
+ raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String
269
+ @key_pem = key_pem
270
+ end
271
+
251
272
  def check
252
- raise "Key not configured" unless @key
253
- raise "Cert not configured" unless @cert
273
+ raise "Key not configured" if @key.nil? && @key_pem.nil?
274
+ raise "Cert not configured" if @cert.nil? && @cert_pem.nil?
254
275
  end
255
276
  end
256
277
 
data/lib/puma/null_io.rb CHANGED
@@ -52,5 +52,10 @@ module Puma
52
52
  def flush
53
53
  self
54
54
  end
55
+
56
+ # This is used as singleton class, so can't have state.
57
+ def closed?
58
+ false
59
+ end
55
60
  end
56
61
  end
data/lib/puma/plugin.rb CHANGED
@@ -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
data/lib/puma/request.rb CHANGED
@@ -167,13 +167,22 @@ module Puma
167
167
  end
168
168
 
169
169
  ensure
170
- uncork_socket io
171
-
172
- body.close
173
- client.tempfile.unlink if client.tempfile
174
- res_body.close if res_body.respond_to? :close
170
+ begin
171
+ uncork_socket io
172
+
173
+ body.close
174
+ client.tempfile.unlink if client.tempfile
175
+ ensure
176
+ # Whatever happens, we MUST call `close` on the response body.
177
+ # Otherwise Rack::BodyProxy callbacks may not fire and lead to various state leaks
178
+ res_body.close if res_body.respond_to? :close
179
+ end
175
180
 
176
- after_reply.each { |o| o.call }
181
+ begin
182
+ after_reply.each { |o| o.call }
183
+ rescue StandardError => e
184
+ @log_writer.debug_error e
185
+ end
177
186
  end
178
187
 
179
188
  res_info[:keep_alive]
data/lib/puma/runner.rb CHANGED
@@ -15,6 +15,16 @@ module Puma
15
15
  @app = nil
16
16
  @control = nil
17
17
  @started_at = Time.now
18
+ @wakeup = nil
19
+ end
20
+
21
+ def wakeup!
22
+ return unless @wakeup
23
+
24
+ @wakeup.write "!" unless @wakeup.closed?
25
+
26
+ rescue SystemCallError, IOError
27
+ Puma::Util.purge_interrupt_queue
18
28
  end
19
29
 
20
30
  def development?
@@ -59,7 +69,7 @@ module Puma
59
69
 
60
70
  control.binder.parse [str], self, 'Starting control server'
61
71
 
62
- control.run thread_name: 'control'
72
+ control.run thread_name: 'ctl'
63
73
  @control = control
64
74
  end
65
75
 
@@ -84,12 +94,13 @@ module Puma
84
94
  def output_header(mode)
85
95
  min_t = @options[:min_threads]
86
96
  max_t = @options[:max_threads]
97
+ environment = @options[:environment]
87
98
 
88
99
  log "Puma starting in #{mode} mode..."
89
100
  log "* Puma version: #{Puma::Const::PUMA_VERSION} (#{ruby_engine}) (\"#{Puma::Const::CODE_NAME}\")"
90
101
  log "* Min threads: #{min_t}"
91
102
  log "* Max threads: #{max_t}"
92
- log "* Environment: #{ENV['RACK_ENV']}"
103
+ log "* Environment: #{environment}"
93
104
 
94
105
  if mode == "cluster"
95
106
  log "* Master PID: #{Process.pid}"
@@ -108,9 +119,7 @@ module Puma
108
119
  append = @options[:redirect_append]
109
120
 
110
121
  if stdout
111
- unless Dir.exist?(File.dirname(stdout))
112
- raise "Cannot redirect STDOUT to #{stdout}"
113
- end
122
+ ensure_output_directory_exists(stdout, 'STDOUT')
114
123
 
115
124
  STDOUT.reopen stdout, (append ? "a" : "w")
116
125
  STDOUT.puts "=== puma startup: #{Time.now} ==="
@@ -118,9 +127,7 @@ module Puma
118
127
  end
119
128
 
120
129
  if stderr
121
- unless Dir.exist?(File.dirname(stderr))
122
- raise "Cannot redirect STDERR to #{stderr}"
123
- end
130
+ ensure_output_directory_exists(stderr, 'STDERR')
124
131
 
125
132
  STDERR.reopen stderr, (append ? "a" : "w")
126
133
  STDERR.puts "=== puma startup: #{Time.now} ==="
@@ -159,5 +166,12 @@ module Puma
159
166
  server.inherit_binder @launcher.binder
160
167
  server
161
168
  end
169
+
170
+ private
171
+ def ensure_output_directory_exists(path, io_name)
172
+ unless Dir.exist?(File.dirname(path))
173
+ raise "Cannot redirect #{io_name} to #{path}"
174
+ end
175
+ end
162
176
  end
163
177
  end
data/lib/puma/server.rb CHANGED
@@ -39,6 +39,7 @@ module Puma
39
39
  attr_reader :events
40
40
  attr_reader :min_threads, :max_threads # for #stats
41
41
  attr_reader :requests_count # @version 5.0.0
42
+ attr_reader :log_writer # to help with backports
42
43
 
43
44
  # @todo the following may be deprecated in the future
44
45
  attr_reader :auto_trim_time, :early_hints, :first_data_timeout,
@@ -73,6 +74,7 @@ module Puma
73
74
  def initialize(app, events=Events.stdio, options={})
74
75
  @app = app
75
76
  @events = events
77
+ @log_writer = events
76
78
 
77
79
  @check, @notify = nil
78
80
  @status = :stop
@@ -146,7 +148,7 @@ module Puma
146
148
  begin
147
149
  skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 1) if skt.kind_of? TCPSocket
148
150
  rescue IOError, SystemCallError
149
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
151
+ Puma::Util.purge_interrupt_queue
150
152
  end
151
153
  end
152
154
 
@@ -155,7 +157,7 @@ module Puma
155
157
  begin
156
158
  skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 0) if skt.kind_of? TCPSocket
157
159
  rescue IOError, SystemCallError
158
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
160
+ Puma::Util.purge_interrupt_queue
159
161
  end
160
162
  end
161
163
  else
@@ -176,7 +178,7 @@ module Puma
176
178
  begin
177
179
  tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
178
180
  rescue IOError, SystemCallError
179
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
181
+ Puma::Util.purge_interrupt_queue
180
182
  @precheck_closing = false
181
183
  false
182
184
  else
@@ -220,7 +222,7 @@ module Puma
220
222
  # up in the background to handle requests. Otherwise requests
221
223
  # are handled synchronously.
222
224
  #
223
- def run(background=true, thread_name: 'server')
225
+ def run(background=true, thread_name: 'srv')
224
226
  BasicSocket.do_not_reverse_lookup = true
225
227
 
226
228
  @events.fire :state, :booting
@@ -315,16 +317,15 @@ module Puma
315
317
  queue_requests = @queue_requests
316
318
  drain = @options[:drain_on_shutdown] ? 0 : nil
317
319
 
318
- remote_addr_value = nil
319
- remote_addr_header = nil
320
-
321
- case @options[:remote_address]
320
+ addr_send_name, addr_value = case @options[:remote_address]
322
321
  when :value
323
- remote_addr_value = @options[:remote_address_value]
322
+ [:peerip=, @options[:remote_address_value]]
324
323
  when :header
325
- remote_addr_header = @options[:remote_address_header]
324
+ [:remote_addr_header=, @options[:remote_address_header]]
326
325
  when :proxy_protocol
327
- remote_addr_proxy_protocol = @options[:remote_address_proxy_protocol]
326
+ [:expect_proxy_proto=, @options[:remote_address_proxy_protocol]]
327
+ else
328
+ [nil, nil]
328
329
  end
329
330
 
330
331
  while @status == :run || (drain && shutting_down?)
@@ -344,16 +345,10 @@ module Puma
344
345
  next
345
346
  end
346
347
  drain += 1 if shutting_down?
347
- client = Client.new io, @binder.env(sock)
348
- client.listener = sock
349
- if remote_addr_value
350
- client.peerip = remote_addr_value
351
- elsif remote_addr_header
352
- client.remote_addr_header = remote_addr_header
353
- elsif remote_addr_proxy_protocol
354
- client.expect_proxy_proto = remote_addr_proxy_protocol
355
- end
356
- pool << client
348
+ pool << Client.new(io, @binder.env(sock)).tap { |c|
349
+ c.listener = sock
350
+ c.send(addr_send_name, addr_value) if addr_value
351
+ }
357
352
  end
358
353
  end
359
354
  rescue IOError, Errno::EBADF
@@ -375,13 +370,14 @@ module Puma
375
370
  rescue Exception => e
376
371
  @events.unknown_error e, nil, "Exception handling servers"
377
372
  ensure
378
- begin
379
- @check.close unless @check.closed?
380
- rescue Errno::EBADF, RuntimeError
381
- # RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
382
- # Errno::EBADF is infrequently raised
373
+ # RuntimeError is Ruby 2.2 issue, can't modify frozen IOError
374
+ # Errno::EBADF is infrequently raised
375
+ [@check, @notify].each do |io|
376
+ begin
377
+ io.close unless io.closed?
378
+ rescue Errno::EBADF, RuntimeError
379
+ end
383
380
  end
384
- @notify.close
385
381
  @notify = nil
386
382
  @check = nil
387
383
  end
@@ -491,7 +487,7 @@ module Puma
491
487
  begin
492
488
  client.close if close_socket
493
489
  rescue IOError, SystemCallError
494
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
490
+ Puma::Util.purge_interrupt_queue
495
491
  # Already closed
496
492
  rescue StandardError => e
497
493
  @events.unknown_error e, nil, "Client"
@@ -521,6 +517,9 @@ module Puma
521
517
  when HttpParserError
522
518
  client.write_error(400)
523
519
  @events.parse_error e, client
520
+ when HttpParserError501
521
+ client.write_error(501)
522
+ @events.parse_error e, client
524
523
  else
525
524
  client.write_error(500)
526
525
  @events.unknown_error e, nil, "Read"
@@ -583,11 +582,11 @@ module Puma
583
582
  @notify << message
584
583
  rescue IOError, NoMethodError, Errno::EPIPE
585
584
  # The server, in another thread, is shutting down
586
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
585
+ Puma::Util.purge_interrupt_queue
587
586
  rescue RuntimeError => e
588
587
  # Temporary workaround for https://bugs.ruby-lang.org/issues/13239
589
588
  if e.message.include?('IOError')
590
- Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
589
+ Puma::Util.purge_interrupt_queue
591
590
  else
592
591
  raise e
593
592
  end
@@ -1,15 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module Puma
4
+
5
+ # Puma::Launcher uses StateFile to write a yaml file for use with Puma::ControlCLI.
6
+ #
7
+ # In previous versions of Puma, YAML was used to read/write the state file.
8
+ # Since Puma is similar to Bundler/RubyGems in that it may load before one's app
9
+ # does, minimizing the dependencies that may be shared with the app is desired.
10
+ #
11
+ # At present, it only works with numeric and string values. It is still a valid
12
+ # yaml file, and the CI tests parse it with Psych.
13
+ #
6
14
  class StateFile
15
+
16
+ ALLOWED_FIELDS = %w!control_url control_auth_token pid running_from!
17
+
18
+ # @deprecated 6.0.0
19
+ FIELDS = ALLOWED_FIELDS
20
+
7
21
  def initialize
8
22
  @options = {}
9
23
  end
10
24
 
11
25
  def save(path, permission = nil)
12
- contents =YAML.dump @options
26
+ contents = "---\n".dup
27
+ @options.each do |k,v|
28
+ next unless ALLOWED_FIELDS.include? k
29
+ case v
30
+ when Numeric
31
+ contents << "#{k}: #{v}\n"
32
+ when String
33
+ next if v.strip.empty?
34
+ contents << (k == 'running_from' || v.to_s.include?(' ') ?
35
+ "#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
36
+ end
37
+ end
13
38
  if permission
14
39
  File.write path, contents, mode: 'wb:UTF-8'
15
40
  else
@@ -18,12 +43,22 @@ module Puma
18
43
  end
19
44
 
20
45
  def load(path)
21
- @options = YAML.load File.read(path)
46
+ File.read(path).lines.each do |line|
47
+ next if line.start_with? '#'
48
+ k,v = line.split ':', 2
49
+ next unless v && ALLOWED_FIELDS.include?(k)
50
+ v = v.strip
51
+ @options[k] =
52
+ case v
53
+ when '' then nil
54
+ when /\A\d+\z/ then v.to_i
55
+ when /\A\d+\.\d+\z/ then v.to_f
56
+ else v.gsub(/\A"|"\z/, '')
57
+ end
58
+ end
22
59
  end
23
60
 
24
- FIELDS = %w!control_url control_auth_token pid running_from!
25
-
26
- FIELDS.each do |f|
61
+ ALLOWED_FIELDS.each do |f|
27
62
  define_method f do
28
63
  @options[f]
29
64
  end
@@ -72,7 +72,7 @@ module Puma
72
72
  attr_accessor :out_of_band_hook # @version 5.0.0
73
73
 
74
74
  def self.clean_thread_locals
75
- Thread.current.keys.each do |key| # rubocop: disable Performance/HashEachMethods
75
+ Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
76
76
  Thread.current[key] = nil unless key == :__recursive_key__
77
77
  end
78
78
  end
@@ -102,7 +102,7 @@ module Puma
102
102
  @spawned += 1
103
103
 
104
104
  th = Thread.new(@spawned) do |spawned|
105
- Puma.set_thread_name '%s threadpool %03i' % [@name, spawned]
105
+ Puma.set_thread_name '%s tp %03i' % [@name, spawned]
106
106
  todo = @todo
107
107
  block = @block
108
108
  mutex = @mutex
data/lib/puma/util.rb CHANGED
@@ -10,18 +10,34 @@ module Puma
10
10
  IO.pipe
11
11
  end
12
12
 
13
- # Unescapes a URI escaped string with +encoding+. +encoding+ will be the
14
- # target encoding of the string returned, and it defaults to UTF-8
13
+ # An instance method on Thread has been provided to address https://bugs.ruby-lang.org/issues/13632,
14
+ # which currently effects some older versions of Ruby: 2.2.7 2.2.8 2.2.9 2.2.10 2.3.4 2.4.1
15
+ # Additional context: https://github.com/puma/puma/pull/1345
16
+ def purge_interrupt_queue
17
+ Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
18
+ end
19
+
20
+ # Escapes and unescapes a URI escaped string with
21
+ # +encoding+. +encoding+ will be the target encoding of the string
22
+ # returned, and it defaults to UTF-8
15
23
  if defined?(::Encoding)
24
+ def escape(s, encoding = Encoding::UTF_8)
25
+ URI.encode_www_form_component(s, encoding)
26
+ end
27
+
16
28
  def unescape(s, encoding = Encoding::UTF_8)
17
29
  URI.decode_www_form_component(s, encoding)
18
30
  end
19
31
  else
32
+ def escape(s, encoding = nil)
33
+ URI.encode_www_form_component(s, encoding)
34
+ end
35
+
20
36
  def unescape(s, encoding = nil)
21
37
  URI.decode_www_form_component(s, encoding)
22
38
  end
23
39
  end
24
- module_function :unescape
40
+ module_function :unescape, :escape
25
41
 
26
42
  # @version 5.0.0
27
43
  def nakayoshi_gc(events)
data/lib/puma.rb CHANGED
@@ -10,9 +10,11 @@ require 'stringio'
10
10
 
11
11
  require 'thread'
12
12
 
13
+ # extension files should not be loaded with `require_relative`
13
14
  require 'puma/puma_http11'
14
- require 'puma/detect'
15
- require 'puma/json_serialization'
15
+ require_relative 'puma/detect'
16
+ require_relative 'puma/json_serialization'
17
+ require_relative 'rack/version_restriction'
16
18
 
17
19
  module Puma
18
20
  autoload :Const, 'puma/const'
@@ -23,7 +25,7 @@ module Puma
23
25
  # not in minissl.rb
24
26
  HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
25
27
 
26
- HAS_UNIX_SOCKET = Object.const_defined? :UNIXSocket
28
+ HAS_UNIX_SOCKET = Object.const_defined?(:UNIXSocket) && !IS_WINDOWS
27
29
 
28
30
  if HAS_SSL
29
31
  require 'puma/minissl'
@@ -0,0 +1,15 @@
1
+ begin
2
+ begin
3
+ # rack/version exists in Rack 2.2.0 and later, compatible with Ruby 2.3 and later
4
+ # we prefer to not load Rack
5
+ require 'rack/version'
6
+ rescue LoadError
7
+ require 'rack'
8
+ end
9
+
10
+ # Rack.release is needed for Rack v1, Rack::RELEASE was added in v2
11
+ if Gem::Version.new(Rack.release) >= Gem::Version.new("3.0.0")
12
+ raise StandardError.new "Puma 5 is not compatible with Rack 3, please upgrade to Puma 6 or higher."
13
+ end
14
+ rescue LoadError
15
+ end
data/tools/Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # Use this Dockerfile to create minimal reproductions of issues
2
2
 
3
- FROM ruby:2.6
3
+ FROM ruby:3.1
4
4
 
5
5
  # throw errors if Gemfile has been modified since Gemfile.lock
6
6
  RUN bundle config --global frozen 1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.0
4
+ version: 5.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-19 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -115,6 +115,7 @@ files:
115
115
  - lib/puma/thread_pool.rb
116
116
  - lib/puma/util.rb
117
117
  - lib/rack/handler/puma.rb
118
+ - lib/rack/version_restriction.rb
118
119
  - tools/Dockerfile
119
120
  - tools/trickletest.rb
120
121
  homepage: https://puma.io
@@ -140,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
141
  - !ruby/object:Gem::Version
141
142
  version: '0'
142
143
  requirements: []
143
- rubygems_version: 3.2.3
144
+ rubygems_version: 3.4.12
144
145
  signing_key:
145
146
  specification_version: 4
146
147
  summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for