puma 5.6.4-java → 6.0.0-java
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 +136 -3
- data/README.md +21 -17
- data/bin/puma-wild +1 -1
- data/docs/compile_options.md +34 -0
- data/docs/fork_worker.md +1 -3
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/extconf.rb +18 -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 +63 -24
- 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 +166 -65
- data/ext/puma_http11/puma_http11.c +17 -9
- data/lib/puma/app/status.rb +6 -3
- data/lib/puma/binder.rb +37 -43
- data/lib/puma/cli.rb +11 -17
- data/lib/puma/client.rb +22 -12
- data/lib/puma/cluster/worker.rb +13 -11
- data/lib/puma/cluster/worker_handle.rb +4 -1
- data/lib/puma/cluster.rb +28 -25
- data/lib/puma/configuration.rb +74 -58
- data/lib/puma/const.rb +14 -18
- data/lib/puma/control_cli.rb +21 -18
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +94 -49
- data/lib/puma/error_logger.rb +17 -9
- data/lib/puma/events.rb +6 -126
- data/lib/puma/io_buffer.rb +29 -4
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +107 -156
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +23 -12
- data/lib/puma/minissl.rb +91 -15
- data/lib/puma/null_io.rb +5 -0
- data/lib/puma/plugin/tmp_restart.rb +1 -1
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/rack/builder.rb +4 -4
- data/lib/puma/rack_default.rb +1 -1
- data/lib/puma/reactor.rb +3 -3
- data/lib/puma/request.rb +291 -156
- data/lib/puma/runner.rb +41 -20
- data/lib/puma/server.rb +53 -64
- data/lib/puma/single.rb +10 -10
- data/lib/puma/state_file.rb +2 -4
- data/lib/puma/systemd.rb +3 -2
- data/lib/puma/thread_pool.rb +16 -13
- data/lib/puma/util.rb +12 -14
- data/lib/puma.rb +11 -8
- data/lib/rack/handler/puma.rb +9 -9
- metadata +7 -3
- data/lib/puma/queue_close.rb +0 -26
@@ -36,13 +36,13 @@ static VALUE global_request_method;
|
|
36
36
|
static VALUE global_request_uri;
|
37
37
|
static VALUE global_fragment;
|
38
38
|
static VALUE global_query_string;
|
39
|
-
static VALUE
|
39
|
+
static VALUE global_server_protocol;
|
40
40
|
static VALUE global_request_path;
|
41
41
|
|
42
42
|
/** Defines common length and error messages for input length validation. */
|
43
43
|
#define QUOTE(s) #s
|
44
|
-
#define
|
45
|
-
#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the "
|
44
|
+
#define EXPAND_MAX_LENGTH_VALUE(s) QUOTE(s)
|
45
|
+
#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N " is longer than the " EXPAND_MAX_LENGTH_VALUE(length) " allowed length (was %d)"
|
46
46
|
|
47
47
|
/** Validates the max length of given input and throws an HttpParserError exception if over. */
|
48
48
|
#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR, len); }
|
@@ -52,15 +52,23 @@ static VALUE global_request_path;
|
|
52
52
|
|
53
53
|
|
54
54
|
/* Defines the maximum allowed lengths for various input elements.*/
|
55
|
+
#ifndef PUMA_REQUEST_URI_MAX_LENGTH
|
56
|
+
#define PUMA_REQUEST_URI_MAX_LENGTH (1024 * 12)
|
57
|
+
#endif
|
58
|
+
|
59
|
+
#ifndef PUMA_REQUEST_PATH_MAX_LENGTH
|
60
|
+
#define PUMA_REQUEST_PATH_MAX_LENGTH (8192)
|
61
|
+
#endif
|
62
|
+
|
55
63
|
#ifndef PUMA_QUERY_STRING_MAX_LENGTH
|
56
64
|
#define PUMA_QUERY_STRING_MAX_LENGTH (1024 * 10)
|
57
65
|
#endif
|
58
66
|
|
59
67
|
DEF_MAX_LENGTH(FIELD_NAME, 256);
|
60
68
|
DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
|
61
|
-
DEF_MAX_LENGTH(REQUEST_URI,
|
69
|
+
DEF_MAX_LENGTH(REQUEST_URI, PUMA_REQUEST_URI_MAX_LENGTH);
|
62
70
|
DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
|
63
|
-
DEF_MAX_LENGTH(REQUEST_PATH,
|
71
|
+
DEF_MAX_LENGTH(REQUEST_PATH, PUMA_REQUEST_PATH_MAX_LENGTH);
|
64
72
|
DEF_MAX_LENGTH(QUERY_STRING, PUMA_QUERY_STRING_MAX_LENGTH);
|
65
73
|
DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
|
66
74
|
|
@@ -236,10 +244,10 @@ void query_string(puma_parser* hp, const char *at, size_t length)
|
|
236
244
|
rb_hash_aset(hp->request, global_query_string, val);
|
237
245
|
}
|
238
246
|
|
239
|
-
void
|
247
|
+
void server_protocol(puma_parser* hp, const char *at, size_t length)
|
240
248
|
{
|
241
249
|
VALUE val = rb_str_new(at, length);
|
242
|
-
rb_hash_aset(hp->request,
|
250
|
+
rb_hash_aset(hp->request, global_server_protocol, val);
|
243
251
|
}
|
244
252
|
|
245
253
|
/** Finalizes the request header to have a bunch of stuff that's
|
@@ -281,7 +289,7 @@ VALUE HttpParser_alloc(VALUE klass)
|
|
281
289
|
hp->fragment = fragment;
|
282
290
|
hp->request_path = request_path;
|
283
291
|
hp->query_string = query_string;
|
284
|
-
hp->
|
292
|
+
hp->server_protocol = server_protocol;
|
285
293
|
hp->header_done = header_done;
|
286
294
|
hp->request = Qnil;
|
287
295
|
|
@@ -461,7 +469,7 @@ void Init_puma_http11(void)
|
|
461
469
|
DEF_GLOBAL(request_uri, "REQUEST_URI");
|
462
470
|
DEF_GLOBAL(fragment, "FRAGMENT");
|
463
471
|
DEF_GLOBAL(query_string, "QUERY_STRING");
|
464
|
-
DEF_GLOBAL(
|
472
|
+
DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
|
465
473
|
DEF_GLOBAL(request_path, "REQUEST_PATH");
|
466
474
|
|
467
475
|
eHttpParserError = rb_define_class_under(mPuma, "HttpParserError", rb_eIOError);
|
data/lib/puma/app/status.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
require_relative '../json_serialization'
|
3
3
|
|
4
4
|
module Puma
|
5
5
|
module App
|
@@ -39,6 +39,9 @@ module Puma
|
|
39
39
|
when 'phased-restart'
|
40
40
|
@launcher.phased_restart ? 200 : 404
|
41
41
|
|
42
|
+
when 'refork'
|
43
|
+
@launcher.refork ? 200 : 404
|
44
|
+
|
42
45
|
when 'reload-worker-directory'
|
43
46
|
@launcher.send(:reload_worker_directory) ? 200 : 404
|
44
47
|
|
@@ -82,8 +85,8 @@ module Puma
|
|
82
85
|
|
83
86
|
def rack_response(status, body, content_type='application/json')
|
84
87
|
headers = {
|
85
|
-
'
|
86
|
-
'
|
88
|
+
'content-type' => content_type,
|
89
|
+
'content-length' => body.bytesize.to_s
|
87
90
|
}
|
88
91
|
|
89
92
|
[status, headers, [body]]
|
data/lib/puma/binder.rb
CHANGED
@@ -3,24 +3,15 @@
|
|
3
3
|
require 'uri'
|
4
4
|
require 'socket'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require_relative 'const'
|
7
|
+
require_relative 'util'
|
8
|
+
require_relative 'configuration'
|
9
9
|
|
10
10
|
module Puma
|
11
11
|
|
12
12
|
if HAS_SSL
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Odd bug in 'pure Ruby' nio4r version 2.5.2, which installs with Ruby 2.3.
|
17
|
-
# NIO doesn't create any OpenSSL objects, but it rescues an OpenSSL error.
|
18
|
-
# The bug was that it did not require openssl.
|
19
|
-
# @todo remove when Ruby 2.3 support is dropped
|
20
|
-
#
|
21
|
-
if windows? && RbConfig::CONFIG['ruby_version'] == '2.3.0'
|
22
|
-
require 'openssl'
|
23
|
-
end
|
13
|
+
require_relative 'minissl'
|
14
|
+
require_relative 'minissl/context_builder'
|
24
15
|
end
|
25
16
|
|
26
17
|
class Binder
|
@@ -28,8 +19,8 @@ module Puma
|
|
28
19
|
|
29
20
|
RACK_VERSION = [1,6].freeze
|
30
21
|
|
31
|
-
def initialize(
|
32
|
-
@
|
22
|
+
def initialize(log_writer, conf = Configuration.new)
|
23
|
+
@log_writer = log_writer
|
33
24
|
@conf = conf
|
34
25
|
@listeners = []
|
35
26
|
@inherited_fds = {}
|
@@ -38,7 +29,7 @@ module Puma
|
|
38
29
|
|
39
30
|
@proto_env = {
|
40
31
|
"rack.version".freeze => RACK_VERSION,
|
41
|
-
"rack.errors".freeze =>
|
32
|
+
"rack.errors".freeze => log_writer.stderr,
|
42
33
|
"rack.multithread".freeze => conf.options[:max_threads] > 1,
|
43
34
|
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
44
35
|
"rack.run_once".freeze => false,
|
@@ -51,7 +42,6 @@ module Puma
|
|
51
42
|
# infer properly.
|
52
43
|
|
53
44
|
"QUERY_STRING".freeze => "",
|
54
|
-
SERVER_PROTOCOL => HTTP_11,
|
55
45
|
SERVER_SOFTWARE => PUMA_SERVER_STRING,
|
56
46
|
GATEWAY_INTERFACE => CGI_VER
|
57
47
|
}
|
@@ -80,7 +70,7 @@ module Puma
|
|
80
70
|
# @!attribute [r] connected_ports
|
81
71
|
# @version 5.0.0
|
82
72
|
def connected_ports
|
83
|
-
ios.map { |io| io.addr[1] }.uniq
|
73
|
+
t = ios.map { |io| io.addr[1] }; t.uniq!; t
|
84
74
|
end
|
85
75
|
|
86
76
|
# @version 5.0.0
|
@@ -98,7 +88,7 @@ module Puma
|
|
98
88
|
# @version 5.0.0
|
99
89
|
#
|
100
90
|
def create_activated_fds(env_hash)
|
101
|
-
@
|
91
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
102
92
|
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
103
93
|
env_hash['LISTEN_FDS'].to_i.times do |index|
|
104
94
|
sock = TCPServer.for_fd(socket_activation_fd(index))
|
@@ -106,11 +96,11 @@ module Puma
|
|
106
96
|
[:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
|
107
97
|
rescue ArgumentError # Try to parse as a port/ip
|
108
98
|
port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
|
109
|
-
addr = "[#{addr}]" if addr
|
99
|
+
addr = "[#{addr}]" if addr&.include? ':'
|
110
100
|
[:tcp, addr, port]
|
111
101
|
end
|
112
102
|
@activated_sockets[key] = sock
|
113
|
-
@
|
103
|
+
@log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
|
114
104
|
end
|
115
105
|
["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
|
116
106
|
end
|
@@ -152,17 +142,18 @@ module Puma
|
|
152
142
|
end
|
153
143
|
end
|
154
144
|
|
155
|
-
def parse(binds,
|
145
|
+
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
146
|
+
log_writer ||= @log_writer
|
156
147
|
binds.each do |str|
|
157
148
|
uri = URI.parse str
|
158
149
|
case uri.scheme
|
159
150
|
when "tcp"
|
160
151
|
if fd = @inherited_fds.delete(str)
|
161
152
|
io = inherit_tcp_listener uri.host, uri.port, fd
|
162
|
-
|
153
|
+
log_writer.log "* Inherited #{str}"
|
163
154
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
164
155
|
io = inherit_tcp_listener uri.host, uri.port, sock
|
165
|
-
|
156
|
+
log_writer.log "* Activated #{str}"
|
166
157
|
else
|
167
158
|
ios_len = @ios.length
|
168
159
|
params = Util.parse_query uri.query
|
@@ -174,7 +165,7 @@ module Puma
|
|
174
165
|
|
175
166
|
@ios[ios_len..-1].each do |i|
|
176
167
|
addr = loc_addr_str i
|
177
|
-
|
168
|
+
log_writer.log "* #{log_msg} on http://#{addr}"
|
178
169
|
end
|
179
170
|
end
|
180
171
|
|
@@ -189,14 +180,14 @@ module Puma
|
|
189
180
|
end
|
190
181
|
|
191
182
|
if fd = @inherited_fds.delete(str)
|
192
|
-
@unix_paths << path unless abstract
|
183
|
+
@unix_paths << path unless abstract || File.exist?(path)
|
193
184
|
io = inherit_unix_listener path, fd
|
194
|
-
|
185
|
+
log_writer.log "* Inherited #{str}"
|
195
186
|
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
196
187
|
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
197
188
|
@unix_paths << path unless abstract || File.exist?(path)
|
198
189
|
io = inherit_unix_listener path, sock
|
199
|
-
|
190
|
+
log_writer.log "* Activated #{str}"
|
200
191
|
else
|
201
192
|
umask = nil
|
202
193
|
mode = nil
|
@@ -220,11 +211,12 @@ module Puma
|
|
220
211
|
|
221
212
|
@unix_paths << path unless abstract || File.exist?(path)
|
222
213
|
io = add_unix_listener path, umask, mode, backlog
|
223
|
-
|
214
|
+
log_writer.log "* #{log_msg} on #{str}"
|
224
215
|
end
|
225
216
|
|
226
217
|
@listeners << [str, io]
|
227
218
|
when "ssl"
|
219
|
+
cert_key = %w[cert key]
|
228
220
|
|
229
221
|
raise "Puma compiled without SSL support" unless HAS_SSL
|
230
222
|
|
@@ -233,28 +225,29 @@ module Puma
|
|
233
225
|
# If key and certs are not defined and localhost gem is required.
|
234
226
|
# localhost gem will be used for self signed
|
235
227
|
# Load localhost authority if not loaded.
|
236
|
-
|
228
|
+
# Ruby 3 `values_at` accepts an array, earlier do not
|
229
|
+
if params.values_at(*cert_key).all? { |v| v.to_s.empty? }
|
237
230
|
ctx = localhost_authority && localhost_authority_context
|
238
231
|
end
|
239
232
|
|
240
233
|
ctx ||=
|
241
234
|
begin
|
242
235
|
# Extract cert_pem and key_pem from options[:store] if present
|
243
|
-
|
244
|
-
if params[v]
|
236
|
+
cert_key.each do |v|
|
237
|
+
if params[v]&.start_with?('store:')
|
245
238
|
index = Integer(params.delete(v).split('store:').last)
|
246
239
|
params["#{v}_pem"] = @conf.options[:store][index]
|
247
240
|
end
|
248
241
|
end
|
249
|
-
MiniSSL::ContextBuilder.new(params, @
|
242
|
+
MiniSSL::ContextBuilder.new(params, @log_writer).context
|
250
243
|
end
|
251
244
|
|
252
245
|
if fd = @inherited_fds.delete(str)
|
253
|
-
|
246
|
+
log_writer.log "* Inherited #{str}"
|
254
247
|
io = inherit_ssl_listener fd, ctx
|
255
248
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
256
249
|
io = inherit_ssl_listener sock, ctx
|
257
|
-
|
250
|
+
log_writer.log "* Activated #{str}"
|
258
251
|
else
|
259
252
|
ios_len = @ios.length
|
260
253
|
backlog = params.fetch('backlog', 1024).to_i
|
@@ -262,20 +255,20 @@ module Puma
|
|
262
255
|
|
263
256
|
@ios[ios_len..-1].each do |i|
|
264
257
|
addr = loc_addr_str i
|
265
|
-
|
258
|
+
log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
|
266
259
|
end
|
267
260
|
end
|
268
261
|
|
269
262
|
@listeners << [str, io] if io
|
270
263
|
else
|
271
|
-
|
264
|
+
log_writer.error "Invalid URI: #{str}"
|
272
265
|
end
|
273
266
|
end
|
274
267
|
|
275
268
|
# If we inherited fds but didn't use them (because of a
|
276
269
|
# configuration change), then be sure to close them.
|
277
270
|
@inherited_fds.each do |str, fd|
|
278
|
-
|
271
|
+
log_writer.log "* Closing unused inherited connection: #{str}"
|
279
272
|
|
280
273
|
begin
|
281
274
|
IO.for_fd(fd).close
|
@@ -295,7 +288,7 @@ module Puma
|
|
295
288
|
fds = @ios.map(&:to_i)
|
296
289
|
@activated_sockets.each do |key, sock|
|
297
290
|
next if fds.include? sock.to_i
|
298
|
-
|
291
|
+
log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
|
299
292
|
begin
|
300
293
|
sock.close
|
301
294
|
rescue SystemCallError
|
@@ -319,7 +312,7 @@ module Puma
|
|
319
312
|
local_certificates_path = File.expand_path("~/.localhost")
|
320
313
|
[File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
|
321
314
|
end
|
322
|
-
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @
|
315
|
+
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context
|
323
316
|
end
|
324
317
|
|
325
318
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -482,9 +475,10 @@ module Puma
|
|
482
475
|
|
483
476
|
# @!attribute [r] loopback_addresses
|
484
477
|
def loopback_addresses
|
485
|
-
Socket.ip_address_list.select do |addrinfo|
|
478
|
+
t = Socket.ip_address_list.select do |addrinfo|
|
486
479
|
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
487
|
-
end
|
480
|
+
end
|
481
|
+
t.map! { |addrinfo| addrinfo.ip_address }; t.uniq!; t
|
488
482
|
end
|
489
483
|
|
490
484
|
def loc_addr_str(io)
|
data/lib/puma/cli.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
require 'optparse'
|
4
4
|
require 'uri'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require_relative '../puma'
|
7
|
+
require_relative 'configuration'
|
8
|
+
require_relative 'launcher'
|
9
|
+
require_relative 'const'
|
10
|
+
require_relative 'log_writer'
|
11
11
|
|
12
12
|
module Puma
|
13
13
|
class << self
|
@@ -21,19 +21,13 @@ module Puma
|
|
21
21
|
# Handles invoke a Puma::Server in a command line style.
|
22
22
|
#
|
23
23
|
class CLI
|
24
|
-
# @deprecated 6.0.0
|
25
|
-
KEYS_NOT_TO_PERSIST_IN_STATE = Launcher::KEYS_NOT_TO_PERSIST_IN_STATE
|
26
|
-
|
27
24
|
# Create a new CLI object using +argv+ as the command line
|
28
25
|
# arguments.
|
29
26
|
#
|
30
|
-
|
31
|
-
# this object will report status on.
|
32
|
-
#
|
33
|
-
def initialize(argv, events=Events.stdio)
|
27
|
+
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new)
|
34
28
|
@debug = false
|
35
29
|
@argv = argv.dup
|
36
|
-
|
30
|
+
@log_writer = log_writer
|
37
31
|
@events = events
|
38
32
|
|
39
33
|
@conf = nil
|
@@ -69,7 +63,7 @@ module Puma
|
|
69
63
|
end
|
70
64
|
end
|
71
65
|
|
72
|
-
@launcher = Puma::Launcher.new(@conf, :events => @events, :argv => argv)
|
66
|
+
@launcher = Puma::Launcher.new(@conf, :log_writer => @log_writer, :events => @events, :argv => argv)
|
73
67
|
end
|
74
68
|
|
75
69
|
attr_reader :launcher
|
@@ -83,7 +77,7 @@ module Puma
|
|
83
77
|
|
84
78
|
private
|
85
79
|
def unsupported(str)
|
86
|
-
@
|
80
|
+
@log_writer.error(str)
|
87
81
|
raise UnsupportedOption
|
88
82
|
end
|
89
83
|
|
@@ -152,7 +146,7 @@ module Puma
|
|
152
146
|
|
153
147
|
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
154
148
|
"Use -b for more advanced options" do |arg|
|
155
|
-
user_config.bind "tcp://#{Configuration::
|
149
|
+
user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
|
156
150
|
end
|
157
151
|
|
158
152
|
o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
|
@@ -186,7 +180,7 @@ module Puma
|
|
186
180
|
end
|
187
181
|
|
188
182
|
o.on "-s", "--silent", "Do not log prompt messages other than errors" do
|
189
|
-
@
|
183
|
+
@log_writer = LogWriter.new(NullIO.new, $stderr)
|
190
184
|
end
|
191
185
|
|
192
186
|
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|
data/lib/puma/client.rb
CHANGED
@@ -8,7 +8,7 @@ class IO
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
require_relative 'detect'
|
12
12
|
require 'tempfile'
|
13
13
|
require 'forwardable'
|
14
14
|
|
@@ -25,6 +25,9 @@ module Puma
|
|
25
25
|
|
26
26
|
class HttpParserError501 < IOError; end
|
27
27
|
|
28
|
+
#———————————————————————— DO NOT USE — this class is for internal use only ———
|
29
|
+
|
30
|
+
|
28
31
|
# An instance of this class represents a unique request from a client.
|
29
32
|
# For example, this could be a web request from a browser or from CURL.
|
30
33
|
#
|
@@ -38,7 +41,7 @@ module Puma
|
|
38
41
|
# the header and body are fully buffered via the `try_to_finish` method.
|
39
42
|
# They can be used to "time out" a response via the `timeout_at` reader.
|
40
43
|
#
|
41
|
-
class Client
|
44
|
+
class Client # :nodoc:
|
42
45
|
|
43
46
|
# this tests all values but the last, which must be chunked
|
44
47
|
ALLOWED_TRANSFER_ENCODING = %w[compress deflate gzip].freeze
|
@@ -63,11 +66,7 @@ module Puma
|
|
63
66
|
@io = io
|
64
67
|
@to_io = io.to_io
|
65
68
|
@proto_env = env
|
66
|
-
|
67
|
-
@env = nil
|
68
|
-
else
|
69
|
-
@env = env.dup
|
70
|
-
end
|
69
|
+
@env = env ? env.dup : nil
|
71
70
|
|
72
71
|
@parser = HttpParser.new
|
73
72
|
@parsed_bytes = 0
|
@@ -86,6 +85,7 @@ module Puma
|
|
86
85
|
@hijacked = false
|
87
86
|
|
88
87
|
@peerip = nil
|
88
|
+
@peer_family = nil
|
89
89
|
@listener = nil
|
90
90
|
@remote_addr_header = nil
|
91
91
|
@expect_proxy_proto = false
|
@@ -273,7 +273,7 @@ module Puma
|
|
273
273
|
return @peerip if @peerip
|
274
274
|
|
275
275
|
if @remote_addr_header
|
276
|
-
hdr = (@env[@remote_addr_header] ||
|
276
|
+
hdr = (@env[@remote_addr_header] || @io.peeraddr.last).split(/[\s,]/).first
|
277
277
|
@peerip = hdr
|
278
278
|
return hdr
|
279
279
|
end
|
@@ -281,6 +281,16 @@ module Puma
|
|
281
281
|
@peerip ||= @io.peeraddr.last
|
282
282
|
end
|
283
283
|
|
284
|
+
def peer_family
|
285
|
+
return @peer_family if @peer_family
|
286
|
+
|
287
|
+
@peer_family ||= begin
|
288
|
+
@io.local_address.afamily
|
289
|
+
rescue
|
290
|
+
Socket::AF_INET
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
284
294
|
# Returns true if the persistent connection can be closed immediately
|
285
295
|
# without waiting for the configured idle/shutdown timeout.
|
286
296
|
# @version 5.0.0
|
@@ -304,7 +314,7 @@ module Puma
|
|
304
314
|
private
|
305
315
|
|
306
316
|
def setup_body
|
307
|
-
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
317
|
+
@body_read_start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond)
|
308
318
|
|
309
319
|
if @env[HTTP_EXPECT] == CONTINUE
|
310
320
|
# TODO allow a hook here to check the headers before
|
@@ -348,7 +358,7 @@ module Puma
|
|
348
358
|
|
349
359
|
if cl
|
350
360
|
# cannot contain characters that are not \d
|
351
|
-
if cl
|
361
|
+
if CONTENT_LENGTH_VALUE_INVALID.match? cl
|
352
362
|
raise HttpParserError, "Invalid Content-Length: #{cl.inspect}"
|
353
363
|
end
|
354
364
|
else
|
@@ -513,7 +523,7 @@ module Puma
|
|
513
523
|
# Puma doesn't process chunk extensions, but should parse if they're
|
514
524
|
# present, which is the reason for the semicolon regex
|
515
525
|
chunk_hex = line.strip[/\A[^;]+/]
|
516
|
-
if chunk_hex
|
526
|
+
if CHUNK_SIZE_INVALID.match? chunk_hex
|
517
527
|
raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
|
518
528
|
end
|
519
529
|
len = chunk_hex.to_i(16)
|
@@ -576,7 +586,7 @@ module Puma
|
|
576
586
|
|
577
587
|
def set_ready
|
578
588
|
if @body_read_start
|
579
|
-
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :
|
589
|
+
@env['puma.request_body_wait'] = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - @body_read_start
|
580
590
|
end
|
581
591
|
@requests_served += 1
|
582
592
|
@ready = true
|
data/lib/puma/cluster/worker.rb
CHANGED
@@ -2,27 +2,29 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Puma::Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class is instantiated by the `Puma::Cluster` and represents a single
|
6
9
|
# worker process.
|
7
10
|
#
|
8
11
|
# At the core of this class is running an instance of `Puma::Server` which
|
9
12
|
# gets created via the `start_server` method from the `Puma::Runner` class
|
10
13
|
# that this inherits from.
|
11
|
-
class Worker < Puma::Runner
|
14
|
+
class Worker < Puma::Runner # :nodoc:
|
12
15
|
attr_reader :index, :master
|
13
16
|
|
14
17
|
def initialize(index:, master:, launcher:, pipes:, server: nil)
|
15
|
-
super
|
18
|
+
super(launcher)
|
16
19
|
|
17
20
|
@index = index
|
18
21
|
@master = master
|
19
|
-
@launcher = launcher
|
20
|
-
@options = launcher.options
|
21
22
|
@check_pipe = pipes[:check_pipe]
|
22
23
|
@worker_write = pipes[:worker_write]
|
23
24
|
@fork_pipe = pipes[:fork_pipe]
|
24
25
|
@wakeup = pipes[:wakeup]
|
25
26
|
@server = server
|
27
|
+
@hook_data = {}
|
26
28
|
end
|
27
29
|
|
28
30
|
def run
|
@@ -52,13 +54,14 @@ module Puma
|
|
52
54
|
|
53
55
|
# Invoke any worker boot hooks so they can get
|
54
56
|
# things in shape before booting the app.
|
55
|
-
@
|
57
|
+
@config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
|
56
58
|
|
57
59
|
begin
|
58
60
|
server = @server ||= start_server
|
59
61
|
rescue Exception => e
|
60
62
|
log "! Unable to start worker"
|
61
|
-
log e
|
63
|
+
log e
|
64
|
+
log e.backtrace.join("\n ")
|
62
65
|
exit 1
|
63
66
|
end
|
64
67
|
|
@@ -83,8 +86,7 @@ module Puma
|
|
83
86
|
if restart_server.length > 0
|
84
87
|
restart_server.clear
|
85
88
|
server.begin_restart(true)
|
86
|
-
@
|
87
|
-
Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
|
89
|
+
@config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
|
88
90
|
end
|
89
91
|
elsif idx == 0 # restart server
|
90
92
|
restart_server << true << false
|
@@ -138,7 +140,7 @@ module Puma
|
|
138
140
|
|
139
141
|
# Invoke any worker shutdown hooks so they can prevent the worker
|
140
142
|
# exiting until any background operations are completed
|
141
|
-
@
|
143
|
+
@config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
|
142
144
|
ensure
|
143
145
|
@worker_write << "t#{Process.pid}\n" rescue nil
|
144
146
|
@worker_write.close
|
@@ -147,7 +149,7 @@ module Puma
|
|
147
149
|
private
|
148
150
|
|
149
151
|
def spawn_worker(idx)
|
150
|
-
@
|
152
|
+
@config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
|
151
153
|
|
152
154
|
pid = fork do
|
153
155
|
new_worker = Worker.new index: idx,
|
@@ -165,7 +167,7 @@ module Puma
|
|
165
167
|
exit! 1
|
166
168
|
end
|
167
169
|
|
168
|
-
@
|
170
|
+
@config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
|
169
171
|
pid
|
170
172
|
end
|
171
173
|
end
|
@@ -2,12 +2,15 @@
|
|
2
2
|
|
3
3
|
module Puma
|
4
4
|
class Cluster < Runner
|
5
|
+
#—————————————————————— DO NOT USE — this class is for internal use only ———
|
6
|
+
|
7
|
+
|
5
8
|
# This class represents a worker process from the perspective of the puma
|
6
9
|
# master process. It contains information about the process and its health
|
7
10
|
# and it exposes methods to control the process via IPC. It does not
|
8
11
|
# include the actual logic executed by the worker process itself. For that,
|
9
12
|
# see Puma::Cluster::Worker.
|
10
|
-
class WorkerHandle
|
13
|
+
class WorkerHandle # :nodoc:
|
11
14
|
def initialize(idx, pid, phase, options)
|
12
15
|
@index = idx
|
13
16
|
@pid = pid
|