puma 6.4.0 → 6.6.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +235 -18
  3. data/README.md +87 -26
  4. data/docs/fork_worker.md +11 -1
  5. data/docs/java_options.md +54 -0
  6. data/docs/kubernetes.md +1 -1
  7. data/docs/plugins.md +4 -0
  8. data/docs/restart.md +1 -0
  9. data/docs/signals.md +2 -2
  10. data/docs/stats.md +8 -3
  11. data/docs/systemd.md +13 -6
  12. data/ext/puma_http11/extconf.rb +21 -14
  13. data/ext/puma_http11/mini_ssl.c +16 -2
  14. data/ext/puma_http11/org/jruby/puma/Http11.java +31 -8
  15. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
  16. data/ext/puma_http11/puma_http11.c +4 -1
  17. data/lib/puma/app/status.rb +1 -1
  18. data/lib/puma/binder.rb +12 -4
  19. data/lib/puma/cli.rb +9 -5
  20. data/lib/puma/client.rb +104 -16
  21. data/lib/puma/cluster/worker.rb +9 -6
  22. data/lib/puma/cluster/worker_handle.rb +4 -5
  23. data/lib/puma/cluster.rb +112 -27
  24. data/lib/puma/configuration.rb +37 -21
  25. data/lib/puma/const.rb +22 -3
  26. data/lib/puma/control_cli.rb +4 -4
  27. data/lib/puma/detect.rb +3 -4
  28. data/lib/puma/dsl.rb +303 -58
  29. data/lib/puma/error_logger.rb +4 -4
  30. data/lib/puma/jruby_restart.rb +0 -16
  31. data/lib/puma/launcher.rb +21 -8
  32. data/lib/puma/log_writer.rb +9 -9
  33. data/lib/puma/minissl/context_builder.rb +3 -0
  34. data/lib/puma/minissl.rb +6 -0
  35. data/lib/puma/null_io.rb +42 -2
  36. data/lib/puma/request.rb +35 -14
  37. data/lib/puma/runner.rb +10 -3
  38. data/lib/puma/sd_notify.rb +1 -4
  39. data/lib/puma/server.rb +53 -21
  40. data/lib/puma/single.rb +1 -1
  41. data/lib/puma/state_file.rb +2 -2
  42. data/lib/puma/thread_pool.rb +14 -2
  43. data/lib/puma/util.rb +1 -1
  44. data/lib/rack/handler/puma.rb +8 -5
  45. data/tools/Dockerfile +5 -3
  46. metadata +10 -12
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'rack/builder'
4
3
  require_relative 'plugin'
5
4
  require_relative 'const'
6
- # note that dsl is loaded at end of file, requires ConfigDefault constants
5
+ require_relative 'dsl'
7
6
 
8
7
  module Puma
9
8
  # A class used for storing "leveled" configuration options.
@@ -131,6 +130,7 @@ module Puma
131
130
  binds: ['tcp://0.0.0.0:9292'.freeze],
132
131
  clean_thread_locals: false,
133
132
  debug: false,
133
+ enable_keep_alives: true,
134
134
  early_hints: nil,
135
135
  environment: 'development'.freeze,
136
136
  # Number of seconds to wait until we get the first data for the request.
@@ -173,8 +173,8 @@ module Puma
173
173
  http_content_length_limit: nil
174
174
  }
175
175
 
176
- def initialize(user_options={}, default_options = {}, &block)
177
- default_options = self.puma_default_options.merge(default_options)
176
+ def initialize(user_options={}, default_options = {}, env = ENV, &block)
177
+ default_options = self.puma_default_options(env).merge(default_options)
178
178
 
179
179
  @options = UserFileDefaultOptions.new(user_options, default_options)
180
180
  @plugins = PluginLoader.new
@@ -186,6 +186,8 @@ module Puma
186
186
  default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
187
187
  end
188
188
 
189
+ @puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
190
+
189
191
  if block
190
192
  configure(&block)
191
193
  end
@@ -216,22 +218,27 @@ module Puma
216
218
  self
217
219
  end
218
220
 
219
- def puma_default_options
221
+ def puma_default_options(env = ENV)
220
222
  defaults = DEFAULTS.dup
221
- puma_options_from_env.each { |k,v| defaults[k] = v if v }
223
+ puma_options_from_env(env).each { |k,v| defaults[k] = v if v }
222
224
  defaults
223
225
  end
224
226
 
225
- def puma_options_from_env
226
- min = ENV['PUMA_MIN_THREADS'] || ENV['MIN_THREADS']
227
- max = ENV['PUMA_MAX_THREADS'] || ENV['MAX_THREADS']
228
- workers = ENV['WEB_CONCURRENCY']
227
+ def puma_options_from_env(env = ENV)
228
+ min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
229
+ max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
230
+ workers = if env['WEB_CONCURRENCY'] == 'auto'
231
+ require_processor_counter
232
+ ::Concurrent.available_processor_count
233
+ else
234
+ env['WEB_CONCURRENCY']
235
+ end
229
236
 
230
237
  {
231
- min_threads: min && Integer(min),
232
- max_threads: max && Integer(max),
233
- workers: workers && Integer(workers),
234
- environment: ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'],
238
+ min_threads: min && min != "" && Integer(min),
239
+ max_threads: max && max != "" && Integer(max),
240
+ workers: workers && workers != "" && Integer(workers),
241
+ environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
235
242
  }
236
243
  end
237
244
 
@@ -311,6 +318,8 @@ module Puma
311
318
  # @param arg [Launcher, Int] `:on_restart` passes Launcher
312
319
  #
313
320
  def run_hooks(key, arg, log_writer, hook_data = nil)
