123456789_123456789_123456789_123456789_123456789_

Class: Bundler::Fetcher::ConnectionPools

Relationships & Source Files
Namespace Children
Classes:
Inherits: Object
Defined in: lib/bundler/fetcher/connection_pools.rb

Overview

Hands out pools of configured Gem::Net::HTTP connections, compatible with the checkout/checkin interface that Gem::Request expects. Connection policy (proxy, SSL, timeouts) follows ::Bundler settings first, falling back to RubyGems configuration.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(size:, timeout:) ⇒ ConnectionPools

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 38

def initialize(size:, timeout:)
  @size = size
  @timeout = timeout
  @override_headers = {}
  @cert_files = Gem::Request.get_cert_files
  @pools = {}
  @pool_mutex = Thread::Mutex.new
end

Instance Attribute Details

#cert_files (readonly)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 36

attr_reader :override_headers, :cert_files

#override_headers (readonly)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 36

attr_reader :override_headers, :cert_files

Instance Method Details

#build_connection(uri, proxy_uri)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 82

def build_connection(uri, proxy_uri) # :nodoc:
  args = [uri.hostname, uri.port]
  args += if proxy_uri
    [proxy_uri.hostname, proxy_uri.port,
     Gem::UriFormatter.new(proxy_uri.user).unescape,
     Gem::UriFormatter.new(proxy_uri.password).unescape]
  else
    [nil, nil]
  end

  connection = Gem::Request::ConnectionPools.client.new(*args)
  configure_ssl(connection) if uri.scheme == "https"
  connection.open_timeout = @timeout
  connection.read_timeout = @timeout
  # Stale connections are already resent by Gem::Request#perform_request,
  # and Bundler::Retry retries whole requests, so the Gem::Net::HTTP
  # level retry would only multiply the time spent on a timing out host.
  connection.max_retries = 0
  connection.start
  connection
end

#bundler_cert_store (private)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 131

def bundler_cert_store
  store = OpenSSL::X509::Store.new
  ssl_ca_cert = Bundler.settings[:ssl_ca_cert] ||
                (Gem.configuration.ssl_ca_cert if
                  Gem.configuration.respond_to?(:ssl_ca_cert))
  if ssl_ca_cert
    if File.directory? ssl_ca_cert
      store.add_path ssl_ca_cert
    else
      store.add_file ssl_ca_cert
    end
  else
    store.set_default_paths
    cert_files.each {|c| store.add_file c }
  end
  store
end

#configure_ssl(connection) (private)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 116

def configure_ssl(connection)
  connection.use_ssl = true
  connection.verify_mode = Bundler.settings[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_PEER
  connection.cert_store = bundler_cert_store

  ssl_client_cert = Bundler.settings[:ssl_client_cert] ||
                    (Gem.configuration.ssl_client_cert if
                      Gem.configuration.respond_to?(:ssl_client_cert))
  return unless ssl_client_cert

  pem = File.read(ssl_client_cert)
  connection.cert = OpenSSL::X509::Certificate.new(pem)
  connection.key  = OpenSSL::PKey.read(pem)
end

#env_proxy_for(uri) (private)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 106

def env_proxy_for(uri)
  proxy = Gem::Request.get_proxy_from_env(uri.scheme)
  proxy = Gem::Request.get_proxy_from_env("http") if proxy == :no_proxy && uri.scheme == "https"
  proxy == :no_proxy ? nil : proxy
end

#no_proxy_env (private)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 112

def no_proxy_env
  ENV["no_proxy"] || ENV["NO_PROXY"] || ""
end

#pool_for(uri)

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 56

def pool_for(uri)
  key = [uri.scheme, uri.hostname, uri.port]
  @pool_mutex.synchronize do
    @pools[key] ||= Pool.new(self, uri, proxy_for(uri), @size)
  end
end

#proxy_for(uri)

The proxy that will be used for Bundler::Fetcher#uri, or nil. RubyGems configuration takes precedence over the environment, like Gem::RemoteFetcher. Unlike Gem::Request, an https URI falls back to Bundler::Fetcher#http_proxy when no https-specific proxy is set, which is what the previous net-http-persistent based transport did.

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 68

def proxy_for(uri)
  proxy = if config_proxy = Gem.configuration[:http_proxy]
    Gem::Request.proxy_uri(config_proxy)
  else
    env_proxy_for(uri)
  end
  return unless proxy
  # NO_PROXY="*" bypasses the proxy for every host, which
  # Gem::URI::Generic.use_proxy? does not understand.
  return if no_proxy_env.strip == "*"
  return unless Gem::URI::Generic.use_proxy?(uri.hostname, nil, uri.port, no_proxy_env)
  proxy
end

#request(uri, headers = nil)

Performs a GET request through Gem::Request, which handles resetting and retrying stale connections, and returns the raw response.

[ GitHub ]

  
# File 'lib/bundler/fetcher/connection_pools.rb', line 49

def request(uri, headers = nil)
  Gem::Request.new(uri, Gem::Net::HTTP::Get, nil, pool_for(uri)).fetch do |request|
    @override_headers.each {|key, value| request[key] = value }
    headers&.each {|key, value| request[key] = value }
  end
end