puma 5.2.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +483 -4
  3. data/README.md +101 -20
  4. data/bin/puma-wild +1 -1
  5. data/docs/architecture.md +50 -16
  6. data/docs/compile_options.md +38 -2
  7. data/docs/deployment.md +53 -67
  8. data/docs/fork_worker.md +1 -3
  9. data/docs/jungle/rc.d/README.md +1 -1
  10. data/docs/kubernetes.md +1 -1
  11. data/docs/nginx.md +1 -1
  12. data/docs/plugins.md +15 -15
  13. data/docs/rails_dev_mode.md +2 -3
  14. data/docs/restart.md +7 -7
  15. data/docs/signals.md +11 -10
  16. data/docs/stats.md +8 -8
  17. data/docs/systemd.md +65 -69
  18. data/docs/testing_benchmarks_local_files.md +150 -0
  19. data/docs/testing_test_rackup_ci_files.md +36 -0
  20. data/ext/puma_http11/extconf.rb +44 -13
  21. data/ext/puma_http11/http11_parser.c +24 -11
  22. data/ext/puma_http11/http11_parser.h +2 -2
  23. data/ext/puma_http11/http11_parser.java.rl +2 -2
  24. data/ext/puma_http11/http11_parser.rl +2 -2
  25. data/ext/puma_http11/http11_parser_common.rl +3 -3
  26. data/ext/puma_http11/mini_ssl.c +150 -23
  27. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  28. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +50 -48
  29. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +188 -102
  30. data/ext/puma_http11/puma_http11.c +18 -10
  31. data/lib/puma/app/status.rb +10 -7
  32. data/lib/puma/binder.rb +112 -62
  33. data/lib/puma/cli.rb +24 -20
  34. data/lib/puma/client.rb +162 -36
  35. data/lib/puma/cluster/worker.rb +31 -27
  36. data/lib/puma/cluster/worker_handle.rb +12 -1
  37. data/lib/puma/cluster.rb +102 -61
  38. data/lib/puma/commonlogger.rb +21 -14
  39. data/lib/puma/configuration.rb +78 -54
  40. data/lib/puma/const.rb +135 -97
  41. data/lib/puma/control_cli.rb +25 -20
  42. data/lib/puma/detect.rb +12 -2
  43. data/lib/puma/dsl.rb +308 -58
  44. data/lib/puma/error_logger.rb +20 -11
  45. data/lib/puma/events.rb +6 -126
  46. data/lib/puma/io_buffer.rb +39 -4
  47. data/lib/puma/jruby_restart.rb +2 -1
  48. data/lib/puma/{json.rb → json_serialization.rb} +1 -1
  49. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  50. data/lib/puma/launcher.rb +114 -173
  51. data/lib/puma/log_writer.rb +147 -0
  52. data/lib/puma/minissl/context_builder.rb +30 -16
  53. data/lib/puma/minissl.rb +132 -38
  54. data/lib/puma/null_io.rb +5 -0
  55. data/lib/puma/plugin/systemd.rb +90 -0
  56. data/lib/puma/plugin/tmp_restart.rb +1 -1
  57. data/lib/puma/plugin.rb +2 -2
  58. data/lib/puma/rack/builder.rb +7 -7
  59. data/lib/puma/rack_default.rb +19 -4
  60. data/lib/puma/reactor.rb +19 -10
  61. data/lib/puma/request.rb +373 -153
  62. data/lib/puma/runner.rb +74 -28
  63. data/lib/puma/sd_notify.rb +149 -0
  64. data/lib/puma/server.rb +127 -136
  65. data/lib/puma/single.rb +13 -11
  66. data/lib/puma/state_file.rb +39 -7
  67. data/lib/puma/thread_pool.rb +33 -26
  68. data/lib/puma/util.rb +20 -15
  69. data/lib/puma.rb +28 -11
  70. data/lib/rack/handler/puma.rb +113 -86
  71. data/tools/Dockerfile +1 -1
  72. metadata +15 -10
  73. data/lib/puma/queue_close.rb +0 -26
  74. data/lib/puma/systemd.rb +0 -46
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'thread'
4
4
 
