Skip to main content

Capabilities

Struct Capabilities 

Source
#[non_exhaustive]
pub struct Capabilities {
Show 19 fields pub streaming_request_body: bool, pub full_duplex: bool, pub request_trailers: bool, pub response_trailers: bool, pub redirects: RedirectSupport, pub cancel_on_drop: CancelSupport, pub connection_reuse: ReuseSupport, pub response_decompression: DecompressionSupport, pub early_data: EarlyDataSupport, pub tls_config: TlsSupport, pub client_certs: bool, pub proxy: bool, pub owns_cookie_jar: bool, pub owns_cache: bool, pub version_select: bool, pub version_reported: bool, pub timeouts: TimeoutSupport, pub informational_1xx: bool, pub forbidden_request_headers: &'static [HeaderName],
}
Expand description

What the transport can do in this process, right now.

A runtime fact, not a cfg!: one wasm binary runs in both Chrome (streaming request body available since 131) and Safari (not available).

§Two kinds of field

Every field here is one of two things, and reading them as one kind is what makes a field like proxy look dead when it is not.

  • A gate. The field guards a setting a caller made on the Client, and ClientBuilder::build refuses when the transport cannot honour it — the model this whole type exists for, taken from wasi:http’s own setters returning result<_, request-options-error::not-supported>. A gate with no branch is the silently ignored setting defect, and this project has closed four of them: redirects, owns_cookie_jar, owns_cache and the timeouts triple each earned a branch the day the setting arrived.
  • A report. The field states a fact about the transport, and nothing at the client level could refuse it, because the setting it describes is configured on the transport. proxy, client_certs, tls_config, early_data, connection_reuse, cancel_on_drop, full_duplex, streaming_request_body, the two trailer flags and version_reported are all this kind. Its reader is the caller.

A report is not a dead field. upgrade was deleted for having no reader, and the difference is that its four variants encoded a distinction with one reachable side — where a report has both values reachable and answers a question only it can answer.

The classification is enforced rather than described: every_capability_is_a_gate_or_a_report in this module destructures the struct with no .., so a field added later is a compile error until somebody decides which kind it is.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§streaming_request_body: bool

Whether a request body may be written as it is produced.

Reported. Client does not gate on it — see this type’s doc for why some fields do and some do not — which is why hclient-urlsession refuses a Streaming body with a typed error of its own rather than relying on a check that does not happen.

§full_duplex: bool

Whether the response may begin arriving before the request body has finished. Reported.

§request_trailers: bool

Reported.

§response_trailers: bool

Reported.

§redirects: RedirectSupport

Who follows a redirect — see RedirectSupport.

A gate: RedirectPolicy and a redirect predicate are Client settings, and RedirectSupport::Internal means the transport has already followed the chain by the time anything is handed back, so either setting would silently not apply.

§cancel_on_drop: CancelSupport

What dropping an in-flight execute future does — see CancelSupport and the contract on Transport::execute.

§connection_reuse: ReuseSupport

Whether a connection is reused across requests — see ReuseSupport.

§response_decompression: DecompressionSupport

Whether the transport already decoded the response body’s Content-Encoding — see DecompressionSupport.

§early_data: EarlyDataSupport

Whether the transport can put a marked request into TLS 1.3 early data — see EarlyDataSupport, which says less than its name suggests and says so at length.

§tls_config: TlsSupport

What TLS configuration this transport accepts — see TlsSupport.

Reported, not a gate. A Client has no TLS setting to refuse: the trust store, the client certificate and the ALPN list are all configured on the TlsConnect a transport was built with. See this type’s own doc for the two kinds of field.

§client_certs: bool

Whether the TLS configuration this transport holds presents a client certificate.

Reported, for tls_config’s reason. Read off TlsIdentity::presents_client_certs by the backends rather than from a constant, which is what stopped one connector giving two answers depending on which stack held it.

§proxy: bool

Whether this transport sends through a proxy.

Reported, and it will never be a gate. The setting it would guard is Native::proxy, which is on the transport that would answer the question, so there is nothing at the client level to refuse. That makes it unlike owns_cookie_jar, where the client owns the setting and the transport owns the conflict.

It is not upgrade’s case either, the four-variant enum deleted for having no reader: both values here are reachable, and the reader is the caller — will my requests go through a proxy is a question a diagnostic asks and only this field answers.

§owns_cookie_jar: bool

