puma 3.11.4 → 6.0.1
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 +1717 -432
- data/LICENSE +23 -20
- data/README.md +190 -64
- data/bin/puma-wild +3 -9
- data/docs/architecture.md +59 -21
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +69 -58
- data/docs/fork_worker.md +31 -0
- 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 +9 -0
- data/{tools → docs}/jungle/rc.d/README.md +1 -1
- data/{tools → docs}/jungle/rc.d/puma +2 -2
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/docs/kubernetes.md +66 -0
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +22 -12
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +47 -22
- data/docs/signals.md +13 -11
- data/docs/stats.md +142 -0
- data/docs/systemd.md +95 -120
- 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 +2 -2
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +61 -3
- data/ext/puma_http11/http11_parser.c +106 -118
- data/ext/puma_http11/http11_parser.h +2 -2
- data/ext/puma_http11/http11_parser.java.rl +22 -38
- data/ext/puma_http11/http11_parser.rl +6 -4
- data/ext/puma_http11/http11_parser_common.rl +6 -6
- data/ext/puma_http11/mini_ssl.c +376 -93
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +84 -99
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +250 -88
- data/ext/puma_http11/puma_http11.c +49 -57
- data/lib/puma/app/status.rb +71 -49
- data/lib/puma/binder.rb +243 -148
- data/lib/puma/cli.rb +50 -36
- data/lib/puma/client.rb +373 -233
- data/lib/puma/cluster/worker.rb +175 -0
- data/lib/puma/cluster/worker_handle.rb +97 -0
- data/lib/puma/cluster.rb +268 -235
- data/lib/puma/commonlogger.rb +4 -2
- data/lib/puma/configuration.rb +116 -88
- data/lib/puma/const.rb +49 -30
- data/lib/puma/control_cli.rb +123 -76
- data/lib/puma/detect.rb +33 -2
- data/lib/puma/dsl.rb +685 -135
- data/lib/puma/error_logger.rb +112 -0
- data/lib/puma/events.rb +17 -111
- data/lib/puma/io_buffer.rb +44 -5
- data/lib/puma/jruby_restart.rb +4 -59
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +196 -130
- data/lib/puma/log_writer.rb +137 -0
- data/lib/puma/minissl/context_builder.rb +92 -0
- data/lib/puma/minissl.rb +249 -69
- data/lib/puma/null_io.rb +20 -1
- data/lib/puma/plugin/tmp_restart.rb +3 -1
- data/lib/puma/plugin.rb +9 -13
- data/lib/puma/rack/builder.rb +8 -9
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +3 -1
- data/lib/puma/reactor.rb +90 -187
- data/lib/puma/request.rb +644 -0
- data/lib/puma/runner.rb +94 -71
- data/lib/puma/server.rb +337 -715
- data/lib/puma/single.rb +27 -72
- data/lib/puma/state_file.rb +46 -7
- data/lib/puma/systemd.rb +47 -0
- data/lib/puma/thread_pool.rb +184 -93
- data/lib/puma/util.rb +23 -10
- data/lib/puma.rb +60 -3
- data/lib/rack/handler/puma.rb +17 -15
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +0 -1
- metadata +53 -33
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- data/lib/puma/tcp_logger.rb +0 -39
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/binder.rb
CHANGED
@@ -1,17 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'socket'
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
+
require_relative 'const'
|
7
|
+
require_relative 'util'
|
8
|
+
require_relative 'configuration'
|
6
9
|
|
7
10
|
module Puma
|
11
|
+
|
12
|
+
if HAS_SSL
|
13
|
+
require_relative 'minissl'
|
14
|
+
require_relative 'minissl/context_builder'
|
15
|
+
end
|
16
|
+
|
8
17
|
class Binder
|
9
18
|
include Puma::Const
|
10
19
|
|
11
|
-
RACK_VERSION = [1,
|
20
|
+
RACK_VERSION = [1,6].freeze
|
12
21
|
|
13
|
-
def initialize(
|
14
|
-
@
|
22
|
+
def initialize(log_writer, conf = Configuration.new)
|
23
|
+
@log_writer = log_writer
|
24
|
+
@conf = conf
|
15
25
|
@listeners = []
|
16
26
|
@inherited_fds = {}
|
17
27
|
@activated_sockets = {}
|
@@ -19,10 +29,11 @@ module Puma
|
|
19
29
|
|
20
30
|
@proto_env = {
|
21
31
|
"rack.version".freeze => RACK_VERSION,
|
22
|
-
"rack.errors".freeze =>
|
23
|
-
"rack.multithread".freeze =>
|
24
|
-
"rack.multiprocess".freeze =>
|
32
|
+
"rack.errors".freeze => log_writer.stderr,
|
33
|
+
"rack.multithread".freeze => conf.options[:max_threads] > 1,
|
34
|
+
"rack.multiprocess".freeze => conf.options[:workers] >= 1,
|
25
35
|
"rack.run_once".freeze => false,
|
36
|
+
RACK_URL_SCHEME => conf.options[:rack_url_scheme],
|
26
37
|
"SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
|
27
38
|
|
28
39
|
# I'd like to set a default CONTENT_TYPE here but some things
|
@@ -31,16 +42,22 @@ module Puma
|
|
31
42
|
# infer properly.
|
32
43
|
|
33
44
|
"QUERY_STRING".freeze => "",
|
34
|
-
SERVER_PROTOCOL => HTTP_11,
|
35
45
|
SERVER_SOFTWARE => PUMA_SERVER_STRING,
|
36
46
|
GATEWAY_INTERFACE => CGI_VER
|
37
47
|
}
|
38
48
|
|
39
49
|
@envs = {}
|
40
50
|
@ios = []
|
51
|
+
localhost_authority
|
41
52
|
end
|
42
53
|
|
43
|
-
attr_reader :
|
54
|
+
attr_reader :ios
|
55
|
+
|
56
|
+
# @version 5.0.0
|
57
|
+
attr_reader :activated_sockets, :envs, :inherited_fds, :listeners, :proto_env, :unix_paths
|
58
|
+
|
59
|
+
# @version 5.0.0
|
60
|
+
attr_writer :ios, :listeners
|
44
61
|
|
45
62
|
def env(sock)
|
46
63
|
@envs.fetch(sock, @proto_env)
|
@@ -48,76 +65,130 @@ module Puma
|
|
48
65
|
|
49
66
|
def close
|
50
67
|
@ios.each { |i| i.close }
|
51
|
-
@unix_paths.each { |i| File.unlink i }
|
52
68
|
end
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
70
|
+
# @!attribute [r] connected_ports
|
71
|
+
# @version 5.0.0
|
72
|
+
def connected_ports
|
73
|
+
t = ios.map { |io| io.addr[1] }; t.uniq!; t
|
74
|
+
end
|
75
|
+
|
76
|
+
# @version 5.0.0
|
77
|
+
def create_inherited_fds(env_hash)
|
78
|
+
env_hash.select {|k,v| k =~ /PUMA_INHERIT_\d+/}.each do |_k, v|
|
79
|
+
fd, url = v.split(":", 2)
|
80
|
+
@inherited_fds[url] = fd.to_i
|
81
|
+
end.keys # pass keys back for removal
|
82
|
+
end
|
83
|
+
|
84
|
+
# systemd socket activation.
|
85
|
+
# LISTEN_FDS = number of listening sockets. e.g. 2 means accept on 2 sockets w/descriptors 3 and 4.
|
86
|
+
# LISTEN_PID = PID of the service process, aka us
|
87
|
+
# @see https://www.freedesktop.org/software/systemd/man/systemd-socket-activate.html
|
88
|
+
# @version 5.0.0
|
89
|
+
#
|
90
|
+
def create_activated_fds(env_hash)
|
91
|
+
@log_writer.debug "ENV['LISTEN_FDS'] #{ENV['LISTEN_FDS'].inspect} env_hash['LISTEN_PID'] #{env_hash['LISTEN_PID'].inspect}"
|
92
|
+
return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
|
93
|
+
env_hash['LISTEN_FDS'].to_i.times do |index|
|
94
|
+
sock = TCPServer.for_fd(socket_activation_fd(index))
|
95
|
+
key = begin # Try to parse as a path
|
96
|
+
[:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
|
97
|
+
rescue ArgumentError # Try to parse as a port/ip
|
98
|
+
port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
|
99
|
+
addr = "[#{addr}]" if addr&.include? ':'
|
100
|
+
[:tcp, addr, port]
|
79
101
|
end
|
102
|
+
@activated_sockets[key] = sock
|
103
|
+
@log_writer.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
|
80
104
|
end
|
105
|
+
["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
|
106
|
+
end
|
107
|
+
|
108
|
+
# Synthesize binds from systemd socket activation
|
109
|
+
#
|
110
|
+
# When systemd socket activation is enabled, it can be tedious to keep the
|
111
|
+
# binds in sync. This method can synthesize any binds based on the received
|
112
|
+
# activated sockets. Any existing matching binds will be respected.
|
113
|
+
#
|
114
|
+
# When only_matching is true in, all binds that do not match an activated
|
115
|
+
# socket is removed in place.
|
116
|
+
#
|
117
|
+
# It's a noop if no activated sockets were received.
|
118
|
+
def synthesize_binds_from_activated_fs(binds, only_matching)
|
119
|
+
return binds unless activated_sockets.any?
|
81
120
|
|
82
|
-
|
83
|
-
|
121
|
+
activated_binds = []
|
122
|
+
|
123
|
+
activated_sockets.keys.each do |proto, addr, port|
|
124
|
+
if port
|
125
|
+
tcp_url = "#{proto}://#{addr}:#{port}"
|
126
|
+
ssl_url = "ssl://#{addr}:#{port}"
|
127
|
+
ssl_url_prefix = "#{ssl_url}?"
|
128
|
+
|
129
|
+
existing = binds.find { |bind| bind == tcp_url || bind == ssl_url || bind.start_with?(ssl_url_prefix) }
|
130
|
+
|
131
|
+
activated_binds << (existing || tcp_url)
|
132
|
+
else
|
133
|
+
# TODO: can there be a SSL bind without a port?
|
134
|
+
activated_binds << "#{proto}://#{addr}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if only_matching
|
139
|
+
activated_binds
|
140
|
+
else
|
141
|
+
binds | activated_binds
|
84
142
|
end
|
85
143
|
end
|
86
144
|
|
87
|
-
def parse(binds,
|
145
|
+
def parse(binds, log_writer = nil, log_msg = 'Listening')
|
146
|
+
log_writer ||= @log_writer
|
88
147
|
binds.each do |str|
|
89
148
|
uri = URI.parse str
|
90
149
|
case uri.scheme
|
91
150
|
when "tcp"
|
92
151
|
if fd = @inherited_fds.delete(str)
|
93
|
-
logger.log "* Inherited #{str}"
|
94
152
|
io = inherit_tcp_listener uri.host, uri.port, fd
|
153
|
+
log_writer.log "* Inherited #{str}"
|
95
154
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
96
|
-
logger.log "* Activated #{str}"
|
97
155
|
io = inherit_tcp_listener uri.host, uri.port, sock
|
156
|
+
log_writer.log "* Activated #{str}"
|
98
157
|
else
|
158
|
+
ios_len = @ios.length
|
99
159
|
params = Util.parse_query uri.query
|
100
160
|
|
101
|
-
opt = params.key?('low_latency')
|
102
|
-
|
161
|
+
opt = params.key?('low_latency') && params['low_latency'] != 'false'
|
162
|
+
backlog = params.fetch('backlog', 1024).to_i
|
103
163
|
|
104
|
-
|
105
|
-
|
164
|
+
io = add_tcp_listener uri.host, uri.port, opt, backlog
|
165
|
+
|
166
|
+
@ios[ios_len..-1].each do |i|
|
167
|
+
addr = loc_addr_str i
|
168
|
+
log_writer.log "* #{log_msg} on http://#{addr}"
|
169
|
+
end
|
106
170
|
end
|
107
171
|
|
108
172
|
@listeners << [str, io] if io
|
109
173
|
when "unix"
|
110
174
|
path = "#{uri.host}#{uri.path}".gsub("%20", " ")
|
175
|
+
abstract = false
|
176
|
+
if str.start_with? 'unix://@'
|
177
|
+
raise "OS does not support abstract UNIXSockets" unless Puma.abstract_unix_socket?
|
178
|
+
abstract = true
|
179
|
+
path = "@#{path}"
|
180
|
+
end
|
111
181
|
|
112
182
|
if fd = @inherited_fds.delete(str)
|
113
|
-
|
183
|
+
@unix_paths << path unless abstract || File.exist?(path)
|
114
184
|
io = inherit_unix_listener path, fd
|
115
|
-
|
116
|
-
|
185
|
+
log_writer.log "* Inherited #{str}"
|
186
|
+
elsif sock = @activated_sockets.delete([ :unix, path ]) ||
|
187
|
+
@activated_sockets.delete([ :unix, File.realdirpath(path) ])
|
188
|
+
@unix_paths << path unless abstract || File.exist?(path)
|
117
189
|
io = inherit_unix_listener path, sock
|
190
|
+
log_writer.log "* Activated #{str}"
|
118
191
|
else
|
119
|
-
logger.log "* Listening on #{str}"
|
120
|
-
|
121
192
|
umask = nil
|
122
193
|
mode = nil
|
123
194
|
backlog = 1024
|
@@ -138,87 +209,66 @@ module Puma
|
|
138
209
|
end
|
139
210
|
end
|
140
211
|
|
212
|
+
@unix_paths << path unless abstract || File.exist?(path)
|
141
213
|
io = add_unix_listener path, umask, mode, backlog
|
214
|
+
log_writer.log "* #{log_msg} on #{str}"
|
142
215
|
end
|
143
216
|
|
144
217
|
@listeners << [str, io]
|
145
218
|
when "ssl"
|
146
|
-
|
147
|
-
require 'puma/minissl'
|
219
|
+
cert_key = %w[cert key]
|
148
220
|
|
149
|
-
|
150
|
-
|
151
|
-
ctx = MiniSSL::Context.new
|
152
|
-
|
153
|
-
if defined?(JRUBY_VERSION)
|
154
|
-
unless params['keystore']
|
155
|
-
@events.error "Please specify the Java keystore via 'keystore='"
|
156
|
-
end
|
157
|
-
|
158
|
-
ctx.keystore = params['keystore']
|
159
|
-
|
160
|
-
unless params['keystore-pass']
|
161
|
-
@events.error "Please specify the Java keystore password via 'keystore-pass='"
|
162
|
-
end
|
221
|
+
raise "Puma compiled without SSL support" unless HAS_SSL
|
163
222
|
|
164
|
-
|
165
|
-
else
|
166
|
-
unless params['key']
|
167
|
-
@events.error "Please specify the SSL key via 'key='"
|
168
|
-
end
|
169
|
-
|
170
|
-
ctx.key = params['key']
|
171
|
-
|
172
|
-
unless params['cert']
|
173
|
-
@events.error "Please specify the SSL cert via 'cert='"
|
174
|
-
end
|
223
|
+
params = Util.parse_query uri.query
|
175
224
|
|
176
|
-
|
225
|
+
# If key and certs are not defined and localhost gem is required.
|
226
|
+
# localhost gem will be used for self signed
|
227
|
+
# Load localhost authority if not loaded.
|
228
|
+
# Ruby 3 `values_at` accepts an array, earlier do not
|
229
|
+
if params.values_at(*cert_key).all? { |v| v.to_s.empty? }
|
230
|
+
ctx = localhost_authority && localhost_authority_context
|
231
|
+
end
|
177
232
|
|
178
|
-
|
179
|
-
|
180
|
-
|
233
|
+
ctx ||=
|
234
|
+
begin
|
235
|
+
# Extract cert_pem and key_pem from options[:store] if present
|
236
|
+
cert_key.each do |v|
|
237
|
+
if params[v]&.start_with?('store:')
|
238
|
+
index = Integer(params.delete(v).split('store:').last)
|
239
|
+
params["#{v}_pem"] = @conf.options[:store][index]
|
240
|
+
end
|
181
241
|
end
|
242
|
+
MiniSSL::ContextBuilder.new(params, @log_writer).context
|
182
243
|
end
|
183
244
|
|
184
|
-
ctx.ca = params['ca'] if params['ca']
|
185
|
-
end
|
186
|
-
|
187
|
-
if params['verify_mode']
|
188
|
-
ctx.verify_mode = case params['verify_mode']
|
189
|
-
when "peer"
|
190
|
-
MiniSSL::VERIFY_PEER
|
191
|
-
when "force_peer"
|
192
|
-
MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
193
|
-
when "none"
|
194
|
-
MiniSSL::VERIFY_NONE
|
195
|
-
else
|
196
|
-
@events.error "Please specify a valid verify_mode="
|
197
|
-
MiniSSL::VERIFY_NONE
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
245
|
if fd = @inherited_fds.delete(str)
|
202
|
-
|
246
|
+
log_writer.log "* Inherited #{str}"
|
203
247
|
io = inherit_ssl_listener fd, ctx
|
204
248
|
elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
|
205
|
-
logger.log "* Activated #{str}"
|
206
249
|
io = inherit_ssl_listener sock, ctx
|
250
|
+
log_writer.log "* Activated #{str}"
|
207
251
|
else
|
208
|
-
|
209
|
-
|
252
|
+
ios_len = @ios.length
|
253
|
+
backlog = params.fetch('backlog', 1024).to_i
|
254
|
+
io = add_ssl_listener uri.host, uri.port, ctx, optimize_for_latency = true, backlog
|
255
|
+
|
256
|
+
@ios[ios_len..-1].each do |i|
|
257
|
+
addr = loc_addr_str i
|
258
|
+
log_writer.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
|
259
|
+
end
|
210
260
|
end
|
211
261
|
|
212
262
|
@listeners << [str, io] if io
|
213
263
|
else
|
214
|
-
|
264
|
+
log_writer.error "Invalid URI: #{str}"
|
215
265
|
end
|
216
266
|
end
|
217
267
|
|
218
268
|
# If we inherited fds but didn't use them (because of a
|
219
269
|
# configuration change), then be sure to close them.
|
220
270
|
@inherited_fds.each do |str, fd|
|
221
|
-
|
271
|
+
log_writer.log "* Closing unused inherited connection: #{str}"
|
222
272
|
|
223
273
|
begin
|
224
274
|
IO.for_fd(fd).close
|
@@ -234,21 +284,35 @@ module Puma
|
|
234
284
|
end
|
235
285
|
|
236
286
|
# Also close any unused activated sockets
|
237
|
-
@activated_sockets.
|
238
|
-
|
239
|
-
|
240
|
-
sock.
|
241
|
-
|
287
|
+
unless @activated_sockets.empty?
|
288
|
+
fds = @ios.map(&:to_i)
|
289
|
+
@activated_sockets.each do |key, sock|
|
290
|
+
next if fds.include? sock.to_i
|
291
|
+
log_writer.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
|
292
|
+
begin
|
293
|
+
sock.close
|
294
|
+
rescue SystemCallError
|
295
|
+
end
|
296
|
+
# We have to unlink a unix socket path that's not being used
|
297
|
+
File.unlink key[1] if key.first == :unix
|
242
298
|
end
|
243
|
-
# We have to unlink a unix socket path that's not being used
|
244
|
-
File.unlink key[1] if key[0] == :unix
|
245
299
|
end
|
246
300
|
end
|
247
301
|
|
248
|
-
def
|
249
|
-
|
250
|
-
|
251
|
-
|
302
|
+
def localhost_authority
|
303
|
+
@localhost_authority ||= Localhost::Authority.fetch if defined?(Localhost::Authority) && !Puma::IS_JRUBY
|
304
|
+
end
|
305
|
+
|
306
|
+
def localhost_authority_context
|
307
|
+
return unless localhost_authority
|
308
|
+
|
309
|
+
key_path, crt_path = if [:key_path, :certificate_path].all? { |m| localhost_authority.respond_to?(m) }
|
310
|
+
[localhost_authority.key_path, localhost_authority.certificate_path]
|
311
|
+
else
|
312
|
+
local_certificates_path = File.expand_path("~/.localhost")
|
313
|
+
[File.join(local_certificates_path, "localhost.key"), File.join(local_certificates_path, "localhost.crt")]
|
314
|
+
end
|
315
|
+
MiniSSL::ContextBuilder.new({ "key" => key_path, "cert" => crt_path }, @log_writer).context
|
252
316
|
end
|
253
317
|
|
254
318
|
# Tell the server to listen on host +host+, port +port+.
|
@@ -267,26 +331,20 @@ module Puma
|
|
267
331
|
end
|
268
332
|
|
269
333
|
host = host[1..-2] if host and host[0..0] == '['
|
270
|
-
|
334
|
+
tcp_server = TCPServer.new(host, port)
|
335
|
+
|
271
336
|
if optimize_for_latency
|
272
|
-
|
337
|
+
tcp_server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
273
338
|
end
|
274
|
-
|
275
|
-
|
276
|
-
@connected_port = s.addr[1]
|
339
|
+
tcp_server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
|
340
|
+
tcp_server.listen backlog
|
277
341
|
|
278
|
-
@ios <<
|
279
|
-
|
342
|
+
@ios << tcp_server
|
343
|
+
tcp_server
|
280
344
|
end
|
281
345
|
|
282
|
-
attr_reader :connected_port
|
283
|
-
|
284
346
|
def inherit_tcp_listener(host, port, fd)
|
285
|
-
|
286
|
-
s = fd
|
287
|
-
else
|
288
|
-
s = TCPServer.for_fd(fd)
|
289
|
-
end
|
347
|
+
s = fd.kind_of?(::TCPServer) ? fd : ::TCPServer.for_fd(fd)
|
290
348
|
|
291
349
|
@ios << s
|
292
350
|
s
|
@@ -294,9 +352,10 @@ module Puma
|
|
294
352
|
|
295
353
|
def add_ssl_listener(host, port, ctx,
|
296
354
|
optimize_for_latency=true, backlog=1024)
|
297
|
-
require 'puma/minissl'
|
298
355
|
|
299
|
-
|
356
|
+
raise "Puma compiled without SSL support" unless HAS_SSL
|
357
|
+
# Puma will try to use local authority context if context is supplied nil
|
358
|
+
ctx ||= localhost_authority_context
|
300
359
|
|
301
360
|
if host == "localhost"
|
302
361
|
loopback_addresses.each do |addr|
|
@@ -323,14 +382,12 @@ module Puma
|
|
323
382
|
end
|
324
383
|
|
325
384
|
def inherit_ssl_listener(fd, ctx)
|
326
|
-
|
327
|
-
|
385
|
+
raise "Puma compiled without SSL support" unless HAS_SSL
|
386
|
+
# Puma will try to use local authority context if context is supplied nil
|
387
|
+
ctx ||= localhost_authority_context
|
388
|
+
|
389
|
+
s = fd.kind_of?(::TCPServer) ? fd : ::TCPServer.for_fd(fd)
|
328
390
|
|
329
|
-
if fd.kind_of? TCPServer
|
330
|
-
s = fd
|
331
|
-
else
|
332
|
-
s = TCPServer.for_fd(fd)
|
333
|
-
end
|
334
391
|
ssl = MiniSSL::Server.new(s, ctx)
|
335
392
|
|
336
393
|
env = @proto_env.dup
|
@@ -345,8 +402,6 @@ module Puma
|
|
345
402
|
# Tell the server to listen on +path+ as a UNIX domain socket.
|
346
403
|
#
|
347
404
|
def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
|
348
|
-
@unix_paths << path
|
349
|
-
|
350
405
|
# Let anyone connect by default
|
351
406
|
umask ||= 0
|
352
407
|
|
@@ -363,8 +418,7 @@ module Puma
|
|
363
418
|
raise "There is already a server bound to: #{path}"
|
364
419
|
end
|
365
420
|
end
|
366
|
-
|
367
|
-
s = UNIXServer.new(path)
|
421
|
+
s = UNIXServer.new path.sub(/\A@/, "\0") # check for abstract UNIXSocket
|
368
422
|
s.listen backlog
|
369
423
|
@ios << s
|
370
424
|
ensure
|
@@ -383,13 +437,8 @@ module Puma
|
|
383
437
|
end
|
384
438
|
|
385
439
|
def inherit_unix_listener(path, fd)
|
386
|
-
|
440
|
+
s = fd.kind_of?(::TCPServer) ? fd : ::UNIXServer.for_fd(fd)
|
387
441
|
|
388
|
-
if fd.kind_of? TCPServer
|
389
|
-
s = fd
|
390
|
-
else
|
391
|
-
s = UNIXServer.for_fd fd
|
392
|
-
end
|
393
442
|
@ios << s
|
394
443
|
|
395
444
|
env = @proto_env.dup
|
@@ -399,5 +448,51 @@ module Puma
|
|
399
448
|
s
|
400
449
|
end
|
401
450
|
|
451
|
+
def close_listeners
|
452
|
+
@listeners.each do |l, io|
|
453
|
+
io.close unless io.closed?
|
454
|
+
uri = URI.parse l
|
455
|
+
next unless uri.scheme == 'unix'
|
456
|
+
unix_path = "#{uri.host}#{uri.path}"
|
457
|
+
File.unlink unix_path if @unix_paths.include?(unix_path) && File.exist?(unix_path)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def redirects_for_restart
|
462
|
+
redirects = @listeners.map { |a| [a[1].to_i, a[1].to_i] }.to_h
|
463
|
+
redirects[:close_others] = true
|
464
|
+
redirects
|
465
|
+
end
|
466
|
+
|
467
|
+
# @version 5.0.0
|
468
|
+
def redirects_for_restart_env
|
469
|
+
@listeners.each_with_object({}).with_index do |(listen, memo), i|
|
470
|
+
memo["PUMA_INHERIT_#{i}"] = "#{listen[1].to_i}:#{listen[0]}"
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
private
|
475
|
+
|
476
|
+
# @!attribute [r] loopback_addresses
|
477
|
+
def loopback_addresses
|
478
|
+
t = Socket.ip_address_list.select do |addrinfo|
|
479
|
+
addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
|
480
|
+
end
|
481
|
+
t.map! { |addrinfo| addrinfo.ip_address }; t.uniq!; t
|
482
|
+
end
|
483
|
+
|
484
|
+
def loc_addr_str(io)
|
485
|
+
loc_addr = io.to_io.local_address
|
486
|
+
if loc_addr.ipv6?
|
487
|
+
"[#{loc_addr.ip_unpack[0]}]:#{loc_addr.ip_unpack[1]}"
|
488
|
+
else
|
489
|
+
loc_addr.ip_unpack.join(':')
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
# @version 5.0.0
|
494
|
+
def socket_activation_fd(int)
|
495
|
+
int + 3 # 3 is the magic number you add to follow the SA protocol
|
496
|
+
end
|
402
497
|
end
|
403
498
|
end
|