5
+ require_relative 'io_buffer'
6
+
5
7
  module Puma
6
8
  # Internal Docs for A simple thread pool management object.
7
9
  #
@@ -13,7 +15,7 @@ module Puma
13
15
  # a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in a `@todo` array.
14
16
  #
15
17
  # Each thread in the pool has an internal loop where it pulls a request from the `@todo` array
16
- # and proceses it.
18
+ # and processes it.
17
19
  class ThreadPool
18
20
  class ForceShutdown < RuntimeError
19
21
  end
@@ -29,7 +31,7 @@ module Puma
29
31
  # The block passed is the work that will be performed in each
30
32
  # thread.
31
33
  #
32
- def initialize(min, max, *extra, &block)
34
+ def initialize(name, options = {}, &block)
33
35
  @not_empty = ConditionVariable.new
34
36
  @not_full = ConditionVariable.new
35
37
  @mutex = Mutex.new
@@ -39,10 +41,18 @@ module Puma
39
41
  @spawned = 0
40
42
  @waiting = 0
41
43
 
42
- @min = Integer(min)
43
- @max = Integer(max)
44
+ @name = name
45
+ @min = Integer(options[:min_threads])
46
+ @max = Integer(options[:max_threads])
47
+ # Not an 'exposed' option, options[:pool_shutdown_grace_time] is used in CI
48
+ # to shorten @shutdown_grace_time from SHUTDOWN_GRACE_TIME. Parallel CI
49
+ # makes stubbing constants difficult.
50
+ @shutdown_grace_time = Float(options[:pool_shutdown_grace_time] || SHUTDOWN_GRACE_TIME)
44
51
  @block = block
45
- @extra = extra
52
+ @out_of_band = options[:out_of_band]
53
+ @clean_thread_locals = options[:clean_thread_locals]
54
+ @reaping_time = options[:reaping_time]
55
+ @auto_trim_time = options[:auto_trim_time]
46
56
 
47
57
  @shutdown = false
48
58
 
@@ -61,17 +71,14 @@ module Puma
61
71
  end
62
72
  end
63
73
 
64
- @clean_thread_locals = false
65
74
  @force_shutdown = false
66
75
  @shutdown_mutex = Mutex.new
67
76
  end
68
77
 
69
78
  attr_reader :spawned, :trim_requested, :waiting
70
- attr_accessor :clean_thread_locals
71
- attr_accessor :out_of_band_hook # @version 5.0.0
72
79
 
73
80
  def self.clean_thread_locals
74
- Thread.current.keys.each do |key| # rubocop: disable Performance/HashEachMethods
81
+ Thread.current.keys.each do |key| # rubocop: disable Style/HashEachMethods
75
82
  Thread.current[key] = nil unless key == :__recursive_key__
76
83
  end
77
84
  end
@@ -101,15 +108,13 @@ module Puma
101
108
  @spawned += 1
102
109
 
103
110
  th = Thread.new(@spawned) do |spawned|
104
- Puma.set_thread_name 'threadpool %03i' % spawned
111
+ Puma.set_thread_name '%s tp %03i' % [@name, spawned]
105
112
  todo = @todo
106
113
  block = @block
107
114
  mutex = @mutex
108
115
  not_empty = @not_empty
109
116
  not_full = @not_full
110
117
 
111
- extra = @extra.map { |i| i.new }
112
-
113
118
  while true
114
119
  work = nil
115
120
 
@@ -119,6 +124,7 @@ module Puma
119
124
  @trim_requested -= 1
120
125
  @spawned -= 1
121
126
  @workers.delete th
127
+ not_full.signal
122
128
  Thread.exit
123
129
  end
124
130
 
@@ -142,7 +148,7 @@ module Puma
142
148
  end
143
149
 
144
150
  begin
145
- @out_of_band_pending = true if block.call(work, *extra)
151
+ @out_of_band_pending = true if block.call(work)
146
152
  rescue Exception => e
