impl AsyncReadFieldSection for FieldSection { asyncfn async_read<S: AsyncRead + Unpin>(mode: Mode, mut src: S) -> Res<Self> { let fields = if mode == Mode::KnownLength { // Known-length fields can just be read into a buffer. iflet Some(buf) = read_vec(&mut src).await? { Self::read_bhttp_fields(false, &mut Cursor::new(&buf[..]))?
} else {
Vec::new()
}
} else { // The async version needs to be implemented directly. letmut fields: Vec<Field> = Vec::new(); letmut cookie_index: Option<usize> = None; loop { iflet Some(n) = read_vec(&mut src).await? { if n.is_empty() { break fields;
} letmut v = read_vec(&mut src).await?.ok_or(Error::Truncated)?; if n == COOKIE { iflet Some(i) = &cookie_index {
fields[*i].value.extend_from_slice(b"; ");
fields[*i].value.append(&mut v); continue;
}
cookie_index = Some(fields.len());
}
fields.push(Field::new(n, v));
} elseif fields.is_empty() { break fields;
} else { return Err(Error::Truncated);
}
}
};
Ok(Self(fields))
}
}
#[derive(Default)] enum BodyState { // The starting state. #[default]
Init, // When reading the length, use this.
ReadLength {
buf: [u8; 8],
read: usize,
}, // When reading the data, track how much is left.
ReadData {
remaining: usize,
},
}
/// A helper function for the more complex body-reading code. fn poll_error(e: Error) -> Poll<IoResult<usize>> {
Poll::Ready(Err(IoError::other(e)))
}
enum AsyncMessageState {
Init, // Processing Informational responses (or before that).
Informational(bool), // Having obtained the control data for the header, this is it.
Header(ControlData), // Processing the Body.
Body(BodyState), // Processing the trailer.
Trailer, // All done.
Done,
}
pubstruct AsyncMessage<S> { // Whether this is a request and which mode.
mode: Option<Mode>,
state: AsyncMessageState,
src: S,
}
unsafeimpl<S: Send> Send for AsyncMessage<S> {}
impl<S: AsyncRead + Unpin> AsyncMessage<S> { asyncfn next_info(&mutself) -> Res<Option<InformationalResponse>> { let request = if matches!(self.state, AsyncMessageState::Init) { // Read control data ... let t = read_varint(&mutself.src).await?.ok_or(Error::Truncated)?; let request = t == 0 || t == 2; self.mode = Some(Mode::try_from(t)?); self.state = AsyncMessageState::Informational(request);
request
} else { // ... or recover it. let AsyncMessageState::Informational(request) = self.state else { return Err(Error::InvalidState);
};
request
};
let control = ControlData::async_read(request, &mutself.src).await?; iflet Some(status) = control.informational() { let mode = self.mode.unwrap(); let fields = FieldSection::async_read(mode, &mutself.src).await?;
Ok(Some(InformationalResponse::new(status, fields)))
} else { self.state = AsyncMessageState::Header(control);
Ok(None)
}
}
/// Produces a stream of informational responses from a fresh message. /// Returns an empty stream if passed a request (or if there are no informational responses). /// Error values on the stream indicate failures. /// /// There is no need to call this method to read a request, though /// doing so is harmless. /// /// You can discard the stream that this function returns /// without affecting the message. You can then either call this /// method again to get any additional informational responses or /// call `header()` to get the message header. pubfn informational(&mutself) -> impl Stream<Item = Res<InformationalResponse>> + '_ {
unfold(self, |this| asyncmove {
this.next_info().await.transpose().map(|info| (info, this))
})
}
/// This reads the header. If you have not called `informational` /// and drained the resulting stream, this will do that for you. /// # Panics /// Never. pubasyncfn header(&mutself) -> Res<Header> { if matches!( self.state,
AsyncMessageState::Init | AsyncMessageState::Informational(_)
) { // Need to scrub for errors, // so that this can abort properly if there is one. // The `try_any` usage is there to ensure that the stream is fully drained.
_ = self.informational().try_any(|_| async { false }).await?;
}
if matches!(self.state, AsyncMessageState::Header(_)) { let mode = self.mode.unwrap(); let hfields = FieldSection::async_read(mode, &mutself.src).await?;
/// Read the length of a body chunk. /// This updates the values of `read` and `buf` to track the portion of the length /// that was successfully read. /// Returns `Some` with the error code that should be used if the reading /// resulted in a conclusive outcome. fn read_body_len(
cx: &mut Context<'_>,
src: &mut S,
first: bool,
read: &mut usize,
buf: &mut [u8; 8],
) -> Option<Poll<Result<usize, IoError>>> { letmut src = pin!(src); if *read == 0 { letmut b = [0; 1]; match src.as_mut().poll_read(cx, &mut b[..]) {
Poll::Pending => return Some(Poll::Pending),
Poll::Ready(Ok(0)) => { returnif first { // It's OK for the first length to be absent. // Just skip to the end.
*read = 8;
None
} else { // ...it's not OK to drop length when continuing.
Some(poll_error(Error::Truncated))
};
}
Poll::Ready(Ok(1)) => match b[0] >> 6 { 0 => {
buf[7] = b[0] & 0x3f;
*read = 8;
} 1 => {
buf[6] = b[0] & 0x3f;
*read = 7;
} 2 => {
buf[4] = b[0] & 0x3f;
*read = 5;
} 3 => {
buf[0] = b[0] & 0x3f;
*read = 1;
}
_ => unreachable!(),
},
Poll::Ready(Ok(_)) => unreachable!(),
Poll::Ready(Err(e)) => return Some(Poll::Ready(Err(e))),
}
} if *read < 8 { match src.as_mut().poll_read(cx, &mut buf[*read..]) {
Poll::Pending => return Some(Poll::Pending),
Poll::Ready(Ok(0)) => return Some(poll_error(Error::Truncated)),
Poll::Ready(Ok(len)) => {
*read += len;
}
Poll::Ready(Err(e)) => return Some(Poll::Ready(Err(e))),
}
}
None
}
fn read_body(&mutself, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<IoResult<usize>> { // The length that precedes the first chunk can be absent. // Only allow that for the first chunk (if indeterminate length). let first = iflet AsyncMessageState::Body(BodyState::Init) = &self.state { self.body_state(BodyState::read_len()); true
} else { false
};
// Read the length. This uses `read_body_len` to track the state of this reading. // This doesn't use `ReadVarint` or any convenience functions because we // need to track the state and we don't want the borrow checker to flip out. iflet AsyncMessageState::Body(BodyState::ReadLength { buf, read }) = &mutself.state { iflet Some(res) = Self::read_body_len(cx, &mutself.src, first, read, buf) { return res;
} if *read == 8 { match usize::try_from(u64::from_be_bytes(*buf)) {
Ok(0) => { self.body_done(); return Poll::Ready(Ok(0));
}
Ok(remaining) => { self.body_state(BodyState::ReadData { remaining });
}
Err(e) => return poll_error(Error::IntRange(e)),
}
}
}
match &mutself.state {
AsyncMessageState::Body(BodyState::ReadData { remaining }) => { let amount = min(*remaining, buf.len()); let res = pin!(&mutself.src).poll_read(cx, &mut buf[..amount]); match res {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(0)) => poll_error(Error::Truncated),
Poll::Ready(Ok(len)) => {
*remaining -= len; if *remaining == 0 { let mode = self.mode.unwrap(); if mode == Mode::IndeterminateLength { self.body_state(BodyState::read_len());
} else { self.body_done();
}
}
Poll::Ready(Ok(len))
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
}
}
AsyncMessageState::Trailer => Poll::Ready(Ok(0)),
_ => Poll::Pending,
}
}
/// Read the body. /// This produces an implementation of `AsyncRead` that filters out /// the framing from the message body. /// # Errors /// This errors when the header has not been read. /// Any IO errors are generated by the returned `Body` instance. pubfn body(&mutself) -> Res<Body<'_, S>> { matchself.state {
AsyncMessageState::Body(_) => Ok(Body { msg: self }),
_ => Err(Error::InvalidState),
}
}
/// Read any trailer. /// This might be empty. /// # Errors /// This errors when the body has not been read. /// # Panics /// Never. pubasyncfn trailer(&mutself) -> Res<FieldSection> { if matches!(self.state, AsyncMessageState::Trailer) { let trailer = FieldSection::async_read(self.mode.unwrap(), &mutself.src).await?; self.state = AsyncMessageState::Done;
Ok(trailer)
} else {
Err(Error::InvalidState)
}
}
}
/// Asynchronous reading for a [`Message`]. pubtrait AsyncReadMessage: Sized { fn async_read<S: AsyncRead + Unpin>(src: S) -> AsyncMessage<S>;
}
#[test] fn truncated_header() { // The indefinite-length request example includes 10 bytes of padding. // The three additional zero values at the end represent: // 1. The terminating zero for the header field section. // 2. The terminating zero for the (empty) body. // 3. The terminating zero for the (absent) trailer field section. // The latter two (body and trailer) can be cut and the message will still work. // The first is not optional; dropping it means that the message is truncated. letmut buf = &mut &REQUEST2[..REQUEST2.len() - 13]; letmut msg = Message::async_read(&mut buf); // Use this test to test skipping a few things. let err = pin!(msg.header()).sync_resolve().unwrap_err();
assert!(matches!(err, Error::Truncated));
}
{ letmut body = pin!(msg.body().unwrap());
assert_eq!(body.sync_read_exact(12), b"Hello World!");
} // Attempting to read the trailer before finishing the body should fail.
assert!(matches!(
pin!(msg.trailer()).sync_resolve(),
Err(Error::InvalidState)
));
{ // Picking up the body again should work fine. letmut body = pin!(msg.body().unwrap());
assert_eq!(
body.sync_read_to_end(),
b" My content includes a trailing CRLF.\r\n"
);
} let trailer = pin!(msg.trailer()).sync_resolve().unwrap();
assert!(trailer.is_empty());
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.7 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.