feat: Introduce Bodies of Unknown Size

This commit is contained in:
Lorenz Leutgeb
2026-05-15 10:13:47 +02:00
committed by GitHub
parent c853e44ffc
commit c2612e2839
6 changed files with 159 additions and 1 deletions
+27
View File
@@ -1,5 +1,8 @@
//! HTTP body utilities.
mod unknown;
pub(crate) use unknown::Unknown;
use crate::{BoxError, Error};
use bytes::Bytes;
use futures_core::{Stream, TryStream};
@@ -53,6 +56,30 @@ impl Body {
Self::new(http_body_util::Empty::new())
}
/// Create a body of unknown size.
///
/// This is useful in cases where a body is required to construct a
/// response, but the size of the body is not known.
///
/// For example, this can be used to respond to `HEAD` requests,
/// for which the body of the corresponding `GET` request would be expensive
/// to compute. Note that this particular case is also mentioned in
/// [RFC 9110 (Section 9.3.2, Paragraph 2)].
///
/// The most notable difference compared to an empty body as returned by
/// [`Body::empty`] lies in the upper bound returned by [`Body::size_hint`]:
/// The upper bound of the size of an empty body is 0 bytes, while there
/// is no upper bound for the size of an unknown body.
///
/// Other than the size hint, an unknown body behaves like an empty body,
/// i.e., [`Body::is_end_stream`] returns `true`, and when polled via
/// [`Body::poll_frame`], it immediately returns `Poll::Ready(None)`.
///
/// [RFC 9110 (Section 9.3.2, Paragraph 2)]: https://datatracker.ietf.org/doc/html/rfc9110#section-9.3.2-2
pub fn unknown() -> Self {
Self::new(Unknown::new())
}
/// Create a new `Body` from a [`Stream`].
///
/// [`Stream`]: https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html
+63
View File
@@ -0,0 +1,63 @@
use bytes::Buf;
use http_body::{Body, Frame, SizeHint};
use std::{
convert::Infallible,
fmt,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};
/// Refer to the documentation of [`super::Body::unknown`] which is `pub`.
pub(crate) struct Unknown<D> {
_marker: PhantomData<fn() -> D>,
}
impl<D> Unknown<D> {
pub(crate) const fn new() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<D: Buf> Body for Unknown<D> {
type Data = D;
type Error = Infallible;
#[inline]
fn poll_frame(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
Poll::Ready(None)
}
fn is_end_stream(&self) -> bool {
true
}
fn size_hint(&self) -> SizeHint {
SizeHint::default()
}
}
impl<D> fmt::Debug for Unknown<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Unknown").finish()
}
}
impl<D> Default for Unknown<D> {
fn default() -> Self {
Self::new()
}
}
impl<D> Clone for Unknown<D> {
fn clone(&self) -> Self {
*self
}
}
impl<D> Copy for Unknown<D> {}
+1 -1
View File
@@ -128,7 +128,7 @@ impl IntoResponse for StatusCode {
impl IntoResponse for () {
fn into_response(self) -> Response {
Body::empty().into_response()
Body::unknown().into_response()
}
}