puma 6.0.0 → 6.6.0

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +392 -13
  3. data/LICENSE +0 -0
  4. data/README.md +135 -29
  5. data/bin/puma-wild +0 -0
  6. data/docs/architecture.md +0 -0
  7. data/docs/compile_options.md +0 -0
  8. data/docs/deployment.md +0 -0
  9. data/docs/fork_worker.md +11 -1
  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/java_options.md +54 -0
  14. data/docs/jungle/README.md +0 -0
  15. data/docs/jungle/rc.d/README.md +0 -0
  16. data/docs/jungle/rc.d/puma.conf +0 -0
  17. data/docs/kubernetes.md +12 -0
  18. data/docs/nginx.md +1 -1
  19. data/docs/plugins.md +4 -0
  20. data/docs/rails_dev_mode.md +0 -0
  21. data/docs/restart.md +1 -0
  22. data/docs/signals.md +2 -2
  23. data/docs/stats.md +8 -3
  24. data/docs/systemd.md +13 -7
  25. data/docs/testing_benchmarks_local_files.md +0 -0
  26. data/docs/testing_test_rackup_ci_files.md +0 -0
  27. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  28. data/ext/puma_http11/ext_help.h +0 -0
  29. data/ext/puma_http11/extconf.rb +21 -14
  30. data/ext/puma_http11/http11_parser.c +0 -0
  31. data/ext/puma_http11/http11_parser.h +0 -0
  32. data/ext/puma_http11/http11_parser.java.rl +0 -0
  33. data/ext/puma_http11/http11_parser.rl +0 -0
  34. data/ext/puma_http11/http11_parser_common.rl +0 -0
  35. data/ext/puma_http11/mini_ssl.c +107 -10
  36. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  37. data/ext/puma_http11/org/jruby/puma/Http11.java +30 -7
  38. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
  39. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
  40. data/ext/puma_http11/puma_http11.c +4 -1
  41. data/lib/puma/app/status.rb +1 -1
  42. data/lib/puma/binder.rb +26 -15
  43. data/lib/puma/cli.rb +13 -5
  44. data/lib/puma/client.rb +113 -26
  45. data/lib/puma/cluster/worker.rb +14 -6
  46. data/lib/puma/cluster/worker_handle.rb +4 -5
  47. data/lib/puma/cluster.rb +93 -22
  48. data/lib/puma/commonlogger.rb +21 -14
  49. data/lib/puma/configuration.rb +42 -22
  50. data/lib/puma/const.rb +149 -89
  51. data/lib/puma/control_cli.rb +16 -9
  52. data/lib/puma/detect.rb +5 -4
  53. data/lib/puma/dsl.rb +432 -40
  54. data/lib/puma/error_logger.rb +6 -5
  55. data/lib/puma/events.rb +0 -0
  56. data/lib/puma/io_buffer.rb +10 -0
  57. data/lib/puma/jruby_restart.rb +0 -16
  58. data/lib/puma/json_serialization.rb +0 -0
  59. data/lib/puma/launcher/bundle_pruner.rb +0 -0
  60. data/lib/puma/launcher.rb +29 -29
  61. data/lib/puma/log_writer.rb +23 -13
  62. data/lib/puma/minissl/context_builder.rb +4 -0
  63. data/lib/puma/minissl.rb +23 -0
  64. data/lib/puma/null_io.rb +42 -2
  65. data/lib/puma/plugin/systemd.rb +90 -0
  66. data/lib/puma/plugin/tmp_restart.rb +0 -0
  67. data/lib/puma/plugin.rb +0 -0
  68. data/lib/puma/rack/builder.rb +2 -2
  69. data/lib/puma/rack/urlmap.rb +1 -1
  70. data/lib/puma/rack_default.rb +18 -3
  71. data/lib/puma/reactor.rb +17 -8
  72. data/lib/puma/request.rb +207 -126
  73. data/lib/puma/runner.rb +26 -4
  74. data/lib/puma/sd_notify.rb +146 -0
  75. data/lib/puma/server.rb +121 -49
  76. data/lib/puma/single.rb +3 -1
  77. data/lib/puma/state_file.rb +2 -2
  78. data/lib/puma/thread_pool.rb +56 -9
  79. data/lib/puma/util.rb +1 -1
  80. data/lib/puma.rb +1 -3
  81. data/lib/rack/handler/puma.rb +116 -86
  82. data/tools/Dockerfile +2 -2
  83. data/tools/trickletest.rb +0 -0
  84. metadata +12 -13
  85. data/lib/puma/systemd.rb +0 -47
