puma 6.4.1 → 7.2.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +407 -8
  3. data/README.md +109 -49
  4. data/docs/deployment.md +58 -23
  5. data/docs/fork_worker.md +11 -1
  6. data/docs/java_options.md +54 -0
  7. data/docs/jungle/README.md +1 -1
  8. data/docs/kubernetes.md +11 -16
  9. data/docs/plugins.md +6 -2
  10. data/docs/restart.md +2 -2
  11. data/docs/signals.md +21 -21
  12. data/docs/stats.md +11 -5
  13. data/docs/systemd.md +14 -5
  14. data/ext/puma_http11/extconf.rb +20 -32
  15. data/ext/puma_http11/mini_ssl.c +29 -9
  16. data/ext/puma_http11/org/jruby/puma/Http11.java +40 -9
  17. data/ext/puma_http11/puma_http11.c +125 -118
  18. data/lib/puma/app/status.rb +11 -3
  19. data/lib/puma/binder.rb +21 -11
  20. data/lib/puma/cli.rb +10 -8
  21. data/lib/puma/client.rb +183 -83
  22. data/lib/puma/cluster/worker.rb +24 -21
  23. data/lib/puma/cluster/worker_handle.rb +38 -8
  24. data/lib/puma/cluster.rb +73 -47
  25. data/lib/puma/cluster_accept_loop_delay.rb +91 -0
  26. data/lib/puma/commonlogger.rb +3 -3
  27. data/lib/puma/configuration.rb +131 -60
  28. data/lib/puma/const.rb +31 -12
  29. data/lib/puma/control_cli.rb +10 -6
  30. data/lib/puma/detect.rb +2 -0
  31. data/lib/puma/dsl.rb +411 -121
  32. data/lib/puma/error_logger.rb +7 -5
  33. data/lib/puma/events.rb +25 -10
  34. data/lib/puma/io_buffer.rb +8 -4
  35. data/lib/puma/jruby_restart.rb +0 -16
  36. data/lib/puma/launcher/bundle_pruner.rb +1 -1
  37. data/lib/puma/launcher.rb +73 -55
  38. data/lib/puma/log_writer.rb +9 -9
  39. data/lib/puma/minissl/context_builder.rb +1 -0
  40. data/lib/puma/minissl.rb +1 -1
  41. data/lib/puma/null_io.rb +26 -0
  42. data/lib/puma/plugin/systemd.rb +3 -3
  43. data/lib/puma/rack/urlmap.rb +1 -1
  44. data/lib/puma/reactor.rb +19 -13
  45. data/lib/puma/request.rb +71 -39
  46. data/lib/puma/runner.rb +15 -17
  47. data/lib/puma/sd_notify.rb +1 -4
  48. data/lib/puma/server.rb +134 -73
  49. data/lib/puma/single.rb +7 -4
  50. data/lib/puma/state_file.rb +3 -2
  51. data/lib/puma/thread_pool.rb +57 -80
  52. data/lib/puma/util.rb +0 -7
  53. data/lib/puma.rb +10 -0
  54. data/lib/rack/handler/puma.rb +10 -7
  55. data/tools/Dockerfile +15 -5
  56. metadata +14 -15
  57. data/ext/puma_http11/ext_help.h +0 -15
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'rack/builder'
4
3
  require_relative 'plugin'
5
4
  require_relative 'const'
6
5
  require_relative 'dsl'
6
+ require_relative 'events'
7
7
 
8
8
  module Puma
9
9
  # A class used for storing "leveled" configuration options.
@@ -113,7 +113,7 @@ module Puma
113
113
  # config = Configuration.new({}) do |user_config, file_config, default_config|
114
114
  # user_config.port 3003
115
115
  # end
116
- # config.load
116
+ # config.clamp
117
117
  # puts config.options[:port]
118
118
  # # => 3003
119
119
  #
@@ -126,11 +126,15 @@ module Puma
126
126
  # is done because an environment variable may have been modified while loading
127
127
  # configuration files.
128
128
  class Configuration
