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.
- checksums.yaml +4 -4
- data/History.md +392 -13
- data/LICENSE +0 -0
- data/README.md +135 -29
- data/bin/puma-wild +0 -0
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +0 -0
- data/docs/deployment.md +0 -0
- data/docs/fork_worker.md +11 -1
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +0 -0
- data/docs/jungle/rc.d/README.md +0 -0
- data/docs/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +12 -0
- data/docs/nginx.md +1 -1
- data/docs/plugins.md +4 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +2 -2
- data/docs/stats.md +8 -3
- data/docs/systemd.md +13 -7
- data/docs/testing_benchmarks_local_files.md +0 -0
- data/docs/testing_test_rackup_ci_files.md +0 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +21 -14
- data/ext/puma_http11/http11_parser.c +0 -0
- data/ext/puma_http11/http11_parser.h +0 -0
- data/ext/puma_http11/http11_parser.java.rl +0 -0
- data/ext/puma_http11/http11_parser.rl +0 -0
- data/ext/puma_http11/http11_parser_common.rl +0 -0
- data/ext/puma_http11/mini_ssl.c +107 -10
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +30 -7
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +0 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +2 -1
- data/ext/puma_http11/puma_http11.c +4 -1
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/binder.rb +26 -15
- data/lib/puma/cli.rb +13 -5
- data/lib/puma/client.rb +113 -26
- data/lib/puma/cluster/worker.rb +14 -6
- data/lib/puma/cluster/worker_handle.rb +4 -5
- data/lib/puma/cluster.rb +93 -22
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +42 -22
- data/lib/puma/const.rb +149 -89
- data/lib/puma/control_cli.rb +16 -9
- data/lib/puma/detect.rb +5 -4
- data/lib/puma/dsl.rb +432 -40
- data/lib/puma/error_logger.rb +6 -5
- data/lib/puma/events.rb +0 -0
- data/lib/puma/io_buffer.rb +10 -0
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +0 -0
- data/lib/puma/launcher.rb +29 -29
- data/lib/puma/log_writer.rb +23 -13
- data/lib/puma/minissl/context_builder.rb +4 -0
- data/lib/puma/minissl.rb +23 -0
- data/lib/puma/null_io.rb +42 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +0 -0
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +2 -2
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +18 -3
- data/lib/puma/reactor.rb +17 -8
- data/lib/puma/request.rb +207 -126
- data/lib/puma/runner.rb +26 -4
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +121 -49
- data/lib/puma/single.rb +3 -1
- data/lib/puma/state_file.rb +2 -2
- data/lib/puma/thread_pool.rb +56 -9
- data/lib/puma/util.rb +1 -1
- data/lib/puma.rb +1 -3
- data/lib/rack/handler/puma.rb +116 -86
- data/tools/Dockerfile +2 -2
- data/tools/trickletest.rb +0 -0
- metadata +12 -13
- data/lib/puma/systemd.rb +0 -47
data/lib/puma/commonlogger.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Puma
|
4
4
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
5
5
|
# logs a line in the
|
6
|
-
# {Apache common log format}[https://httpd.apache.org/docs/
|
6
|
+
# {Apache common log format}[https://httpd.apache.org/docs/2.4/logs.html#common]
|
7
7
|
# to the +logger+.
|
8
8
|
#
|
9
9
|
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
@@ -16,7 +16,7 @@ module Puma
|
|
16
16
|
# (which is called without arguments in order to make the error appear for
|
17
17
|
# sure)
|
18
18
|
class CommonLogger
|
19
|
-
# Common Log Format: https://httpd.apache.org/docs/
|
19
|
+
# Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
|
20
20
|
#
|
21
21
|
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
22
22
|
#
|
@@ -25,10 +25,17 @@ module Puma
|
|
25
25
|
|
26
26
|
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
|
29
|
+
|
30
|
+
CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
|
31
|
+
# Util::HeaderHash allows mixed
|
32
|
+
HTTP_VERSION = Const::HTTP_VERSION
|
33
|
+
HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
|
34
|
+
PATH_INFO = Const::PATH_INFO
|
35
|
+
QUERY_STRING = Const::QUERY_STRING
|
36
|
+
REMOTE_ADDR = Const::REMOTE_ADDR
|
37
|
+
REMOTE_USER = 'REMOTE_USER'
|
38
|
+
REQUEST_METHOD = Const::REQUEST_METHOD
|
32
39
|
|
33
40
|
def initialize(app, logger=nil)
|
34
41
|
@app = app
|
@@ -57,13 +64,13 @@ module Puma
|
|
57
64
|
now = Time.now
|
58
65
|
|
59
66
|
msg = HIJACK_FORMAT % [
|
60
|
-
env[
|
61
|
-
env[
|
62
|
-
now.strftime(
|
67
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
68
|
+
env[REMOTE_USER] || "-",
|
69
|
+
now.strftime(LOG_TIME_FORMAT),
|
63
70
|
env[REQUEST_METHOD],
|
64
71
|
env[PATH_INFO],
|
65
72
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
66
|
-
env[
|
73
|
+
env[HTTP_VERSION],
|
67
74
|
now - began_at ]
|
68
75
|
|
69
76
|
write(msg)
|
@@ -74,13 +81,13 @@ module Puma
|
|
74
81
|
length = extract_content_length(header)
|
75
82
|
|
76
83
|
msg = FORMAT % [
|
77
|
-
env[
|
78
|
-
env[
|
79
|
-
now.strftime(
|
84
|
+
env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
|
85
|
+
env[REMOTE_USER] || "-",
|
86
|
+
now.strftime(LOG_TIME_FORMAT),
|
80
87
|
env[REQUEST_METHOD],
|
81
88
|
env[PATH_INFO],
|
82
89
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
83
|
-
env[
|
90
|
+
env[HTTP_VERSION],
|
84
91
|
status.to_s[0..3],
|
85
92
|
length,
|
86
93
|
now - began_at ]
|
data/lib/puma/configuration.rb
CHANGED
@@ -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
|
-
|
5
|
+
require_relative 'dsl'
|
7
6
|
|
8
7
|
module Puma
|
9
8
|
# A class used for storing "leveled" configuration options.
|
@@ -131,10 +130,13 @@ 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
|
-
# Number of seconds to wait until we get the first data for the request
|
136
|
+
# Number of seconds to wait until we get the first data for the request.
|
137
137
|
first_data_timeout: 30,
|
138
|
+
# Number of seconds to wait until the next request before shutting down.
|
139
|
+
idle_timeout: nil,
|
138
140
|
io_selector_backend: :auto,
|
139
141
|
log_requests: false,
|
140
142
|
logger: STDOUT,
|
@@ -157,6 +159,7 @@ module Puma
|
|
157
159
|
reaping_time: 1,
|
158
160
|
remote_address: :socket,
|
159
161
|
silence_single_worker_warning: false,
|
162
|
+
silence_fork_callback_warning: false,
|
160
163
|
tag: File.basename(Dir.getwd),
|
161
164
|
tcp_host: '0.0.0.0'.freeze,
|
162
165
|
tcp_port: 9292,
|
@@ -167,10 +170,11 @@ module Puma
|
|
167
170
|
worker_shutdown_timeout: 30,
|
168
171
|
worker_timeout: 60,
|
169
172
|
workers: 0,
|
173
|
+
http_content_length_limit: nil
|
170
174
|
}
|
171
175
|
|
172
|
-
def initialize(user_options={}, default_options = {}, &block)
|
173
|
-
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)
|
174
178
|
|
175
179
|
@options = UserFileDefaultOptions.new(user_options, default_options)
|
176
180
|
@plugins = PluginLoader.new
|
@@ -182,6 +186,8 @@ module Puma
|
|
182
186
|
default_options[:preload_app] = (@options[:workers] > 1) && Puma.forkable?
|
183
187
|
end
|
184
188
|
|
189
|
+
@puma_bundler_pruned = env.key? 'PUMA_BUNDLER_PRUNED'
|
190
|
+
|
185
191
|
if block
|
186
192
|
configure(&block)
|
187
193
|
end
|
@@ -212,22 +218,27 @@ module Puma
|
|
212
218
|
self
|
213
219
|
end
|
214
220
|
|
215
|
-
def puma_default_options
|
221
|
+
def puma_default_options(env = ENV)
|
216
222
|
defaults = DEFAULTS.dup
|
217
|
-
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 }
|
218
224
|
defaults
|
219
225
|
end
|
220
226
|
|
221
|
-
def puma_options_from_env
|
222
|
-
min =
|
223
|
-
max =
|
224
|
-
workers =
|
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
|
225
236
|
|
226
237
|
{
|
227
|
-
min_threads: min && Integer(min),
|
228
|
-
max_threads: max && Integer(max),
|
229
|
-
workers: workers && Integer(workers),
|
230
|
-
environment:
|
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'],
|
231
242
|
}
|
232
243
|
end
|
233
244
|
|
@@ -307,6 +318,8 @@ module Puma
|
|
307
318
|
# @param arg [Launcher, Int] `:on_restart` passes Launcher
|
308
319
|
#
|
309
320
|
def run_hooks(key, arg, log_writer, hook_data = nil)
|
321
|
+
log_writer.debug "Running #{key} hooks"
|
322
|
+
|
310
323
|
@options.all_of(key).each do |b|
|
311
324
|
begin
|
312
325
|
if Array === b
|
@@ -335,12 +348,22 @@ module Puma
|
|
335
348
|
|
336
349
|
private
|
337
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
|
+
|
338
361
|
# Load and use the normal Rack builder if we can, otherwise
|
339
362
|
# fallback to our minimal version.
|
340
363
|
def rack_builder
|
341
364
|
# Load bundler now if we can so that we can pickup rack from
|
342
365
|
# a Gemfile
|
343
|
-
if
|
366
|
+
if @puma_bundler_pruned
|
344
367
|
begin
|
345
368
|
require 'bundler/setup'
|
346
369
|
rescue LoadError
|
@@ -350,11 +373,10 @@ module Puma
|
|
350
373
|
begin
|
351
374
|
require 'rack'
|
352
375
|
require 'rack/builder'
|
376
|
+
::Rack::Builder
|
353
377
|
rescue LoadError
|
354
|
-
|
355
|
-
|
356
|
-
else
|
357
|
-
return ::Rack::Builder
|
378
|
+
require_relative 'rack/builder'
|
379
|
+
Puma::Rack::Builder
|
358
380
|
end
|
359
381
|
end
|
360
382
|
|
@@ -383,5 +405,3 @@ module Puma
|
|
383
405
|
end
|
384
406
|
end
|
385
407
|
end
|
386
|
-
|
387
|
-
require_relative 'dsl'
|
data/lib/puma/const.rb
CHANGED
@@ -5,7 +5,6 @@ module Puma
|
|
5
5
|
class UnsupportedOption < RuntimeError
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
8
|
# Every standard HTTP code mapped to the appropriate message. These are
|
10
9
|
# used so frequently that they are placed directly in Puma for easy
|
11
10
|
# access rather than Puma::Const itself.
|
@@ -19,6 +18,7 @@ module Puma
|
|
19
18
|
100 => 'Continue',
|
20
19
|
101 => 'Switching Protocols',
|
21
20
|
102 => 'Processing',
|
21
|
+
103 => 'Early Hints',
|
22
22
|
200 => 'OK',
|
23
23
|
201 => 'Created',
|
24
24
|
202 => 'Accepted',
|
@@ -50,16 +50,16 @@ module Puma
|
|
50
50
|
410 => 'Gone',
|
51
51
|
411 => 'Length Required',
|
52
52
|
412 => 'Precondition Failed',
|
53
|
-
413 => '
|
53
|
+
413 => 'Content Too Large',
|
54
54
|
414 => 'URI Too Long',
|
55
55
|
415 => 'Unsupported Media Type',
|
56
56
|
416 => 'Range Not Satisfiable',
|
57
57
|
417 => 'Expectation Failed',
|
58
|
-
418 => 'I\'m A Teapot',
|
59
58
|
421 => 'Misdirected Request',
|
60
|
-
422 => 'Unprocessable
|
59
|
+
422 => 'Unprocessable Content',
|
61
60
|
423 => 'Locked',
|
62
61
|
424 => 'Failed Dependency',
|
62
|
+
425 => 'Too Early',
|
63
63
|
426 => 'Upgrade Required',
|
64
64
|
428 => 'Precondition Required',
|
65
65
|
429 => 'Too Many Requests',
|
@@ -74,7 +74,7 @@ module Puma
|
|
74
74
|
506 => 'Variant Also Negotiates',
|
75
75
|
507 => 'Insufficient Storage',
|
76
76
|
508 => 'Loop Detected',
|
77
|
-
510 => 'Not Extended',
|
77
|
+
510 => 'Not Extended (OBSOLETED)',
|
78
78
|
511 => 'Network Authentication Required'
|
79
79
|
}.freeze
|
80
80
|
|
@@ -100,10 +100,10 @@ module Puma
|
|
100
100
|
# too taxing on performance.
|
101
101
|
module Const
|
102
102
|
|
103
|
-
PUMA_VERSION = VERSION = "6.
|
104
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "6.6.0"
|
104
|
+
CODE_NAME = "Return to Forever"
|
105
105
|
|
106
|
-
PUMA_SERVER_STRING = [
|
106
|
+
PUMA_SERVER_STRING = ["puma", PUMA_VERSION, CODE_NAME].join(" ").freeze
|
107
107
|
|
108
108
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
109
109
|
|
@@ -112,32 +112,32 @@ module Puma
|
|
112
112
|
WRITE_TIMEOUT = 10
|
113
113
|
|
114
114
|
# The original URI requested by the client.
|
115
|
-
REQUEST_URI=
|
116
|
-
REQUEST_PATH =
|
117
|
-
QUERY_STRING =
|
118
|
-
CONTENT_LENGTH = "CONTENT_LENGTH"
|
115
|
+
REQUEST_URI= "REQUEST_URI"
|
116
|
+
REQUEST_PATH = "REQUEST_PATH"
|
117
|
+
QUERY_STRING = "QUERY_STRING"
|
118
|
+
CONTENT_LENGTH = "CONTENT_LENGTH"
|
119
119
|
|
120
|
-
PATH_INFO =
|
120
|
+
PATH_INFO = "PATH_INFO"
|
121
121
|
|
122
|
-
PUMA_TMP_BASE = "puma"
|
122
|
+
PUMA_TMP_BASE = "puma"
|
123
123
|
|
124
124
|
ERROR_RESPONSE = {
|
125
125
|
# Indicate that we couldn't parse the request
|
126
|
-
400 => "HTTP/1.1 400 Bad Request\r\n\r\n"
|
126
|
+
400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
|
127
127
|
# 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\
|
128
|
+
404 => "HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n",
|
129
129
|
# The standard empty 408 response for requests that timed out.
|
130
|
-
408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\
|
130
|
+
408 => "HTTP/1.1 408 Request Timeout\r\nConnection: close\r\n\r\n",
|
131
131
|
# Indicate that there was an internal error, obviously.
|
132
|
-
500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
132
|
+
500 => "HTTP/1.1 500 Internal Server Error\r\n\r\n",
|
133
133
|
# Incorrect or invalid header value
|
134
|
-
501 => "HTTP/1.1 501 Not Implemented\r\n\r\n"
|
134
|
+
501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
|
135
135
|
# A common header for indicating the server is too busy. Not used yet.
|
136
|
-
503 => "HTTP/1.1 503 Service Unavailable\r\n\r\
|
136
|
+
503 => "HTTP/1.1 503 Service Unavailable\r\n\r\n"
|
137
137
|
}.freeze
|
138
138
|
|
139
139
|
# The basic max request size we'll try to read.
|
140
|
-
CHUNK_SIZE =
|
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.
|
@@ -146,103 +146,163 @@ module Puma
|
|
146
146
|
# Maximum request body size before it is moved out of memory and into a tempfile for reading.
|
147
147
|
MAX_BODY = MAX_HEADER
|
148
148
|
|
149
|
-
REQUEST_METHOD = "REQUEST_METHOD"
|
150
|
-
HEAD = "HEAD"
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
149
|
+
REQUEST_METHOD = "REQUEST_METHOD"
|
150
|
+
HEAD = "HEAD"
|
151
|
+
|
152
|
+
# based on https://www.rfc-editor.org/rfc/rfc9110.html#name-overview,
|
153
|
+
# with CONNECT removed, and PATCH added
|
154
|
+
SUPPORTED_HTTP_METHODS = %w[HEAD GET POST PUT DELETE OPTIONS TRACE PATCH].freeze
|
155
|
+
|
156
|
+
# list from https://www.iana.org/assignments/http-methods/http-methods.xhtml
|
157
|
+
# as of 04-May-23
|
158
|
+
IANA_HTTP_METHODS = %w[
|
159
|
+
ACL
|
160
|
+
BASELINE-CONTROL
|
161
|
+
BIND
|
162
|
+
CHECKIN
|
163
|
+
CHECKOUT
|
164
|
+
CONNECT
|
165
|
+
COPY
|
166
|
+
DELETE
|
167
|
+
GET
|
168
|
+
HEAD
|
169
|
+
LABEL
|
170
|
+
LINK
|
171
|
+
LOCK
|
172
|
+
MERGE
|
173
|
+
MKACTIVITY
|
174
|
+
MKCALENDAR
|
175
|
+
MKCOL
|
176
|
+
MKREDIRECTREF
|
177
|
+
MKWORKSPACE
|
178
|
+
MOVE
|
179
|
+
OPTIONS
|
180
|
+
ORDERPATCH
|
181
|
+
PATCH
|
182
|
+
POST
|
183
|
+
PRI
|
184
|
+
PROPFIND
|
185
|
+
PROPPATCH
|
186
|
+
PUT
|
187
|
+
REBIND
|
188
|
+
REPORT
|
189
|
+
SEARCH
|
190
|
+
TRACE
|
191
|
+
UNBIND
|
192
|
+
UNCHECKOUT
|
193
|
+
UNLINK
|
194
|
+
UNLOCK
|
195
|
+
UPDATE
|
196
|
+
UPDATEREDIRECTREF
|
197
|
+
VERSION-CONTROL
|
198
|
+
].freeze
|
199
|
+
|
159
200
|
# ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
|
160
|
-
LINE_END = "\r\n"
|
161
|
-
REMOTE_ADDR = "REMOTE_ADDR"
|
162
|
-
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
163
|
-
HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
|
164
|
-
HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
|
165
|
-
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
|
201
|
+
LINE_END = "\r\n"
|
202
|
+
REMOTE_ADDR = "REMOTE_ADDR"
|
203
|
+
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
204
|
+
HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
|
205
|
+
HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
|
206
|
+
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
|
166
207
|
|
167
|
-
SERVER_NAME = "SERVER_NAME"
|
168
|
-
SERVER_PORT = "SERVER_PORT"
|
169
|
-
HTTP_HOST = "HTTP_HOST"
|
170
|
-
PORT_80 = "80"
|
171
|
-
PORT_443 = "443"
|
172
|
-
LOCALHOST = "localhost"
|
173
|
-
LOCALHOST_IPV4 = "127.0.0.1"
|
174
|
-
LOCALHOST_IPV6 = "::1"
|
175
|
-
UNSPECIFIED_IPV4 = "0.0.0.0"
|
176
|
-
UNSPECIFIED_IPV6 = "::"
|
208
|
+
SERVER_NAME = "SERVER_NAME"
|
209
|
+
SERVER_PORT = "SERVER_PORT"
|
210
|
+
HTTP_HOST = "HTTP_HOST"
|
211
|
+
PORT_80 = "80"
|
212
|
+
PORT_443 = "443"
|
213
|
+
LOCALHOST = "localhost"
|
214
|
+
LOCALHOST_IPV4 = "127.0.0.1"
|
215
|
+
LOCALHOST_IPV6 = "::1"
|
216
|
+
UNSPECIFIED_IPV4 = "0.0.0.0"
|
217
|
+
UNSPECIFIED_IPV6 = "::"
|
177
218
|
|
178
|
-
SERVER_PROTOCOL = "SERVER_PROTOCOL"
|
179
|
-
HTTP_11 = "HTTP/1.1"
|
219
|
+
SERVER_PROTOCOL = "SERVER_PROTOCOL"
|
220
|
+
HTTP_11 = "HTTP/1.1"
|
180
221
|
|
181
|
-
SERVER_SOFTWARE = "SERVER_SOFTWARE"
|
182
|
-
GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
|
183
|
-
CGI_VER = "CGI/1.2"
|
222
|
+
SERVER_SOFTWARE = "SERVER_SOFTWARE"
|
223
|
+
GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
|
224
|
+
CGI_VER = "CGI/1.2"
|
184
225
|
|
185
|
-
STOP_COMMAND = "?"
|
186
|
-
HALT_COMMAND = "!"
|
187
|
-
RESTART_COMMAND = "R"
|
226
|
+
STOP_COMMAND = "?"
|
227
|
+
HALT_COMMAND = "!"
|
228
|
+
RESTART_COMMAND = "R"
|
188
229
|
|
189
|
-
RACK_INPUT = "rack.input"
|
190
|
-
RACK_URL_SCHEME = "rack.url_scheme"
|
191
|
-
RACK_AFTER_REPLY = "rack.after_reply"
|
192
|
-
PUMA_SOCKET = "puma.socket"
|
193
|
-
PUMA_CONFIG = "puma.config"
|
194
|
-
PUMA_PEERCERT = "puma.peercert"
|
230
|
+
RACK_INPUT = "rack.input"
|
231
|
+
RACK_URL_SCHEME = "rack.url_scheme"
|
232
|
+
RACK_AFTER_REPLY = "rack.after_reply"
|
233
|
+
PUMA_SOCKET = "puma.socket"
|
234
|
+
PUMA_CONFIG = "puma.config"
|
235
|
+
PUMA_PEERCERT = "puma.peercert"
|
195
236
|
|
196
|
-
HTTP = "http"
|
197
|
-
HTTPS = "https"
|
237
|
+
HTTP = "http"
|
238
|
+
HTTPS = "https"
|
198
239
|
|
199
|
-
HTTPS_KEY = "HTTPS"
|
240
|
+
HTTPS_KEY = "HTTPS"
|
200
241
|
|
201
|
-
HTTP_VERSION = "HTTP_VERSION"
|
202
|
-
HTTP_CONNECTION = "HTTP_CONNECTION"
|
203
|
-
HTTP_EXPECT = "HTTP_EXPECT"
|
204
|
-
CONTINUE = "100-continue"
|
242
|
+
HTTP_VERSION = "HTTP_VERSION"
|
243
|
+
HTTP_CONNECTION = "HTTP_CONNECTION"
|
244
|
+
HTTP_EXPECT = "HTTP_EXPECT"
|
245
|
+
CONTINUE = "100-continue"
|
205
246
|
|
206
|
-
HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
|
207
|
-
HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
|
208
|
-
HTTP_10_200 = "HTTP/1.0 200 OK\r\n"
|
247
|
+
HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
|
248
|
+
HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
|
249
|
+
HTTP_10_200 = "HTTP/1.0 200 OK\r\n"
|
209
250
|
|
210
|
-
CLOSE = "close"
|
211
|
-
KEEP_ALIVE = "keep-alive"
|
251
|
+
CLOSE = "close"
|
252
|
+
KEEP_ALIVE = "keep-alive"
|
212
253
|
|
213
|
-
CONTENT_LENGTH2 = "content-length"
|
214
|
-
CONTENT_LENGTH_S = "Content-Length: "
|
215
|
-
TRANSFER_ENCODING = "transfer-encoding"
|
216
|
-
TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
|
254
|
+
CONTENT_LENGTH2 = "content-length"
|
255
|
+
CONTENT_LENGTH_S = "Content-Length: "
|
256
|
+
TRANSFER_ENCODING = "transfer-encoding"
|
257
|
+
TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING"
|
217
258
|
|
218
|
-
CONNECTION_CLOSE = "Connection: close\r\n"
|
219
|
-
CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
|
259
|
+
CONNECTION_CLOSE = "Connection: close\r\n"
|
260
|
+
CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
|
220
261
|
|
221
|
-
TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
|
222
|
-
CLOSE_CHUNKED = "0\r\n\r\n"
|
262
|
+
TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
|
263
|
+
CLOSE_CHUNKED = "0\r\n\r\n"
|
223
264
|
|
224
|
-
CHUNKED = "chunked"
|
265
|
+
CHUNKED = "chunked"
|
225
266
|
|
226
|
-
COLON = ": "
|
267
|
+
COLON = ": "
|
227
268
|
|
228
|
-
NEWLINE = "\n"
|
269
|
+
NEWLINE = "\n"
|
229
270
|
|
230
|
-
HIJACK_P = "rack.hijack?"
|
231
|
-
HIJACK = "rack.hijack"
|
232
|
-
HIJACK_IO = "rack.hijack_io"
|
271
|
+
HIJACK_P = "rack.hijack?"
|
272
|
+
HIJACK = "rack.hijack"
|
273
|
+
HIJACK_IO = "rack.hijack_io"
|
233
274
|
|
234
|
-
EARLY_HINTS = "rack.early_hints"
|
275
|
+
EARLY_HINTS = "rack.early_hints"
|
235
276
|
|
236
277
|
# Illegal character in the key or value of response header
|
237
|
-
DQUOTE = "\""
|
278
|
+
DQUOTE = "\""
|
238
279
|
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
239
280
|
ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
|
240
281
|
# header values can contain HTAB?
|
241
282
|
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
242
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
|
+
|
243
292
|
# Banned keys of response header
|
244
293
|
BANNED_HEADER_KEY = /\A(rack\.|status\z)/.freeze
|
245
294
|
|
246
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
|
247
307
|
end
|
248
308
|
end
|
data/lib/puma/control_cli.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'optparse'
|
4
|
-
require_relative 'state_file'
|
5
4
|
require_relative 'const'
|
6
5
|
require_relative 'detect'
|
7
|
-
require_relative 'configuration'
|
8
6
|
require 'uri'
|
9
7
|
require 'socket'
|
10
8
|
|
@@ -39,7 +37,7 @@ module Puma
|
|
39
37
|
# @version 5.0.0
|
40
38
|
PRINTABLE_COMMANDS = %w[gc-stats stats thread-backtraces].freeze
|
41
39
|
|
42
|
-
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
40
|
+
def initialize(argv, stdout=STDOUT, stderr=STDERR, env: ENV)
|
43
41
|
@state = nil
|
44
42
|
@quiet = false
|
45
43
|
@pidfile = nil
|
@@ -48,7 +46,7 @@ module Puma
|
|
48
46
|
@control_auth_token = nil
|
49
47
|
@config_file = nil
|
50
48
|
@command = nil
|
51
|
-
@environment =
|
49
|
+
@environment = env['APP_ENV'] || env['RACK_ENV'] || env['RAILS_ENV']
|
52
50
|
|
53
51
|
@argv = argv.dup
|
54
52
|
@stdout = stdout
|
@@ -62,7 +60,7 @@ module Puma
|
|
62
60
|
@state = arg
|
63
61
|
end
|
64
62
|
|
65
|
-
o.on "-Q", "--quiet", "
|
63
|
+
o.on "-Q", "--quiet", "Do not display messages" do |arg|
|
66
64
|
@quiet = true
|
67
65
|
end
|
68
66
|
|
@@ -126,7 +124,10 @@ module Puma
|
|
126
124
|
end
|
127
125
|
|
128
126
|
if @config_file
|
129
|
-
|
127
|
+
require_relative 'configuration'
|
128
|
+
require_relative 'log_writer'
|
129
|
+
|
130
|
+
config = Puma::Configuration.new({ config_files: [@config_file] }, {} , env)
|
130
131
|
config.load
|
131
132
|
@state ||= config.options[:state]
|
132
133
|
@control_url ||= config.options[:control_url]
|
@@ -149,6 +150,8 @@ module Puma
|
|
149
150
|
raise "State file not found: #{@state}"
|
150
151
|
end
|
151
152
|
|
153
|
+
require_relative 'state_file'
|
154
|
+
|
152
155
|
sf = Puma::StateFile.new
|
153
156
|
sf.load @state
|
154
157
|
|
@@ -164,22 +167,26 @@ module Puma
|
|
164
167
|
def send_request
|
165
168
|
uri = URI.parse @control_url
|
166
169
|
|
170
|
+
host = uri.host
|
171
|
+
|
167
172
|
# create server object by scheme
|
168
173
|
server =
|
169
174
|
case uri.scheme
|
170
175
|
when 'ssl'
|
171
176
|
require 'openssl'
|
177
|
+
host = host[1..-2] if host&.start_with? '['
|
172
178
|
OpenSSL::SSL::SSLSocket.new(
|
173
|
-
TCPSocket.new(
|
179
|
+
TCPSocket.new(host, uri.port),
|
174
180
|
OpenSSL::SSL::SSLContext.new)
|
175
181
|
.tap { |ssl| ssl.sync_close = true } # default is false
|
176
182
|
.tap(&:connect)
|
177
183
|
when 'tcp'
|
178
|
-
|
184
|
+
host = host[1..-2] if host&.start_with? '['
|
185
|
+
TCPSocket.new host, uri.port
|
179
186
|
when 'unix'
|
180
187
|
# check for abstract UNIXSocket
|
181
188
|
UNIXSocket.new(@control_url.start_with?('unix://@') ?
|
182
|
-
"\0#{
|
189
|
+
"\0#{host}#{uri.path}" : "#{host}#{uri.path}")
|
183
190
|
else
|
184
191
|
raise "Invalid scheme: #{uri.scheme}"
|
185
192
|
end
|
data/lib/puma/detect.rb
CHANGED
@@ -12,13 +12,14 @@ module Puma
|
|
12
12
|
|
13
13
|
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
14
14
|
|
15
|
-
IS_OSX =
|
15
|
+
IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
|
16
16
|
|
17
|
-
IS_WINDOWS =
|
18
|
-
|
17
|
+
IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
|
18
|
+
|
19
|
+
IS_LINUX = !(IS_OSX || IS_WINDOWS)
|
19
20
|
|
20
21
|
# @version 5.2.0
|
21
|
-
IS_MRI =
|
22
|
+
IS_MRI = RUBY_ENGINE == 'ruby'
|
22
23
|
|
23
24
|
def self.jruby?
|
24
25
|
IS_JRUBY
|