diff --git a/lib/net/http.rb b/lib/net/http.rb index f64f7ba..1858404 100644 --- a/lib/net/http.rb +++ b/lib/net/http.rb @@ -1654,14 +1654,20 @@ def connect end debug "opening connection to #{conn_addr}:#{conn_port}..." - s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { - begin - TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) - rescue => e - raise e, "Failed to open TCP connection to " + - "#{conn_addr}:#{conn_port} (#{e.message})" + begin + # Use built-in timeout in Socket.tcp if available + s = if Socket.method(:tcp).parameters.any? {|param| param[0] == :key && param[1] == :open_timeout } + Socket.tcp(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout) + else + Timeout.timeout(@open_timeout, Net::OpenTimeout) { + TCPSocket.open(conn_addr, conn_port, @local_host, @local_port) + } end - } + rescue => e + e = Net::OpenTimeout.new(e) if e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions + raise e, "Failed to open TCP connection to " + + "#{conn_addr}:#{conn_port} (#{e.message})" + end s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) debug "opened" if use_ssl? diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index 366b4cd..af05ff9 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -246,8 +246,8 @@ def test_failure_message_includes_failed_domain_and_port # hostname to be included in the error message host = Struct.new(:to_s).new("") port = 2119 - # hack to let TCPSocket.open fail - def host.to_str; raise SocketError, "open failure"; end + # hack to let Socket.tcp fail + def host.match?(_); raise SocketError, "open failure"; end uri = Struct.new(:scheme, :hostname, :port).new("http", host, port) assert_raise_with_message(SocketError, /#{host}:#{port}/) do TestNetHTTPUtils.clean_http_proxy_env{ Net::HTTP.get(uri) }