321
+ log_writer.debug "Running #{key} hooks"
322
+
314
323
  @options.all_of(key).each do |b|
315
324
  begin
316
325
  if Array === b
@@ -339,12 +348,22 @@ module Puma
339
348
 
340
349
  private
341
350
 
351
+ def require_processor_counter
352
+ require 'concurrent/utility/processor_counter'
353
+ rescue LoadError
354
+ warn <<~MESSAGE
355
+ WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
356
+ Please add "concurrent-ruby" to your Gemfile.
357
+ MESSAGE
358
+ raise
359
+ end
360
+
342
361
  # Load and use the normal Rack builder if we can, otherwise
343
362
  # fallback to our minimal version.
344
363
  def rack_builder
345
364
  # Load bundler now if we can so that we can pickup rack from
346
365
  # a Gemfile
347
- if ENV.key? 'PUMA_BUNDLER_PRUNED'
366
+ if @puma_bundler_pruned
348
367
  begin
349
368
  require 'bundler/setup'
350
369
  rescue LoadError
@@ -354,11 +373,10 @@ module Puma
354
373
  begin
355
374
  require 'rack'
356
375
  require 'rack/builder'
376
+ ::Rack::Builder
357
377
  rescue LoadError
358
- # ok, use builtin version
359
- return Puma::Rack::Builder
360
- else
361
- return ::Rack::Builder
378
+ require_relative 'rack/builder'
379
+ Puma::Rack::Builder
362
380
  end
363
381
  end
364
382
 
@@ -387,5 +405,3 @@ module Puma
387
405
  end
388
406
  end
389
407
  end
390
-
391
- require_relative 'dsl'
data/lib/puma/const.rb CHANGED
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "6.4.0"
104
- CODE_NAME = "The Eagle of Durango"
103
+ PUMA_VERSION = VERSION = "6.6.1"
104
+ CODE_NAME = "Return to Forever"
105
105
 
106
106
  PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
107
107
 
@@ -137,7 +137,7 @@ module Puma
137
137
  }.freeze
138
138
 
139
139
  # The basic max request size we'll try to read.
140
- CHUNK_SIZE = 16 * 1024
140
+ CHUNK_SIZE = 64 * 1024
141
141
 
142
142
  # This is the maximum header that is allowed before a client is booted. The parser detects
143
143
  # this, but we'd also like to do this as well.
@@ -281,9 +281,28 @@ module Puma
281
281
  # header values can contain HTAB?
282
282
  ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
283
283
 
284
+ # The keys of headers that should not be convert to underscore
285
+ # normalized versions. These headers are ignored at the request reading layer,
286
+ # but if we normalize them after reading, it's just confusing for the application.
287
+ UNMASKABLE_HEADERS = {
288
+ "HTTP_TRANSFER,ENCODING" => true,
289
+ "HTTP_CONTENT,LENGTH" => true,
290
+ }
291
+
284
292
  # Banned keys of response header
285
293
  BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
286
294
 
287
295
  PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
296
+
297
+ # All constants are prefixed with `PIPE_` to avoid name collisions.
298
+ module PipeRequest
299
+ PIPE_WAKEUP = "!"
300
+ PIPE_BOOT = "b"
301
+ PIPE_FORK = "f"
302
+ PIPE_EXTERNAL_TERM = "e"
303
+ PIPE_TERM = "t"
304
+ PIPE_PING = "p"
305
+ PIPE_IDLE = "i"
306
+ end
288
307
  end
289
308
  end
@@ -37,7 +37,7 @@ module Puma
37
37
  # @version 5.0.0
38
38
  PRINTABLE_COMMANDS = %w[gc-stats stats thread-backtraces].freeze
39
39
 
40
- def initialize(argv, stdout=STDOUT, stderr=STDERR)
40
+ def initialize(argv, stdout=STDOUT, stderr=STDERR, env: ENV)
41
41
  @state = nil
42
42
  @quiet = false
43
43
  @pidfile = nil
@@ -46,7 +46,7 @@ module Puma
46
46
  @control_auth_token = nil
47
47
  @config_file = nil
48
48
  @command = nil
49
- @environment = ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV']
49
+ @environment = env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV']
50
50
 
51
51
  @argv = argv.dup
52
52
  @stdout = stdout
@@ -60,7 +60,7 @@ module Puma
60
60
  @state = arg
61
61
  end
62
62
 
63
- o.on "-Q", "--quiet", "Not display messages" do |arg|
63
+ o.on "-Q", "--quiet", "Do not display messages" do |arg|
64
64
  @quiet = true
65
65
  end
66
66
 
@@ -127,7 +127,7 @@ module Puma
127
127
  require_relative 'configuration'
128
128
  require_relative 'log_writer'
129
129
 
130
- config = Puma::Configuration.new({ config_files: [@config_file] }, {})
130
+ config = Puma::Configuration.new({ config_files: [@config_file] }, {} , env)
131
131
  config.load
132
132
  @state ||= config.options[:state]
133
133
  @control_url ||= config.options[:control_url]
data/lib/puma/detect.rb CHANGED
@@ -12,15 +12,14 @@ module Puma
12
12
 
13
13
  IS_JRUBY = Object.const_defined? :JRUBY_VERSION
14
14
 
15
- IS_OSX = RUBY_PLATFORM.include? 'darwin'
15
+ IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
16
16
 
17
- IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/) ||
18
- IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
17
+ IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
19
18
 
20
19
  IS_LINUX = !(IS_OSX || IS_WINDOWS)
21
20
 
22
21
  # @version 5.2.0
23
- IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
22
+ IS_MRI = RUBY_ENGINE == 'ruby'
24
23
 
25
24
  def self.jruby?
26
25
  IS_JRUBY