pub struct EnvelopeLayerBuilder { /* private fields */ }Expand description
Configuration for an super::EnvelopeLayer. Nothing is checked until
build, and the calls may come in any order.
Implementations§
Source§impl EnvelopeLayerBuilder
impl EnvelopeLayerBuilder
Sourcepub fn build(self) -> Result<EnvelopeLayer, CratestackError>
pub fn build(self) -> Result<EnvelopeLayer, CratestackError>
Check the configuration: CratestackError::Validation when the
audience is empty (it would bind no recipient), the policy or the
transport is missing, the REST route table is empty (a rest(..)
given another schema’s, or an RPC schema’s, empty table would bind
nothing), the body limit or the contract trials is zero, an allow-listed template does not
start with /, or the envelope’s media type is not a valid header
value naming application/cose or a type the envelope claims.
Source§impl EnvelopeLayerBuilder
impl EnvelopeLayerBuilder
Sourcepub fn policy(self, policy: impl EnvelopePolicy) -> EnvelopeLayerBuilder
pub fn policy(self, policy: impl EnvelopePolicy) -> EnvelopeLayerBuilder
Which mode each op runs in: an super::EnvelopeMode for all of
them, or a closure per op. Required (decision D9).
Sourcepub fn rest(
self,
prefix: &str,
routes: &'static [RouteTransportDescriptor],
) -> EnvelopeLayerBuilder
pub fn rest( self, prefix: &str, routes: &'static [RouteTransportDescriptor], ) -> EnvelopeLayerBuilder
A REST router mounted at prefix ("" at the root), over the
generated cratestack_schema::axum::ROUTE_TRANSPORTS, which must not
be empty.
Sourcepub fn rpc(self, prefix: &str) -> EnvelopeLayerBuilder
pub fn rpc(self, prefix: &str) -> EnvelopeLayerBuilder
A transport rpc router mounted at prefix ("" at the root).
Sourcepub fn binding_resolver(
self,
resolver: impl BindingResolver,
) -> EnvelopeLayerBuilder
pub fn binding_resolver( self, resolver: impl BindingResolver, ) -> EnvelopeLayerBuilder
A custom BindingResolver, instead of rest or
rpc.
Sourcepub fn mount_prefix(self, prefix: &str) -> EnvelopeLayerBuilder
pub fn mount_prefix(self, prefix: &str) -> EnvelopeLayerBuilder
Where the router is mounted ("/api" for Router::nest("/api", router)). It wins over the prefix given to rest or
rpc, whichever order the calls come in: the
generated envelope_layer passes the root to those, so this is how
its layer is told about a mount. Also what
allow_unresolved templates are relative
to.
Sourcepub fn allow_unresolved<I, T>(self, templates: I) -> EnvelopeLayerBuilder
pub fn allow_unresolved<I, T>(self, templates: I) -> EnvelopeLayerBuilder
Route templates (as given to Router::route, relative to the mount
prefix, e.g. "/health") that the router may match without the
resolver knowing them: hand-written routes merged into the generated
router before the layer. Plain traffic to them passes through
unsigned. Any other matched route the resolver cannot bind fails
closed with a 500 when the policy’s unresolved_mode is
Required (decision S2), which is what a wrong or missing mount
prefix looks like. A COSE body to an allow-listed route is still
refused (415).
Sourcepub fn unresolved_mode(self, mode: EnvelopeMode) -> EnvelopeLayerBuilder
pub fn unresolved_mode(self, mode: EnvelopeMode) -> EnvelopeLayerBuilder
Replace the policy’s
unresolved_mode with
mode, whatever the policy answers (second-review nit). An explicit
opt-in, mostly for a closure policy, whose unresolved_mode is
always Required: with Optional or Off here, a matched route the
resolver cannot bind passes through plain (warned about once per
process) instead of failing closed with the 500, and so does
every route when the mount prefix is wrong. It also lets through a
method the schema does not generate on a generated path (normally
the layer’s own 405), so a hand-written handler for that method
runs unsigned. Prefer listing
hand-written routes with allow_unresolved,
which keeps a misconfiguration loud. The ops’ own modes are
unchanged; a /rpc/batch whose frames cannot be read uses this
mode too.
Sourcepub fn principal_mapper(
self,
mapper: impl PrincipalMapper,
) -> EnvelopeLayerBuilder
pub fn principal_mapper( self, mapper: impl PrincipalMapper, ) -> EnvelopeLayerBuilder
Replace super::ThumbprintPrincipal (cose:<hex thumbprint>;
ThumbprintPrincipal::with_prefix(..) keeps the thumbprint and
changes the prefix).
Sourcepub fn response_seal_policy(
self,
policy: impl ResponseSealPolicy,
) -> EnvelopeLayerBuilder
pub fn response_seal_policy( self, policy: impl ResponseSealPolicy, ) -> EnvelopeLayerBuilder
Replace super::AcceptNamesEnvelope (decision D10).
Sourcepub fn max_contract_trials(self, trials: usize) -> EnvelopeLayerBuilder
pub fn max_contract_trials(self, trials: usize) -> EnvelopeLayerBuilder
How many accepted digests the layer tries for a request that names
none (no Cratestack-Contract header: a hand-built client), newest
first. Default super::DEFAULT_MAX_CONTRACT_TRIALS; at least 1.
A request that does name one is verified under it alone, so an
up-to-date generated client costs one verification however long an
op’s accepted list grows, and a forged request without the header
costs one parse, one key resolution and at most this many signature
verifications (the COSE envelope’s open_request_any; a custom
ServerEnvelope that keeps the default
pays the parse and the resolution per trial). A failed trial records
no nonce.
Sourcepub fn max_body_bytes(self, limit: usize) -> EnvelopeLayerBuilder
pub fn max_body_bytes(self, limit: usize) -> EnvelopeLayerBuilder
The largest request body the layer buffers. Default
super::DEFAULT_MAX_BODY_BYTES; keep it a little above the
router’s own body limit, which applies to the payload after opening.
Source§impl EnvelopeLayerBuilder
impl EnvelopeLayerBuilder
Sourcepub fn payload_media_types<I, J>(
self,
request: I,
response: J,
) -> EnvelopeLayerBuilderwhere
I: IntoIterator,
<I as IntoIterator>::Item: Into<String>,
J: IntoIterator,
<J as IntoIterator>::Item: Into<String>,
pub fn payload_media_types<I, J>(
self,
request: I,
response: J,
) -> EnvelopeLayerBuilderwhere
I: IntoIterator,
<I as IntoIterator>::Item: Into<String>,
J: IntoIterator,
<J as IntoIterator>::Item: Into<String>,
The payload media types the layer allows inside the seal: request
for what a client seals, response for what the layer seals back.
Default: application/cbor for both, so a layer that never calls
this changes nothing for anyone: a request that names no type is
bound and opened with the bytes 0.15.3 used (AAD and body), and
answered by a response whose AAD and body are 0.15.3’s too. The one
difference a 0.15.3 client can see is a new response header,
Cratestack-Payload-Type, which it ignores.
A client names the type of its request in the unbound
Cratestack-Payload-Type header and the response types it reads, in
order, in Cratestack-Payload-Accept (the same selector pattern as
Cratestack-Contract: they select among what is allowed and never
widen it). Both are authenticated by the binding, not by the headers:
a request binding names the request payload’s type, a response
binding names the response payload’s own type, and a response
repeats it in Cratestack-Payload-Type. A header that lies about the
request fails the signature with the coarse 401. Binding version 2
and the COSE wire are unchanged.
What an op allows is this set intersected with the route’s declared
types (ResolvedRoute::with_payload_types, filled from the schema’s
capabilities by RestBindingResolver and RpcBindingResolver).
/rpc/batch stays CBOR both ways. An empty route list (the generated
reads and deletes, which take no payload) constrains nothing, and a
GET, HEAD or DELETE is not checked for the type its empty
payload names (bound as sent, never refused): a payload that is not
empty is held to this set and the route’s once opened, and refused as
a sealed 415.
A retry under the same Idempotency-Key must repeat its
Cratestack-Payload-Accept: the idempotency layer fingerprints the
request’s content type and body, not the types it reads, so a
response stored for the first attempt in a type the retry did not
negotiate is never sealed for it (a sealed 500, fail closed).
Refusals are unsigned and made before any key is looked up or nonce
spent: a selector header sent twice or malformed is a 400, a request
type outside the op’s set a 415 (payload_type_unsupported), and a
Cratestack-Payload-Accept with no type the op can answer in a 406
(payload_type_not_acceptable). A handler’s success in a type the
request did not negotiate is a sealed 500; its error in one is
re-encoded in the transport’s error shape, in the client’s first
choice of CBOR or JSON, and sealed.
build refuses a type outside the grammar of
cratestack_core::parse_payload_type, one that may never be sealed
(application/cose*, application/cbor-seq, text/event-stream,
multipart/*), an empty request set, and a response set without
application/cbor or application/json, which the layer’s own
errors are sealed in.
use cratestack_axum::envelope_layer::EnvelopeLayer;
// vpay's shape: forms in, JSON out, and CBOR for the generated clients.
let builder = EnvelopeLayer::builder(envelope, "payments", &[]).payload_media_types(
["application/cbor", "application/x-www-form-urlencoded"],
["application/cbor", "application/json"],
);Auto Trait Implementations§
impl !RefUnwindSafe for EnvelopeLayerBuilder
impl !UnwindSafe for EnvelopeLayerBuilder
impl Freeze for EnvelopeLayerBuilder
impl Send for EnvelopeLayerBuilder
impl Sync for EnvelopeLayerBuilder
impl Unpin for EnvelopeLayerBuilder
impl UnsafeUnpin for EnvelopeLayerBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more§impl<'src, T> IntoMaybe<'src, T> for Twhere
T: 'src,
impl<'src, T> IntoMaybe<'src, T> for Twhere
T: 'src,
impl<T> MaybeSend for T
impl<T> MaybeSendSync for T
§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling [Attribute] value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi [Quirk] value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the [Condition] value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);