diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2021-03-02 20:37:31 +0900 |
---|---|---|
committer | NARUSE, Yui <nurse@users.noreply.github.com> | 2021-03-11 17:24:52 +0900 |
commit | f375bc77d2f347dd2a44705b8abd29398feae427 (patch) | |
tree | 0988ab2b519e713ae653cc2e23609b339a9b5979 /lib/rubygems | |
parent | 38f8b8d070aaac02f1d048b5d9947b2e58401e2b (diff) |
Merge RubyGems-3.2.11 and Bundler-2.2.11
Diffstat (limited to 'lib/rubygems')
-rw-r--r-- | lib/rubygems/config_file.rb | 9 | ||||
-rw-r--r-- | lib/rubygems/core_ext/tcpsocket_init.rb | 49 | ||||
-rw-r--r-- | lib/rubygems/remote_fetcher.rb | 1 |
3 files changed, 59 insertions, 0 deletions
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 854d09ef3d..9dc41a2995 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -45,6 +45,7 @@ class Gem::ConfigFile DEFAULT_UPDATE_SOURCES = true DEFAULT_CONCURRENT_DOWNLOADS = 8 DEFAULT_CERT_EXPIRATION_LENGTH_DAYS = 365 + DEFAULT_IPV4_FALLBACK_ENABLED = false ## # For Ruby packagers to set configuration defaults. Set in @@ -141,6 +142,12 @@ class Gem::ConfigFile attr_accessor :cert_expiration_length_days ## + # == Experimental == + # Fallback to IPv4 when IPv6 is not reachable or slow (default: false) + + attr_accessor :ipv4_fallback_enabled + + ## # Path name of directory or file of openssl client certificate, used for remote https connection with client authentication attr_reader :ssl_client_cert @@ -175,6 +182,7 @@ class Gem::ConfigFile @update_sources = DEFAULT_UPDATE_SOURCES @concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS @cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS + @ipv4_fallback_enabled = ENV['IPV4_FALLBACK_ENABLED'] == 'true' || DEFAULT_IPV4_FALLBACK_ENABLED operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS) platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS) @@ -203,6 +211,7 @@ class Gem::ConfigFile @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server @sources = @hash[:sources] if @hash.key? :sources @cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days + @ipv4_fallback_enabled = @hash[:ipv4_fallback_enabled] if @hash.key? :ipv4_fallback_enabled @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert diff --git a/lib/rubygems/core_ext/tcpsocket_init.rb b/lib/rubygems/core_ext/tcpsocket_init.rb new file mode 100644 index 0000000000..3275c58112 --- /dev/null +++ b/lib/rubygems/core_ext/tcpsocket_init.rb @@ -0,0 +1,49 @@ +require 'socket' + +module CoreExtensions + module TCPSocketExt + def self.prepended(base) + base.prepend Initializer + end + + module Initializer + CONNECTION_TIMEOUT = 5 + IPV4_DELAY_SECONDS = 0.1 + + def initialize(host, serv, *rest) + mutex = Mutex.new + addrs = [] + cond_var = ConditionVariable.new + + Addrinfo.foreach(host, serv, nil, :STREAM) do |addr| + Thread.report_on_exception = false if defined? Thread.report_on_exception = () + + Thread.new(addr) do + # give head start to ipv6 addresses + sleep IPV4_DELAY_SECONDS if addr.ipv4? + + # raises Errno::ECONNREFUSED when ip:port is unreachable + Socket.tcp(addr.ip_address, serv, connect_timeout: CONNECTION_TIMEOUT).close + mutex.synchronize do + addrs << addr.ip_address + cond_var.signal + end + end + end + + mutex.synchronize do + timeout_time = CONNECTION_TIMEOUT + Time.now.to_f + while addrs.empty? && (remaining_time = timeout_time - Time.now.to_f) > 0 + cond_var.wait(mutex, remaining_time) + end + + host = addrs.shift unless addrs.empty? + end + + super(host, serv, *rest) + end + end + end +end + +TCPSocket.prepend CoreExtensions::TCPSocketExt diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index 53e840978c..7ac334d30d 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -78,6 +78,7 @@ class Gem::RemoteFetcher # fetching the gem. def initialize(proxy=nil, dns=nil, headers={}) + require 'rubygems/core_ext/tcpsocket_init' if Gem.configuration.ipv4_fallback_enabled require 'net/http' require 'stringio' require 'uri' |