data/lib/puma.rb CHANGED
@@ -3,8 +3,6 @@
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
 
@@ -28,7 +26,7 @@ module Puma
28
26
  # not in minissl.rb
29
27
  HAS_SSL = const_defined?(:MiniSSL, false) && MiniSSL.const_defined?(:Engine, false)
30
28
 
31
- HAS_UNIX_SOCKET = Object.const_defined? :UNIXSocket
29
+ HAS_UNIX_SOCKET = Object.const_defined?(:UNIXSocket) && !IS_WINDOWS
32
30
 
33
31
  if HAS_SSL
34
32
  require_relative 'puma/minissl'
@@ -1,114 +1,144 @@
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_relative '../../puma'
15
- require_relative '../../puma/configuration'
16
- require_relative '../../puma/log_writer'
17
- require_relative '../../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
+ module Puma
4
+
5
+ # This module is used as an 'include' file in code at bottom of file. It loads
6
+ # into either `Rackup::Handler::Puma` or `Rack::Handler::Puma`.
7
+
8
+ module RackHandler
9
+ DEFAULT_OPTIONS = {
10
+ :Verbose => false,
11
+ :Silent => false
12
+ }
13
+
14
+ def config(app, options = {})
15
+ require_relative '../../puma'
16
+ require_relative '../../puma/configuration'
17
+ require_relative '../../puma/log_writer'
18
+ require_relative '../../puma/launcher'
19
+
20
+ default_options = DEFAULT_OPTIONS.dup
21
+
22
+ # Libraries pass in values such as :Port and there is no way to determine
23
+ # if it is a default provided by the library or a special value provided
24
+ # by the user. A special key `user_supplied_options` can be passed. This
25
+ # contains an array of all explicitly defined user options. We then
26
+ # know that all other values are defaults
27
+ if user_supplied_options = options.delete(:user_supplied_options)
28
+ (options.keys - user_supplied_options).each do |k|
29
+ default_options[k] = options.delete(k)
30
30
  end
31
+ end
31
32
 
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
33
+ @events = options[:events] || ::Puma::Events.new
37
34
 
38
- if options[:environment]
39
- user_config.environment options[:environment]
35
+ conf = ::Puma::Configuration.new(options, default_options.merge({events: @events})) do |user_config, file_config, default_config|
36
+ if options.delete(:Verbose)
37
+ begin
38
+ require 'rack/commonlogger' # Rack 1.x
39
+ rescue LoadError
40
+ require 'rack/common_logger' # Rack 2 and later
40
41
  end
42
+ app = ::Rack::CommonLogger.new(app, STDOUT)
43
+ end
41
44
 
42
- if options[:Threads]
43
- min, max = options.delete(:Threads).split(':', 2)
44
- user_config.threads min, max
45
- end
45
+ if options[:environment]
46
+ user_config.environment options[:environment]
47
+ end
46
48
 
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
49
+ if options[:Threads]
50
+ min, max = options.delete(:Threads).split(':', 2)
51
+ user_config.threads min, max
52
+ end
52
53
 
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)
54
+ if options[:Host] || options[:Port]
55
+ host = options[:Host] || default_options[:Host]
56
+ port = options[:Port] || default_options[:Port]
57
+ self.set_host_port_to_config(host, port, user_config)
58
+ end
57
59
 
58
- user_config.app app
60
+ if default_options[:Host]
61
+ file_config.set_default_host(default_options[:Host])
59
62
  end
