class ActiveMerchant::Connection

Constants

CA_FILE
CA_PATH
MAX_RETRIES
MIN_VERSION
OPEN_TIMEOUT
READ_TIMEOUT
RETRY_SAFE
RUBY_184_POST_HEADERS
VERIFY_PEER

Attributes

ca_file[RW]
ca_path[RW]
endpoint[RW]
ignore_http_status[RW]
logger[RW]
max_retries[RW]
open_timeout[RW]
pem[RW]
pem_password[RW]
proxy_address[RW]
proxy_port[RW]
read_timeout[RW]
ssl_connection[R]
ssl_version[RW]
tag[RW]
verify_peer[RW]
wiredump_device[R]

Public Class Methods

new(endpoint) click to toggle source
# File lib/active_merchant/connection.rb, line 43
def initialize(endpoint)
  @endpoint     = endpoint.is_a?(URI) ? endpoint : URI.parse(endpoint)
  @open_timeout = OPEN_TIMEOUT
  @read_timeout = READ_TIMEOUT
  @retry_safe   = RETRY_SAFE
  @verify_peer  = VERIFY_PEER
  @ca_file      = CA_FILE
  @ca_path      = CA_PATH
  @max_retries  = MAX_RETRIES
  @ignore_http_status = false
  @ssl_version = nil
  if Net::HTTP.instance_methods.include?(:min_version=)
    @min_version = MIN_VERSION
    @max_version = nil
  end
  @ssl_connection = {}
  @proxy_address = :ENV
  @proxy_port = nil
end

Public Instance Methods

request(method, body, headers = {}) click to toggle source
# File lib/active_merchant/connection.rb, line 68
def request(method, body, headers = {})
  request_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  headers = headers.dup
  headers['connection'] ||= 'close'

  retry_exceptions(:max_retries => max_retries, :logger => logger, :tag => tag) do
    begin
      info "connection_http_method=#{method.to_s.upcase} connection_uri=#{endpoint}", tag

      result = nil

      realtime = Benchmark.realtime do
        http.start unless http.started?
        @ssl_connection = http.ssl_connection
        info "connection_ssl_version=#{ssl_connection[:version]} connection_ssl_cipher=#{ssl_connection[:cipher]}", tag

        result = case method
        when :get
          raise ArgumentError, 'GET requests do not support a request body' if body
          http.get(endpoint.request_uri, headers)
        when :post
          debug body
          http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers))
        when :put
          debug body
          http.put(endpoint.request_uri, body, headers)
        when :patch
          debug body
          http.patch(endpoint.request_uri, body, headers)
        when :delete
          # It's kind of ambiguous whether the RFC allows bodies
          # for DELETE requests. But Net::HTTP's delete method
          # very unambiguously does not.
          if body
            debug body
            req = Net::HTTP::Delete.new(endpoint.request_uri, headers)
            req.body = body
            http.request(req)
          else
            http.delete(endpoint.request_uri, headers)
          end
        else
          raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
        end
      end

      info '--> %d %s (%d %.4fs)' % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
      debug result.body
      result
    end
  end
ensure
  info 'connection_request_total_time=%.4fs' % [Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start], tag
  http.finish if http.started?
end
wiredump_device=(device) click to toggle source
# File lib/active_merchant/connection.rb, line 63
def wiredump_device=(device)
  raise ArgumentError, "can't wiredump to frozen #{device.class}" if device&.frozen?
  @wiredump_device = device
end

Private Instance Methods

configure_cert(http) click to toggle source
# File lib/active_merchant/connection.rb, line 166
def configure_cert(http)
  return if pem.blank?

  http.cert = OpenSSL::X509::Certificate.new(pem)

  if pem_password
    http.key = OpenSSL::PKey::RSA.new(pem, pem_password)
  else
    http.key = OpenSSL::PKey::RSA.new(pem)
  end
end
configure_debugging(http) click to toggle source
# File lib/active_merchant/connection.rb, line 138
def configure_debugging(http)
  http.set_debug_output(wiredump_device)
end
configure_ssl(http) click to toggle source
# File lib/active_merchant/connection.rb, line 147
def configure_ssl(http)
  return unless endpoint.scheme == 'https'

  http.use_ssl = true
  http.ssl_version = ssl_version if ssl_version
  if http.respond_to?(:min_version=)
    http.min_version = min_version if min_version
    http.max_version = max_version if max_version
  end

  if verify_peer
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    http.ca_file     = ca_file
    http.ca_path     = ca_path
  else
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  end
end
configure_timeouts(http) click to toggle source
# File lib/active_merchant/connection.rb, line 142
def configure_timeouts(http)
  http.open_timeout = open_timeout
  http.read_timeout = read_timeout
end
debug(message, tag = nil) click to toggle source
# File lib/active_merchant/connection.rb, line 178
def debug(message, tag = nil)
  log(:debug, message, tag)
end
error(message, tag = nil) click to toggle source
# File lib/active_merchant/connection.rb, line 186
def error(message, tag = nil)
  log(:error, message, tag)
end
http() click to toggle source
# File lib/active_merchant/connection.rb, line 127
def http
  @http ||= begin
    http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port)
    configure_debugging(http)
    configure_timeouts(http)
    configure_ssl(http)
    configure_cert(http)
    http
  end
end
info(message, tag = nil) click to toggle source
# File lib/active_merchant/connection.rb, line 182
def info(message, tag = nil)
  log(:info, message, tag)
end
log(level, message, tag) click to toggle source
# File lib/active_merchant/connection.rb, line 190
def log(level, message, tag)
  message = "[#{tag}] #{message}" if tag
  logger&.send(level, message)
end