Class: Recurly::HTTP::DefaultHttpAdapter

Inherits:
Adapter
  • Object
show all
Defined in:
lib/recurly/http/default_http_adapter.rb

Overview

The default transport adapter, backed by Net::HTTP. It uses the shared connection pool passed in at construction (it does NOT own a private pool) and preserves the byte-identical behavior the client had before the adapter seam was introduced.

Instance Method Summary collapse

Constructor Details

#initialize(connection_pool:, keep_alive_timeout:, ca_file: nil, read_timeout: 60, open_timeout: 20) ⇒ DefaultHttpAdapter

Returns a new instance of DefaultHttpAdapter.

Parameters:

  • connection_pool (Recurly::ConnectionPool)

    the shared, class-level pool

  • keep_alive_timeout (Integer)

    seconds; forwarded to the pool

  • ca_file (String, nil) (defaults to: nil)

    CA bundle path; forwarded to the pool

  • read_timeout (Numeric) (defaults to: 60)

    default read timeout in SECONDS (default 60). Same unit as the per-request read_timeout: override accepted by #call.

  • open_timeout (Numeric) (defaults to: 20)

    default open timeout in SECONDS (default 20). Same unit as the per-request open_timeout: override accepted by #call.



17
18
19
20
21
22
23
# File 'lib/recurly/http/default_http_adapter.rb', line 17

def initialize(connection_pool:, keep_alive_timeout:, ca_file: nil, read_timeout: 60, open_timeout: 20)
  @connection_pool = connection_pool
  @keep_alive_timeout = keep_alive_timeout
  @ca_file = ca_file
  @read_timeout = read_timeout
  @open_timeout = open_timeout
end

Instance Method Details

#call(method, url, headers, body, open_timeout: nil, read_timeout: nil) ⇒ Recurly::HTTP::AdapterResponse

Parameters:

  • method (String)

    a HttpMethod constant

  • url (String)

    the ABSOLUTE request url (scheme+host+path+query)

  • headers (Hash)

    app-level request headers

  • body (String, nil)

    serialized request body

  • open_timeout (Numeric, nil) (defaults to: nil)

    per-request open timeout override, in SECONDS

  • read_timeout (Numeric, nil) (defaults to: nil)

    per-request read timeout override, in SECONDS

Returns:

Raises:



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/recurly/http/default_http_adapter.rb', line 33

def call(method, url, headers, body, open_timeout: nil, read_timeout: nil)
  # Parse/build outside the transport rescue: a bad URL or unsupported verb
  # is a programming error and must raise immediately, not be wrapped in a
  # (retried) TransportError.
  uri = parse_url(url)
  request = build_request(method, uri, headers, body)

  net_response = begin
      @connection_pool.with_connection(uri: uri, keep_alive_timeout: @keep_alive_timeout, ca_file: @ca_file) do |http|
        http.open_timeout = open_timeout || @open_timeout
        http.read_timeout = read_timeout || @read_timeout
        http.start unless http.started?
        http.request(request)
      end
    rescue Net::OpenTimeout, Errno::ETIMEDOUT => ex
      raise Recurly::Errors::TransportError.new("Request timed out", kind: :timeout, cause: ex)
    rescue Timeout::Error => ex
      # Net::ReadTimeout < Timeout::Error. This clause MUST precede the
      # StandardError clause so read timeouts map to :timeout (invariant A).
      raise Recurly::Errors::TransportError.new("Request timed out", kind: :timeout, cause: ex)
    rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ECONNABORTED,
           Errno::EPIPE, EOFError, SocketError => ex
      raise Recurly::Errors::TransportError.new("Failed to connect to Recurly: #{ex.message}", kind: :connection, cause: ex)
    rescue OpenSSL::SSL::SSLError => ex
      raise Recurly::Errors::TransportError.new(ex.message, kind: :ssl, cause: ex)
    rescue StandardError => ex
      raise Recurly::Errors::TransportError.new(ex.message, kind: :network, cause: ex)
    end

  to_adapter_response(net_response)
end