60
- conf
63
+ self.set_host_port_to_config(default_options[:Host], default_options[:Port], default_config)
64
+
65
+ user_config.app app
61
66
  end
67
+ conf
68
+ end
62
69
 
63
- def self.run(app, **options)
64
- conf = self.config(app, options)
70
+ def run(app, **options)
71
+ conf = self.config(app, options)
65
72
 
66
- log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio
73
+ log_writer = options.delete(:Silent) ? ::Puma::LogWriter.strings : ::Puma::LogWriter.stdio
67
74
 
68
- launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer)
75
+ launcher = ::Puma::Launcher.new(conf, :log_writer => log_writer, events: @events)
69
76
 
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
77
+ yield launcher if block_given?
78
+ begin
79
+ launcher.run
80
+ rescue Interrupt
81
+ puts "* Gracefully stopping, waiting for requests to finish"
82
+ launcher.stop
83
+ puts "* Goodbye!"
78
84
  end
85
+ end
79
86
 
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
87
+ def valid_options
88
+ {
89
+ "Host=HOST" => "Hostname to listen on (default: localhost)",
90
+ "Port=PORT" => "Port to listen on (default: 8080)",
91
+ "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
92
+ "Verbose" => "Don't report each request (default: false)"
93
+ }
94
+ end
88
95
 
89
- def self.set_host_port_to_config(host, port, config)
90
- config.clear_binds! if host || port
96
+ def set_host_port_to_config(host, port, config)
97
+ config.clear_binds! if host || port
91
98
 
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::DEFAULTS[:tcp_port]
97
- config.bind uri.to_s
98
- else
99
+ if host&.start_with? '.', '/', '@'
100
+ config.bind "unix://#{host}"
101
+ elsif host&.start_with? 'ssl://'
102
+ uri = URI.parse(host)
103
+ uri.port ||= port || ::Puma::Configuration::DEFAULTS[:tcp_port]
104
+ config.bind uri.to_s
105
+ else
99
106
 
100
- if host
101
- port ||= ::Puma::Configuration::DEFAULTS[:tcp_port]
102
- end
107
+ if host
108
+ port ||= ::Puma::Configuration::DEFAULTS[:tcp_port]
109
+ end
103
110
 
104
- if port
105
- host ||= ::Puma::Configuration::DEFAULTS[:tcp_host]
106
- config.port port, host
107
- end
111
+ if port
112
+ host ||= ::Puma::Configuration::DEFAULTS[:tcp_host]
113
+ config.port port, host
108
114
  end
109
115
  end
110
116
  end
117
+ end
118
+ end
111
119
 
112
- register :puma, Puma
120
+ # rackup was removed in Rack 3, it is now a separate gem
121
+ if Object.const_defined?(:Rackup) && ::Rackup.const_defined?(:Handler)
122
+ module Rackup
123
+ module Handler
124
+ module Puma
125
+ class << self
126
+ include ::Puma::RackHandler
127
+ end
128
+ end
129
+ register :puma, Puma
130
+ end
131
+ end
132
+ else
133
+ do_register = Object.const_defined?(:Rack) && ::Rack.release < '3'
134
+ module Rack
135
+ module Handler
136
+ module Puma
137
+ class << self
138
+ include ::Puma::RackHandler
139
+ end
140
+ end
141
+ end
113
142
  end
143
+ ::Rack::Handler.register(:puma, ::Rack::Handler::Puma) if do_register
114
144
  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
 
data/tools/trickletest.rb CHANGED
File without changes
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0
4
+ version: 6.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 1980-01-01 00:00:00.000000000 Z
10
+ date: 2025-01-28 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: nio4r
@@ -24,10 +23,11 @@ dependencies:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
25
  version: '2.0'