129
+ class NotLoadedError < StandardError; end
130
+ class NotClampedError < StandardError; end
131
+
129
132
  DEFAULTS = {
130
133
  auto_trim_time: 30,
131
134
  binds: ['tcp://0.0.0.0:9292'.freeze],
132
- clean_thread_locals: false,
135
+ fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
133
136
  debug: false,
137
+ enable_keep_alives: true,
134
138
  early_hints: nil,
135
139
  environment: 'development'.freeze,
136
140
  # Number of seconds to wait until we get the first data for the request.
@@ -140,19 +144,18 @@ module Puma
140
144
  io_selector_backend: :auto,
141
145
  log_requests: false,
142
146
  logger: STDOUT,
143
- # How many requests to attempt inline before sending a client back to
144
- # the reactor to be subject to normal ordering. The idea here is that
145
- # we amortize the cost of going back to the reactor for a well behaved
146
- # but very "greedy" client across 10 requests. This prevents a not
147
- # well behaved client from monopolizing the thread forever.
148
- max_fast_inline: 10,
147
+ # Limits how many requests a keep alive connection can make.
148
+ # The connection will be closed after it reaches `max_keep_alive`
149
+ # requests.
150
+ max_keep_alive: 999,
149
151
  max_threads: Puma.mri? ? 5 : 16,
150
152
  min_threads: 0,
151
153
  mode: :http,
152
154
  mutate_stdout_and_stderr_to_sync_on_write: true,
153
155
  out_of_band: [],
154
156
  # Number of seconds for another request within a persistent session.
155
- persistent_timeout: 20,
157
+ persistent_timeout: 65, # PUMA_PERSISTENT_TIMEOUT
158
+ prune_bundler: false,
156
159
  queue_requests: true,
157
160
  rackup: 'config.ru'.freeze,
158
161
  raise_exception_on_sigterm: true,
@@ -173,25 +176,34 @@ module Puma
173
176
  http_content_length_limit: nil
174
177
  }
175
178
 
176
- def initialize(user_options={}, default_options = {}, &block)
177
- default_options = self.puma_default_options.merge(default_options)
179
+ def initialize(user_options={}, default_options = {}, env = ENV, &block)
180
+ default_options = self.puma_default_options(env).merge(default_options)
178
181
 
179
- @options = UserFileDefaultOptions.new(user_options, default_options)
182
+ @_options = UserFileDefaultOptions.new(user_options, default_options)
180
183
  @plugins = PluginLoader.new
181
- @user_dsl = DSL.new(@options.user_options, self)
182
- @file_dsl = DSL.new(@options.file_options, self)
183
- @default_dsl = DSL.new(@options.default_options, self)
184
+ @events = @_options[:events] || Events.new
185
+ @hooks = {}
186
+ @user_dsl = DSL.new(@_options.user_options, self)
187
+ @file_dsl = DSL.new(@_options.file_options, self)
188
+ @default_dsl = DSL.new(@_options.default_options, self)
184
189
 
185
- if !@options[:prune_bundler]
186
- default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
187
- end
190
+ @puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
188
191
 
189
192
  if block
190
193
  configure(&block)
191
194
  end
195
+
196
+ @loaded = false
197
+ @clamped = false
192
198
  end
193
199
 
194
- attr_reader :options, :plugins
200
+ attr_reader :plugins, :events, :hooks, :_options
201
+
202
+ def options
203
+ raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
204
+
205
+ @_options
206
+ end
195
207
 
196
208
  def configure
197
209
  yield @user_dsl, @file_dsl, @default_dsl
@@ -204,7 +216,7 @@ module Puma
204
216
  def initialize_copy(other)
205
217
  @conf = nil
206
218
  @cli_options = nil
207
- @options = @options.dup
219
+ @_options = @_options.dup
208
220
  end
209
221
 
210
222
  def flatten
@@ -212,42 +224,47 @@ module Puma
212
224
  end
213
225
 
214
226
  def flatten!
215
- @options = @options.flatten
227
+ @_options = @_options.flatten
216
228
  self
217
229
  end
218
230
 
219
- def puma_default_options
231
+ def puma_default_options(env = ENV)
220
232
  defaults = DEFAULTS.dup
221
- puma_options_from_env.each { |k,v| defaults[k] = v if v }
233
+ puma_options_from_env(env).each { |k,v| defaults[k] = v if v }
222
234
  defaults
223
235
  end
224
236
 
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']
237
+ def puma_options_from_env(env = ENV)
238
+ min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
239
+ max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
240
+ persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
241
+ workers_env = env['WEB_CONCURRENCY']
242
+ workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
229
243
 