147
153
  STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
148
154
  end
@@ -158,12 +164,12 @@ module Puma
158
164
 
159
165
  # @version 5.0.0
160
166
  def trigger_out_of_band_hook
161
- return false unless out_of_band_hook && out_of_band_hook.any?
167
+ return false unless @out_of_band&.any?
162
168
 
163
169
  # we execute on idle hook when all threads are free
164
170
  return false unless @spawned == @waiting
165
171
 
166
- out_of_band_hook.each(&:call)
172
+ @out_of_band.each(&:call)
167
173
  true
168
174
  rescue Exception => e
169
175
  STDERR.puts "Exception calling out_of_band_hook: #{e.message} (#{e.class})"
@@ -220,7 +226,7 @@ module Puma
220
226
  # then the `@todo` array would stay the same size as the reactor works
221
227
  # to try to buffer the request. In that scenario the next call to this
222
228
  # method would not block and another request would be added into the reactor
223
- # by the server. This would continue until a fully bufferend request
229
+ # by the server. This would continue until a fully buffered request
224
230
  # makes it through the reactor and can then be processed by the thread pool.
225
231
  def wait_until_not_full
226
232
  with_mutex do
@@ -240,11 +246,12 @@ module Puma
240
246
 
241
247
  # @version 5.0.0
242
248
  def wait_for_less_busy_worker(delay_s)
249
+ return unless delay_s && delay_s > 0
250
+
243
251
  # Ruby MRI does GVL, this can result
244
252
  # in processing contention when multiple threads
245
253
  # (requests) are running concurrently
246
254
  return unless Puma.mri?
247
- return unless delay_s > 0
248
255
 
249
256
  with_mutex do
250
257
  return if @shutdown
@@ -316,13 +323,13 @@ module Puma
316
323
  end
317
324
  end
318
325
 
319
- def auto_trim!(timeout=30)
320
- @auto_trim = Automaton.new(self, timeout, "threadpool trimmer", :trim)
326
+ def auto_trim!(timeout=@auto_trim_time)
327
+ @auto_trim = Automaton.new(self, timeout, "#{@name} threadpool trimmer", :trim)
321
328
  @auto_trim.start!
322
329
  end
323
330
 
324
- def auto_reap!(timeout=5)
325
- @reaper = Automaton.new(self, timeout, "threadpool reaper", :reap)
331
+ def auto_reap!(timeout=@reaping_time)
332
+ @reaper = Automaton.new(self, timeout, "#{@name} threadpool reaper", :reap)
326
333
  @reaper.start!
327
334
  end
328
335
 
@@ -341,8 +348,8 @@ module Puma
341
348
 
342
349
  # Tell all threads in the pool to exit and wait for them to finish.
343
350
  # Wait +timeout+ seconds then raise +ForceShutdown+ in remaining threads.
344
- # Next, wait an extra +grace+ seconds then force-kill remaining threads.
345
- # Finally, wait +kill_grace+ seconds for remaining threads to exit.
351
+ # Next, wait an extra +@shutdown_grace_time+ seconds then force-kill remaining
352
+ # threads. Finally, wait 1 second for remaining threads to exit.
346
353
  #
347
354
  def shutdown(timeout=-1)
348
355
  threads = with_mutex do
@@ -351,8 +358,8 @@ module Puma
351
358
  @not_empty.broadcast
352
359
  @not_full.broadcast
353
360
 
354
- @auto_trim.stop if @auto_trim
355
- @reaper.stop if @reaper
361
+ @auto_trim&.stop
362
+ @reaper&.stop
356
363
  # dup workers so that we join them all safely
357
364
  @workers.dup
358
365
  end
@@ -379,7 +386,7 @@ module Puma
379
386
  t.raise ForceShutdown if t[:with_force_shutdown]
380
387
  end
381
388
  end
382
- join.call(SHUTDOWN_GRACE_TIME)
389
+ join.call(@shutdown_grace_time)
383
390
 
