@@ -1179,6 +1179,7 @@ def initialize(address, port = nil) # :nodoc:
11791179 @debug_output = options [ :debug_output ]
11801180 @response_body_encoding = options [ :response_body_encoding ]
11811181 @ignore_eof = options [ :ignore_eof ]
1182+ @tcpsocket_supports_open_timeout = nil
11821183
11831184 @proxy_from_env = false
11841185 @proxy_uri = nil
@@ -1672,14 +1673,36 @@ def connect
16721673 end
16731674
16741675 debug "opening connection to #{ conn_addr } :#{ conn_port } ..."
1675- s = Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1676- begin
1677- TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1678- rescue => e
1679- raise e , "Failed to open TCP connection to " +
1680- "#{ conn_addr } :#{ conn_port } (#{ e . message } )"
1681- end
1682- }
1676+ begin
1677+ s =
1678+ case @tcpsocket_supports_open_timeout
1679+ when nil , true
1680+ begin
1681+ # Use built-in timeout in TCPSocket.open if available
1682+ sock = TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port , open_timeout : @open_timeout )
1683+ @tcpsocket_supports_open_timeout = true
1684+ sock
1685+ rescue ArgumentError => e
1686+ raise if !( e . message . include? ( 'unknown keyword: :open_timeout' ) || e . message . include? ( 'wrong number of arguments (given 5, expected 2..4)' ) )
1687+ @tcpsocket_supports_open_timeout = false
1688+
1689+ # Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1690+ Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1691+ TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1692+ }
1693+ end
1694+ when false
1695+ # The current Ruby is known to not support TCPSocket(open_timeout:).
1696+ # Directly fall back to Timeout.timeout to avoid performance penalty incured by rescue.
1697+ Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1698+ TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1699+ }
1700+ end
1701+ rescue => e
1702+ e = Net ::OpenTimeout . new ( e ) if e . is_a? ( Errno ::ETIMEDOUT ) # for compatibility with previous versions
1703+ raise e , "Failed to open TCP connection to " +
1704+ "#{ conn_addr } :#{ conn_port } (#{ e . message } )"
1705+ end
16831706 s . setsockopt ( Socket ::IPPROTO_TCP , Socket ::TCP_NODELAY , 1 )
16841707 debug "opened"
16851708 if use_ssl?
0 commit comments