mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-29 00:00:18 +02:00
feat: Introduce Bodies of Unknown Size
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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> {}
|
||||
@@ -128,7 +128,7 @@ impl IntoResponse for StatusCode {
|
||||
|
||||
impl IntoResponse for () {
|
||||
fn into_response(self) -> Response {
|
||||
Body::empty().into_response()
|
||||
Body::unknown().into_response()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user