puma 5.6.8 → 6.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +322 -16
  3. data/README.md +79 -29
  4. data/bin/puma-wild +1 -1
  5. data/docs/compile_options.md +34 -0
  6. data/docs/fork_worker.md +1 -3
  7. data/docs/kubernetes.md +12 -0
  8. data/docs/nginx.md +1 -1
  9. data/docs/restart.md +1 -0
  10. data/docs/systemd.md +3 -6
  11. data/docs/testing_benchmarks_local_files.md +150 -0
  12. data/docs/testing_test_rackup_ci_files.md +36 -0
  13. data/ext/puma_http11/extconf.rb +16 -9
  14. data/ext/puma_http11/http11_parser.c +1 -1
  15. data/ext/puma_http11/http11_parser.h +1 -1
  16. data/ext/puma_http11/http11_parser.java.rl +2 -2
  17. data/ext/puma_http11/http11_parser.rl +2 -2
  18. data/ext/puma_http11/http11_parser_common.rl +2 -2
  19. data/ext/puma_http11/mini_ssl.c +127 -19
  20. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  21. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  22. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +157 -53
  23. data/ext/puma_http11/puma_http11.c +17 -9
  24. data/lib/puma/app/status.rb +4 -4
  25. data/lib/puma/binder.rb +50 -53
  26. data/lib/puma/cli.rb +16 -18
  27. data/lib/puma/client.rb +59 -19
  28. data/lib/puma/cluster/worker.rb +18 -11
  29. data/lib/puma/cluster/worker_handle.rb +4 -1
  30. data/lib/puma/cluster.rb +102 -40
  31. data/lib/puma/commonlogger.rb +21 -14
  32. data/lib/puma/configuration.rb +77 -59
  33. data/lib/puma/const.rb +129 -92
  34. data/lib/puma/control_cli.rb +15 -11
  35. data/lib/puma/detect.rb +7 -4
  36. data/lib/puma/dsl.rb +250 -56
  37. data/lib/puma/error_logger.rb +18 -9
  38. data/lib/puma/events.rb +6 -126
  39. data/lib/puma/io_buffer.rb +39 -4
  40. data/lib/puma/jruby_restart.rb +2 -1
  41. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  42. data/lib/puma/launcher.rb +102 -175
  43. data/lib/puma/log_writer.rb +147 -0
  44. data/lib/puma/minissl/context_builder.rb +26 -12
  45. data/lib/puma/minissl.rb +104 -11
  46. data/lib/puma/null_io.rb +16 -2
  47. data/lib/puma/plugin/systemd.rb +90 -0
  48. data/lib/puma/plugin/tmp_restart.rb +1 -1
  49. data/lib/puma/rack/builder.rb +6 -6
  50. data/lib/puma/rack/urlmap.rb +1 -1
  51. data/lib/puma/rack_default.rb +19 -4
  52. data/lib/puma/reactor.rb +19 -10
  53. data/lib/puma/request.rb +365 -170
  54. data/lib/puma/runner.rb +56 -20
  55. data/lib/puma/sd_notify.rb +149 -0
  56. data/lib/puma/server.rb +137 -89
  57. data/lib/puma/single.rb +13 -11
  58. data/lib/puma/state_file.rb +3 -6
  59. data/lib/puma/thread_pool.rb +57 -19
  60. data/lib/puma/util.rb +0 -11
  61. data/lib/puma.rb +9 -10
  62. data/lib/rack/handler/puma.rb +113 -86
  63. data/tools/Dockerfile +2 -2
  64. metadata +9 -5
  65. data/lib/puma/queue_close.rb +0 -26
  66. data/lib/puma/systemd.rb +0 -46
  67. data/lib/rack/version_restriction.rb +0 -15
data/lib/puma/util.rb CHANGED
@@ -39,17 +39,6 @@ module Puma
39
39
  end
40
40
  module_function :unescape, :escape
41
41
 
42
- # @version 5.0.0
43
- def nakayoshi_gc(events)
44
- events.log "! Promoting existing objects to old generation..."
45
- 4.times { GC.start(full_mark: false) }
46
- if GC.respond_to?(:compact)
47
- events.log "! Compacting..."
48
- GC.compact
49
- end
50
- events.log "! Friendly fork preparation complete."
51
- end
52
-
53
42
  DEFAULT_SEP = /[&;] */n
54
43
 
55
44
  # Stolen from Mongrel, with some small modifications:
data/lib/puma.rb CHANGED
@@ -3,23 +3,24 @@
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
 
13
- # extension files should not be loaded with `require_relative`
11
+ # use require, see https://github.com/puma/puma/pull/2381
14
12
  require 'puma/puma_http11'
13
+
15
14
  require_relative 'puma/detect'
