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.
- checksums.yaml +4 -4
- data/History.md +407 -8
- data/README.md +109 -49
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +11 -1
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +6 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +21 -21
- data/docs/stats.md +11 -5
- data/docs/systemd.md +14 -5
- data/ext/puma_http11/extconf.rb +20 -32
- data/ext/puma_http11/mini_ssl.c +29 -9
- data/ext/puma_http11/org/jruby/puma/Http11.java +40 -9
- data/ext/puma_http11/puma_http11.c +125 -118
- data/lib/puma/app/status.rb +11 -3
- data/lib/puma/binder.rb +21 -11
- data/lib/puma/cli.rb +10 -8
- data/lib/puma/client.rb +183 -83
- data/lib/puma/cluster/worker.rb +24 -21
- data/lib/puma/cluster/worker_handle.rb +38 -8
- data/lib/puma/cluster.rb +73 -47
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +131 -60
- data/lib/puma/const.rb +31 -12
- data/lib/puma/control_cli.rb +10 -6
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +411 -121
- data/lib/puma/error_logger.rb +7 -5
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +73 -55
- data/lib/puma/log_writer.rb +9 -9
- data/lib/puma/minissl/context_builder.rb +1 -0
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/null_io.rb +26 -0
- 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 +71 -39
- data/lib/puma/runner.rb +15 -17
- data/lib/puma/sd_notify.rb +1 -4
- data/lib/puma/server.rb +134 -73
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +57 -80
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +10 -7
- data/tools/Dockerfile +15 -5
- metadata +14 -15
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/configuration.rb
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
#
|
|
144
|
-
#
|
|
145
|
-
#
|
|
146
|
-
|
|
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:
|
|
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
|
-
@
|
|
182
|
+
@_options = UserFileDefaultOptions.new(user_options, default_options)
|
|
180
183
|
@plugins = PluginLoader.new
|
|
181
|
-
@
|
|
182
|
-
@
|
|
183
|
-
@
|
|
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
|
-
|
|
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 :
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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 =
|
|
227
|
-
max =
|
|
228
|
-
|
|
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
|
-
|
|
234
|
-
|
|
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
|
-
|
|
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/#{@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
|
|
303
|
+
options[:app] || File.exist?(rackup)
|
|
280
304
|
end
|
|
281
305
|
|
|
282
306
|
def rackup
|
|
283
|
-
|
|
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
|
|
316
|
+
if options[:log_requests]
|
|
293
317
|
require_relative 'commonlogger'
|
|
294
|
-
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
|
-
|
|
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] `:
|
|
335
|
+
# @param arg [Launcher, Int] `:before_restart` passes Launcher
|
|
312
336
|
#
|
|
313
337
|
def run_hooks(key, arg, log_writer, hook_data = nil)
|
|
314
|
-
|
|
338
|
+
log_writer.debug "Running #{key} hooks"
|
|
339
|
+
|
|
340
|
+
options.all_of(key).each do |hook_options|
|
|
315
341
|
begin
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
384
|
-
|
|
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
|
-
|
|
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 = "
|
|
104
|
-
CODE_NAME = "The
|
|
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\
|
|
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
|
|
@@ -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 =
|
|
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 = "
|
|
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"
|
|
@@ -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 =
|
|
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
|
data/lib/puma/control_cli.rb
CHANGED
|
@@ -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 =
|
|
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", "
|
|
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.
|
|
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.
|
|
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'"
|