230
244
  {
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'],
245
+ min_threads: min && min != "" && Integer(min),
246
+ max_threads: max && max != "" && Integer(max),
247
+ persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
248
+ workers: workers,
249
+ environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
235
250
  }
236
251
  end
237
252
 
238
253
  def load
254
+ @loaded = true
239
255
  config_files.each { |config_file| @file_dsl._load_from(config_file) }
240
-
241
- @options
256
+ @_options
242
257
  end
243
258
 
244
259
  def config_files
245
- files = @options.all_of(:config_files)
260
+ raise NotLoadedError, "ensure load is called before accessing config_files" unless @loaded
261
+
262
+ files = @_options.all_of(:config_files)
246
263
 
247
264
  return [] if files == ['-']
248
265
  return files if files.any?
249
266
 
250
- first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
267
+ first_default_file = %W(config/puma/#{@_options[:environment]}.rb config/puma.rb).find do |f|
251
268
  File.exist?(f)
252
269
  end
253
270
 
@@ -255,9 +272,16 @@ module Puma
255
272
  end
256
273
 
257
274
  # Call once all configuration (included from rackup files)
258
- # is loaded to flesh out any defaults
275
+ # is loaded to finalize defaults and lock in the configuration.
276
+ #
277
+ # This also calls load if it hasn't been called yet.
259
278
  def clamp
260
- @options.finalize_values
279
+ load unless @loaded
280
+ set_conditional_default_options
281
+ @_options.finalize_values
282
+ @clamped = true
283
+ warn_hooks
284
+ options
261
285
  end
262
286
 
263
287
  # Injects the Configuration object into the env
@@ -276,11 +300,11 @@ module Puma
276
300
  # Indicate if there is a properly configured app
277
301
  #
278
302
  def app_configured?
279
- @options[:app] || File.exist?(rackup)
303
+ options[:app] || File.exist?(rackup)
280
304
  end
281
305
 
282
306
  def rackup
283
- @options[:rackup]
307
+ options[:rackup]
284
308
  end
285
309
 
286
310
  # Load the specified rackup file, pull options from
@@ -289,9 +313,9 @@ module Puma
289
313
  def app
290
314
  found = options[:app] || load_rackup
291
315
 
292
- if @options[:log_requests]
316
+ if options[:log_requests]
293
317
  require_relative 'commonlogger'
294
- logger = @options[:logger]
318
+ logger = options[:custom_logger] ? options[:custom_logger] : options[:logger]
295
319
  found = CommonLogger.new(found, logger)
296
320
  end
297
321
 
@@ -300,7 +324,7 @@ module Puma
300
324
 
301
325
  # Return which environment we're running in
302
326
  def environment
303
- @options[:environment]
327
+ options[:environment]
304
328
  end
305
329
 
306
330
  def load_plugin(name)
@@ -308,16 +332,19 @@ module Puma
308
332
  end
309
333
 
310
334
  # @param key [:Symbol] hook to run
311
- # @param arg [Launcher, Int] `:on_restart` passes Launcher
335
+ # @param arg [Launcher, Int] `:before_restart` passes Launcher
312
336
  #
313
337
  def run_hooks(key, arg, log_writer, hook_data = nil)
314
- @options.all_of(key).each do |b|
338
+ log_writer.debug "Running #{key} hooks"
339
+
340
+ options.all_of(key).each do |hook_options|
315
341
  begin
316
- if Array === b
317
- hook_data[b[1]] ||= Hash.new
318
- b[0].call arg, hook_data[b[1]]
342
+ block = hook_options[:block]
343
+ if id = hook_options[:id]
344
+ hook_data[id] ||= Hash.new
345
+ block.call arg, hook_data[id]
319
346
  else
320
- b.call arg
347
+ block.call arg
321
348
  end
322
349
  rescue => e
323
350
  log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
@@ -327,7 +354,7 @@ module Puma
327
354
  end
328
355
 
329
356
  def final_options
330
- @options.final_options
357
+ options.final_options
331
358
  end
332
359
 
333
360
  def self.temp_path
@@ -337,14 +364,41 @@ module Puma
337
364
  "#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
338
365
  end
339
366
 
367
+ def self.random_token
368
+ require 'securerandom' unless defined?(SecureRandom)
369
+
370
+ SecureRandom.hex(16)
371
+ end
372
+
340
373
  private
341
374
 
375
+ def require_processor_counter
376
+ require 'concurrent/utility/processor_counter'
377
+ rescue LoadError
378
+ warn <<~MESSAGE
379
+ WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
380
+ Please add "concurrent-ruby" to your Gemfile.
381
+ MESSAGE
382
+ raise
383
+ end
384
+
385
+ def parse_workers(value)
386
+ if value == :auto || value == 'auto'
387
+ require_processor_counter
388
+ Integer(::Concurrent.available_processor_count)
389
+ else
390
+ Integer(value)
391
+ end
392
+ rescue ArgumentError, TypeError
393
+ raise ArgumentError, "workers must be an Integer or :auto"
394
+ end
395
+
342
396
  # Load and use the normal Rack builder if we can, otherwise
343
397
  # fallback to our minimal version.
344
398
  def rack_builder
345
399
  # Load bundler now if we can so that we can pickup rack from
346
400
  # a Gemfile
347
- if ENV.key? 'PUMA_BUNDLER_PRUNED'
401
+ if @puma_bundler_pruned
348
402
  begin
349
403
  require 'bundler/setup'
350
404
  rescue LoadError
@@ -354,11 +408,10 @@ module Puma
354
408
  begin
355
409
  require 'rack'
356
410
  require 'rack/builder'
411
+ ::Rack::Builder
357
412
  rescue LoadError
358
- # ok, use builtin version
359
- return Puma::Rack::Builder
360
- else
361
- return ::Rack::Builder
413
+ require_relative 'rack/builder'
414
+ Puma::Rack::Builder
362
415
  end
363
416
  end
364
417
 
@@ -368,22 +421,40 @@ module Puma
368
421
  rack_app, rack_options = rack_builder.parse_file(rackup)
369
422
  rack_options = rack_options || {}
370
423
 
371
- @options.file_options.merge!(rack_options)
424
+ options.file_options.merge!(rack_options)
372
425
 
373
426
  config_ru_binds = []
374
427
  rack_options.each do |k, v|
375
428
  config_ru_binds << v if k.to_s.start_with?("bind")
376
429
  end
377
430
 
378
- @options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
431
+ options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
379
432
 
380
433
  rack_app
381
434
  end
382
435
 
383
- def self.random_token
384
- require 'securerandom' unless defined?(SecureRandom)
436
+ def set_conditional_default_options
437
+ @_options.default_options[:preload_app] = !@_options[:prune_bundler] &&
438
+ (@_options[:workers] > 1) && Puma.forkable?
439
+ end
385
440
 
386
- SecureRandom.hex(16)
441
+ def warn_hooks
442
+ return if options[:workers] > 0
443
+ return if options[:silence_fork_callback_warning]
444
+
445
+ log_writer = LogWriter.stdio
446
+ @hooks.each_key do |hook|
447
+ options.all_of(hook).each do |hook_options|
448
+ next unless hook_options[:cluster_only]
449
+
450
+ log_writer.log(<<~MSG.tr("\n", " "))
451
+ Warning: The code in the `#{hook}` block will not execute
452
+ in the current Puma configuration. The `#{hook}` block only
453
+ executes in Puma's cluster mode. To fix this, either remove the
454
+ `#{hook}` call or increase Puma's worker count above zero.
455
+ MSG
456
+ end
457
+ end
387
458
  end
388
459
  end
389
460
  end
data/lib/puma/const.rb CHANGED
@@ -100,13 +100,11 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "6.4.1"
104
- CODE_NAME = "The Eagle of Durango"
103
+ PUMA_VERSION = VERSION = "7.2.1"
104
+ CODE_NAME = "On The Corner"
105
105
 
106
106
  PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
107
107
 
108
- FAST_TRACK_KA_TIMEOUT = 0.2
109
-
110
108
  # How long to wait when getting some write blocking on the socket when
111
109
  # sending data back
112
110
  WRITE_TIMEOUT = 10
@@ -125,9 +123,9 @@ module Puma
125
123
  # Indicate that we couldn't parse the request
126
124
  400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
127
125
  # The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
128
- 404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n",
126
+ 404 => "HTTP/1.1 404 Not Found\r\nconnection: close\r\n\r\n",
129
127
  # The standard empty 408 response for requests that timed out.
130
- 408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n",
128
+ 408 => "HTTP/1.1 408 Request Timeout\r\nconnection: close\r\n\r\n",
131
129
  # Indicate that there was an internal error, obviously.
132
130
  500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
133
131
  # Incorrect or invalid header value
@@ -137,7 +135,7 @@ module Puma
137
135
  }.freeze