27
- description: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server
28
- for Ruby/Rack applications. Puma is intended for use in both development and production
29
- environments. It's great for highly parallel Ruby implementations such as Rubinius
30
- and JRuby as well as as providing process worker support to support CRuby well.
26
+ description: |
27
+ Puma is a simple, fast, multi-threaded, and highly parallel HTTP 1.1 server
28
+ for Ruby/Rack applications. Puma is intended for use in both development and
29
+ production environments. It's great for highly parallel Ruby implementations such as
30
+ JRuby and TruffleRuby as well as as providing process worker support to support CRuby well.
31
31
  email:
32
32
  - evan@phx.io
33
33
  executables:
@@ -50,6 +50,7 @@ files:
50
50
  - docs/images/puma-connection-flow-no-reactor.png
51
51
  - docs/images/puma-connection-flow.png
52
52
  - docs/images/puma-general-arch.png
53
+ - docs/java_options.md
53
54
  - docs/jungle/README.md
54
55
  - docs/jungle/rc.d/README.md
55
56
  - docs/jungle/rc.d/puma
@@ -104,6 +105,7 @@ files:
104
105
  - lib/puma/minissl/context_builder.rb
105
106
  - lib/puma/null_io.rb
106
107
  - lib/puma/plugin.rb
108
+ - lib/puma/plugin/systemd.rb
107
109
  - lib/puma/plugin/tmp_restart.rb
108
110
  - lib/puma/rack/builder.rb
109
111
  - lib/puma/rack/urlmap.rb
@@ -111,10 +113,10 @@ files:
111
113
  - lib/puma/reactor.rb
112
114
  - lib/puma/request.rb
113
115
  - lib/puma/runner.rb
116
+ - lib/puma/sd_notify.rb
114
117
  - lib/puma/server.rb
115
118
  - lib/puma/single.rb
116
119
  - lib/puma/state_file.rb
117
- - lib/puma/systemd.rb
118
120
  - lib/puma/thread_pool.rb
119
121
  - lib/puma/util.rb
120
122
  - lib/rack/handler/puma.rb
@@ -129,7 +131,6 @@ metadata:
129
131
  homepage_uri: https://puma.io
130
132
  source_code_uri: https://github.com/puma/puma
131
133
  rubygems_mfa_required: 'true'
132
- post_install_message:
133
134
  rdoc_options: []
134
135
  require_paths:
135
136
  - lib
@@ -144,9 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
145
  - !ruby/object:Gem::Version
145
146
  version: '0'
146
147
  requirements: []
147
- rubygems_version: 3.2.26
148
- signing_key:
148
+ rubygems_version: 3.6.3
149
149
  specification_version: 4
150
- summary: Puma is a simple, fast, threaded, and highly parallel HTTP 1.1 server for
151
- Ruby/Rack applications
150
+ summary: A Ruby/Rack web server built for parallelism.
152
151
  test_files: []
data/lib/puma/systemd.rb DELETED
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sd_notify'
4
-
5
- module Puma
6
- class Systemd
7
- def initialize(log_writer, events)
8
- @log_writer = log_writer
9
- @events = events
10
- end
11
-
12
- def hook_events
13
- @events.on_booted { SdNotify.ready }
14
- @events.on_stopped { SdNotify.stopping }
15
- @events.on_restart { SdNotify.reloading }
16
- end
17
-
18
- def start_watchdog
19
- return unless SdNotify.watchdog?
20
-
21
- ping_f = watchdog_sleep_time
22
-
23
- log "Pinging systemd watchdog every #{ping_f.round(1)} sec"
24
- Thread.new do
25
- loop do
26
- sleep ping_f
27
- SdNotify.watchdog
28
- end
29
- end
30
- end
31
-
32
- private
33
-
34
- def watchdog_sleep_time
35
- usec = Integer(ENV["WATCHDOG_USEC"])
36
-
37
- sec_f = usec / 1_000_000.0
38
- # "It is recommended that a daemon sends a keep-alive notification message
39
- # to the service manager every half of the time returned here."
40
- sec_f / 2
41
- end
42
-
43
- def log(str)
44
- @log_writer.log(str)
45
- end
46
- end
47
- end