pub struct DigestingBody<B> { /* private fields */ }Expand description
Request body that enforces an HMAC-signed body digest while
STREAMING (DW-036): every data frame is folded into an incremental
SHA-256 — nothing is buffered, so a signed body of any size costs
O(1) memory beyond the frame in flight — and the final digest is
compared (constant-time, subtle) against the digest the verified
signature bound at authn time (Identity::body_digest,
security::authn). A mismatch surfaces as
SignatureBodyError::DigestMismatch, aborting the upstream send
WITH the last frame withheld on declared-length bodies (the digest
is final the moment the declared byte count is hashed) or at the
terminating frame on unknown-length bodies: the tampered request
never completes upstream and the proxy answers 401.
The hashed read is therefore exactly the forwarded read — and when
the route caps bodies (max_body_bytes, DW-027), this wrapper sits
INSIDE the route’s LimitedBody, so the cap still rejects
oversized bodies first. Unsigned requests construct the wrapper
with None (one uniform type on the proxy path): the None form
is a strict passthrough — no hashing, and
is_end_stream/size_hint delegate untouched. The Some form
reports is_end_stream: false so the consumer always polls to the
terminating frame (the last resort of the digest check — an
end-stream short-circuit would skip verification for empty and
chunked bodies; declared-length bodies additionally check at
saturation, see exact_hint). The one shape the forwarding
encoder never polls is a declared size of EXACTLY zero — hyper
writes Content-Length: 0 straight from the size hint and drops
the stream without a single poll_frame — so new decides that
case eagerly and the proxy consults
DigestingBody::eager_digest_mismatch before forwarding: an
empty signed body is verified against its signed digest like any
other.
Implementations§
Source§impl<B> DigestingBody<B>where
B: Body<Data = Bytes>,
impl<B> DigestingBody<B>where
B: Body<Data = Bytes>,
Sourcepub fn new(inner: B, expected: Option<[u8; 32]>) -> Self
pub fn new(inner: B, expected: Option<[u8; 32]>) -> Self
expected is the SIGNED digest (decoded from the presented
X-Dwara-Body-Sha256 header) — public material, already
verified as MAC-covered at authn time. None wraps without
enforcing (see the struct docs).
Sourcepub fn eager_digest_mismatch(&self) -> bool
pub fn eager_digest_mismatch(&self) -> bool
The digest verdict new could already decide without seeing a
frame (the wrapped body declared exact size 0, the one shape
the forwarding encoder never polls). The proxy MUST consult
this before forwarding an enforced body: a mismatch on a
zero-length body has no poll to surface through, so this is
its only signal — the same decision the streaming path
enforces in poll_frame.
Trait Implementations§
Source§impl<B> Body for DigestingBody<B>
impl<B> Body for DigestingBody<B>
Source§type Error = SignatureBodyError
type Error = SignatureBodyError
Body might generate.Source§fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Bytes>, SignatureBodyError>>>
fn poll_frame( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Option<Result<Frame<Bytes>, SignatureBodyError>>>
Source§fn size_hint(&self) -> SizeHint
fn size_hint(&self) -> SizeHint
Source§fn is_end_stream(&self) -> bool
fn is_end_stream(&self) -> bool
true when the end of stream has been reached. Read moreAuto Trait Implementations§
impl<B> Freeze for DigestingBody<B>
impl<B> RefUnwindSafe for DigestingBody<B>where
B: RefUnwindSafe,
impl<B> Send for DigestingBody<B>where
B: Send,
impl<B> Sync for DigestingBody<B>where
B: Sync,
impl<B> Unpin for DigestingBody<B>
impl<B> UnwindSafe for DigestingBody<B>where
B: UnwindSafe,
Blanket Implementations§
§impl<T> AnyExt for T
impl<T> AnyExt for T
§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind reference§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable reference§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointer§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointer§fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
fn downcast_box<T>(this: Box<Self>) -> Result<Box<T>, Box<Self>>where
T: Any,
T behind Box pointer§fn downcast_move<T>(this: Self) -> Option<T>
fn downcast_move<T>(this: Self) -> Option<T>
Self to T,
useful only in generic context as a workaround for specialization§impl<T> BodyExt for Twhere
T: Body + ?Sized,
impl<T> BodyExt for Twhere
T: Body + ?Sized,
§fn frame(&mut self) -> Frame<'_, Self>where
Self: Unpin,
fn frame(&mut self) -> Frame<'_, Self>where
Self: Unpin,
Frame, if any.§fn inspect_frame<F>(self, f: F) -> InspectFrame<Self, F>
fn inspect_frame<F>(self, f: F) -> InspectFrame<Self, F>
§fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
fn inspect_err<F>(self, f: F) -> InspectErr<Self, F>
§fn boxed_unsync(self) -> UnsyncBoxBody<Self::Data, Self::Error>
fn boxed_unsync(self) -> UnsyncBoxBody<Self::Data, Self::Error>
§fn collect(self) -> Collect<Self>where
Self: Sized,
fn collect(self) -> Collect<Self>where
Self: Sized,
Collected] body which will collect all the DATA frames
and trailers.§fn with_trailers<F>(self, trailers: F) -> WithTrailers<Self, F>
fn with_trailers<F>(self, trailers: F) -> WithTrailers<Self, F>
§fn into_stream(self) -> BodyStream<Self>where
Self: Sized,
fn into_stream(self) -> BodyStream<Self>where
Self: Sized,
BodyStream].§fn into_data_stream(self) -> BodyDataStream<Self>where
Self: Sized,
fn into_data_stream(self) -> BodyDataStream<Self>where
Self: Sized,
BodyDataStream].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<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
§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