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