puma 5.6.4 → 6.4.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- 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
|