138
136
 
139
137
  # The basic max request size we'll try to read.
140
- CHUNK_SIZE = 16 * 1024
138
+ CHUNK_SIZE = 64 * 1024
141
139
 
142
140
  # This is the maximum header that is allowed before a client is booted. The parser detects
143
141
  # this, but we'd also like to do this as well.
@@ -230,6 +228,7 @@ module Puma
230
228
  RACK_INPUT = "rack.input"
231
229
  RACK_URL_SCHEME = "rack.url_scheme"
232
230
  RACK_AFTER_REPLY = "rack.after_reply"
231
+ RACK_RESPONSE_FINISHED = "rack.response_finished"
233
232
  PUMA_SOCKET = "puma.socket"
234
233
  PUMA_CONFIG = "puma.config"
235
234
  PUMA_PEERCERT = "puma.peercert"
@@ -252,14 +251,14 @@ module Puma
252
251
  KEEP_ALIVE = "keep-alive"
253
252
 
254
253
  CONTENT_LENGTH2 = "content-length"
255
- CONTENT_LENGTH_S = "Content-Length: "
254
+ CONTENT_LENGTH_S = "content-length: "
256
255
  TRANSFER_ENCODING = "transfer-encoding"
257
256
  TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
258
257
 
259
- CONNECTION_CLOSE = "Connection: close\r\n"
260
- CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
258
+ CONNECTION_CLOSE = "connection: close\r\n"
259
+ CONNECTION_KEEP_ALIVE = "connection: keep-alive\r\n"
261
260
 
