summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeha Pansare <neha.pansare@progress.com>2023-05-04 21:47:22 +0530
committerNeha Pansare <neha.pansare@progress.com>2023-05-17 16:47:24 +0530
commit67990efc48fc73b6906c48bfdc5202694db58209 (patch)
tree1e230ab9d6bfaa177c48b57074ad44d1a883677a
parent89d6265e75b3daf795c7fd1345d40398a9b634df (diff)
downloadchef-neha-p6/patch_ruby_new_http.tar.gz
Add monkey-patch to net-http which to fix increased IPv6 url response time with ruby 3.1.xneha-p6/patch_ruby_new_http
Signed-off-by: Neha Pansare <neha.pansare@progress.com> Fix linting Signed-off-by: Neha Pansare <neha.pansare@progress.com> Add condition to load net/http patch only for ruby3.1 Signed-off-by: Neha Pansare <neha.pansare@progress.com>
-rw-r--r--cspell.json6
-rw-r--r--lib/chef/application/base.rb2
-rw-r--r--lib/chef/monkey_patches/net-http.rb123
3 files changed, 131 insertions, 0 deletions
diff --git a/cspell.json b/cspell.json
index ce2e83937e..13e5946b21 100644
--- a/cspell.json
+++ b/cspell.json
@@ -436,6 +436,7 @@
"getsebool",
"getspnam",
"gettext",
+ "gettime",
"GETTHUMBPRINTCODE",
"gettimezone",
"gettype",
@@ -572,11 +573,14 @@
"IPADDR",
"ipaddr",
"ipaddress",
+ "IPPROTO",
"ireton",
"isalnum",
"isalpha",
"isatty",
"isdigit",
+ "IVNAMES",
+ "ivname",
"Jagtap",
"jailmode",
"janky",
@@ -829,6 +833,7 @@
"nobrowse",
"NOCHANGES",
"NOCOMPACT",
+ "NODELAY",
"noconfirm",
"Nodearray",
"Nodename",
@@ -1194,6 +1199,7 @@
"setools",
"setsebool",
"setsid",
+ "setsockopt",
"settimezone",
"SETTINGCHANGE",
"setuid",
diff --git a/lib/chef/application/base.rb b/lib/chef/application/base.rb
index f4c365d390..fd1d3db023 100644
--- a/lib/chef/application/base.rb
+++ b/lib/chef/application/base.rb
@@ -24,6 +24,8 @@ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
require_relative "../daemon"
require "chef-config/mixin/dot_d"
require "license_acceptance/cli_flags/mixlib_cli"
+require "chef/monkey_patches/net-http"
+
module Mixlib
autoload :Archive, "mixlib/archive"
end
diff --git a/lib/chef/monkey_patches/net-http.rb b/lib/chef/monkey_patches/net-http.rb
new file mode 100644
index 0000000000..fc192faf71
--- /dev/null
+++ b/lib/chef/monkey_patches/net-http.rb
@@ -0,0 +1,123 @@
+if RUBY_VERSION.split(".")[0..1].join(".") == "3.1"
+ require "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 < Protocol
+ 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
+
+ # 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 \ No newline at end of file