384
391
  # If threads are _still_ running, forcefully kill them and wait to finish.
385
392
  threads.each(&:kill)
data/lib/puma/util.rb CHANGED
@@ -10,29 +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
20
- def unescape(s, encoding = nil)
21
- URI.decode_www_form_component(s, encoding)
32
+ def escape(s, encoding = nil)
33
+ URI.encode_www_form_component(s, encoding)
22
34
  end
23
- end
24
- module_function :unescape
25
35
 
26
- # @version 5.0.0
27
- def nakayoshi_gc(events)
28
- events.log "! Promoting existing objects to old generation..."
29
- 4.times { GC.start(full_mark: false) }
30
- if GC.respond_to?(:compact)
31
- events.log "! Compacting..."
32
- GC.compact
36
+ def unescape(s, encoding = nil)
37
+ URI.decode_www_form_component(s, encoding)
33
38
  end
34
- events.log "! Friendly fork preparation complete."
35
39
  end
40
+ module_function :unescape, :escape
36
41
 
37
42
  DEFAULT_SEP = /[&;] */n
38
43
 
@@ -61,7 +66,7 @@ module Puma
61
66
  end
62
67
  end
63
68
 
64
- return params
69
+ params
65
70
  end
66
71
 
67
72
  # A case-insensitive Hash that preserves the original case of a
data/lib/puma.rb CHANGED
@@ -3,28 +3,33 @@
3
3
  # Standard libraries
4
4
  require 'socket'
5
5
  require 'tempfile'
6
- require 'time'
7
- require 'etc'
8
6
  require 'uri'
9
7
  require 'stringio'
10
8
 
11
9
  require 'thread'
12
10
 
11
+ # use require, see https://github.com/puma/puma/pull/2381
13
12
  require 'puma/puma_http11'
14
- require 'puma/detect'
15
- require 'puma/json'
13
+
14
+ require_relative 'puma/detect'
15
+ require_relative 'puma/json_serialization'
16
16
 
17
17
  module Puma
18
- autoload :Const, 'puma/const'
19
- autoload :Server, 'puma/server'
20
- autoload :Launcher, 'puma/launcher'
18
+ # when Puma is loaded via `Puma::CLI`, all files are loaded via
19
+ # `require_relative`. The below are for non-standard loading
20
+ autoload :Const, "#{__dir__}/puma/const"
21
+ autoload :Server, "#{__dir__}/puma/server"
22
+ autoload :Launcher, "#{__dir__}/puma/launcher"
23
+ autoload :LogWriter, "#{__dir__}/puma/log_writer"
21
24
 
22
25
  # at present, MiniSSL::Engine is only defined in extension code (puma_http11),
23
26
  # not in minissl.rb
24
27
  HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
25
28
 
29
+ HAS_UNIX_SOCKET = Object.const_defined?(:UNIXSocket) && !IS_WINDOWS
30
+
26
31
  if HAS_SSL
27
- require 'puma/minissl'
32
+ require_relative 'puma/minissl'
28
33
  else
29
34
  module MiniSSL
30
35
  # this class is defined so that it exists when Puma is compiled
@@ -37,6 +42,20 @@ module Puma
37
42
  HAS_SSL
38
43
  end
39
44
 
45
+ def self.abstract_unix_socket?
46
+ @abstract_unix ||=
47
+ if HAS_UNIX_SOCKET
48
+ begin
49
+ ::UNIXServer.new("\0puma.temp.unix").close
50
+ true
51
+ rescue ArgumentError # darwin
52
+ false
53
+ end
54
+ else
55
+ false
56
+ end
57
+ end
58
+
40
59
  # @!attribute [rw] stats_object=
41
60
  def self.stats_object=(val)
42
61
  @get_stats = val
@@ -44,7 +63,7 @@ module Puma
44
63
 
45
64
  # @!attribute [rw] stats_object
46
65
  def self.stats
47
- Puma::JSON.generate @get_stats.stats
66
+ Puma::JSONSerialization.generate @get_stats.stats
48
67
  end
49
68
 
