@@ -90,6 +90,12 @@ class TCP < TCPSocket
9090 # options - supports enhanced logging in the case of a timeout
9191 attr_accessor :options
9292
93+ # Expected parameter signature for unmodified TCPSocket#initialize.
94+ # Used to detect when gems like socksify or resolv-replace have monkey-patched
95+ # TCPSocket, which breaks the connect_timeout: keyword argument.
96+ TCPSOCKET_NATIVE_PARAMETERS = [ [ :rest ] ] . freeze
97+ private_constant :TCPSOCKET_NATIVE_PARAMETERS
98+
9399 def self . open ( host , port , options = { } )
94100 create_socket_with_timeout ( host , port , options ) do |sock |
95101 sock . options = { host : host , port : port } . merge ( options )
@@ -99,15 +105,18 @@ def self.open(host, port, options = {})
99105 end
100106 end
101107
108+ # Detect and cache whether TCPSocket supports the connect_timeout: keyword argument.
109+ # Returns false if TCPSocket#initialize has been monkey-patched by gems like
110+ # socksify or resolv-replace, which don't support keyword arguments.
111+ def self . supports_connect_timeout?
112+ return @supports_connect_timeout if defined? ( @supports_connect_timeout )
113+
114+ @supports_connect_timeout = RUBY_VERSION >= '3.0' &&
115+ ::TCPSocket . instance_method ( :initialize ) . parameters == TCPSOCKET_NATIVE_PARAMETERS
116+ end
117+
102118 def self . create_socket_with_timeout ( host , port , options )
103- # Check that TCPSocket#initialize was not overwritten by resolv-replace gem
104- # (part of ruby standard library since 3.0.0, should be removed in 3.4.0),
105- # as it does not handle keyword arguments correctly.
106- # To check this we are using the fact that resolv-replace
107- # aliases TCPSocket#initialize method to #original_resolv_initialize.
108- # https://github.com/ruby/resolv-replace/blob/v0.1.1/lib/resolv-replace.rb#L21
109- if RUBY_VERSION >= '3.0' &&
110- !::TCPSocket . private_method_defined? ( :original_resolv_initialize )
119+ if supports_connect_timeout?
111120 sock = new ( host , port , connect_timeout : options [ :socket_timeout ] )
112121 yield ( sock )
113122 else
0 commit comments