pub trait HttpTransport:
Send
+ Sync
+ Debug {
// Required method
fn execute<'life0, 'async_trait>(
&'life0 self,
req: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, HttpTransportError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
}Expand description
Performs outbound HTTP on PPE’s behalf.
Implemented by the host, never by this crate. A proxy implements it over its own client so PPE’s outbound calls share the process’s pool, TLS material, egress policy, and tracing. A WASM host implements it over host imports. Tests implement it over a canned table, which is how timeout and error mapping become assertable without socket timing.
§One instance, shared
An implementation is never cloned. The host constructs exactly
one, hands it over as Arc<dyn HttpTransport>, and every holder
downstream — the engine, each request’s Extensions, each plugin’s
filtered view — carries a refcount bump on that same object. So the
connection pool, the TLS material, and any circuit-breaker state are
process-wide by construction rather than by discipline. That is the
whole point: a second instance would be a second pool against the
same IdP, which is what this seam exists to prevent.
The trait therefore does not require Clone, and an implementation
holding a pool need not make one cheap to copy. It does need interior
mutability and to be safe to call concurrently from many tasks, since
one instance serves every request in the process.
§Retries
An implementation must not retry at the application level. Two of
PPE’s three callers issue non-idempotent POSTs — a token exchange
and a CIBA backchannel registration — where a blind repeat mints a
second credential or asks a human to approve the same thing twice.
The transport cannot know which requests are safe to repeat; the
caller can, and owns the decision. See
HttpTransportError::may_have_reached_peer.
One narrow exception is not an application retry and is expected: if
a connection came from a keepalive pool and turned out to be closed
before any request bytes were written, resending on a fresh
connection is invisible to the peer and correct even for a POST.
The distinction is whether the peer could have observed the request,
never whether the failure looked transient.
§Runtime binding
An implementation must not bind pooled connections to whichever runtime happened to construct it. A host may build the transport during a short-lived initialization runtime that is dropped before the first request arrives, at which point connections created eagerly are already dead. Build pools lazily on first use.
Required Methods§
Sourcefn execute<'life0, 'async_trait>(
&'life0 self,
req: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, HttpTransportError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn execute<'life0, 'async_trait>(
&'life0 self,
req: HttpRequest,
) -> Pin<Box<dyn Future<Output = Result<HttpResponse, HttpTransportError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Perform one request and buffer the response.
§Errors
Returns HttpTransportError when no response was obtained. A
response carrying any status, including 5xx, is Ok.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".