puma 6.6.0 → 8.0.2
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.
- checksums.yaml +4 -4
- data/History.md +309 -5
- data/README.md +41 -42
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +5 -5
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -0
- data/docs/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +2 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +21 -21
- data/docs/stats.md +4 -3
- data/docs/systemd.md +4 -4
- data/ext/puma_http11/extconf.rb +2 -17
- data/ext/puma_http11/http11_parser.java.rl +51 -65
- data/ext/puma_http11/mini_ssl.c +18 -8
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +174 -102
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +71 -85
- data/ext/puma_http11/puma_http11.c +122 -118
- data/lib/puma/app/status.rb +10 -2
- data/lib/puma/binder.rb +12 -10
- data/lib/puma/cli.rb +4 -6
- data/lib/puma/client.rb +205 -131
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +17 -17
- data/lib/puma/cluster/worker_handle.rb +38 -7
- data/lib/puma/cluster.rb +44 -30
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +173 -58
- data/lib/puma/const.rb +11 -11
- data/lib/puma/control_cli.rb +7 -3
- data/lib/puma/detect.rb +13 -0
- data/lib/puma/dsl.rb +225 -108
- data/lib/puma/error_logger.rb +3 -1
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/launcher/bundle_pruner.rb +3 -5
- data/lib/puma/launcher.rb +57 -53
- data/lib/puma/log_writer.rb +8 -2
- data/lib/puma/minissl.rb +0 -1
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -13
- data/lib/puma/{request.rb → response.rb} +56 -212
- data/lib/puma/runner.rb +9 -18
- data/lib/puma/server.rb +182 -97
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +170 -99
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +3 -3
- data/tools/Dockerfile +15 -5
- metadata +19 -7
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/configuration.rb
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
3
6
|
require_relative 'plugin'
|
|
4
7
|
require_relative 'const'
|
|
5
8
|
require_relative 'dsl'
|
|
9
|
+
require_relative 'events'
|
|
6
10
|
|
|
7
11
|
module Puma
|
|
8
12
|
# A class used for storing "leveled" configuration options.
|
|
@@ -112,7 +116,7 @@ module Puma
|
|
|
112
116
|
# config = Configuration.new({}) do |user_config, file_config, default_config|
|
|
113
117
|
# user_config.port 3003
|
|
114
118
|
# end
|
|
115
|
-
# config.
|
|
119
|
+
# config.clamp
|
|
116
120
|
# puts config.options[:port]
|
|
117
121
|
# # => 3003
|
|
118
122
|
#
|
|
@@ -125,43 +129,48 @@ module Puma
|
|
|
125
129
|
# is done because an environment variable may have been modified while loading
|
|
126
130
|
# configuration files.
|
|
127
131
|
class Configuration
|
|
132
|
+
class NotLoadedError < StandardError; end
|
|
133
|
+
class NotClampedError < StandardError; end
|
|
134
|
+
|
|
128
135
|
DEFAULTS = {
|
|
129
136
|
auto_trim_time: 30,
|
|
130
|
-
binds: ['tcp://
|
|
131
|
-
clean_thread_locals: false,
|
|
137
|
+
binds: ['tcp://[::]:9292'.freeze],
|
|
132
138
|
debug: false,
|
|
133
|
-
enable_keep_alives: true,
|
|
134
139
|
early_hints: nil,
|
|
140
|
+
enable_keep_alives: true,
|
|
135
141
|
environment: 'development'.freeze,
|
|
142
|
+
fiber_per_request: !!ENV.fetch("PUMA_FIBER_PER_REQUEST", false),
|
|
136
143
|
# Number of seconds to wait until we get the first data for the request.
|
|
137
144
|
first_data_timeout: 30,
|
|
145
|
+
force_shutdown_after: -1,
|
|
146
|
+
http_content_length_limit: nil,
|
|
138
147
|
# Number of seconds to wait until the next request before shutting down.
|
|
139
148
|
idle_timeout: nil,
|
|
140
149
|
io_selector_backend: :auto,
|
|
141
150
|
log_requests: false,
|
|
142
151
|
logger: STDOUT,
|
|
143
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
max_fast_inline: 10,
|
|
152
|
+
# Limits how many requests a keep alive connection can make.
|
|
153
|
+
# The connection will be closed after it reaches `max_keep_alive`
|
|
154
|
+
# requests.
|
|
155
|
+
max_io_threads: 0,
|
|
156
|
+
max_keep_alive: 999,
|
|
149
157
|
max_threads: Puma.mri? ? 5 : 16,
|
|
150
158
|
min_threads: 0,
|
|
151
159
|
mode: :http,
|
|
152
160
|
mutate_stdout_and_stderr_to_sync_on_write: true,
|
|
153
161
|
out_of_band: [],
|
|
154
162
|
# Number of seconds for another request within a persistent session.
|
|
155
|
-
persistent_timeout:
|
|
163
|
+
persistent_timeout: 65, # PUMA_PERSISTENT_TIMEOUT
|
|
164
|
+
prune_bundler: false,
|
|
156
165
|
queue_requests: true,
|
|
157
166
|
rackup: 'config.ru'.freeze,
|
|
158
167
|
raise_exception_on_sigterm: true,
|
|
159
168
|
reaping_time: 1,
|
|
160
169
|
remote_address: :socket,
|
|
161
|
-
silence_single_worker_warning: false,
|
|
162
170
|
silence_fork_callback_warning: false,
|
|
171
|
+
silence_single_worker_warning: false,
|
|
163
172
|
tag: File.basename(Dir.getwd),
|
|
164
|
-
tcp_host: '
|
|
173
|
+
tcp_host: '::'.freeze,
|
|
165
174
|
tcp_port: 9292,
|
|
166
175
|
wait_for_less_busy_worker: 0.005,
|
|
167
176
|
worker_boot_timeout: 60,
|
|
@@ -170,30 +179,36 @@ module Puma
|
|
|
170
179
|
worker_shutdown_timeout: 30,
|
|
171
180
|
worker_timeout: 60,
|
|
172
181
|
workers: 0,
|
|
173
|
-
http_content_length_limit: nil
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
def initialize(user_options={}, default_options = {}, env = ENV, &block)
|
|
177
|
-
default_options = self.puma_default_options(env).merge(default_options)
|
|
185
|
+
default_options = self.puma_default_options(env).merge(events: Events.new).merge(default_options)
|
|
178
186
|
|
|
179
|
-
@
|
|
187
|
+
@_options = UserFileDefaultOptions.new(user_options, default_options)
|
|
180
188
|
@plugins = PluginLoader.new
|
|
181
|
-
@
|
|
182
|
-
@
|
|
183
|
-
@
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
|
187
|
-
end
|
|
189
|
+
@events = @_options[:events] || Events.new
|
|
190
|
+
@hooks = {}
|
|
191
|
+
@user_dsl = DSL.new(@_options.user_options, self)
|
|
192
|
+
@file_dsl = DSL.new(@_options.file_options, self)
|
|
193
|
+
@default_dsl = DSL.new(@_options.default_options, self)
|
|
188
194
|
|
|
189
195
|
@puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
|
|
190
196
|
|
|
191
197
|
if block
|
|
192
198
|
configure(&block)
|
|
193
199
|
end
|
|
200
|
+
|
|
201
|
+
@loaded = false
|
|
202
|
+
@clamped = false
|
|
194
203
|
end
|
|
195
204
|
|
|
196
|
-
attr_reader :
|
|
205
|
+
attr_reader :plugins, :events, :hooks, :_options
|
|
206
|
+
|
|
207
|
+
def options
|
|
208
|
+
raise NotClampedError, "ensure clamp is called before accessing options" unless @clamped
|
|
209
|
+
|
|
210
|
+
@_options
|
|
211
|
+
end
|
|
197
212
|
|
|
198
213
|
def configure
|
|
199
214
|
yield @user_dsl, @file_dsl, @default_dsl
|
|
@@ -206,7 +221,7 @@ module Puma
|
|
|
206
221
|
def initialize_copy(other)
|
|
207
222
|
@conf = nil
|
|
208
223
|
@cli_options = nil
|
|
209
|
-
@
|
|
224
|
+
@_options = @_options.dup
|
|
210
225
|
end
|
|
211
226
|
|
|
212
227
|
def flatten
|
|
@@ -214,12 +229,14 @@ module Puma
|
|
|
214
229
|
end
|
|
215
230
|
|
|
216
231
|
def flatten!
|
|
217
|
-
@
|
|
232
|
+
@_options = @_options.flatten
|
|
218
233
|
self
|
|
219
234
|
end
|
|
220
235
|
|
|
221
236
|
def puma_default_options(env = ENV)
|
|
222
237
|
defaults = DEFAULTS.dup
|
|
238
|
+
defaults[:tcp_host] = self.class.default_tcp_host
|
|
239
|
+
defaults[:binds] = [self.class.default_tcp_bind]
|
|
223
240
|
puma_options_from_env(env).each { |k,v| defaults[k] = v if v }
|
|
224
241
|
defaults
|
|
225
242
|
end
|
|
@@ -227,34 +244,34 @@ module Puma
|
|
|
227
244
|
def puma_options_from_env(env = ENV)
|
|
228
245
|
min = env['PUMA_MIN_THREADS'] || env['MIN_THREADS']
|
|
229
246
|
max = env['PUMA_MAX_THREADS'] || env['MAX_THREADS']
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
else
|
|
234
|
-
env['WEB_CONCURRENCY']
|
|
235
|
-
end
|
|
247
|
+
persistent_timeout = env['PUMA_PERSISTENT_TIMEOUT']
|
|
248
|
+
workers_env = env['WEB_CONCURRENCY']
|
|
249
|
+
workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
|
|
236
250
|
|
|
237
251
|
{
|
|
238
252
|
min_threads: min && min != "" && Integer(min),
|
|
239
253
|
max_threads: max && max != "" && Integer(max),
|
|
240
|
-
|
|
254
|
+
persistent_timeout: persistent_timeout && persistent_timeout != "" && Integer(persistent_timeout),
|
|
255
|
+
workers: workers,
|
|
241
256
|
environment: env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV'],
|
|
242
257
|
}
|
|
243
258
|
end
|
|
244
259
|
|
|
245
260
|
def load
|
|
261
|
+
@loaded = true
|
|
246
262
|
config_files.each { |config_file| @file_dsl._load_from(config_file) }
|
|
247
|
-
|
|
248
|
-
@options
|
|
263
|
+
@_options
|
|
249
264
|
end
|
|
250
265
|
|
|
251
266
|
def config_files
|
|
252
|
-
|
|
267
|
+
raise NotLoadedError, "ensure load is called before accessing config_files" unless @loaded
|
|
268
|
+
|
|
269
|
+
files = @_options.all_of(:config_files)
|
|
253
270
|
|
|
254
271
|
return [] if files == ['-']
|
|
255
272
|
return files if files.any?
|
|
256
273
|
|
|
257
|
-
first_default_file = %W(config/puma/#{@
|
|
274
|
+
first_default_file = %W(config/puma/#{@_options[:environment]}.rb config/puma.rb).find do |f|
|
|
258
275
|
File.exist?(f)
|
|
259
276
|
end
|
|
260
277
|
|
|
@@ -262,9 +279,18 @@ module Puma
|
|
|
262
279
|
end
|
|
263
280
|
|
|
264
281
|
# Call once all configuration (included from rackup files)
|
|
265
|
-
# is loaded to
|
|
282
|
+
# is loaded to finalize defaults and lock in the configuration.
|
|
283
|
+
#
|
|
284
|
+
# This also calls load if it hasn't been called yet.
|
|
266
285
|
def clamp
|
|
267
|
-
@
|
|
286
|
+
load unless @loaded
|
|
287
|
+
run_mode_hooks
|
|
288
|
+
set_conditional_default_options
|
|
289
|
+
@_options.finalize_values
|
|
290
|
+
rewrite_unavailable_ipv6_binds!
|
|
291
|
+
@clamped = true
|
|
292
|
+
warn_hooks
|
|
293
|
+
options
|
|
268
294
|
end
|
|
269
295
|
|
|
270
296
|
# Injects the Configuration object into the env
|
|
@@ -283,11 +309,11 @@ module Puma
|
|
|
283
309
|
# Indicate if there is a properly configured app
|
|
284
310
|
#
|
|
285
311
|
def app_configured?
|
|
286
|
-
|
|
312
|
+
options[:app] || File.exist?(rackup)
|
|
287
313
|
end
|
|
288
314
|
|
|
289
315
|
def rackup
|
|
290
|
-
|
|
316
|
+
options[:rackup]
|
|
291
317
|
end
|
|
292
318
|
|
|
293
319
|
# Load the specified rackup file, pull options from
|
|
@@ -296,9 +322,9 @@ module Puma
|
|
|
296
322
|
def app
|
|
297
323
|
found = options[:app] || load_rackup
|
|
298
324
|
|
|
299
|
-
if
|
|
325
|
+
if options[:log_requests]
|
|
300
326
|
require_relative 'commonlogger'
|
|
301
|
-
logger =
|
|
327
|
+
logger = options[:custom_logger] ? options[:custom_logger] : options[:logger]
|
|
302
328
|
found = CommonLogger.new(found, logger)
|
|
303
329
|
end
|
|
304
330
|
|
|
@@ -307,7 +333,7 @@ module Puma
|
|
|
307
333
|
|
|
308
334
|
# Return which environment we're running in
|
|
309
335
|
def environment
|
|
310
|
-
|
|
336
|
+
options[:environment]
|
|
311
337
|
end
|
|
312
338
|
|
|
313
339
|
def load_plugin(name)
|
|
@@ -315,18 +341,19 @@ module Puma
|
|
|
315
341
|
end
|
|
316
342
|
|
|
317
343
|
# @param key [:Symbol] hook to run
|
|
318
|
-
# @param arg [Launcher, Int] `:
|
|
344
|
+
# @param arg [Launcher, Int] `:before_restart` passes Launcher
|
|
319
345
|
#
|
|
320
346
|
def run_hooks(key, arg, log_writer, hook_data = nil)
|
|
321
|
-
log_writer.debug "Running #{key} hooks"
|
|
347
|
+
log_writer.debug { "Running #{key} hooks" }
|
|
322
348
|
|
|
323
|
-
|
|
349
|
+
options.all_of(key).each do |hook_options|
|
|
324
350
|
begin
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
351
|
+
block = hook_options[:block]
|
|
352
|
+
if id = hook_options[:id]
|
|
353
|
+
hook_data[id] ||= Hash.new
|
|
354
|
+
block.call arg, hook_data[id]
|
|
328
355
|
else
|
|
329
|
-
|
|
356
|
+
block.call arg
|
|
330
357
|
end
|
|
331
358
|
rescue => e
|
|
332
359
|
log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
|
@@ -336,7 +363,24 @@ module Puma
|
|
|
336
363
|
end
|
|
337
364
|
|
|
338
365
|
def final_options
|
|
339
|
-
|
|
366
|
+
options.final_options
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def self.default_tcp_host
|
|
370
|
+
ipv6_interface_available? ? Const::UNSPECIFIED_IPV6 : Const::UNSPECIFIED_IPV4
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def self.default_tcp_bind(port = DEFAULTS[:tcp_port])
|
|
374
|
+
URI::Generic.build(scheme: 'tcp', host: default_tcp_host, port: Integer(port)).to_s
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def self.ipv6_interface_available?
|
|
378
|
+
Socket.getifaddrs.any? do |ifaddr|
|
|
379
|
+
addr = ifaddr.addr
|
|
380
|
+
addr&.ipv6? && !addr&.ipv6_loopback?
|
|
381
|
+
end
|
|
382
|
+
rescue StandardError
|
|
383
|
+
false
|
|
340
384
|
end
|
|
341
385
|
|
|
342
386
|
def self.temp_path
|
|
@@ -346,18 +390,60 @@ module Puma
|
|
|
346
390
|
"#{Dir.tmpdir}/puma-status-#{t}-#{$$}"
|
|
347
391
|
end
|
|
348
392
|
|
|
393
|
+
def self.random_token
|
|
394
|
+
require 'securerandom' unless defined?(SecureRandom)
|
|
395
|
+
|
|
396
|
+
SecureRandom.hex(16)
|
|
397
|
+
end
|
|
398
|
+
|
|
349
399
|
private
|
|
350
400
|
|
|
401
|
+
def rewrite_unavailable_ipv6_binds!
|
|
402
|
+
return if self.class.ipv6_interface_available?
|
|
403
|
+
|
|
404
|
+
tried_ipv6_bind = false
|
|
405
|
+
bind_schemes = ['tcp', 'ssl']
|
|
406
|
+
|
|
407
|
+
@_options[:binds] = Array(@_options[:binds]).map do |bind|
|
|
408
|
+
uri = URI.parse(bind)
|
|
409
|
+
next bind unless bind_schemes.include?(uri.scheme)
|
|
410
|
+
|
|
411
|
+
host = uri.host&.delete_prefix('[')&.delete_suffix(']')
|
|
412
|
+
next bind unless host&.include?(':')
|
|
413
|
+
|
|
414
|
+
tried_ipv6_bind = true
|
|
415
|
+
next bind unless host == Const::UNSPECIFIED_IPV6
|
|
416
|
+
|
|
417
|
+
uri.host = Const::UNSPECIFIED_IPV4
|
|
418
|
+
uri.to_s
|
|
419
|
+
rescue URI::InvalidURIError
|
|
420
|
+
bind
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
warn "WARNING: IPv6 bind requested but no non-loopback IPv6 interface was detected" if tried_ipv6_bind
|
|
424
|
+
end
|
|
425
|
+
|
|
351
426
|
def require_processor_counter
|
|
352
427
|
require 'concurrent/utility/processor_counter'
|
|
353
428
|
rescue LoadError
|
|
354
429
|
warn <<~MESSAGE
|
|
355
|
-
WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
|
|
430
|
+
WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
|
|
356
431
|
Please add "concurrent-ruby" to your Gemfile.
|
|
357
432
|
MESSAGE
|
|
358
433
|
raise
|
|
359
434
|
end
|
|
360
435
|
|
|
436
|
+
def parse_workers(value)
|
|
437
|
+
if value == :auto || value == 'auto'
|
|
438
|
+
require_processor_counter
|
|
439
|
+
Integer(::Concurrent.available_processor_count)
|
|
440
|
+
else
|
|
441
|
+
Integer(value)
|
|
442
|
+
end
|
|
443
|
+
rescue ArgumentError, TypeError
|
|
444
|
+
raise ArgumentError, "workers must be an Integer or :auto"
|
|
445
|
+
end
|
|
446
|
+
|
|
361
447
|
# Load and use the normal Rack builder if we can, otherwise
|
|
362
448
|
# fallback to our minimal version.
|
|
363
449
|
def rack_builder
|
|
@@ -386,22 +472,51 @@ module Puma
|
|
|
386
472
|
rack_app, rack_options = rack_builder.parse_file(rackup)
|
|
387
473
|
rack_options = rack_options || {}
|
|
388
474
|
|
|
389
|
-
|
|
475
|
+
options.file_options.merge!(rack_options)
|
|
390
476
|
|
|
391
477
|
config_ru_binds = []
|
|
392
478
|
rack_options.each do |k, v|
|
|
393
479
|
config_ru_binds << v if k.to_s.start_with?("bind")
|
|
394
480
|
end
|
|
395
481
|
|
|
396
|
-
|
|
482
|
+
options.file_options[:binds] = config_ru_binds unless config_ru_binds.empty?
|
|
397
483
|
|
|
398
484
|
rack_app
|
|
399
485
|
end
|
|
400
486
|
|
|
401
|
-
def
|
|
402
|
-
|
|
487
|
+
def run_mode_hooks
|
|
488
|
+
workers_before = @_options[:workers]
|
|
489
|
+
key = workers_before > 0 ? :cluster : :single
|
|
403
490
|
|
|
404
|
-
|
|
491
|
+
@_options.all_of(key).each(&:call)
|
|
492
|
+
|
|
493
|
+
unless @_options[:workers] == workers_before
|
|
494
|
+
raise "cannot change the number of workers inside a #{key} configuration hook"
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def set_conditional_default_options
|
|
499
|
+
@_options.default_options[:preload_app] = !@_options[:prune_bundler] &&
|
|
500
|
+
(@_options[:workers] > 1) && Puma.forkable?
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def warn_hooks
|
|
504
|
+
return if options[:workers] > 0
|
|
505
|
+
return if options[:silence_fork_callback_warning]
|
|
506
|
+
|
|
507
|
+
log_writer = LogWriter.stdio
|
|
508
|
+
@hooks.each_key do |hook|
|
|
509
|
+
options.all_of(hook).each do |hook_options|
|
|
510
|
+
next unless hook_options[:cluster_only]
|
|
511
|
+
|
|
512
|
+
log_writer.log(<<~MSG.tr("\n", " "))
|
|
513
|
+
Warning: The code in the `#{hook}` block will not execute
|
|
514
|
+
in the current Puma configuration. The `#{hook}` block only
|
|
515
|
+
executes in Puma's cluster mode. To fix this, either remove the
|
|
516
|
+
`#{hook}` call or increase Puma's worker count above zero.
|
|
517
|
+
MSG
|
|
518
|
+
end
|
|
519
|
+
end
|
|
405
520
|
end
|
|
406
521
|
end
|
|
407
522
|
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 = "
|
|
104
|
-
CODE_NAME = "
|
|
103
|
+
PUMA_VERSION = VERSION = "8.0.2"
|
|
104
|
+
CODE_NAME = "Into the Arena"
|
|
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\
|
|
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\
|
|
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
|
|
@@ -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 = "
|
|
254
|
+
CONTENT_LENGTH_S = "content-length: "
|
|
256
255
|
TRANSFER_ENCODING = "transfer-encoding"
|
|
257
256
|
TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
|
|
258
257
|
|
|
259
|
-
CONNECTION_CLOSE = "
|
|
260
|
-
CONNECTION_KEEP_ALIVE = "
|
|
258
|
+
CONNECTION_CLOSE = "connection: close\r\n"
|
|
259
|
+
CONNECTION_KEEP_ALIVE = "connection: keep-alive\r\n"
|
|
261
260
|
|
|
262
|
-
TRANSFER_ENCODING_CHUNKED = "
|
|
261
|
+
TRANSFER_ENCODING_CHUNKED = "transfer-encoding: chunked\r\n"
|
|
263
262
|
CLOSE_CHUNKED = "0\r\n\r\n"
|
|
264
263
|
|
|
265
264
|
CHUNKED = "chunked"
|
|
@@ -292,7 +291,8 @@ module Puma
|
|
|
292
291
|
# Banned keys of response header
|
|
293
292
|
BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
|
|
294
293
|
|
|
295
|
-
PROXY_PROTOCOL_V1_REGEX =
|
|
294
|
+
PROXY_PROTOCOL_V1_REGEX = /\APROXY (?:TCP4|TCP6|UNKNOWN) ([^\r]+)\r\n/.freeze
|
|
295
|
+
PROXY_PROTOCOL_V1_MAX_LENGTH = 107
|
|
296
296
|
|
|
297
297
|
# All constants are prefixed with `PIPE_` to avoid name collisions.
|
|
298
298
|
module PipeRequest
|
data/lib/puma/control_cli.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Puma
|
|
|
16
16
|
'gc' => nil,
|
|
17
17
|
'gc-stats' => nil,
|
|
18
18
|
'halt' => 'SIGQUIT',
|
|
19
|
-
'info' =>
|
|
19
|
+
'info' => Puma.backtrace_signal,
|
|
20
20
|
'phased-restart' => 'SIGUSR1',
|
|
21
21
|
'refork' => 'SIGURG',
|
|
22
22
|
'reload-worker-directory' => nil,
|
|
@@ -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
133
|
config = Puma::Configuration.new({ config_files: [@config_file] }, {} , env)
|
|
131
|
-
config.
|
|
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.
|
|
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
|
|
|
@@ -33,6 +35,13 @@ module Puma
|
|
|
33
35
|
IS_WINDOWS
|
|
34
36
|
end
|
|
35
37
|
|
|
38
|
+
BACKTRACE_SIGNAL =
|
|
39
|
+
if Signal.list.key?("INFO")
|
|
40
|
+
"SIGINFO"
|
|
41
|
+
elsif Signal.list.key?("PWR")
|
|
42
|
+
"SIGPWR"
|
|
43
|
+
end
|
|
44
|
+
|
|
36
45
|
# @version 5.0.0
|
|
37
46
|
def self.mri?
|
|
38
47
|
IS_MRI
|
|
@@ -42,4 +51,8 @@ module Puma
|
|
|
42
51
|
def self.forkable?
|
|
43
52
|
HAS_FORK
|
|
44
53
|
end
|
|
54
|
+
|
|
55
|
+
def self.backtrace_signal
|
|
56
|
+
BACKTRACE_SIGNAL
|
|
57
|
+
end
|
|
45
58
|
end
|