50
69
  # @!attribute [r] stats_hash
@@ -53,9 +72,7 @@ module Puma
53
72
  @get_stats.stats
54
73
  end
55
74
 
56
- # Thread name is new in Ruby 2.3
57
75
  def self.set_thread_name(name)
58
- return unless Thread.current.respond_to?(:name=)
59
76
  Thread.current.name = "puma #{name}"
60
77
  end
61
78
  end
@@ -1,114 +1,141 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/handler'
4
-
5
- module Rack
6
- module Handler
7
- module Puma
8
- DEFAULT_OPTIONS = {
9
- :Verbose => false,
10
- :Silent => false
11
- }
12
-
13
- def self.config(app, options = {})
14
- require 'puma'
15
- require 'puma/configuration'
16
- require 'puma/events'
17
- require 'puma/launcher'
18
-
19
- default_options = DEFAULT_OPTIONS.dup
20
-
21
- # Libraries pass in values such as :Port and there is no way to determine
22
- # if it is a default provided by the library or a special value provided
23
- # by the user. A special key `user_supplied_options` can be passed. This
24
- # contains an array of all explicitly defined user options. We then
25
- # know that all other values are defaults
26
- if user_supplied_options = options.delete(:user_supplied_options)
27
- (options.keys - user_supplied_options).each do |k|
28
- default_options[k] = options.delete(k)
29
- end
3
+ # This module is used as an 'include' file in code at bottom of file
4
+ module Puma
5
+ module RackHandler
6
+ DEFAULT_OPTIONS = {
7
+ :Verbose => false,
8
+ :Silent => false
9
+ }
10
+
11
+ def config(app, options = {})
12
+ require_relative '../../puma'
13
+ require_relative '../../puma/configuration'
14
+ require_relative '../../puma/log_writer'
15
+ require_relative '../../puma/launcher'
16
+
17
+ default_options = DEFAULT_OPTIONS.dup
18
+
19
+ # Libraries pass in values such as :Port and there is no way to determine
20
+ # if it is a default provided by the library or a special value provided
21
+ # by the user. A special key `user_supplied_options` can be passed. This
22
+ # contains an array of all explicitly defined user options. We then
23
+ # know that all other values are defaults
24
+ if user_supplied_options = options.delete(:user_supplied_options)
25
+ (options.keys - user_supplied_options).each do |k|
26
+ default_options[k] = options.delete(k)
30
27
  end
28
+ end
31
29
 
32
- conf = ::Puma::Configuration.new(options, default_options) do |user_config, file_config, default_config|
33
- if options.delete(:Verbose)
34
- require 'rack/common_logger'
35
- app = Rack::CommonLogger.new(app, STDOUT)
36
- end
30
+ @events = options[:events] || ::Puma::Events.new
37
31
 
38
- if options[:environment]
39
- user_config.environment options[:environment]
32
+ conf = ::Puma::Configuration.new(options, default_options.merge({events: @events})) do |user_config, file_config, default_config|
33
+ if options.delete(:Verbose)
34
+ begin
35
+ require 'rack/commonlogger' # Rack 1.x
36
+ rescue LoadError
37
+ require 'rack/common_logger' # Rack 2 and later
40
38
  end
39
+ app = ::Rack::CommonLogger.new(app, STDOUT)
40
+ end
41
41
 
42
- if options[:Threads]
43
- min, max = options.delete(:Threads).split(':', 2)
44
- user_config.threads min, max
45
- end
42
+ if options[:environment]
43
+ user_config.environment options[:environment]
44
+ end
46
45
 
47
- if options[:Host] || options[:Port]
48
- host = options[:Host] || default_options[:Host]
49
- port = options[:Port] || default_options[:Port]
50
- self.set_host_port_to_config(host, port, user_config)
51
- end
46
+ if options[:Threads]
47
+ min, max = options.delete(:Threads).split(':', 2)
48
+ user_config.threads min, max
49
+ end
52
50
 
