puma 3.12.0 → 5.3.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.

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +1413 -439
  3. data/LICENSE +23 -20
  4. data/README.md +131 -60
  5. data/bin/puma-wild +3 -9
  6. data/docs/architecture.md +24 -19
  7. data/docs/compile_options.md +19 -0
  8. data/docs/deployment.md +38 -13
  9. data/docs/fork_worker.md +33 -0
  10. data/docs/jungle/README.md +9 -0
  11. data/{tools → docs}/jungle/rc.d/README.md +1 -1
  12. data/{tools → docs}/jungle/rc.d/puma +2 -2
  13. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  14. data/docs/kubernetes.md +66 -0
  15. data/docs/nginx.md +1 -1
  16. data/docs/plugins.md +20 -10
  17. data/docs/rails_dev_mode.md +29 -0
  18. data/docs/restart.md +47 -22
  19. data/docs/signals.md +7 -6
  20. data/docs/stats.md +142 -0
  21. data/docs/systemd.md +48 -70
  22. data/ext/puma_http11/PumaHttp11Service.java +2 -2
  23. data/ext/puma_http11/ext_help.h +1 -1
  24. data/ext/puma_http11/extconf.rb +27 -0
  25. data/ext/puma_http11/http11_parser.c +84 -109
  26. data/ext/puma_http11/http11_parser.h +1 -1
  27. data/ext/puma_http11/http11_parser.java.rl +22 -38
  28. data/ext/puma_http11/http11_parser.rl +4 -2
  29. data/ext/puma_http11/http11_parser_common.rl +3 -3
  30. data/ext/puma_http11/mini_ssl.c +262 -87
  31. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
  32. data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
  33. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +89 -106
  34. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +92 -22
  35. data/ext/puma_http11/puma_http11.c +34 -50
  36. data/lib/puma/app/status.rb +68 -49
  37. data/lib/puma/binder.rb +197 -144
  38. data/lib/puma/cli.rb +17 -15
  39. data/lib/puma/client.rb +257 -226
  40. data/lib/puma/cluster/worker.rb +176 -0
  41. data/lib/puma/cluster/worker_handle.rb +90 -0
  42. data/lib/puma/cluster.rb +223 -212
  43. data/lib/puma/commonlogger.rb +4 -2
  44. data/lib/puma/configuration.rb +58 -51
  45. data/lib/puma/const.rb +41 -19
  46. data/lib/puma/control_cli.rb +117 -73
  47. data/lib/puma/detect.rb +26 -3
  48. data/lib/puma/dsl.rb +531 -123
  49. data/lib/puma/error_logger.rb +104 -0
  50. data/lib/puma/events.rb +57 -31
  51. data/lib/puma/io_buffer.rb +9 -5
  52. data/lib/puma/jruby_restart.rb +2 -58
  53. data/lib/puma/json.rb +96 -0
  54. data/lib/puma/launcher.rb +182 -70
  55. data/lib/puma/minissl/context_builder.rb +79 -0
  56. data/lib/puma/minissl.rb +149 -48
  57. data/lib/puma/null_io.rb +15 -1
  58. data/lib/puma/plugin/tmp_restart.rb +2 -0
  59. data/lib/puma/plugin.rb +8 -12
  60. data/lib/puma/queue_close.rb +26 -0
  61. data/lib/puma/rack/builder.rb +4 -5
  62. data/lib/puma/rack/urlmap.rb +2 -0
  63. data/lib/puma/rack_default.rb +2 -0
  64. data/lib/puma/reactor.rb +87 -316
  65. data/lib/puma/request.rb +456 -0
  66. data/lib/puma/runner.rb +33 -52
  67. data/lib/puma/server.rb +288 -679
  68. data/lib/puma/single.rb +13 -67
  69. data/lib/puma/state_file.rb +10 -3
  70. data/lib/puma/systemd.rb +46 -0
  71. data/lib/puma/thread_pool.rb +131 -81
  72. data/lib/puma/util.rb +14 -6
  73. data/lib/puma.rb +54 -0
  74. data/lib/rack/handler/puma.rb +8 -6
  75. data/tools/Dockerfile +16 -0
  76. data/tools/trickletest.rb +0 -1
  77. metadata +45 -29
  78. data/ext/puma_http11/io_buffer.c +0 -155
  79. data/lib/puma/accept_nonblock.rb +0 -23
  80. data/lib/puma/compat.rb +0 -14
  81. data/lib/puma/convenient.rb +0 -23
  82. data/lib/puma/daemon_ext.rb +0 -31
  83. data/lib/puma/delegation.rb +0 -11
  84. data/lib/puma/java_io_buffer.rb +0 -45
  85. data/lib/puma/rack/backports/uri/common_193.rb +0 -33
  86. data/lib/puma/tcp_logger.rb +0 -39
  87. data/tools/jungle/README.md +0 -19
  88. data/tools/jungle/init.d/README.md +0 -61
  89. data/tools/jungle/init.d/puma +0 -421
  90. data/tools/jungle/init.d/run-puma +0 -18
  91. data/tools/jungle/upstart/README.md +0 -61
  92. data/tools/jungle/upstart/puma-manager.conf +0 -31
  93. data/tools/jungle/upstart/puma.conf +0 -69
