@@ -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
@@ -1655,16 +1656,30 @@ def connect
16551656
16561657 debug "opening connection to #{ conn_addr } :#{ conn_port } ..."
16571658 begin
1658- s = begin
1659- # Use built-in timeout in TCPSocket.open if available
1660- TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port , open_timeout : @open_timeout )
1661- rescue ArgumentError => e
1662- raise if !( e . message . include? ( 'unknown keyword: :open_timeout' ) || e . message . include? ( 'wrong number of arguments (given 5, expected 2..4)' ) )
1663- # Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1664- Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1665- TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1666- }
1667- end
1659+ s =
1660+ case @tcpsocket_supports_open_timeout
1661+ when nil , true
1662+ begin
1663+ # Use built-in timeout in TCPSocket.open if available
1664+ sock = TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port , open_timeout : @open_timeout )
1665+ @tcpsocket_supports_open_timeout = true
1666+ sock
1667+ rescue ArgumentError => e
1668+ raise if !( e . message . include? ( 'unknown keyword: :open_timeout' ) || e . message . include? ( 'wrong number of arguments (given 5, expected 2..4)' ) )
1669+ @tcpsocket_supports_open_timeout = false
1670+
1671+ # Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1672+ Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1673+ TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1674+ }
1675+ end
1676+ when false
1677+ # The current Ruby is known to not support TCPSocket(open_timeout:).
1678+ # Directly fall back to Timeout.timeout to avoid performance penalty incured by rescue.
1679+ Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1680+ TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1681+ }
1682+ end
16681683 rescue => e
16691684 e = Net ::OpenTimeout . new ( e ) if e . is_a? ( Errno ::ETIMEDOUT ) # for compatibility with previous versions
16701685 raise e , "Failed to open TCP connection to " +
0 commit comments