53
- if default_options[:Host]
54
- file_config.set_default_host(default_options[:Host])
55
- end
56
- self.set_host_port_to_config(default_options[:Host], default_options[:Port], default_config)
51
+ if options[:Host] || options[:Port]
52
+ host = options[:Host] || default_options[:Host]
53
+ port = options[:Port] || default_options[:Port]
54
+ self.set_host_port_to_config(host, port, user_config)
55
+ end
57
56
 
58
- user_config.app app
57
+ if default_options[:Host]
58
+ file_config.set_default_host(default_options[:Host])
59
59
  end
60
- conf
60
+ self.set_host_port_to_config(default_options[:Host], default_options[:Port], default_config)
61
+
62
+ user_config.app app
61
63
  end
64
+ conf
65
+ end
62
66
 
63
- def self.run(app, **options)
64
- conf = self.config(app, options)
67
+ def run(app, **options)
68
+ conf = self.config(app, options)
65
69
 
66
- events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio
70
+ log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio
67
71
 
68
- launcher = ::Puma::Launcher.new(conf, :events => events)
72
+ launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer, events: @events)
69
73
 
70
- yield launcher if block_given?
71
- begin
72
- launcher.run
73
- rescue Interrupt
74
- puts "* Gracefully stopping, waiting for requests to finish"
75
- launcher.stop
76
- puts "* Goodbye!"
77
- end
74
+ yield launcher if block_given?
75
+ begin
76
+ launcher.run
77
+ rescue Interrupt
78
+ puts "* Gracefully stopping, waiting for requests to finish"
79
+ launcher.stop
80
+ puts "* Goodbye!"
78
81
  end
82
+ end
79
83
 
80
- def self.valid_options
81
- {
82
- "Host=HOST" => "Hostname to listen on (default: localhost)",
83
- "Port=PORT" => "Port to listen on (default: 8080)",
84
- "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
85
- "Verbose" => "Don't report each request (default: false)"
86
- }
87
- end
84
+ def valid_options
85
+ {
86
+ "Host=HOST" => "Hostname to listen on (default: localhost)",
87
+ "Port=PORT" => "Port to listen on (default: 8080)",
88
+ "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
89
+ "Verbose" => "Don't report each request (default: false)"
90
+ }
91
+ end
88
92
 
89
- def self.set_host_port_to_config(host, port, config)
90
- config.clear_binds! if host || port
93
+ def set_host_port_to_config(host, port, config)
94
+ config.clear_binds! if host || port
91
95
 
92
- if host && (host[0,1] == '.' || host[0,1] == '/')
93
- config.bind "unix://#{host}"
94
- elsif host && host =~ /^ssl:\/\//
95
- uri = URI.parse(host)
96
- uri.port ||= port || ::Puma::Configuration::DefaultTCPPort
97
- config.bind uri.to_s
98
- else
96
+ if host && (host[0,1] == '.' || host[0,1] == '/')
97
+ config.bind "unix://#{host}"
98
+ elsif host && host =~ /^ssl:\/\//
99
+ uri = URI.parse(host)
100
+ uri.port ||= port || ::Puma::Configuration::DEFAULTS[:tcp_port]
101
+ config.bind uri.to_s
102
+ else
99
103
 
100
- if host
101
- port ||= ::Puma::Configuration::DefaultTCPPort
102
- end
104
+ if host
105
+ port ||= ::Puma::Configuration::DEFAULTS[:tcp_port]
106
+ end
103
107
 
104
- if port
105
- host ||= ::Puma::Configuration::DefaultTCPHost
106
- config.port port, host
107
- end
108
+ if port
109
+ host ||= ::Puma::Configuration::DEFAULTS[:tcp_host]
110
+ config.port port, host
108
111
  end
109
112
  end
110
113
  end
114
+ end
115
+ end
111
116
 
