if RUBY_VERSION.split(".")[0..1].join(".") == "3.1" require "net/http" unless defined?(Net::HTTP) # This is monkey-patch for ruby 3.1.x # Due to change https://github.com/ruby/net-http/pull/10, when making net/http requests to a url which supports only IPv6 and not IPv4, # ruby waits for IPv4 request to timeout first, then makes IPv6 request. This increased response time. # NOTE 1: This is already reverted https://github.com/ruby/ruby/commit/f88bff770578583a708093f4a0d8b1483a1d2039 but under ruby 3.2.2 # NOTE 2: We are patching action `connect` from here https://github.com/ruby/ruby/blob/f88bff770578583a708093f4a0d8b1483a1d2039/lib/net/http.rb#L1000 module Net class HTTP def connect if use_ssl? # reference early to load OpenSSL before connecting, # as OpenSSL may take time to load. @ssl_context = OpenSSL::SSL::SSLContext.new end if proxy? conn_addr = proxy_address conn_port = proxy_port else conn_addr = conn_address conn_port = port end puts "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})" end } s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) puts "opened" if use_ssl? if proxy? plain_sock = BufferedIO.new(s, read_timeout: @read_timeout, write_timeout: @write_timeout, continue_timeout: @continue_timeout, debug_output: @debug_output) buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" buf << "Host: #{@address}:#{@port}\r\n" if proxy_user credential = ["#{proxy_user}:#{proxy_pass}"].pack("m0") buf << "Proxy-Authorization: Basic #{credential}\r\n" end buf << "\r\n" plain_sock.write(buf) HTTPResponse.read_new(plain_sock).value # assuming nothing left in buffers after successful CONNECT response end ssl_parameters = {} iv_list = instance_variables SSL_IVNAMES.each_with_index do |ivname, i| if iv_list.include?(ivname) value = instance_variable_get(ivname) unless value.nil? ssl_parameters[SSL_ATTRIBUTES[i]] = value end end end @ssl_context.set_params(ssl_parameters) unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby @ssl_context.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE end if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby @ssl_context.session_new_cb = proc { |sock, sess| @ssl_session = sess } end # Still do the post_connection_check below even if connecting # to IP address verify_hostname = @ssl_context.verify_hostname # requiring 'resolv' near the top of the file causes registry.rb monkey patch to fail # Windows 2012 R2 somehow fails to have Resolv defined unless we require it manually require "resolv" unless defined?(Resolv) # Server Name Indication (SNI) RFC 3546/6066 case @address when ::Resolv::IPv4::Regex, ::Resolv::IPv6::Regex # don't set SNI, as IP addresses in SNI is not valid # per RFC 6066, section 3. # Avoid openssl warning @ssl_context.verify_hostname = false else ssl_host_address = @address end puts "starting SSL for #{conn_addr}:#{conn_port}..." s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) s.sync_close = true s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address if @ssl_session && (Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout) s.session = @ssl_session end ssl_socket_connect(s, @open_timeout) if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname s.post_connection_check(@address) end puts "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}" end @socket = BufferedIO.new(s, read_timeout: @read_timeout, write_timeout: @write_timeout, continue_timeout: @continue_timeout, debug_output: @debug_output) @last_communicated = nil on_connect rescue => exception if s puts "Conn close because of connect error #{exception}" s.close end raise end end end else warn "Not applying net/http monkey patch needed for ruby 3.1" end