class Gems::Connection

Manages HTTP connections to the RubyGems API

The connection of a client is its own, and cannot be given to it or read from it, so this class can change within 3.x as the rest of the internals can. Its settings are options of {Client} and of the {Gems} module, such as ‘open_timeout` and `proxy_url`, which is where they are configured.

@api private

Constants

DEFAULT_KEEP_ALIVE_TIMEOUT
DEFAULT_OPEN_TIMEOUT

Default timeout for opening connections in seconds

DEFAULT_READ_TIMEOUT
DEFAULT_WRITE_TIMEOUT

Attributes

The IO object for debug output

The credentials requests and responses carry are redacted from what is written to it (see {RedactedOutput}).

@api private @return [IO, nil] the IO object for debug output @example Get or set the debug output

connection.debug_output = $stderr

The parsed proxy URI @api private @return [URI::Generic, nil] the parsed proxy URI @example Get the proxy URI

connection.proxy_uri

The proxy URL for requests @api private @return [String, nil] the proxy URL for requests @example Get the proxy URL

connection.proxy_url

Public Class Methods

Initialize a new connection

@api private @param open_timeout [Numeric] the timeout for opening connections in seconds @param read_timeout [Numeric] the timeout for reading responses in seconds @param write_timeout [Numeric] the timeout for writing requests in seconds @param debug_output [IO, nil] the IO object for debug output @param proxy_url [String, nil] the proxy URL for requests @param keep_alive_timeout [Numeric] the seconds an idle connection is kept open for another request @param ca_file [String, nil] the path of a file of certificates TLS is verified with @param ca_path [String, nil] the path of a directory of certificates TLS is verified with @param cert_store [OpenSSL::X509::Store, nil] the store of certificates TLS is verified with @param client_cert [OpenSSL::X509::Certificate, nil] the certificate presented to a host that asks for one @param client_key [OpenSSL::PKey::PKey, nil] the private key of the client certificate @return [Connection] a new connection instance @raise [ArgumentError] if the proxy URL is invalid, or a certificate path names nothing @example Create a connection with default settings

connection = Gems::Connection.new

@example Create a connection with custom timeouts

connection = Gems::Connection.new(open_timeout: 30, read_timeout: 30)

@example Create a connection that trusts a certificate of its own

connection = Gems::Connection.new(ca_file: "/etc/ssl/certs/internal.pem")
# File lib/gems/connection.rb, line 160
def initialize(open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT,
  write_timeout: DEFAULT_WRITE_TIMEOUT, debug_output: nil, proxy_url: nil,
  keep_alive_timeout: DEFAULT_KEEP_ALIVE_TIMEOUT, ca_file: nil, ca_path: nil, cert_store: nil,
  client_cert: nil, client_key: nil)
  self.open_timeout = open_timeout
  self.read_timeout = read_timeout
  self.write_timeout = write_timeout
  @debug_output = debug_output
  self.keep_alive_timeout = keep_alive_timeout
  @pool = ConnectionPool.new
  self.proxy_url = proxy_url
  initialize_certificates(ca_file:, ca_path:, cert_store:, client_cert:, client_key:)
end

Public Instance Methods

Close the connections kept open for the next request

The connections are opened again as they are needed, so a connection that is closed while it is being used is not interrupted, and requests can still be made afterwards.

@api private @return [Connection] the connection @example Close the connections a client keeps open

connection.close
# File lib/gems/connection.rb, line 205
def close
  pool.close
  self
end

Summarize the connection for the console

@api private @return [String] the summary, which includes the proxy URL without its user and password @example Inspect a connection

connection.inspect # => #<Gems::Connection proxy_url=nil open_timeout=60 read_timeout=60 write_timeout=60 keep_alive_timeout=2>
# File lib/gems/connection.rb, line 133
def inspect
  "#<#{self.class} proxy_url=#{redact(proxy_url).inspect} open_timeout=#{open_timeout} " \
    "read_timeout=#{read_timeout} write_timeout=#{write_timeout} keep_alive_timeout=#{keep_alive_timeout}>"
end

Perform an HTTP request

The request is sent on the connection kept open for its host, when there is one it can be sent on, and that connection is kept open for the next request (see {#keep_alive_timeout}).

The settings are read once, before the connection is taken, and a connection that has to be opened is opened with them and kept under them, so that a setting changed while the request is being sent, from another thread, closes the connection when the next request is sent rather than keeping it as though it had been opened with the setting as it is now, and a connection is never opened with one setting and kept under another.

@api private @param request [Net::HTTPRequest] the HTTP request to perform @return [Net::HTTPResponse] the HTTP response @raise [NetworkError] if a network error occurs @example Perform a request

response = connection.perform(request: request)
# File lib/gems/connection.rb, line 190
def perform(request:)
  send_request(request, settings_for(request.uri))
rescue *NetworkError::WRAPPED => e
  raise NetworkError, "Network error: #{e}"
end

Set the proxy URL for requests

@api private @param proxy_url [String, nil] the proxy URL, or nil to read proxies from the environment again @return [void] @raise [ArgumentError] if the proxy URL is invalid, in which case the proxy is left as it was @example Set the proxy URL

connection.proxy_url = "http://proxy.example.com:8080"

@example Clear the proxy URL

connection.proxy_url = nil
# File lib/gems/connection.rb, line 220
def proxy_url=(proxy_url)
  proxy_uri = proxy_url && parse_proxy_uri(proxy_url)
  @proxy_url = proxy_url
  @proxy_uri = proxy_uri
end