data/lib/puma/binder.rb CHANGED
@@ -1,16 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'socket'
3
5
 
4
6
  require 'puma/const'
5
7
  require 'puma/util'
8
+ require 'puma/configuration'
6
9
 
7
10
  module Puma
11
+
12
+ if HAS_SSL
13
+ require 'puma/minissl'
14
+ require 'puma/minissl/context_builder'
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
24
+ end
25
+
8
26
  class Binder
9
27
  include Puma::Const
10
28
 
11
- RACK_VERSION = [1,3].freeze
29
+ RACK_VERSION = [1,6].freeze
12
30
 
13
- def initialize(events)
31
+ def initialize(events, conf = Configuration.new)
14
32
  @events = events
15
33
  @listeners = []
16
34
  @inherited_fds = {}
@@ -20,8 +38,8 @@ module Puma
20
38
  @proto_env = {
21
39
  "rack.version".freeze => RACK_VERSION,
22
40
  "rack.errors".freeze => events.stderr,
23
- "rack.multithread".freeze => true,
24
- "rack.multiprocess".freeze => false,
41
+ "rack.multithread".freeze => conf.options[:max_threads] > 1,
42
+ "rack.multiprocess".freeze => conf.options[:workers] >= 1,
25
43
  "rack.run_once".freeze => false,
26
44
  "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
27
45
 
@@ -40,7 +58,13 @@ module Puma
40
58
  @ios = []
41
59
  end
42
60
 
43
- attr_reader :listeners, :ios
61
+ attr_reader :ios
62
+
63
+ # @version 5.0.0
64
+ attr_reader :activated_sockets, :envs, :inherited_fds, :listeners, :proto_env, :unix_paths
65
+
66
+ # @version 5.0.0
67
+ attr_writer :ios, :listeners
44
68
 
45
69
  def env(sock)
46
70
  @envs.fetch(sock, @proto_env)
@@ -48,76 +72,127 @@ module Puma
48
72
 
49
73
  def close
50
74
  @ios.each { |i| i.close }
51
- @unix_paths.each { |i| File.unlink i }
52
75
  end
53
76
 
54
- def import_from_env
55
- remove = []
56
-
57
- ENV.each do |k,v|
58
- if k =~ /PUMA_INHERIT_\d+/
59
- fd, url = v.split(":", 2)
60
- @inherited_fds[url] = fd.to_i
61
- remove << k
62
- elsif k == 'LISTEN_FDS' && ENV['LISTEN_PID'].to_i == $$
63
- v.to_i.times do |num|
64
- fd = num + 3
65
- sock = TCPServer.for_fd(fd)
66
- begin
67
- key = [ :unix, Socket.unpack_sockaddr_un(sock.getsockname) ]
68
- rescue ArgumentError
69
- port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
70
- if addr =~ /\:/
71
- addr = "[#{addr}]"
72
- end
73
- key = [ :tcp, addr, port ]
74
- end
75
- @activated_sockets[key] = sock
76
- @events.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
77
- end
78
- remove << k << 'LISTEN_PID'
77
+ # @!attribute [r] connected_ports
78
+ # @version 5.0.0
79
+ def connected_ports
80
+ ios.map { |io| io.addr[1] }.uniq
81
+ end
82
+
83
+ # @version 5.0.0
84
+ def create_inherited_fds(env_hash)
85
+ env_hash.select {|k,v| k =~ /PUMA_INHERIT_\d+/}.each do |_k, v|
86
+ fd, url = v.split(":", 2)
87
+ @inherited_fds[url] = fd.to_i
88
+ end.keys # pass keys back for removal
89
+ end
90
+
91
+ # systemd socket activation.
92
+ # LISTEN_FDS = number of listening sockets. e.g. 2 means accept on 2 sockets w/descriptors 3 and 4.
93
+ # LISTEN_PID = PID of the service process, aka us
94
+ # @see https://www.freedesktop.org/software/systemd/man/systemd-socket-activate.html
95
+ # @version 5.0.0
96
+ #
97
+ def create_activated_fds(env_hash)
98
+ return [] unless env_hash['LISTEN_FDS'] && env_hash['LISTEN_PID'].to_i == $$
99
+ env_hash['LISTEN_FDS'].to_i.times do |index|
100
+ sock = TCPServer.for_fd(socket_activation_fd(index))
101
+ key = begin # Try to parse as a path
102
+ [:unix, Socket.unpack_sockaddr_un(sock.getsockname)]
103
+ rescue ArgumentError # Try to parse as a port/ip
104
+ port, addr = Socket.unpack_sockaddr_in(sock.getsockname)
105
+ addr = "[#{addr}]" if addr =~ /\:/
106
+ [:tcp, addr, port]
107
+ end
108
+ @activated_sockets[key] = sock
109
+ @events.debug "Registered #{key.join ':'} for activation from LISTEN_FDS"
110
+ end
111
+ ["LISTEN_FDS", "LISTEN_PID"] # Signal to remove these keys from ENV
112
+ end
113
+
114
+ # Synthesize binds from systemd socket activation
115
+ #
116
+ # When systemd socket activation is enabled, it can be tedious to keep the
117
+ # binds in sync. This method can synthesize any binds based on the received
118
+ # activated sockets. Any existing matching binds will be respected.
119
+ #
120
+ # When only_matching is true in, all binds that do not match an activated
121
+ # socket is removed in place.
122
+ #
123
+ # It's a noop if no activated sockets were received.
124
+ def synthesize_binds_from_activated_fs(binds, only_matching)
125
+ return binds unless activated_sockets.any?
126
+
127
+ activated_binds = []
128
+
129
+ activated_sockets.keys.each do |proto, addr, port|
130
+ if port
131
+ tcp_url = "#{proto}://#{addr}:#{port}"
132
+ ssl_url = "ssl://#{addr}:#{port}"
133
+ ssl_url_prefix = "#{ssl_url}?"
134
+
135
+ existing = binds.find { |bind| bind == tcp_url || bind == ssl_url || bind.start_with?(ssl_url_prefix) }
136
+
137
+ activated_binds << (existing || tcp_url)
138
+ else
139
+ # TODO: can there be a SSL bind without a port?
140
+ activated_binds << "#{proto}://#{addr}"
79
141
  end
80
142
  end
81
143
 
82
- remove.each do |k|
83
- ENV.delete k
144
+ if only_matching
145
+ activated_binds
146
+ else
147
+ binds | activated_binds
84
148
  end
85
149
  end
86
150
 
87
- def parse(binds, logger)
151
+ def parse(binds, logger, log_msg = 'Listening')
88
152
  binds.each do |str|
89
153
  uri = URI.parse str
90
154
  case uri.scheme
91
155
  when "tcp"
92
156
  if fd = @inherited_fds.delete(str)
93
- logger.log "* Inherited #{str}"
94
157
  io = inherit_tcp_listener uri.host, uri.port, fd
158
+ logger.log "* Inherited #{str}"
95
159
  elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
96
- logger.log "* Activated #{str}"
97
160
  io = inherit_tcp_listener uri.host, uri.port, sock
161
+ logger.log "* Activated #{str}"
98
162
  else
163
+ ios_len = @ios.length
99
164
  params = Util.parse_query uri.query
100
165
 
101
166
  opt = params.key?('low_latency')
102
167
  bak = params.fetch('backlog', 1024).to_i
103
168
 
104
- logger.log "* Listening on #{str}"
105
169
  io = add_tcp_listener uri.host, uri.port, opt, bak
170
+
171
+ @ios[ios_len..-1].each do |i|
172
+ addr = loc_addr_str i
173
+ logger.log "* #{log_msg} on http://#{addr}"
174
+ end
106
175
  end
107
176
 
108
177
  @listeners << [str, io] if io
109
178
  when "unix"
110
179
  path = "#{uri.host}#{uri.path}".gsub("%20", " ")
180
+ abstract = false
181
+ if str.start_with? 'unix://@'
182
+ raise "OS does not support abstract UNIXSockets" unless Puma.abstract_unix_socket?
183
+ abstract = true
184
+ path = "@#{path}"
185
+ end
111
186
 
112
187
  if fd = @inherited_fds.delete(str)
113
- logger.log "* Inherited #{str}"
188
+ @unix_paths << path unless abstract
114
189
  io = inherit_unix_listener path, fd
190
+ logger.log "* Inherited #{str}"
115
191
  elsif sock = @activated_sockets.delete([ :unix, path ])
116
- logger.log "* Activated #{str}"
192
+ @unix_paths << path unless abstract || File.exist?(path)
117
193
  io = inherit_unix_listener path, sock
194
+ logger.log "* Activated #{str}"
118
195
  else
119
- logger.log "* Listening on #{str}"
120
-
121
196
  umask = nil
122
197
  mode = nil
123
198
  backlog = 1024
@@ -138,77 +213,33 @@ module Puma
138
213
  end
139
214
  end
140
215
 
216
+ @unix_paths << path unless abstract || File.exist?(path)
141
217
  io = add_unix_listener path, umask, mode, backlog
218
+ logger.log "* #{log_msg} on #{str}"
142
219
  end
143
220
 
144
221
  @listeners << [str, io]
145
222
  when "ssl"
146
- params = Util.parse_query uri.query
147
- require 'puma/minissl'
148
-
149
- MiniSSL.check
150
223
 
151
- ctx = MiniSSL::Context.new
224
+ raise "Puma compiled without SSL support" unless HAS_SSL
152
225
 
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
163
-
164
- ctx.keystore_pass = params['keystore-pass']
165
- ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list']
166
- else
167
- unless params['key']
168
- @events.error "Please specify the SSL key via 'key='"
169
- end
170
-
171
- ctx.key = params['key']
172
-
173
- unless params['cert']
174
- @events.error "Please specify the SSL cert via 'cert='"
175
- end
176
-
177
- ctx.cert = params['cert']
178
-
179
- if ['peer', 'force_peer'].include?(params['verify_mode'])
180
- unless params['ca']
181
- @events.error "Please specify the SSL ca via 'ca='"
182
- end
183
- end
184
-
185
- ctx.ca = params['ca'] if params['ca']
186
- ctx.ssl_cipher_filter = params['ssl_cipher_filter'] if params['ssl_cipher_filter']
187
- end
188
-
189
- if params['verify_mode']
190
- ctx.verify_mode = case params['verify_mode']
191
- when "peer"
192
- MiniSSL::VERIFY_PEER
193
- when "force_peer"
194
- MiniSSL::VERIFY_PEER | MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
195
- when "none"
196
- MiniSSL::VERIFY_NONE
197
- else
198
- @events.error "Please specify a valid verify_mode="
199
- MiniSSL::VERIFY_NONE
200
- end
201
- end
226
+ params = Util.parse_query uri.query
227
+ ctx = MiniSSL::ContextBuilder.new(params, @events).context
202
228
 
203
229
  if fd = @inherited_fds.delete(str)
204
230
  logger.log "* Inherited #{str}"
205
231
  io = inherit_ssl_listener fd, ctx
206
232
  elsif sock = @activated_sockets.delete([ :tcp, uri.host, uri.port ])
207
- logger.log "* Activated #{str}"
208
233
  io = inherit_ssl_listener sock, ctx
234
+ logger.log "* Activated #{str}"
209
235
  else
210
- logger.log "* Listening on #{str}"
236
+ ios_len = @ios.length
211
237
  io = add_ssl_listener uri.host, uri.port, ctx
238
+
239
+ @ios[ios_len..-1].each do |i|
240
+ addr = loc_addr_str i
241
+ logger.log "* #{log_msg} on ssl://#{addr}?#{uri.query}"
242
+ end
212
243
  end
213
244
 
214
245
  @listeners << [str, io] if io
@@ -236,23 +267,21 @@ module Puma
236
267
  end
237
268
 
238
269
  # Also close any unused activated sockets
239
- @activated_sockets.each do |key, sock|
240
- logger.log "* Closing unused activated socket: #{key.join ':'}"
241
- begin
242
- sock.close
243
- rescue SystemCallError
270
+ unless @activated_sockets.empty?
271
+ fds = @ios.map(&:to_i)
272
+ @activated_sockets.each do |key, sock|
273
+ next if fds.include? sock.to_i
274
+ logger.log "* Closing unused activated socket: #{key.first}://#{key[1..-1].join ':'}"
275
+ begin
276
+ sock.close
277
+ rescue SystemCallError
278
+ end
279
+ # We have to unlink a unix socket path that's not being used
280
+ File.unlink key[1] if key.first == :unix
244
281
  end
245
- # We have to unlink a unix socket path that's not being used
246
- File.unlink key[1] if key[0] == :unix
247
282
  end
248
283
  end
249
284
 
250
- def loopback_addresses
251
- Socket.ip_address_list.select do |addrinfo|
252
- addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
253
- end.map { |addrinfo| addrinfo.ip_address }.uniq
254
- end
255
-
256
285
  # Tell the server to listen on host +host+, port +port+.
257
286
  # If +optimize_for_latency+ is true (the default) then clients connecting
258
287
  # will be optimized for latency over throughput.
@@ -269,26 +298,19 @@ module Puma
269
298
  end
270
299
 
271
300
  host = host[1..-2] if host and host[0..0] == '['
272
- s = TCPServer.new(host, port)
301
+ tcp_server = TCPServer.new(host, port)
273
302
  if optimize_for_latency
274
- s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
303
+ tcp_server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
275
304
  end
276
- s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
277
- s.listen backlog
278
- @connected_port = s.addr[1]
305
+ tcp_server.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
306
+ tcp_server.listen backlog
279
307
 
280
- @ios << s
281
- s
308
+ @ios << tcp_server
309
+ tcp_server
282
310
  end
283
311
 
284
- attr_reader :connected_port
285
-
286
312
  def inherit_tcp_listener(host, port, fd)
287
- if fd.kind_of? TCPServer
288
- s = fd
289
- else
290
- s = TCPServer.for_fd(fd)
291
- end
313
+ s = fd.kind_of?(::TCPServer) ? fd : ::TCPServer.for_fd(fd)
292
314
 
293
315
  @ios << s
294
316
  s
@@ -296,9 +318,8 @@ module Puma
296
318
 
297
319
  def add_ssl_listener(host, port, ctx,
298
320
  optimize_for_latency=true, backlog=1024)
299
- require 'puma/minissl'
300
321
 
301
- MiniSSL.check
322
+ raise "Puma compiled without SSL support" unless HAS_SSL
302
323
 
303
324
  if host == "localhost"
304
325
  loopback_addresses.each do |addr|
@@ -315,7 +336,6 @@ module Puma
315
336
  s.setsockopt(Socket::SOL_SOCKET,Socket::SO_REUSEADDR, true)
316
337
  s.listen backlog
317
338
 
318
-
319
339
  ssl = MiniSSL::Server.new s, ctx
320
340
  env = @proto_env.dup
321
341
  env[HTTPS_KEY] = HTTPS
@@ -326,14 +346,10 @@ module Puma
326
346
  end
327
347
 
328
348
  def inherit_ssl_listener(fd, ctx)
329
- require 'puma/minissl'
330
- MiniSSL.check
349
+ raise "Puma compiled without SSL support" unless HAS_SSL
350
+
351
+ s = fd.kind_of?(::TCPServer) ? fd : ::TCPServer.for_fd(fd)
331
352
 
332
- if fd.kind_of? TCPServer
333
- s = fd
334
- else
335
- s = TCPServer.for_fd(fd)
336
- end
337
353
  ssl = MiniSSL::Server.new(s, ctx)
338
354
 
339
355
  env = @proto_env.dup
@@ -348,8 +364,6 @@ module Puma
348
364
  # Tell the server to listen on +path+ as a UNIX domain socket.
349
365
  #
350
366
  def add_unix_listener(path, umask=nil, mode=nil, backlog=1024)
351
- @unix_paths << path
352
-
353
367
  # Let anyone connect by default
354
368
  umask ||= 0
355
369
 
@@ -366,8 +380,7 @@ module Puma
366
380
  raise "There is already a server bound to: #{path}"
367
381
  end
368
382
  end
369
-
370
- s = UNIXServer.new(path)
383
+ s = UNIXServer.new path.sub(/\A@/, "\0") # check for abstract UNIXSocket
371
384
  s.listen backlog
372
385
  @ios << s
373
386
  ensure
@@ -386,13 +399,8 @@ module Puma
386
399
  end
387
400
 
388
401
  def inherit_unix_listener(path, fd)
389
- @unix_paths << path
402
+ s = fd.kind_of?(::TCPServer) ? fd : ::UNIXServer.for_fd(fd)
390
403
 
391
- if fd.kind_of? TCPServer
392
- s = fd
393
- else
394
- s = UNIXServer.for_fd fd
395
- end
396
404
  @ios << s
397
405
 
398
406
  env = @proto_env.dup
@@ -402,5 +410,50 @@ module Puma
402
410
  s
403
411
  end
404
412
 
413
+ def close_listeners
414
+ @listeners.each do |l, io|
415
+ io.close unless io.closed?
416
+ uri = URI.parse l
417
+ next unless uri.scheme == 'unix'
418
+ unix_path = "#{uri.host}#{uri.path}"
419
+ File.unlink unix_path if @unix_paths.include?(unix_path) && File.exist?(unix_path)
420
+ end
421
+ end
422
+
423
+ def redirects_for_restart
424
+ redirects = @listeners.map { |a| [a[1].to_i, a[1].to_i] }.to_h
425
+ redirects[:close_others] = true
426
+ redirects
427
+ end
428
+
429
+ # @version 5.0.0
430
+ def redirects_for_restart_env
431
+ @listeners.each_with_object({}).with_index do |(listen, memo), i|
432
+ memo["PUMA_INHERIT_#{i}"] = "#{listen[1].to_i}:#{listen[0]}"
433
+ end
434
+ end
435
+
436
+ private
437
+
438
+ # @!attribute [r] loopback_addresses
439
+ def loopback_addresses
440
+ Socket.ip_address_list.select do |addrinfo|
441
+ addrinfo.ipv6_loopback? || addrinfo.ipv4_loopback?
442
+ end.map { |addrinfo| addrinfo.ip_address }.uniq
443
+ end
444
+
445
+ def loc_addr_str(io)
446
+ loc_addr = io.to_io.local_address
447
+ if loc_addr.ipv6?
448
+ "[#{loc_addr.ip_unpack[0]}]:#{loc_addr.ip_unpack[1]}"
449
+ else
450
+ loc_addr.ip_unpack.join(':')
451
+ end
452
+ end
453
+
454
+ # @version 5.0.0
455
+ def socket_activation_fd(int)
456
+ int + 3 # 3 is the magic number you add to follow the SA protocol
457
+ end
405
458
  end
406
459
  end
data/lib/puma/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'optparse'
2
4
  require 'uri'
3
5
 
@@ -78,7 +80,7 @@ module Puma
78
80
  @launcher.run
79
81
  end
80
82
 
81
- private
83
+ private
82
84
  def unsupported(str)
83
85
  @events.error(str)
84
86
  raise UnsupportedOption
@@ -102,6 +104,10 @@ module Puma
102
104
  user_config.bind arg
103
105
  end
104
106
 
107
+ o.on "--bind-to-activated-sockets [only]", "Bind to all activated sockets" do |arg|
108
+ user_config.bind_to_activated_sockets(arg || true)
109
+ end
110
+
105
111
  o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
106
112
  file_config.load arg
107
113
  end
@@ -110,21 +116,11 @@ module Puma
110
116
  configure_control_url(arg)
111
117
  end
112
118
 
113
- # alias --control-url for backwards-compatibility
114
- o.on "--control URL", "DEPRECATED alias for --control-url" do |arg|
115
- configure_control_url(arg)
116
- end
117
-
118
119
  o.on "--control-token TOKEN",
119
120
  "The token to use as authentication for the control server" do |arg|
120
121
  @control_options[:auth_token] = arg
121
122
  end
122
123
 
123
- o.on "-d", "--daemon", "Daemonize the server into the background" do
124
- user_config.daemonize
125
- user_config.quiet
126
- end
127
-
128
124
  o.on "--debug", "Log lowlevel debugging information" do
129
125
  user_config.debug
130
126
  end
@@ -138,6 +134,12 @@ module Puma
138
134
  user_config.environment arg
139
135
  end
140
136
 
137
+ o.on "-f", "--fork-worker=[REQUESTS]", OptionParser::DecimalInteger,
138
+ "Fork new workers from existing worker. Cluster mode only",
139
+ "Auto-refork after REQUESTS (default 1000)" do |*args|
140
+ user_config.fork_worker(*args.compact)
141
+ end
142
+
141
143
  o.on "-I", "--include PATH", "Specify $LOAD_PATH directories" do |arg|
142
144
  $LOAD_PATH.unshift(*arg.split(':'))
143
145
  end
@@ -159,6 +161,10 @@ module Puma
159
161
  user_config.prune_bundler
160
162
  end
161
163
 
164
+ o.on "--extra-runtime-dependencies GEM1,GEM2", "Defines any extra needed gems when using --prune-bundler" do |arg|
165
+ user_config.extra_runtime_dependencies arg.split(',')
166
+ end
167
+
162
168
  o.on "-q", "--quiet", "Do not log requests internally (default true)" do
163
169
  user_config.quiet
164
170
  end
@@ -186,10 +192,6 @@ module Puma
186
192
  end
187
193
  end
188
194
 
189
- o.on "--tcp-mode", "Run the app in raw TCP mode instead of HTTP mode" do
190
- user_config.tcp_mode!
191
- end
192
-
193
195
  o.on "--early-hints", "Enable early hints support" do
194
196
  user_config.early_hints
195
197
  end