puma 5.6.4 → 6.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +372 -6
- data/LICENSE +0 -0
- data/README.md +79 -29
- data/bin/puma-wild +1 -1
- data/docs/architecture.md +0 -0
- data/docs/compile_options.md +34 -0
- data/docs/deployment.md +0 -0
- data/docs/fork_worker.md +1 -3
- 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/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 +0 -0
- data/docs/rails_dev_mode.md +0 -0
- data/docs/restart.md +1 -0
- data/docs/signals.md +0 -0
- data/docs/stats.md +0 -0
- data/docs/systemd.md +3 -6
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/ext_help.h +0 -0
- data/ext/puma_http11/extconf.rb +22 -10
- data/ext/puma_http11/http11_parser.c +1 -1
- data/ext/puma_http11/http11_parser.h +1 -1
- data/ext/puma_http11/http11_parser.java.rl +2 -2
- data/ext/puma_http11/http11_parser.rl +2 -2
- data/ext/puma_http11/http11_parser_common.rl +2 -2
- data/ext/puma_http11/mini_ssl.c +153 -27
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +167 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +7 -4
- data/lib/puma/binder.rb +51 -54
- data/lib/puma/cli.rb +16 -18
- data/lib/puma/client.rb +100 -26
- data/lib/puma/cluster/worker.rb +18 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +102 -40
- data/lib/puma/commonlogger.rb +21 -14
- data/lib/puma/configuration.rb +77 -59
- data/lib/puma/const.rb +129 -92
- data/lib/puma/control_cli.rb +33 -23
- data/lib/puma/detect.rb +7 -4
- data/lib/puma/dsl.rb +251 -53
- data/lib/puma/error_logger.rb +18 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +39 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/json_serialization.rb +0 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +113 -175
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +26 -12
- data/lib/puma/minissl.rb +113 -15
- data/lib/puma/null_io.rb +21 -2
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/plugin.rb +0 -0
- data/lib/puma/rack/builder.rb +6 -6
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/rack_default.rb +19 -4
- data/lib/puma/reactor.rb +19 -10
- data/lib/puma/request.rb +365 -166
- data/lib/puma/runner.rb +56 -20
- data/lib/puma/sd_notify.rb +149 -0
- data/lib/puma/server.rb +137 -87
- data/lib/puma/single.rb +13 -11
- data/lib/puma/state_file.rb +4 -6
- data/lib/puma/thread_pool.rb +57 -19
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +12 -11
- data/lib/rack/handler/puma.rb +113 -86
- data/tools/Dockerfile +2 -2
- data/tools/trickletest.rb +0 -0
- metadata +11 -6
- data/lib/puma/queue_close.rb +0 -26
- data/lib/puma/systemd.rb +0 -46
data/lib/puma/configuration.rb
CHANGED
@@ -1,21 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require_relative 'rack/builder'
|
4
|
+
require_relative 'plugin'
|
5
|
+
require_relative 'const'
|
6
|
+
require_relative 'dsl'
|
6
7
|
|
7
8
|
module Puma
|
8
|
-
|
9
|
-
module ConfigDefault
|
10
|
-
DefaultRackup = "config.ru"
|
11
|
-
|
12
|
-
DefaultTCPHost = "0.0.0.0"
|
13
|
-
DefaultTCPPort = 9292
|
14
|
-
DefaultWorkerCheckInterval = 5
|
15
|
-
DefaultWorkerTimeout = 60
|
16
|
-
DefaultWorkerShutdownTimeout = 30
|
17
|
-
end
|
18
|
-
|
19
9
|
# A class used for storing "leveled" configuration options.
|
20
10
|
#
|
21
11
|
# In this class any "user" specified options take precedence over any
|
@@ -136,7 +126,52 @@ module Puma
|
|
136
126
|
# is done because an environment variable may have been modified while loading
|
137
127
|
# configuration files.
|
138
128
|
class Configuration
|
139
|
-
|
129
|
+
DEFAULTS = {
|
130
|
+
auto_trim_time: 30,
|
131
|
+
binds: ['tcp://0.0.0.0:9292'.freeze],
|
132
|
+
clean_thread_locals: false,
|
133
|
+
debug: false,
|
134
|
+
early_hints: nil,
|
135
|
+
environment: 'development'.freeze,
|
136
|
+
# Number of seconds to wait until we get the first data for the request.
|
137
|
+
first_data_timeout: 30,
|
138
|
+
# Number of seconds to wait until the next request before shutting down.
|
139
|
+
idle_timeout: nil,
|
140
|
+
io_selector_backend: :auto,
|
141
|
+
log_requests: false,
|
142
|
+
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,
|
149
|
+
max_threads: Puma.mri? ? 5 : 16,
|
150
|
+
min_threads: 0,
|
151
|
+
mode: :http,
|
152
|
+
mutate_stdout_and_stderr_to_sync_on_write: true,
|
153
|
+
out_of_band: [],
|
154
|
+
# Number of seconds for another request within a persistent session.
|
155
|
+
persistent_timeout: 20,
|
156
|
+
queue_requests: true,
|
157
|
+
rackup: 'config.ru'.freeze,
|
158
|
+
raise_exception_on_sigterm: true,
|
159
|
+
reaping_time: 1,
|
160
|
+
remote_address: :socket,
|
161
|
+
silence_single_worker_warning: false,
|
162
|
+
silence_fork_callback_warning: false,
|
163
|
+
tag: File.basename(Dir.getwd),
|
164
|
+
tcp_host: '0.0.0.0'.freeze,
|
165
|
+
tcp_port: 9292,
|
166
|
+
wait_for_less_busy_worker: 0.005,
|
167
|
+
worker_boot_timeout: 60,
|
168
|
+
worker_check_interval: 5,
|
169
|
+
worker_culling_strategy: :youngest,
|
170
|
+
worker_shutdown_timeout: 30,
|
171
|
+
worker_timeout: 60,
|
172
|
+
workers: 0,
|
173
|
+
http_content_length_limit: nil
|
174
|
+
}
|
140
175
|
|
141
176
|
def initialize(user_options={}, default_options = {}, &block)
|
142
177
|
default_options = self.puma_default_options.merge(default_options)
|
@@ -181,37 +216,22 @@ module Puma
|
|
181
216
|
self
|
182
217
|
end
|
183
218
|
|
184
|
-
|
185
|
-
|
186
|
-
|
219
|
+
def puma_default_options
|
220
|
+
defaults = DEFAULTS.dup
|
221
|
+
puma_options_from_env.each { |k,v| defaults[k] = v if v }
|
222
|
+
defaults
|
187
223
|
end
|
188
224
|
|
189
|
-
def
|
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']
|
229
|
+
|
190
230
|
{
|
191
|
-
:
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:
|
195
|
-
:binds => ["tcp://#{DefaultTCPHost}:#{DefaultTCPPort}"],
|
196
|
-
:workers => Integer(ENV['WEB_CONCURRENCY'] || 0),
|
197
|
-
:silence_single_worker_warning => false,
|
198
|
-
:mode => :http,
|
199
|
-
:worker_check_interval => DefaultWorkerCheckInterval,
|
200
|
-
:worker_timeout => DefaultWorkerTimeout,
|
201
|
-
:worker_boot_timeout => DefaultWorkerTimeout,
|
202
|
-
:worker_shutdown_timeout => DefaultWorkerShutdownTimeout,
|
203
|
-
:worker_culling_strategy => :youngest,
|
204
|
-
:remote_address => :socket,
|
205
|
-
:tag => method(:infer_tag),
|
206
|
-
:environment => -> { ENV['APP_ENV'] || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development' },
|
207
|
-
:rackup => DefaultRackup,
|
208
|
-
:logger => STDOUT,
|
209
|
-
:persistent_timeout => Const::PERSISTENT_TIMEOUT,
|
210
|
-
:first_data_timeout => Const::FIRST_DATA_TIMEOUT,
|
211
|
-
:raise_exception_on_sigterm => true,
|
212
|
-
:max_fast_inline => Const::MAX_FAST_INLINE,
|
213
|
-
:io_selector_backend => :auto,
|
214
|
-
:mutate_stdout_and_stderr_to_sync_on_write => true,
|
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'],
|
215
235
|
}
|
216
236
|
end
|
217
237
|
|
@@ -227,7 +247,7 @@ module Puma
|
|
227
247
|
return [] if files == ['-']
|
228
248
|
return files if files.any?
|
229
249
|
|
230
|
-
first_default_file = %W(config/puma/#{
|
250
|
+
first_default_file = %W(config/puma/#{@options[:environment]}.rb config/puma.rb).find do |f|
|
231
251
|
File.exist?(f)
|
232
252
|
end
|
233
253
|
|
@@ -270,7 +290,7 @@ module Puma
|
|
270
290
|
found = options[:app] || load_rackup
|
271
291
|
|
272
292
|
if @options[:log_requests]
|
273
|
-
|
293
|
+
require_relative 'commonlogger'
|
274
294
|
logger = @options[:logger]
|
275
295
|
found = CommonLogger.new(found, logger)
|
276
296
|
end
|
@@ -283,21 +303,25 @@ module Puma
|
|
283
303
|
@options[:environment]
|
284
304
|
end
|
285
305
|
|
286
|
-
def environment_str
|
287
|
-
environment.respond_to?(:call) ? environment.call : environment
|
288
|
-
end
|
289
|
-
|
290
306
|
def load_plugin(name)
|
291
307
|
@plugins.create name
|
292
308
|
end
|
293
309
|
|
294
|
-
|
310
|
+
# @param key [:Symbol] hook to run
|
311
|
+
# @param arg [Launcher, Int] `:on_restart` passes Launcher
|
312
|
+
#
|
313
|
+
def run_hooks(key, arg, log_writer, hook_data = nil)
|
295
314
|
@options.all_of(key).each do |b|
|
296
315
|
begin
|
297
|
-
b
|
316
|
+
if Array === b
|
317
|
+
hook_data[b[1]] ||= Hash.new
|
318
|
+
b[0].call arg, hook_data[b[1]]
|
319
|
+
else
|
320
|
+
b.call arg
|
321
|
+
end
|
298
322
|
rescue => e
|
299
|
-
|
300
|
-
|
323
|
+
log_writer.log "WARNING hook #{key} failed with exception (#{e.class}) #{e.message}"
|
324
|
+
log_writer.debug e.backtrace.join("\n")
|
301
325
|
end
|
302
326
|
end
|
303
327
|
end
|
@@ -315,10 +339,6 @@ module Puma
|
|
315
339
|
|
316
340
|
private
|
317
341
|
|
318
|
-
def infer_tag
|
319
|
-
File.basename(Dir.getwd)
|
320
|
-
end
|
321
|
-
|
322
342
|
# Load and use the normal Rack builder if we can, otherwise
|
323
343
|
# fallback to our minimal version.
|
324
344
|
def rack_builder
|
@@ -367,5 +387,3 @@ module Puma
|
|
367
387
|
end
|
368
388
|
end
|
369
389
|
end
|
370
|
-
|
371
|
-
require 'puma/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,55 +100,40 @@ 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 = "6.4.2"
|
104
|
+
CODE_NAME = "The Eagle of Durango"
|
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
|
|
110
|
-
# The default number of seconds for another request within a persistent
|
111
|
-
# session.
|
112
|
-
PERSISTENT_TIMEOUT = 20
|
113
|
-
|
114
|
-
# The default number of seconds to wait until we get the first data
|
115
|
-
# for the request
|
116
|
-
FIRST_DATA_TIMEOUT = 30
|
117
|
-
|
118
110
|
# How long to wait when getting some write blocking on the socket when
|
119
111
|
# sending data back
|
120
112
|
WRITE_TIMEOUT = 10
|
121
113
|
|
122
|
-
# How many requests to attempt inline before sending a client back to
|
123
|
-
# the reactor to be subject to normal ordering. The idea here is that
|
124
|
-
# we amortize the cost of going back to the reactor for a well behaved
|
125
|
-
# but very "greedy" client across 10 requests. This prevents a not
|
126
|
-
# well behaved client from monopolizing the thread forever.
|
127
|
-
MAX_FAST_INLINE = 10
|
128
|
-
|
129
114
|
# The original URI requested by the client.
|
130
|
-
REQUEST_URI=
|
131
|
-
REQUEST_PATH =
|
132
|
-
QUERY_STRING =
|
133
|
-
CONTENT_LENGTH = "CONTENT_LENGTH"
|
115
|
+
REQUEST_URI= "REQUEST_URI"
|
116
|
+
REQUEST_PATH = "REQUEST_PATH"
|
117
|
+
QUERY_STRING = "QUERY_STRING"
|
118
|
+
CONTENT_LENGTH = "CONTENT_LENGTH"
|
134
119
|
|
135
|
-
PATH_INFO =
|
120
|
+
PATH_INFO = "PATH_INFO"
|
136
121
|
|
137
|
-
PUMA_TMP_BASE = "puma"
|
122
|
+
PUMA_TMP_BASE = "puma"
|
138
123
|
|
139
124
|
ERROR_RESPONSE = {
|
140
125
|
# Indicate that we couldn't parse the request
|
141
|
-
400 => "HTTP/1.1 400 Bad Request\r\n\r\n"
|
126
|
+
400 => "HTTP/1.1 400 Bad Request\r\n\r\n",
|
142
127
|
# The standard empty 404 response for bad requests. Use Error4040Handler for custom stuff.
|
143
|
-
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",
|
144
129
|
# The standard empty 408 response for requests that timed out.
|
145
|
-
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",
|
146
131
|
# Indicate that there was an internal error, obviously.
|
147
|
-
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",
|
148
133
|
# Incorrect or invalid header value
|
149
|
-
501 => "HTTP/1.1 501 Not Implemented\r\n\r\n"
|
134
|
+
501 => "HTTP/1.1 501 Not Implemented\r\n\r\n",
|
150
135
|
# A common header for indicating the server is too busy. Not used yet.
|
151
|
-
503 => "HTTP/1.1 503 Service Unavailable\r\n\r\
|
136
|
+
503 => "HTTP/1.1 503 Service Unavailable\r\n\r\n"
|
152
137
|
}.freeze
|
153
138
|
|
154
139
|
# The basic max request size we'll try to read.
|
@@ -161,84 +146,136 @@ module Puma
|
|
161
146
|
# Maximum request body size before it is moved out of memory and into a tempfile for reading.
|
162
147
|
MAX_BODY = MAX_HEADER
|
163
148
|
|
164
|
-
REQUEST_METHOD = "REQUEST_METHOD"
|
165
|
-
HEAD = "HEAD"
|
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
|
+
|
166
200
|
# ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
|
167
|
-
LINE_END = "\r\n"
|
168
|
-
REMOTE_ADDR = "REMOTE_ADDR"
|
169
|
-
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
170
|
-
HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL"
|
171
|
-
HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME"
|
172
|
-
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"
|
173
207
|
|
174
|
-
SERVER_NAME = "SERVER_NAME"
|
175
|
-
SERVER_PORT = "SERVER_PORT"
|
176
|
-
HTTP_HOST = "HTTP_HOST"
|
177
|
-
PORT_80 = "80"
|
178
|
-
PORT_443 = "443"
|
179
|
-
LOCALHOST = "localhost"
|
180
|
-
|
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 = "::"
|
181
218
|
|
182
|
-
SERVER_PROTOCOL = "SERVER_PROTOCOL"
|
183
|
-
HTTP_11 = "HTTP/1.1"
|
219
|
+
SERVER_PROTOCOL = "SERVER_PROTOCOL"
|
220
|
+
HTTP_11 = "HTTP/1.1"
|
184
221
|
|
185
|
-
SERVER_SOFTWARE = "SERVER_SOFTWARE"
|
186
|
-
GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
|
187
|
-
CGI_VER = "CGI/1.2"
|
222
|
+
SERVER_SOFTWARE = "SERVER_SOFTWARE"
|
223
|
+
GATEWAY_INTERFACE = "GATEWAY_INTERFACE"
|
224
|
+
CGI_VER = "CGI/1.2"
|
188
225
|
|
189
|
-
STOP_COMMAND = "?"
|
190
|
-
HALT_COMMAND = "!"
|
191
|
-
RESTART_COMMAND = "R"
|
226
|
+
STOP_COMMAND = "?"
|
227
|
+
HALT_COMMAND = "!"
|
228
|
+
RESTART_COMMAND = "R"
|
192
229
|
|
193
|
-
RACK_INPUT = "rack.input"
|
194
|
-
RACK_URL_SCHEME = "rack.url_scheme"
|
195
|
-
RACK_AFTER_REPLY = "rack.after_reply"
|
196
|
-
PUMA_SOCKET = "puma.socket"
|
197
|
-
PUMA_CONFIG = "puma.config"
|
198
|
-
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"
|
199
236
|
|
200
|
-
HTTP = "http"
|
201
|
-
HTTPS = "https"
|
237
|
+
HTTP = "http"
|
238
|
+
HTTPS = "https"
|
202
239
|
|
203
|
-
HTTPS_KEY = "HTTPS"
|
240
|
+
HTTPS_KEY = "HTTPS"
|
204
241
|
|
205
|
-
HTTP_VERSION = "HTTP_VERSION"
|
206
|
-
HTTP_CONNECTION = "HTTP_CONNECTION"
|
207
|
-
HTTP_EXPECT = "HTTP_EXPECT"
|
208
|
-
CONTINUE = "100-continue"
|
242
|
+
HTTP_VERSION = "HTTP_VERSION"
|
243
|
+
HTTP_CONNECTION = "HTTP_CONNECTION"
|
244
|
+
HTTP_EXPECT = "HTTP_EXPECT"
|
245
|
+
CONTINUE = "100-continue"
|
209
246
|
|
210
|
-
HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n"
|
211
|
-
HTTP_11_200 = "HTTP/1.1 200 OK\r\n"
|
212
|
-
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"
|
213
250
|
|
214
|
-
CLOSE = "close"
|
215
|
-
KEEP_ALIVE = "keep-alive"
|
251
|
+
CLOSE = "close"
|
252
|
+
KEEP_ALIVE = "keep-alive"
|
216
253
|
|
217
|
-
CONTENT_LENGTH2 = "content-length"
|
218
|
-
CONTENT_LENGTH_S = "Content-Length: "
|
219
|
-
TRANSFER_ENCODING = "transfer-encoding"
|
220
|
-
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"
|
221
258
|
|
222
|
-
CONNECTION_CLOSE = "Connection: close\r\n"
|
223
|
-
CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
|
259
|
+
CONNECTION_CLOSE = "Connection: close\r\n"
|
260
|
+
CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n"
|
224
261
|
|
225
|
-
TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
|
226
|
-
CLOSE_CHUNKED = "0\r\n\r\n"
|
262
|
+
TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n"
|
263
|
+
CLOSE_CHUNKED = "0\r\n\r\n"
|
227
264
|
|
228
|
-
CHUNKED = "chunked"
|
265
|
+
CHUNKED = "chunked"
|
229
266
|
|
230
|
-
COLON = ": "
|
267
|
+
COLON = ": "
|
231
268
|
|
232
|
-
NEWLINE = "\n"
|
269
|
+
NEWLINE = "\n"
|
233
270
|
|
234
|
-
HIJACK_P = "rack.hijack?"
|
235
|
-
HIJACK = "rack.hijack"
|
236
|
-
HIJACK_IO = "rack.hijack_io"
|
271
|
+
HIJACK_P = "rack.hijack?"
|
272
|
+
HIJACK = "rack.hijack"
|
273
|
+
HIJACK_IO = "rack.hijack_io"
|
237
274
|
|
238
|
-
EARLY_HINTS = "rack.early_hints"
|
275
|
+
EARLY_HINTS = "rack.early_hints"
|
239
276
|
|
240
277
|
# Illegal character in the key or value of response header
|
241
|
-
DQUOTE = "\""
|
278
|
+
DQUOTE = "\""
|
242
279
|
HTTP_HEADER_DELIMITER = Regexp.escape("(),/:;<=>?@[]{}\\").freeze
|
243
280
|
ILLEGAL_HEADER_KEY_REGEX = /[\x00-\x20#{DQUOTE}#{HTTP_HEADER_DELIMITER}]/.freeze
|
244
281
|
# header values can contain HTAB?
|
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
|
|
@@ -17,26 +15,27 @@ module Puma
|
|
17
15
|
CMD_PATH_SIG_MAP = {
|
18
16
|
'gc' => nil,
|
19
17
|
'gc-stats' => nil,
|
20
|
-
'halt'
|
21
|
-
'
|
22
|
-
'
|
18
|
+
'halt' => 'SIGQUIT',
|
19
|
+
'info' => 'SIGINFO',
|
20
|
+
'phased-restart' => 'SIGUSR1',
|
21
|
+
'refork' => 'SIGURG',
|
23
22
|
'reload-worker-directory' => nil,
|
24
|
-
'
|
23
|
+
'reopen-log' => 'SIGHUP',
|
24
|
+
'restart' => 'SIGUSR2',
|
25
25
|
'start' => nil,
|
26
26
|
'stats' => nil,
|
27
27
|
'status' => '',
|
28
|
-
'stop'
|
29
|
-
'thread-backtraces' => nil
|
28
|
+
'stop' => 'SIGTERM',
|
29
|
+
'thread-backtraces' => nil,
|
30
|
+
'worker-count-down' => 'SIGTTOU',
|
31
|
+
'worker-count-up' => 'SIGTTIN'
|
30
32
|
}.freeze
|
31
33
|
|
32
|
-
# @deprecated 6.0.0
|
33
|
-
COMMANDS = CMD_PATH_SIG_MAP.keys.freeze
|
34
|
-
|
35
34
|
# commands that cannot be used in a request
|
36
|
-
NO_REQ_COMMANDS = %w
|
35
|
+
NO_REQ_COMMANDS = %w[info reopen-log worker-count-down worker-count-up].freeze
|
37
36
|
|
38
37
|
# @version 5.0.0
|
39
|
-
PRINTABLE_COMMANDS = %w
|
38
|
+
PRINTABLE_COMMANDS = %w[gc-stats stats thread-backtraces].freeze
|
40
39
|
|
41
40
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
42
41
|
@state = nil
|
@@ -125,6 +124,9 @@ module Puma
|
|
125
124
|
end
|
126
125
|
|
127
126
|
if @config_file
|
127
|
+
require_relative 'configuration'
|
128
|
+
require_relative 'log_writer'
|
129
|
+
|
128
130
|
config = Puma::Configuration.new({ config_files: [@config_file] }, {})
|
129
131
|
config.load
|
130
132
|
@state ||= config.options[:state]
|
@@ -148,6 +150,8 @@ module Puma
|
|
148
150
|
raise "State file not found: #{@state}"
|
149
151
|
end
|
150
152
|
|
153
|
+
require_relative 'state_file'
|
154
|
+
|
151
155
|
sf = Puma::StateFile.new
|
152
156
|
sf.load @state
|
153
157
|
|
@@ -163,30 +167,32 @@ module Puma
|
|
163
167
|
def send_request
|
164
168
|
uri = URI.parse @control_url
|
165
169
|
|
170
|
+
host = uri.host
|
171
|
+
|
166
172
|
# create server object by scheme
|
167
173
|
server =
|
168
174
|
case uri.scheme
|
169
175
|
when 'ssl'
|
170
176
|
require 'openssl'
|
177
|
+
host = host[1..-2] if host&.start_with? '['
|
171
178
|
OpenSSL::SSL::SSLSocket.new(
|
172
|
-
TCPSocket.new(
|
179
|
+
TCPSocket.new(host, uri.port),
|
173
180
|
OpenSSL::SSL::SSLContext.new)
|
174
181
|
.tap { |ssl| ssl.sync_close = true } # default is false
|
175
182
|
.tap(&:connect)
|
176
183
|
when 'tcp'
|
177
|
-
|
184
|
+
host = host[1..-2] if host&.start_with? '['
|
185
|
+
TCPSocket.new host, uri.port
|
178
186
|
when 'unix'
|
179
187
|
# check for abstract UNIXSocket
|
180
188
|
UNIXSocket.new(@control_url.start_with?('unix://@') ?
|
181
|
-
"\0#{
|
189
|
+
"\0#{host}#{uri.path}" : "#{host}#{uri.path}")
|
182
190
|
else
|
183
191
|
raise "Invalid scheme: #{uri.scheme}"
|
184
192
|
end
|
185
193
|
|
186
194
|
if @command == 'status'
|
187
195
|
message 'Puma is started'
|
188
|
-
elsif NO_REQ_COMMANDS.include? @command
|
189
|
-
raise "Invalid request command: #{@command}"
|
190
196
|
else
|
191
197
|
url = "/#{@command}"
|
192
198
|
|
@@ -242,7 +248,11 @@ module Puma
|
|
242
248
|
@stdout.flush unless @stdout.sync
|
243
249
|
return
|
244
250
|
elsif sig.start_with? 'SIG'
|
245
|
-
|
251
|
+
if Signal.list.key? sig.sub(/\ASIG/, '')
|
252
|
+
Process.kill sig, @pid
|
253
|
+
else
|
254
|
+
raise "Signal '#{sig}' not available'"
|
255
|
+
end
|
246
256
|
elsif @command == 'status'
|
247
257
|
begin
|
248
258
|
Process.kill 0, @pid
|
@@ -268,7 +278,7 @@ module Puma
|
|
268
278
|
return start if @command == 'start'
|
269
279
|
prepare_configuration
|
270
280
|
|
271
|
-
if Puma.windows? || @control_url
|
281
|
+
if Puma.windows? || @control_url && !NO_REQ_COMMANDS.include?(@command)
|
272
282
|
send_request
|
273
283
|
else
|
274
284
|
send_signal
|
@@ -281,7 +291,7 @@ module Puma
|
|
281
291
|
|
282
292
|
private
|
283
293
|
def start
|
284
|
-
|
294
|
+
require_relative 'cli'
|
285
295
|
|
286
296
|
run_args = []
|
287
297
|
|
@@ -293,13 +303,13 @@ module Puma
|
|
293
303
|
run_args += ["-C", @config_file] if @config_file
|
294
304
|
run_args += ["-e", @environment] if @environment
|
295
305
|
|
296
|
-
|
306
|
+
log_writer = Puma::LogWriter.new(@stdout, @stderr)
|
297
307
|
|
298
308
|
# replace $0 because puma use it to generate restart command
|
299
309
|
puma_cmd = $0.gsub(/pumactl$/, 'puma')
|
300
310
|
$0 = puma_cmd if File.exist?(puma_cmd)
|
301
311
|
|
302
|
-
cli = Puma::CLI.new run_args,
|
312
|
+
cli = Puma::CLI.new run_args, log_writer
|
303
313
|
cli.run
|
304
314
|
end
|
305
315
|
end
|
data/lib/puma/detect.rb
CHANGED
@@ -8,15 +8,18 @@ module Puma
|
|
8
8
|
# @version 5.2.1
|
9
9
|
HAS_FORK = ::Process.respond_to? :fork
|
10
10
|
|
11
|
+
HAS_NATIVE_IO_WAIT = ::IO.public_instance_methods(false).include? :wait_readable
|
12
|
+
|
11
13
|
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
12
14
|
|
13
|
-
IS_OSX =
|
15
|
+
IS_OSX = RUBY_DESCRIPTION.include? 'darwin'
|
16
|
+
|
17
|
+
IS_WINDOWS = RUBY_DESCRIPTION.match?(/mswin|ming|cygwin/)
|
14
18
|
|
15
|
-
|
16
|
-
IS_JRUBY && RUBY_DESCRIPTION.include?('mswin')
|
19
|
+
IS_LINUX = !(IS_OSX || IS_WINDOWS)
|
17
20
|
|
18
21
|
# @version 5.2.0
|
19
|
-
IS_MRI =
|
22
|
+
IS_MRI = RUBY_ENGINE == 'ruby'
|
20
23
|
|
21
24
|
def self.jruby?
|
22
25
|
IS_JRUBY
|