@@ -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
@@ -1673,16 +1674,30 @@ def connect
16731674
16741675 debug "opening connection to #{ conn_addr } :#{ conn_port } ..."
16751676 begin
1676- s = begin
1677- # Use built-in timeout in TCPSocket.open if available
1678- TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port , open_timeout : @open_timeout )
1679- rescue ArgumentError => e
1680- raise if !( e . message . include? ( 'unknown keyword: :open_timeout' ) || e . message . include? ( 'wrong number of arguments (given 5, expected 2..4)' ) )
1681- # Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1682- Timeout . timeout ( @open_timeout , Net ::OpenTimeout ) {
1683- TCPSocket . open ( conn_addr , conn_port , @local_host , @local_port )
1684- }
1685- end
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
16861701 rescue => e
16871702 e = Net ::OpenTimeout . new ( e ) if e . is_a? ( Errno ::ETIMEDOUT ) # for compatibility with previous versions
16881703 raise e , "Failed to open TCP connection to " +
0 commit comments