16
15
  require_relative 'puma/json_serialization'
17
- require_relative 'rack/version_restriction'
18
16
 
19
17
  module Puma
20
- autoload :Const, 'puma/const'
21
- autoload :Server, 'puma/server'
22
- 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"
23
24
 
24
25
  # at present, MiniSSL::Engine is only defined in extension code (puma_http11),
25
26
  # not in minissl.rb
@@ -28,7 +29,7 @@ module Puma
28
29
  HAS_UNIX_SOCKET = Object.const_defined?(:UNIXSocket) && !IS_WINDOWS
29
30
 
30
31
  if HAS_SSL
31
- require 'puma/minissl'
32
+ require_relative 'puma/minissl'
32
33
  else
33
34
  module MiniSSL
34
35
  # this class is defined so that it exists when Puma is compiled
@@ -71,9 +72,7 @@ module Puma
71
72
  @get_stats.stats
72
73
  end
73
74
 
74
- # Thread name is new in Ruby 2.3
75
75
  def self.set_thread_name(name)
76
- return unless Thread.current.respond_to?(:name=)
77
76
  Thread.current.name = "puma #{name}"
78
77
  end
79
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:3.1
3
+ FROM ruby:3.2
4
4
 
5
5
  # throw errors if Gemfile has been modified since Gemfile.lock
6
6
  RUN bundle config --global frozen 1
@@ -8,7 +8,7 @@ RUN bundle config --global frozen 1
8
8
  WORKDIR /usr/src/app
9
9
 
10
10
  COPY . .
11
- RUN gem install bundler
11
+
12
12
  RUN bundle install
13
13
  RUN bundle exec rake compile
14
14
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.6.8
4
+ version: 6.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
@@ -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
@@ -96,26 +98,27 @@ files:
96
98
  - lib/puma/jruby_restart.rb
97
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
118
- - lib/rack/version_restriction.rb
119
122
  - tools/Dockerfile
120
123
  - tools/trickletest.rb
121
124
  homepage: https://puma.io
@@ -126,6 +129,7 @@ metadata:
126
129
  changelog_uri: https://github.com/puma/puma/blob/master/History.md
127
130
  homepage_uri: https://puma.io
128
131
  source_code_uri: https://github.com/puma/puma
132
+ rubygems_mfa_required: 'true'
129
133
  post_install_message:
130
134
  rdoc_options: []
131
135
  require_paths:
@@ -134,7 +138,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
138
  requirements:
135
139
  - - ">="
136
140
  - !ruby/object:Gem::Version
137
- version: '2.2'
141
+ version: '2.4'
138
142
  required_rubygems_version: !ruby/object:Gem::Requirement
139
143
  requirements:
140
144
  - - ">="
@@ -1,26 +0,0 @@
1
- class ClosedQueueError < StandardError; end
2
- module Puma
3
-
4
- # Queue#close was added in Ruby 2.3.
5
- # Add a simple implementation for earlier Ruby versions.
6
- #
7
- module QueueClose
8
- def close
9
- num_waiting.times {push nil}
10
- @closed = true
11
- end
12
- def closed?
13
- @closed ||= false
14
- end
15
- def push(object)
16
- raise ClosedQueueError if closed?
17
- super
18
- end
19
- alias << push
20
- def pop(non_block=false)
21
- return nil if !non_block && closed? && empty?
22
- super
23
- end
24
- end
25
- ::Queue.prepend QueueClose
26
- end
data/lib/puma/systemd.rb DELETED
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sd_notify'
4
-
5
- module Puma
6
- class Systemd
7
- def initialize(events)
8
- @events = events
9
- end
10
-
11
- def hook_events
12
- @events.on_booted { SdNotify.ready }
13
- @events.on_stopped { SdNotify.stopping }
14
- @events.on_restart { SdNotify.reloading }
15
- end
16
-
17
- def start_watchdog
18
- return unless SdNotify.watchdog?
19
-
20
- ping_f = watchdog_sleep_time
21
-
22
- log "Pinging systemd watchdog every #{ping_f.round(1)} sec"
23
- Thread.new do
24
- loop do
25
- sleep ping_f
26
- SdNotify.watchdog
27
- end
28
- end
29
- end
30
-
31
- private
32
-
33
- def watchdog_sleep_time
34
- usec = Integer(ENV["WATCHDOG_USEC"])
35
-
36
- sec_f = usec / 1_000_000.0
37
- # "It is recommended that a daemon sends a keep-alive notification message
38
- # to the service manager every half of the time returned here."
39
- sec_f / 2
40
- end
41
-
42
- def log(str)
43
- @events.log str
44
- end
45
- end
46
- end
@@ -1,15 +0,0 @@
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