diff --git a/Library/Homebrew/service.rb b/Library/Homebrew/service.rb index 3d1de39211..09e2fb6b59 100644 --- a/Library/Homebrew/service.rb +++ b/Library/Homebrew/service.rb @@ -1,6 +1,7 @@ # typed: true # frozen_string_literal: true +require "ipaddr" require "extend/on_system" module Homebrew @@ -187,7 +188,7 @@ module Homebrew end end - SOCKET_STRING_REGEX = %r{([a-z]+)://([a-z0-9.]+):([0-9]+)}i.freeze + SOCKET_STRING_REGEX = %r{^([a-z]+)://(.+):([0-9]+)$}i.freeze sig { params(value: T.nilable(T.any(String, T::Hash[Symbol, String]))) @@ -206,6 +207,13 @@ module Homebrew raise TypeError, "Service#sockets a formatted socket definition as ://:" if match.blank? type, host, port = match.captures + + begin + IPAddr.new(host) + rescue IPAddr::InvalidAddressError + raise TypeError, "Service#sockets expects a valid ipv4 or ipv6 host address" + end + { host: host, port: port, type: type } end end @@ -424,7 +432,6 @@ module Homebrew SockNodeName: info[:host], SockServiceName: info[:port], SockProtocol: info[:type].upcase, - SockFamily: "IPv4v6", } end end @@ -522,10 +529,19 @@ module Homebrew .join(" ") end - sockets_hash = if @sockets.present? - @sockets.transform_values do |info| - "#{info[:type]}://#{info[:host]}:#{info[:port]}" - end + sockets_var = if @sockets.present? + @sockets.transform_values { |info| "#{info[:type]}://#{info[:host]}:#{info[:port]}" } + .then do |sockets_hash| + # TODO: Remove this code when all users are running on versions of Homebrew + # that can process sockets hashes (this commit or later). + if sockets_hash.size == 1 && sockets_hash.key?(:listeners) + # When original #sockets argument was a string: `sockets "tcp://127.0.0.1:80"` + sockets_hash.fetch(:listeners) + else + # When original #sockets argument was a hash: `sockets http: "tcp://0.0.0.0:80"` + sockets_hash + end + end end { @@ -546,7 +562,7 @@ module Homebrew restart_delay: @restart_delay, process_type: @process_type, macos_legacy_timers: @macos_legacy_timers, - sockets: sockets_hash, + sockets: sockets_var, }.compact end diff --git a/Library/Homebrew/test/service_spec.rb b/Library/Homebrew/test/service_spec.rb index 7f28005fb0..85f1e8be51 100644 --- a/Library/Homebrew/test/service_spec.rb +++ b/Library/Homebrew/test/service_spec.rb @@ -116,7 +116,7 @@ describe Homebrew::Service do it "throws for missing type" do [ stub_formula_with_service_sockets("127.0.0.1:80"), - stub_formula_with_service_sockets({ "Socket" => "127.0.0.1:80" }), + stub_formula_with_service_sockets({ socket: "127.0.0.1:80" }), ].each do |f| expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message end @@ -125,7 +125,7 @@ describe Homebrew::Service do it "throws for missing host" do [ stub_formula_with_service_sockets("tcp://:80"), - stub_formula_with_service_sockets({ "Socket" => "tcp://:80" }), + stub_formula_with_service_sockets({ socket: "tcp://:80" }), ].each do |f| expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message end @@ -134,11 +134,22 @@ describe Homebrew::Service do it "throws for missing port" do [ stub_formula_with_service_sockets("tcp://127.0.0.1"), - stub_formula_with_service_sockets({ "Socket" => "tcp://127.0.0.1" }), + stub_formula_with_service_sockets({ socket: "tcp://127.0.0.1" }), ].each do |f| expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message end end + + it "throws for invalid host" do + [ + stub_formula_with_service_sockets("tcp://300.0.0.1:80"), + stub_formula_with_service_sockets({ socket: "tcp://300.0.0.1:80" }), + ].each do |f| + expect do + f.service.manual_command + end.to raise_error TypeError, "Service#sockets expects a valid ipv4 or ipv6 host address" + end + end end describe "#manual_command" do @@ -283,8 +294,6 @@ describe Homebrew::Service do \t \t\tlisteners \t\t - \t\t\tSockFamily - \t\t\tIPv4v6 \t\t\tSockNodeName \t\t\t127.0.0.1 \t\t\tSockProtocol @@ -341,8 +350,6 @@ describe Homebrew::Service do \t \t\tsocket \t\t - \t\t\tSockFamily - \t\t\tIPv4v6 \t\t\tSockNodeName \t\t\t0.0.0.0 \t\t\tSockProtocol @@ -352,8 +359,6 @@ describe Homebrew::Service do \t\t \t\tsocket_tls \t\t - \t\t\tSockFamily - \t\t\tIPv4v6 \t\t\tSockNodeName \t\t\t0.0.0.0 \t\t\tSockProtocol @@ -1049,7 +1054,7 @@ describe Homebrew::Service do run_type: :immediate, working_dir: "/$HOME", cron: "0 0 * * 0", - sockets: { listeners: "tcp://0.0.0.0:80" }, + sockets: "tcp://0.0.0.0:80", } end