Skip to content

Commit 3d445c9

Browse files
p-mongop
andauthored
Fix RUBY-2272 Exceptions raised during address resolution are not mapped to Mongo::Error (#1947)
Co-authored-by: Oleg Pudeyev <oleg@bsdpower.com>
1 parent 649d7e1 commit 3d445c9

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

lib/mongo/address.rb

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -180,42 +180,44 @@ def inspect
180180
# @return [ Mongo::Socket::SSL | Mongo::Socket::TCP | Mongo::Socket::Unix ]
181181
# The socket.
182182
#
183-
# @raise [ Exception ] If network connection failed.
183+
# @raise [ Mongo::Error ] If network connection failed.
184184
#
185185
# @since 2.0.0
186186
def socket(socket_timeout, ssl_options = {}, options = {})
187-
if seed.downcase =~ Unix::MATCH
188-
specific_address = Unix.new(seed.downcase)
189-
return specific_address.socket(socket_timeout, ssl_options, options)
190-
end
187+
map_exceptions do
188+
if seed.downcase =~ Unix::MATCH
189+
specific_address = Unix.new(seed.downcase)
190+
return specific_address.socket(socket_timeout, ssl_options, options)
191+
end
192+
193+
options = {
194+
connect_timeout: Server::CONNECT_TIMEOUT,
195+
}.update(options)
191196

192-
options = {
193-
connect_timeout: Server::CONNECT_TIMEOUT,
194-
}.update(options)
195-
196-
# When the driver connects to "localhost", it only attempts IPv4
197-
# connections. When the driver connects to other hosts, it will
198-
# attempt both IPv4 and IPv6 connections.
199-
family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
200-
error = nil
201-
# Sometimes Socket#getaddrinfo returns the same info more than once
202-
# (multiple identical items in the returned array). It does not make
203-
# sense to try to connect to the same address more than once, thus
204-
# eliminate duplicates here.
205-
infos = ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM)
206-
results = infos.map do |info|
207-
[info[4], info[3]]
208-
end.uniq
209-
results.each do |family, address_str|
210-
begin
211-
specific_address = FAMILY_MAP[family].new(address_str, port, host)
212-
socket = specific_address.socket(socket_timeout, ssl_options, options)
213-
return socket
214-
rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
215-
error = e
197+
# When the driver connects to "localhost", it only attempts IPv4
198+
# connections. When the driver connects to other hosts, it will
199+
# attempt both IPv4 and IPv6 connections.
200+
family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
201+
error = nil
202+
# Sometimes Socket#getaddrinfo returns the same info more than once
203+
# (multiple identical items in the returned array). It does not make
204+
# sense to try to connect to the same address more than once, thus
205+
# eliminate duplicates here.
206+
infos = ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM)
207+
results = infos.map do |info|
208+
[info[4], info[3]]
209+
end.uniq
210+
results.each do |family, address_str|
211+
begin
212+
specific_address = FAMILY_MAP[family].new(address_str, port, host)
213+
socket = specific_address.socket(socket_timeout, ssl_options, options)
214+
return socket
215+
rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
216+
error = e
217+
end
216218
end
219+
raise error
217220
end
218-
raise error
219221
end
220222

221223
# Get the address as a string.
@@ -248,5 +250,17 @@ def parse_host_port
248250
else IPv4.parse(address)
249251
end
250252
end
253+
254+
def map_exceptions
255+
begin
256+
yield
257+
rescue Errno::ETIMEDOUT => e
258+
raise Error::SocketTimeoutError, "#{e.class}: #{e} (for #{self})"
259+
rescue IOError, SystemCallError => e
260+
raise Error::SocketError, "#{e.class}: #{e} (for #{self})"
261+
rescue OpenSSL::SSL::SSLError => e
262+
raise Error::SocketError, "#{e.class}: #{e} (for #{self}) (#{SSL_ERROR})"
263+
end
264+
end
251265
end
252266
end

0 commit comments

Comments
 (0)