diff options
author | ThibG <thib@sitedethib.com> | 2019-09-05 05:32:53 +0200 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2019-09-05 05:32:53 +0200 |
commit | 1653b587778db0df201507115d19c0530096a5e3 (patch) | |
tree | b7b0c7a51371d3d72d9cebd6ca05bb0aa0cd4c07 /app/lib | |
parent | 529856a6087a88a14fe19ec0ede96573761bfe34 (diff) |
Attempt to concurrently connect to remote IP addresses (#11757)
* Attempt to concurrently connect to remote IP addresses * Reduce code length to please CodeClimate 🤷
Diffstat (limited to 'app/lib')
-rw-r--r-- | app/lib/request.rb | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/app/lib/request.rb b/app/lib/request.rb index 9d874fe2c..42ccc6513 100644 --- a/app/lib/request.rb +++ b/app/lib/request.rb @@ -191,6 +191,9 @@ class Request end end + socks = [] + addr_by_socket = {} + addresses.each do |address| begin check_private_address(address) @@ -200,30 +203,45 @@ class Request sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1) - begin - sock.connect_nonblock(sockaddr) - rescue IO::WaitWritable - if IO.select(nil, [sock], nil, Request::TIMEOUT[:connect]) - begin - sock.connect_nonblock(sockaddr) - rescue Errno::EISCONN - # Yippee! - rescue - sock.close - raise - end - else - sock.close - raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect]} seconds" - end - end + sock.connect_nonblock(sockaddr) + # If that hasn't raised an exception, we somehow managed to connect + # immediately, close pending sockets and return immediately + socks.each(&:close) return sock + rescue IO::WaitWritable + socks << sock + addr_by_socket[sock] = sockaddr rescue => e outer_e = e end end + until socks.empty? + _, available_socks, = IO.select(nil, socks, nil, Request::TIMEOUT[:connect]) + + if available_socks.nil? + socks.each(&:close) + raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect]} seconds" + end + + available_socks.each do |sock| + socks.delete(sock) + + begin + sock.connect_nonblock(addr_by_socket[sock]) + rescue Errno::EISCONN + rescue => e + sock.close + outer_e = e + next + end + + socks.each(&:close) + return sock + end + end + if outer_e raise outer_e else |