262
- TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
261
+ TRANSFER_ENCODING_CHUNKED = "transfer-encoding: chunked\r\n"
263
262
  CLOSE_CHUNKED = "0\r\n\r\n"
264
263
 
265
264
  CHUNKED = "chunked"
@@ -281,9 +280,29 @@ module Puma
281
280
  # header values can contain HTAB?
282
281
  ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
283
282
 
283
+ # The keys of headers that should not be convert to underscore
284
+ # normalized versions. These headers are ignored at the request reading layer,
285
+ # but if we normalize them after reading, it's just confusing for the application.
286
+ UNMASKABLE_HEADERS = {
287
+ "HTTP_TRANSFER,ENCODING" => true,
288
+ "HTTP_CONTENT,LENGTH" => true,
289
+ }
290
+
284
291
  # Banned keys of response header
285
292
  BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
286
293
 
287
- PROXY_PROTOCOL_V1_REGEX = /^PROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
294
+ PROXY_PROTOCOL_V1_REGEX = /\APROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
295
+ PROXY_PROTOCOL_V1_MAX_LENGTH = 107
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
 
@@ -124,11 +124,15 @@ module Puma
124
124
  end
125
125
 
126
126
  if @config_file
127
+ # needed because neither `Puma::CLI` or `Puma::Server` are loaded
128
+ require_relative '../puma'
129
+
127
130
  require_relative 'configuration'
128
131
  require_relative 'log_writer'
129
132
 
130
- config = Puma::Configuration.new({ config_files: [@config_file] }, {})
131
- config.load
133
+ config = Puma::Configuration.new({ config_files: [@config_file] }, {} , env)
134
+ config.clamp
135
+
132
136
  @state ||= config.options[:state]
133
137
  @control_url ||= config.options[:control_url]
134
138
  @control_auth_token ||= config.options[:control_auth_token]
@@ -248,7 +252,7 @@ module Puma
248
252
  @stdout.flush unless @stdout.sync
249
253
  return
250
254
  elsif sig.start_with? 'SIG'
251
- if Signal.list.key? sig.sub(/\ASIG/, '')
255
+ if Signal.list.key? sig.delete_prefix('SIG')
252
256
  Process.kill sig, @pid
253
257
  else
254
258
  raise "Signal '#{sig}' not available'"
data/lib/puma/detect.rb CHANGED
@@ -18,6 +18,8 @@ module Puma
18
18
 
19
19
  IS_LINUX = !(IS_OSX || IS_WINDOWS)
20
20
 
21
+ IS_ARM = RUBY_PLATFORM.include? 'aarch64'
22
+
21
23
  # @version 5.2.0
22
24
  IS_MRI = RUBY_ENGINE == 'ruby'
23
25