112
- register :puma, Puma
117
+ # rackup was removed in Rack 3, it is now a separate gem
118
+ if Object.const_defined? :Rackup
119
+ module Rackup
120
+ module Handler
121
+ module Puma
122
+ class << self
123
+ include ::Puma::RackHandler
124
+ end
125
+ end
126
+ register :puma, Puma
127
+ end
128
+ end
129
+ else
130
+ do_register = Object.const_defined?(:Rack) && Rack.release < '3'
131
+ module Rack
132
+ module Handler
133
+ module Puma
134
+ class << self
135
+ include ::Puma::RackHandler
136
+ end
137
+ end
138
+ end
113
139
  end
140
+ ::Rack::Handler.register(:puma, ::Rack::Handler::Puma) if do_register
114
141
  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.2.2
4
+ version: 6.3.0
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-03-02 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
@@ -24,9 +24,9 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
27
+ description: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server
28
28
  for Ruby/Rack applications. Puma is intended for use in both development and production
29
- environments. It's great for highly concurrent Ruby implementations such as Rubinius
29
+ environments. It's great for highly parallel Ruby implementations such as Rubinius
30
30
  and JRuby as well as as providing process worker support to support CRuby well.
31
31
  email:
32
32
  - evan@phx.io
@@ -62,6 +62,8 @@ files:
62
62
  - docs/signals.md
63
63
  - docs/stats.md
64
64
  - docs/systemd.md
65
+ - docs/testing_benchmarks_local_files.md
66
+ - docs/testing_test_rackup_ci_files.md
65
67
  - ext/puma_http11/PumaHttp11Service.java
66
68
  - ext/puma_http11/ext_help.h
67
69
  - ext/puma_http11/extconf.rb
@@ -94,24 +96,26 @@ files:
94
96
  - lib/puma/events.rb
95
97
  - lib/puma/io_buffer.rb
96
98
  - lib/puma/jruby_restart.rb
97
- - lib/puma/json.rb
99
+ - lib/puma/json_serialization.rb
98
100
  - lib/puma/launcher.rb
101
+ - lib/puma/launcher/bundle_pruner.rb
102
+ - lib/puma/log_writer.rb
99
103
  - lib/puma/minissl.rb
100
104
  - lib/puma/minissl/context_builder.rb
101
105
  - lib/puma/null_io.rb
102
106
  - lib/puma/plugin.rb
107
+ - lib/puma/plugin/systemd.rb
103
108
  - lib/puma/plugin/tmp_restart.rb
104
- - lib/puma/queue_close.rb
105
109
  - lib/puma/rack/builder.rb
106
110
  - lib/puma/rack/urlmap.rb
107
111
  - lib/puma/rack_default.rb
108
112
  - lib/puma/reactor.rb
109
113
  - lib/puma/request.rb
110
114
  - lib/puma/runner.rb
115
+ - lib/puma/sd_notify.rb
111
116
  - lib/puma/server.rb
112
117
  - lib/puma/single.rb
113
118
  - lib/puma/state_file.rb
114
- - lib/puma/systemd.rb
115
119
  - lib/puma/thread_pool.rb
116
120
  - lib/puma/util.rb
117
121
  - lib/rack/handler/puma.rb
@@ -125,6 +129,7 @@ metadata:
125
129
  changelog_uri: https://github.com/puma/puma/blob/master/History.md
126
130
  homepage_uri: https://puma.io
127
131
  source_code_uri: https://github.com/puma/puma
132
+ rubygems_mfa_required: 'true'
128
133
  post_install_message:
129
134
  rdoc_options: []
130
135
  require_paths:
@@ -133,16 +138,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
138
  requirements:
134
139
  - - ">="
135
140
  - !ruby/object:Gem::Version
136
- version: '2.2'
141
+ version: '2.4'
137
142
  required_rubygems_version: !ruby/object:Gem::Requirement
138
143
  requirements:
139
144
  - - ">="
140
145
  - !ruby/object:Gem::Version
141
146
  version: '0'
142
147
  requirements: []
143
- rubygems_version: 3.2.3
148
+ rubygems_version: 3.4.12
144
149
  signing_key:
145
150
  specification_version: 4
146
- summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
151
+ summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
147
152
  Ruby/Rack applications
148
153
  test_files: []