1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
#![deny(missing_debug_implementations, missing_docs, unreachable_pub)]
#![cfg_attr(test, deny(warnings))]
//! Utilities for [`http_body::Body`].
//!
//! [`BodyExt`] adds extensions to the common trait.
//!
//! [`Empty`] and [`Full`] provide simple implementations.
mod collected;
pub mod combinators;
mod either;
mod empty;
mod full;
mod limited;
mod stream;
mod util;
use self::combinators::{BoxBody, MapErr, MapFrame, UnsyncBoxBody};
pub use self::collected::Collected;
pub use self::either::Either;
pub use self::empty::Empty;
pub use self::full::Full;
pub use self::limited::{LengthLimitError, Limited};
pub use self::stream::{BodyDataStream, BodyStream, StreamBody};
/// An extension trait for [`http_body::Body`] adding various combinators and adapters
pub trait BodyExt: http_body::Body {
/// Returns a future that resolves to the next [`Frame`], if any.
///
/// [`Frame`]: combinators::Frame
fn frame(&mut self) -> combinators::Frame<'_, Self>
where
Self: Unpin,
{
combinators::Frame(self)
}
/// Maps this body's frame to a different kind.
fn map_frame<F, B>(self, f: F) -> MapFrame<Self, F>
where
Self: Sized,
F: FnMut(http_body::Frame<Self::Data>) -> http_body::Frame<B>,
B: bytes::Buf,
{
MapFrame::new(self, f)
}
/// Maps this body's error value to a different value.
fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
where
Self: Sized,
F: FnMut(Self::Error) -> E,
{
MapErr::new(self, f)
}
/// Turn this body into a boxed trait object.
fn boxed(self) -> BoxBody<Self::Data, Self::Error>
where
Self: Sized + Send + Sync + 'static,
{
BoxBody::new(self)
}
/// Turn this body into a boxed trait object that is !Sync.
fn boxed_unsync(self) -> UnsyncBoxBody<Self::Data, Self::Error>
where
Self: Sized + Send + 'static,
{
UnsyncBoxBody::new(self)
}
/// Turn this body into [`Collected`] body which will collect all the DATA frames
/// and trailers.
fn collect(self) -> combinators::Collect<Self>
where
Self: Sized,
{
combinators::Collect {
body: self,
collected: Some(crate::Collected::default()),
}
}
/// Add trailers to the body.
///
/// The trailers will be sent when all previous frames have been sent and the `trailers` future
/// resolves.
///
/// # Example
///
/// ```
/// use http::HeaderMap;
/// use http_body_util::{Full, BodyExt};
/// use bytes::Bytes;
///
/// # #[tokio::main]
/// async fn main() {
/// let (tx, rx) = tokio::sync::oneshot::channel::<HeaderMap>();
///
/// let body = Full::<Bytes>::from("Hello, World!")
/// // add trailers via a future
/// .with_trailers(async move {
/// match rx.await {
/// Ok(trailers) => Some(Ok(trailers)),
/// Err(_err) => None,
/// }
/// });
///
/// // compute the trailers in the background
/// tokio::spawn(async move {
/// let _ = tx.send(compute_trailers().await);
/// });
///
/// async fn compute_trailers() -> HeaderMap {
/// // ...
/// # unimplemented!()
/// }
/// # }
/// ```
fn with_trailers<F>(self, trailers: F) -> combinators::WithTrailers<Self, F>
where
Self: Sized,
F: std::future::Future<Output = Option<Result<http::HeaderMap, Self::Error>>>,
{
combinators::WithTrailers::new(self, trailers)
}
/// Turn this body into [`BodyDataStream`].
fn into_data_stream(self) -> BodyDataStream<Self>
where
Self: Sized,
{
BodyDataStream::new(self)
}
}
impl<T: ?Sized> BodyExt for T where T: http_body::Body {}