puma 6.4.3 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +448 -8
- data/README.md +110 -51
- data/docs/5.0-Upgrade.md +98 -0
- data/docs/6.0-Upgrade.md +56 -0
- data/docs/7.0-Upgrade.md +52 -0
- data/docs/8.0-Upgrade.md +100 -0
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +11 -1
- data/docs/grpc.md +62 -0
- data/docs/images/favicon.svg +1 -0
- data/docs/images/running-puma.svg +1 -0
- data/docs/images/standard-logo.svg +1 -0
- data/docs/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/http11_parser.java.rl +51 -65
- data/ext/puma_http11/mini_ssl.c +29 -9
- data/ext/puma_http11/org/jruby/puma/EnvKey.java +241 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +194 -101
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +71 -85
- data/ext/puma_http11/puma_http11.c +125 -118
- data/lib/puma/app/status.rb +11 -3
- data/lib/puma/binder.rb +22 -12
- data/lib/puma/cli.rb +11 -9
- data/lib/puma/client.rb +233 -136
- data/lib/puma/client_env.rb +171 -0
- data/lib/puma/cluster/worker.rb +24 -21
- data/lib/puma/cluster/worker_handle.rb +38 -8
- data/lib/puma/cluster.rb +74 -48
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +197 -64
- data/lib/puma/const.rb +23 -12
- data/lib/puma/control_cli.rb +11 -7
- data/lib/puma/detect.rb +13 -0
- data/lib/puma/dsl.rb +483 -127
- 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 +3 -5
- data/lib/puma/launcher.rb +76 -59
- data/lib/puma/log_writer.rb +17 -11
- 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 → response.rb} +57 -209
- data/lib/puma/runner.rb +15 -17
- data/lib/puma/sd_notify.rb +1 -4
- data/lib/puma/server.rb +200 -104
- data/lib/puma/server_plugin_control.rb +32 -0
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +179 -96
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +11 -8
- data/tools/Dockerfile +15 -5
- metadata +26 -16
- data/ext/puma_http11/ext_help.h +0 -15
|
@@ -12,7 +12,7 @@ module Puma
|
|
|
12
12
|
# #handle_request, which is called in Server#process_client.
|
|
13
13
|
# @version 5.0.3
|
|
14
14
|
#
|
|
15
|
-
module
|
|
15
|
+
module Response # :nodoc:
|
|
16
16
|
|
|
17
17
|
# Single element array body: smaller bodies are written to io_buffer first,
|
|
18
18
|
# then a single write from io_buffer. Larger sizes are written separately.
|
|
@@ -36,43 +36,28 @@ module Puma
|
|
|
36
36
|
# Takes the request contained in +client+, invokes the Rack application to construct
|
|
37
37
|
# the response and writes it back to +client.io+.
|
|
38
38
|
#
|
|
39
|
-
# It'll return +
|
|
39
|
+
# It'll return +:close+ when the connection is closed, this doesn't mean
|
|
40
40
|
# that the response wasn't successful.
|
|
41
41
|
#
|
|
42
|
+
# It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
|
|
43
|
+
# Which may contain additional requests.
|
|
44
|
+
#
|
|
42
45
|
# It'll return +:async+ if the connection remains open but will be handled
|
|
43
46
|
# elsewhere, i.e. the connection has been hijacked by the Rack application.
|
|
44
47
|
#
|
|
45
48
|
# Finally, it'll return +true+ on keep-alive connections.
|
|
49
|
+
# @param processor [Puma::ThreadPool::ProcessorThread]
|
|
46
50
|
# @param client [Puma::Client]
|
|
47
51
|
# @param requests [Integer]
|
|
48
|
-
# @return [
|
|
49
|
-
|
|
50
|
-
def handle_request(client, requests)
|
|
52
|
+
# @return [:close, :keep_alive, :async]
|
|
53
|
+
def handle_request(processor, client, requests)
|
|
51
54
|
env = client.env
|
|
52
55
|
io_buffer = client.io_buffer
|
|
53
56
|
socket = client.io # io may be a MiniSSL::Socket
|
|
54
57
|
app_body = nil
|
|
58
|
+
error = nil
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
return false if closed_socket?(socket)
|
|
58
|
-
|
|
59
|
-
if client.http_content_length_limit_exceeded
|
|
60
|
-
return prepare_response(413, {}, ["Payload Too Large"], requests, client)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
normalize_env env, client
|
|
64
|
-
|
|
65
|
-
env[PUMA_SOCKET] = socket
|
|
66
|
-
|
|
67
|
-
if env[HTTPS_KEY] && socket.peercert
|
|
68
|
-
env[PUMA_PEERCERT] = socket.peercert
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
env[HIJACK_P] = true
|
|
72
|
-
env[HIJACK] = client
|
|
73
|
-
|
|
74
|
-
env[RACK_INPUT] = client.body
|
|
75
|
-
env[RACK_URL_SCHEME] ||= default_server_port(env) == PORT_443 ? HTTPS : HTTP
|
|
60
|
+
return :close if closed_socket?(socket)
|
|
76
61
|
|
|
77
62
|
if @early_hints
|
|
78
63
|
env[EARLY_HINTS] = lambda { |headers|
|
|
@@ -87,21 +72,11 @@ module Puma
|
|
|
87
72
|
}
|
|
88
73
|
end
|
|
89
74
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# A rack extension. If the app writes #call'ables to this
|
|
93
|
-
# array, we will invoke them when the request is done.
|
|
94
|
-
#
|
|
95
|
-
env[RACK_AFTER_REPLY] ||= []
|
|
75
|
+
env["puma.mark_as_io_bound"] = -> { processor.mark_as_io_thread! }
|
|
96
76
|
|
|
97
77
|
begin
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
@app.call(env)
|
|
101
|
-
end
|
|
102
|
-
else
|
|
103
|
-
@log_writer.log "Unsupported HTTP method used: #{env[REQUEST_METHOD]}"
|
|
104
|
-
status, headers, app_body = [501, {}, ["#{env[REQUEST_METHOD]} method is not supported"]]
|
|
78
|
+
status, headers, app_body = @thread_pool.with_force_shutdown do
|
|
79
|
+
@app.call(env)
|
|
105
80
|
end
|
|
106
81
|
|
|
107
82
|
# app_body needs to always be closed, hold value in case lowlevel_error
|
|
@@ -120,28 +95,40 @@ module Puma
|
|
|
120
95
|
|
|
121
96
|
return :async
|
|
122
97
|
end
|
|
123
|
-
rescue ThreadPool::ForceShutdown =>
|
|
124
|
-
@log_writer.unknown_error
|
|
98
|
+
rescue ThreadPool::ForceShutdown => error
|
|
99
|
+
@log_writer.unknown_error error, client, "Rack app"
|
|
125
100
|
@log_writer.log "Detected force shutdown of a thread"
|
|
126
101
|
|
|
127
|
-
status, headers, res_body = lowlevel_error(
|
|
128
|
-
rescue Exception =>
|
|
129
|
-
@log_writer.unknown_error
|
|
102
|
+
status, headers, res_body = lowlevel_error(error, env, 503)
|
|
103
|
+
rescue Exception => error
|
|
104
|
+
@log_writer.unknown_error error, client, "Rack app"
|
|
130
105
|
|
|
131
|
-
status, headers, res_body = lowlevel_error(
|
|
106
|
+
status, headers, res_body = lowlevel_error(error, env, 500)
|
|
132
107
|
end
|
|
133
108
|
prepare_response(status, headers, res_body, requests, client)
|
|
134
109
|
ensure
|
|
135
110
|
io_buffer.reset
|
|
136
|
-
uncork_socket client.io
|
|
137
111
|
app_body.close if app_body.respond_to? :close
|
|
138
|
-
client
|
|
139
|
-
after_reply = env[RACK_AFTER_REPLY]
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
112
|
+
client&.tempfile_close
|
|
113
|
+
if after_reply = env[RACK_AFTER_REPLY]
|
|
114
|
+
after_reply.each do |o|
|
|
115
|
+
begin
|
|
116
|
+
o.call
|
|
117
|
+
rescue StandardError => e
|
|
118
|
+
@log_writer.debug_error e
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if response_finished = env[RACK_RESPONSE_FINISHED]
|
|
124
|
+
response_finished.reverse_each do |o|
|
|
125
|
+
begin
|
|
126
|
+
o.call(env, status, headers, error)
|
|
127
|
+
rescue StandardError => e
|
|
128
|
+
@log_writer.debug_error e
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
145
132
|
end
|
|
146
133
|
|
|
147
134
|
# Assembles the headers and prepares the body for actually sending the
|
|
@@ -153,21 +140,16 @@ module Puma
|
|
|
153
140
|
# a call to `Server#lowlevel_error`
|
|
154
141
|
# @param requests [Integer] number of inline requests handled
|
|
155
142
|
# @param client [Puma::Client]
|
|
156
|
-
# @return [
|
|
143
|
+
# @return [:close, :keep_alive, :async]
|
|
157
144
|
def prepare_response(status, headers, res_body, requests, client)
|
|
158
145
|
env = client.env
|
|
159
146
|
socket = client.io
|
|
160
147
|
io_buffer = client.io_buffer
|
|
161
148
|
|
|
162
|
-
return
|
|
149
|
+
return :close if closed_socket?(socket)
|
|
163
150
|
|
|
164
151
|
# Close the connection after a reasonable number of inline requests
|
|
165
|
-
|
|
166
|
-
# This allows Puma to service connections fairly when the number
|
|
167
|
-
# of concurrent connections exceeds the size of the threadpool.
|
|
168
|
-
force_keep_alive = requests < @max_fast_inline ||
|
|
169
|
-
@thread_pool.busy_threads < @max_threads ||
|
|
170
|
-
!client.listener.to_io.wait_readable(0)
|
|
152
|
+
force_keep_alive = @enable_keep_alives && client.requests_served < @max_keep_alive
|
|
171
153
|
|
|
172
154
|
resp_info = str_headers(env, status, headers, res_body, io_buffer, force_keep_alive)
|
|
173
155
|
|
|
@@ -187,7 +169,8 @@ module Puma
|
|
|
187
169
|
elsif res_body.is_a?(File) && res_body.respond_to?(:size)
|
|
188
170
|
body = res_body
|
|
189
171
|
content_length = body.size
|
|
190
|
-
elsif res_body.respond_to?(:to_path) &&
|
|
172
|
+
elsif res_body.respond_to?(:to_path) && (fn = res_body.to_path) &&
|
|
173
|
+
File.readable?(fn)
|
|
191
174
|
body = File.open fn, 'rb'
|
|
192
175
|
content_length = body.size
|
|
193
176
|
close_body = true
|
|
@@ -195,7 +178,7 @@ module Puma
|
|
|
195
178
|
body = res_body
|
|
196
179
|
end
|
|
197
180
|
elsif !res_body.is_a?(::File) && res_body.respond_to?(:to_path) &&
|
|
198
|
-
File.readable?(fn = res_body.to_path)
|
|
181
|
+
(fn = res_body.to_path) && File.readable?(fn = res_body.to_path)
|
|
199
182
|
body = File.open fn, 'rb'
|
|
200
183
|
content_length = body.size
|
|
201
184
|
close_body = true
|
|
@@ -233,8 +216,9 @@ module Puma
|
|
|
233
216
|
|
|
234
217
|
io_buffer << LINE_END
|
|
235
218
|
fast_write_str socket, io_buffer.read_and_reset
|
|
236
|
-
|
|
237
|
-
|
|
219
|
+
|
|
220
|
+
uncork_socket socket.flush
|
|
221
|
+
return keep_alive ? :keep_alive : :close
|
|
238
222
|
end
|
|
239
223
|
else
|
|
240
224
|
if content_length
|
|
@@ -252,25 +236,16 @@ module Puma
|
|
|
252
236
|
# response_hijack.call
|
|
253
237
|
if response_hijack
|
|
254
238
|
fast_write_str socket, io_buffer.read_and_reset
|
|
255
|
-
uncork_socket socket
|
|
239
|
+
uncork_socket socket.flush
|
|
256
240
|
response_hijack.call socket
|
|
257
241
|
return :async
|
|
258
242
|
end
|
|
259
243
|
|
|
260
244
|
fast_write_response socket, body, io_buffer, chunked, content_length.to_i
|
|
261
245
|
body.close if close_body
|
|
262
|
-
keep_alive
|
|
263
|
-
end
|
|
264
246
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
#
|
|
268
|
-
def default_server_port(env)
|
|
269
|
-
if ['on', HTTPS].include?(env[HTTPS_KEY]) || env[HTTP_X_FORWARDED_PROTO].to_s[0...5] == HTTPS || env[HTTP_X_FORWARDED_SCHEME] == HTTPS || env[HTTP_X_FORWARDED_SSL] == "on"
|
|
270
|
-
PORT_443
|
|
271
|
-
else
|
|
272
|
-
PORT_80
|
|
273
|
-
end
|
|
247
|
+
# if we're shutting down, close keep_alive connections
|
|
248
|
+
!shutting_down? && keep_alive ? :keep_alive : :close
|
|
274
249
|
end
|
|
275
250
|
|
|
276
251
|
# Used to write 'early hints', 'no body' responses, 'hijacked' responses,
|
|
@@ -387,6 +362,7 @@ module Puma
|
|
|
387
362
|
end
|
|
388
363
|
end
|
|
389
364
|
socket.flush
|
|
365
|
+
uncork_socket socket
|
|
390
366
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
|
391
367
|
raise ConnectionError, SOCKET_WRITE_ERR_MSG
|
|
392
368
|
rescue Errno::EPIPE, SystemCallError, IOError
|
|
@@ -395,85 +371,6 @@ module Puma
|
|
|
395
371
|
|
|
396
372
|
private :fast_write_str, :fast_write_response
|
|
397
373
|
|
|
398
|
-
# Given a Hash +env+ for the request read from +client+, add
|
|
399
|
-
# and fixup keys to comply with Rack's env guidelines.
|
|
400
|
-
# @param env [Hash] see Puma::Client#env, from request
|
|
401
|
-
# @param client [Puma::Client] only needed for Client#peerip
|
|
402
|
-
#
|
|
403
|
-
def normalize_env(env, client)
|
|
404
|
-
if host = env[HTTP_HOST]
|
|
405
|
-
# host can be a hostname, ipv4 or bracketed ipv6. Followed by an optional port.
|
|
406
|
-
if colon = host.rindex("]:") # IPV6 with port
|
|
407
|
-
env[SERVER_NAME] = host[0, colon+1]
|
|
408
|
-
env[SERVER_PORT] = host[colon+2, host.bytesize]
|
|
409
|
-
elsif !host.start_with?("[") && colon = host.index(":") # not hostname or IPV4 with port
|
|
410
|
-
env[SERVER_NAME] = host[0, colon]
|
|
411
|
-
env[SERVER_PORT] = host[colon+1, host.bytesize]
|
|
412
|
-
else
|
|
413
|
-
env[SERVER_NAME] = host
|
|
414
|
-
env[SERVER_PORT] = default_server_port(env)
|
|
415
|
-
end
|
|
416
|
-
else
|
|
417
|
-
env[SERVER_NAME] = LOCALHOST
|
|
418
|
-
env[SERVER_PORT] = default_server_port(env)
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
unless env[REQUEST_PATH]
|
|
422
|
-
# it might be a dumbass full host request header
|
|
423
|
-
uri = begin
|
|
424
|
-
URI.parse(env[REQUEST_URI])
|
|
425
|
-
rescue URI::InvalidURIError
|
|
426
|
-
raise Puma::HttpParserError
|
|
427
|
-
end
|
|
428
|
-
env[REQUEST_PATH] = uri.path
|
|
429
|
-
|
|
430
|
-
# A nil env value will cause a LintError (and fatal errors elsewhere),
|
|
431
|
-
# so only set the env value if there actually is a value.
|
|
432
|
-
env[QUERY_STRING] = uri.query if uri.query
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
env[PATH_INFO] = env[REQUEST_PATH].to_s # #to_s in case it's nil
|
|
436
|
-
|
|
437
|
-
# From https://www.ietf.org/rfc/rfc3875 :
|
|
438
|
-
# "Script authors should be aware that the REMOTE_ADDR and
|
|
439
|
-
# REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
|
|
440
|
-
# may not identify the ultimate source of the request.
|
|
441
|
-
# They identify the client for the immediate request to the
|
|
442
|
-
# server; that client may be a proxy, gateway, or other
|
|
443
|
-
# intermediary acting on behalf of the actual source client."
|
|
444
|
-
#
|
|
445
|
-
|
|
446
|
-
unless env.key?(REMOTE_ADDR)
|
|
447
|
-
begin
|
|
448
|
-
addr = client.peerip
|
|
449
|
-
rescue Errno::ENOTCONN
|
|
450
|
-
# Client disconnects can result in an inability to get the
|
|
451
|
-
# peeraddr from the socket; default to unspec.
|
|
452
|
-
if client.peer_family == Socket::AF_INET6
|
|
453
|
-
addr = UNSPECIFIED_IPV6
|
|
454
|
-
else
|
|
455
|
-
addr = UNSPECIFIED_IPV4
|
|
456
|
-
end
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
# Set unix socket addrs to localhost
|
|
460
|
-
if addr.empty?
|
|
461
|
-
if client.peer_family == Socket::AF_INET6
|
|
462
|
-
addr = LOCALHOST_IPV6
|
|
463
|
-
else
|
|
464
|
-
addr = LOCALHOST_IPV4
|
|
465
|
-
end
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
env[REMOTE_ADDR] = addr
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
# The legacy HTTP_VERSION header can be sent as a client header.
|
|
472
|
-
# Rack v4 may remove using HTTP_VERSION. If so, remove this line.
|
|
473
|
-
env[HTTP_VERSION] = env[SERVER_PROTOCOL]
|
|
474
|
-
end
|
|
475
|
-
private :normalize_env
|
|
476
|
-
|
|
477
374
|
# @param header_key [#to_s]
|
|
478
375
|
# @return [Boolean]
|
|
479
376
|
#
|
|
@@ -487,56 +384,6 @@ module Puma
|
|
|
487
384
|
def illegal_header_value?(header_value)
|
|
488
385
|
!!(ILLEGAL_HEADER_VALUE_REGEX =~ header_value.to_s)
|
|
489
386
|
end
|
|
490
|
-
private :illegal_header_key?, :illegal_header_value?
|
|
491
|
-
|
|
492
|
-
# Fixup any headers with `,` in the name to have `_` now. We emit
|
|
493
|
-
# headers with `,` in them during the parse phase to avoid ambiguity
|
|
494
|
-
# with the `-` to `_` conversion for critical headers. But here for
|
|
495
|
-
# compatibility, we'll convert them back. This code is written to
|
|
496
|
-
# avoid allocation in the common case (ie there are no headers
|
|
497
|
-
# with `,` in their names), that's why it has the extra conditionals.
|
|
498
|
-
#
|
|
499
|
-
# @note If a normalized version of a `,` header already exists, we ignore
|
|
500
|
-
# the `,` version. This prevents clobbering headers managed by proxies
|
|
501
|
-
# but not by clients (Like X-Forwarded-For).
|
|
502
|
-
#
|
|
503
|
-
# @param env [Hash] see Puma::Client#env, from request, modifies in place
|
|
504
|
-
# @version 5.0.3
|
|
505
|
-
#
|
|
506
|
-
def req_env_post_parse(env)
|
|
507
|
-
to_delete = nil
|
|
508
|
-
to_add = nil
|
|
509
|
-
|
|
510
|
-
env.each do |k,v|
|
|
511
|
-
if k.start_with?("HTTP_") && k.include?(",") && !UNMASKABLE_HEADERS.key?(k)
|
|
512
|
-
if to_delete
|
|
513
|
-
to_delete << k
|
|
514
|
-
else
|
|
515
|
-
to_delete = [k]
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
new_k = k.tr(",", "_")
|
|
519
|
-
if env.key?(new_k)
|
|
520
|
-
next
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
unless to_add
|
|
524
|
-
to_add = {}
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
to_add[new_k] = v
|
|
528
|
-
end
|
|
529
|
-
end
|
|
530
|
-
|
|
531
|
-
if to_delete # rubocop:disable Style/SafeNavigation
|
|
532
|
-
to_delete.each { |k| env.delete(k) }
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
if to_add
|
|
536
|
-
env.merge! to_add
|
|
537
|
-
end
|
|
538
|
-
end
|
|
539
|
-
private :req_env_post_parse
|
|
540
387
|
|
|
541
388
|
# Used in the lambda for env[ `Puma::Const::EARLY_HINTS` ]
|
|
542
389
|
# @param headers [Hash] the headers returned by the Rack application
|
|
@@ -577,7 +424,7 @@ module Puma
|
|
|
577
424
|
# response body
|
|
578
425
|
# @param io_buffer [Puma::IOBuffer] modified inn place
|
|
579
426
|
# @param force_keep_alive [Boolean] 'anded' with keep_alive, based on system
|
|
580
|
-
# status and `@
|
|
427
|
+
# status and `@max_keep_alive`
|
|
581
428
|
# @return [Hash] resp_info
|
|
582
429
|
# @version 5.0.3
|
|
583
430
|
#
|
|
@@ -633,7 +480,8 @@ module Puma
|
|
|
633
480
|
headers.each do |k, vs|
|
|
634
481
|
next if illegal_header_key?(k)
|
|
635
482
|
|
|
636
|
-
|
|
483
|
+
key = k.downcase
|
|
484
|
+
case key
|
|
637
485
|
when CONTENT_LENGTH2
|
|
638
486
|
next if illegal_header_value?(vs)
|
|
639
487
|
# nil.to_i is 0, nil&.to_i is nil
|
|
@@ -660,10 +508,10 @@ module Puma
|
|
|
660
508
|
if ary
|
|
661
509
|
ary.each do |v|
|
|
662
510
|
next if illegal_header_value?(v)
|
|
663
|
-
io_buffer.append
|
|
511
|
+
io_buffer.append key, colon, v, line_ending
|
|
664
512
|
end
|
|
665
513
|
else
|
|
666
|
-
io_buffer.append
|
|
514
|
+
io_buffer.append key, colon, line_ending
|
|
667
515
|
end
|
|
668
516
|
end
|
|
669
517
|
|
data/lib/puma/runner.rb
CHANGED
|
@@ -8,6 +8,9 @@ module Puma
|
|
|
8
8
|
# serve requests. This class spawns a new instance of `Puma::Server` via
|
|
9
9
|
# a call to `start_server`.
|
|
10
10
|
class Runner
|
|
11
|
+
|
|
12
|
+
include ::Puma::Const::PipeRequest
|
|
13
|
+
|
|
11
14
|
def initialize(launcher)
|
|
12
15
|
@launcher = launcher
|
|
13
16
|
@log_writer = launcher.log_writer
|
|
@@ -27,10 +30,9 @@ module Puma
|
|
|
27
30
|
def wakeup!
|
|
28
31
|
return unless @wakeup
|
|
29
32
|
|
|
30
|
-
@wakeup.write
|
|
33
|
+
@wakeup.write PIPE_WAKEUP unless @wakeup.closed?
|
|
31
34
|
|
|
32
35
|
rescue SystemCallError, IOError
|
|
33
|
-
Puma::Util.purge_interrupt_queue
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
def development?
|
|
@@ -68,7 +70,7 @@ module Puma
|
|
|
68
70
|
token = nil if token.empty? || token == 'none'
|
|
69
71
|
end
|
|
70
72
|
|
|
71
|
-
app = Puma::App::Status.new @launcher, token
|
|
73
|
+
app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
|
|
72
74
|
|
|
73
75
|
# A Reactor is not created and nio4r is not loaded when 'queue_requests: false'
|
|
74
76
|
# Use `nil` for events, no hooks in control server
|
|
@@ -90,26 +92,14 @@ module Puma
|
|
|
90
92
|
@control.binder.close_listeners if @control
|
|
91
93
|
end
|
|
92
94
|
|
|
93
|
-
# @!attribute [r] ruby_engine
|
|
94
|
-
def ruby_engine
|
|
95
|
-
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
|
96
|
-
"ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
|
97
|
-
else
|
|
98
|
-
if defined?(RUBY_ENGINE_VERSION)
|
|
99
|
-
"#{RUBY_ENGINE} #{RUBY_ENGINE_VERSION} - ruby #{RUBY_VERSION}"
|
|
100
|
-
else
|
|
101
|
-
"#{RUBY_ENGINE} #{RUBY_VERSION}"
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
95
|
def output_header(mode)
|
|
107
96
|
min_t = @options[:min_threads]
|
|
108
97
|
max_t = @options[:max_threads]
|
|
109
98
|
environment = @options[:environment]
|
|
110
99
|
|
|
111
100
|
log "Puma starting in #{mode} mode..."
|
|
112
|
-
log "* Puma version: #{Puma::Const::PUMA_VERSION} (
|
|
101
|
+
log "* Puma version: #{Puma::Const::PUMA_VERSION} (\"#{Puma::Const::CODE_NAME}\")"
|
|
102
|
+
log "* Ruby version: #{RUBY_DESCRIPTION}"
|
|
113
103
|
log "* Min threads: #{min_t}"
|
|
114
104
|
log "* Max threads: #{max_t}"
|
|
115
105
|
log "* Environment: #{environment}"
|
|
@@ -121,6 +111,14 @@ module Puma
|
|
|
121
111
|
end
|
|
122
112
|
end
|
|
123
113
|
|
|
114
|
+
def warn_ruby_mn_threads
|
|
115
|
+
return if !ENV.key?('RUBY_MN_THREADS')
|
|
116
|
+
|
|
117
|
+
log "! WARNING: Detected `RUBY_MN_THREADS=#{ENV['RUBY_MN_THREADS']}`"
|
|
118
|
+
log "! This setting is known to cause performance regressions with Puma."
|
|
119
|
+
log "! Consider disabling this environment variable: https://github.com/puma/puma/issues/3720"
|
|
120
|
+
end
|
|
121
|
+
|
|
124
122
|
def redirected_io?
|
|
125
123
|
@options[:redirect_stdout] || @options[:redirect_stderr]
|
|
126
124
|
end
|
data/lib/puma/sd_notify.rb
CHANGED
|
@@ -137,10 +137,7 @@ module Puma
|
|
|
137
137
|
ENV.delete("NOTIFY_SOCKET") if unset_env
|
|
138
138
|
|
|
139
139
|
begin
|
|
140
|
-
Addrinfo.unix(sock, :DGRAM).connect
|
|
141
|
-
s.close_on_exec = true
|
|
142
|
-
s.write(state)
|
|
143
|
-
end
|
|
140
|
+
Addrinfo.unix(sock, :DGRAM).connect { |s| s.write state }
|
|
144
141
|
rescue StandardError => e
|
|
145
142
|
raise NotifyError, "#{e.class}: #{e.message}", e.backtrace
|
|
146
143
|
end
|