Whether the transport keeps its own cookie jar: attaching Cookie to outgoing requests and processing Set-Cookie on incoming ones, without being asked.

true for hclient-fetch — the browser does both, and Cookie is on that backend’s forbidden_request_headers, so a client-side jar there would not merely be redundant, it would send every cookie twice and store every Set-Cookie twice. false for hclient-native and hclient-wasi.

§Why a bool and not an enum

The same question CancelSupport and ReuseSupport were made to answer: a variant exists only if a caller decision turns on it. This field answers exactly one decision — “do I run a jar of my own for this transport?” — and it is binary. The two axes an enum would add do not carry decisions:

  • Who owns it (the browser, an ambient host) is the split CancelSupport already rejected once, for the same reason.
  • Attaching versus storing could in principle come apart, and in practice never has: a backend that attaches cookies it did not store, or stores cookies it will not attach, is not a shape any of the three backends here or any ambient HTTP API takes.

What it does not answer — deliberately, and this is where a third state would arrive if it ever arrives — is whether a jar-owning backend can be asked to stop, or its jar inspected. There is no portable setting for either, so there is nothing to refuse. When a client-level cookie setting exists, it earns its refusal here the way RedirectSupport::Internal earned its variant: the setting, the variant and the check_supported arm arrive together.

§owns_cache: bool

Whether the transport keeps its own HTTP response cache: serving a stored response instead of sending, and storing what it fetches, without being asked.

true for hclient-fetch — the browser has an HTTP cache and applies it inside fetch(). false for hclient-native, hclient-h3 and hclient-wasi, none of which stores a response anywhere. wasi:http’s host may well have a cache; the guest cannot see it, and a capability is a claim about what this code does rather than about what is downstream of it — the same line owns_cookie_jar holds for the same backend.

§This field had no reader for four verticals

It shipped in v0.1 as false everywhere but one backend, branched on nowhere, and was on the same list version_select was rescued from — a variant exists only if a caller decision turns on it. The decision that arrived is ClientBuilder::cache, and a client-side cache against a transport reporting true is an UnsupportedCapability at build(), the same arm owns_cookie_jar takes for a jar and RedirectSupport::Internal takes for a redirect policy.

§Why a bool and not an enum

Self::owns_cookie_jar’s answer, one field up, applies verbatim: this field settles exactly one decision — do I run a cache of my own for this transport? — and it is binary. Who owns it is the split CancelSupport rejected; storing versus serving could in principle come apart and in practice never has.

What it deliberately does not answer is whether a cache-owning backend can be asked to bypass, revalidate or clear. There is no portable setting for any of the three — fetch()’s cache option is a browser API a Transport seam has no counterpart for — so there is nothing to refuse. That is where a third state would arrive if it ever arrives.

§version_select: bool

Whether the transport honours a per-request RequireVersion demand: reads it, and either serves the request over that version or fails it with VersionNotAvailable before the head is written.

§It says “honours”, not “chooses”

A transport that only ever speaks one version reports true if it answers demands — hclient-h3 does, by proceeding on RequireVersion(HTTP_3) and refusing everything else. Reporting false there would make Client refuse the one demand it trivially satisfies, which is the opposite of honest.

false is for a transport that cannot answer at all: hclient-fetch and hclient-wasi neither select the version nor learn it (both also report version_reported: false), so a demand against either becomes an UnsupportedCapability from Client — the same arm a RedirectPolicy against RedirectSupport::Internal takes.

§Why this field exists

The rule is that a capability exists only if a caller decision turns on itRedirectSupport lost two variants to it. RequireVersion is the decision this one answers, and it is the reason the demand and this field’s first true land in one change.

§version_reported: bool

Whether Response::version() is something the transport observed.

false says the value on the response is http’s builder default standing in for a fact the backend never learned — the browser will not tell a page which protocol it spoke, and wasi:http@0.3.0 has no version concept at all.

The observability seam asks the same question one field over and answers it in the event rather than here, because a Hooks impl is handed an Event and no capabilities: Head::version is Some exactly when this field is true. Two spellings of one fact, in the two places that can each be read on their own.

§timeouts: TimeoutSupport§informational_1xx: bool§forbidden_request_headers: &'static [HeaderName]

Trait Implementations§

Source§

impl Clone for Capabilities

Source§

fn clone(&self) -> Capabilities

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Capabilities

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Capabilities

Source§

fn default() -> Capabilities

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.