Class: ConvertSdk::HttpClient
- Inherits:
-
Object
- Object
- ConvertSdk::HttpClient
- Defined in:
- lib/convert_sdk/http_client.rb
Overview
The single hardened HTTP port every SDK request flows through.
HttpClient is the only file in the gem that touches Net::HTTP (a cheap
architectural regression test asserts this). Every request it sends carries
the ConvertAgent wire invariant and bounded timeouts, and every failure it
encounters is converted into a failed Response rather than raised — the
port NEVER raises to callers, so the config fetch (Story 2.5) and event
delivery (Story 4.1) consumers degrade gracefully on a failed response.
The ConvertAgent wire invariant
The metrics endpoint's bot filter silently DROPS server-side events whose
User-Agent is not ConvertAgent/1.0. The header is therefore applied
LAST, after every header merge, so it cannot be overridden by an
integrator-supplied User-Agent. Without it, tracking events would vanish
silently in production. (JS/PHP precedent: set unconditionally after merge.)
Bounded timeouts
Both open_timeout and read_timeout are set explicitly on EVERY request
(a deliberate improvement over the JS SDK, which sets none). The SDK can
never hang a host thread waiting on a slow or dead endpoint.
TLS / Bearer / proxies
HTTPS endpoints use TLS with verification ON (+verify_mode+ is never
VERIFY_NONE). An Authorization: Bearer ... header is stripped (and a
warning logged) on any non-HTTPS endpoint so the SDK key secret never
crosses the wire in plaintext. Proxies are honoured through the standard
Net::HTTP environment conventions (+http_proxy+/+https_proxy+/+no_proxy+).
JSON boundary
Callers pass and receive Ruby hashes; JSON encode/decode happens only here.
A request body hash is rendered with JSON.generate; a response body is
parsed with JSON.parse (string keys). A parse failure is logged and yields
body: nil on an otherwise intact response.
All logging goes through the injected LogManager (never puts), so the
Redactor masks secrets and strips URL query strings from every line.
Defined Under Namespace
Classes: Response
Constant Summary collapse
- USER_AGENT =
The mandatory wire User-Agent. Applied LAST so it is unoverridable.
"ConvertAgent/1.0"- FAILURE_STATUS =
The status used for a failed Response when no HTTP response was received (network error / timeout). Callers MUST use Response#success?, never compare the status integer, for error detection.
0
Instance Method Summary collapse
-
#initialize(log_manager:, open_timeout:, read_timeout:) ⇒ HttpClient
constructor
A new instance of HttpClient.
-
#request(method:, url:, headers: {}, body: nil) ⇒ Response
Send one HTTP request and return a frozen Response.
Constructor Details
#initialize(log_manager:, open_timeout:, read_timeout:) ⇒ HttpClient
Returns a new instance of HttpClient.
86 87 88 89 90 |
# File 'lib/convert_sdk/http_client.rb', line 86 def initialize(log_manager:, open_timeout:, read_timeout:) @log_manager = log_manager @open_timeout = open_timeout @read_timeout = read_timeout end |
Instance Method Details
#request(method:, url:, headers: {}, body: nil) ⇒ Response
Send one HTTP request and return a frozen Response. Never raises: any transport failure is logged and returned as a failed response.
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/convert_sdk/http_client.rb', line 101 def request(method:, url:, headers: {}, body: nil) uri = URI.parse(url) https = uri.scheme == "https" wire_headers = build_headers(headers, https) @log_manager.debug("HttpClient#request: #{method.to_s.upcase} #{url}") perform(method, uri, https, wire_headers, body) rescue StandardError => e @log_manager.error("HttpClient#request: request failed (#{e.class}: #{e.})") failed_response end |