Skip to main content

http_body/
lib.rs

1#![deny(
2    missing_debug_implementations,
3    missing_docs,
4    unreachable_pub,
5    clippy::missing_safety_doc,
6    clippy::undocumented_unsafe_blocks
7)]
8#![cfg_attr(test, deny(warnings))]
9
10//! Asynchronous HTTP request or response body.
11//!
12//! See [`Body`] for more details.
13//!
14//! [`Body`]: trait.Body.html
15
16mod frame;
17mod size_hint;
18
19pub use self::frame::Frame;
20pub use self::size_hint::SizeHint;
21
22use bytes::{Buf, Bytes};
23use std::convert::Infallible;
24use std::ops;
25use std::pin::Pin;
26use std::task::{Context, Poll};
27
28/// Trait representing a streaming body of a Request or Response.
29///
30/// Individual frames are streamed via the `poll_frame` function, which asynchronously yields
31/// instances of [`Frame<Data>`].
32///
33/// Frames can contain a data buffer of type `Self::Data`. Frames can also contain an optional
34/// set of trailers used to finalize the request/response exchange. This is mostly used when using
35/// the HTTP/2.0 protocol.
36///
37/// The `size_hint` function provides insight into the total number of bytes that will be streamed.
38pub trait Body {
39    /// Values yielded by the `Body`.
40    type Data: Buf;
41
42    /// The error type this `Body` might generate.
43    type Error;
44
45    #[allow(clippy::type_complexity)]
46    /// Attempt to pull out the next frame of this stream.
47    ///
48    /// # Return value
49    ///
50    /// This function returns:
51    ///
52    /// - `Poll::Pending` if the next frame is not ready yet.
53    /// - `Poll::Ready(Some(Ok(frame)))` when the next frame is available.
54    /// - `Poll::Ready(Some(Err(error)))` when an error has been reached.
55    /// - `Poll::Ready(None)` means that all of the frames in this stream have been returned, and
56    ///   that the end of the stream has been reached.
57    ///
58    /// If `Poll::Ready(Some(Err(error)))` is returned, this body should be discarded.
59    ///
60    /// Once the end of the stream is reached, implementations should continue to return
61    /// `Poll::Ready(None)`.
62    fn poll_frame(
63        self: Pin<&mut Self>,
64        cx: &mut Context<'_>,
65    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>>;
66
67    /// A hint that may return `true` when the end of stream has been reached.
68    ///
69    /// An end of stream means that `poll_frame` will return `None`.
70    ///
71    /// A return value of `false` **does not** guarantee that a value will be
72    /// returned from `poll_frame`. Combinators or other implementations may
73    /// not be able to know the end of stream has been reached for this hint.
74    ///
75    /// Returning `true` allows consumers of this body to optimize, such as not
76    /// calling `poll_frame` again.
77    fn is_end_stream(&self) -> bool {
78        false
79    }
80
81    /// A hint that returns the bounds on the remaining length of the stream.
82    ///
83    /// When the **exact** remaining length of the stream is known, the upper bound will be set and
84    /// will equal the lower bound.
85    fn size_hint(&self) -> SizeHint {
86        SizeHint::default()
87    }
88}
89
90impl<T: Body + Unpin + ?Sized> Body for &mut T {
91    type Data = T::Data;
92    type Error = T::Error;
93
94    fn poll_frame(
95        mut self: Pin<&mut Self>,
96        cx: &mut Context<'_>,
97    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
98        Pin::new(&mut **self).poll_frame(cx)
99    }
100
101    fn is_end_stream(&self) -> bool {
102        Pin::new(&**self).is_end_stream()
103    }
104
105    fn size_hint(&self) -> SizeHint {
106        Pin::new(&**self).size_hint()
107    }
108}
109
110impl<P> Body for Pin<P>
111where
112    P: Unpin + ops::DerefMut,
113    P::Target: Body,
114{
115    type Data = <<P as ops::Deref>::Target as Body>::Data;
116    type Error = <<P as ops::Deref>::Target as Body>::Error;
117
118    fn poll_frame(
119        self: Pin<&mut Self>,
120        cx: &mut Context<'_>,
121    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
122        Pin::get_mut(self).as_mut().poll_frame(cx)
123    }
124
125    fn is_end_stream(&self) -> bool {
126        self.as_ref().is_end_stream()
127    }
128
129    fn size_hint(&self) -> SizeHint {
130        self.as_ref().size_hint()
131    }
132}
133
134impl<T: Body + Unpin + ?Sized> Body for Box<T> {
135    type Data = T::Data;
136    type Error = T::Error;
137
138    fn poll_frame(
139        mut self: Pin<&mut Self>,
140        cx: &mut Context<'_>,
141    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
142        Pin::new(&mut **self).poll_frame(cx)
143    }
144
145    fn is_end_stream(&self) -> bool {
146        self.as_ref().is_end_stream()
147    }
148
149    fn size_hint(&self) -> SizeHint {
150        self.as_ref().size_hint()
151    }
152}
153
154impl<B: Body> Body for http::Request<B> {
155    type Data = B::Data;
156    type Error = B::Error;
157
158    fn poll_frame(
159        self: Pin<&mut Self>,
160        cx: &mut Context<'_>,
161    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
162        // SAFETY:
163        // A pin projection.
164        unsafe {
165            self.map_unchecked_mut(http::Request::body_mut)
166                .poll_frame(cx)
167        }
168    }
169
170    fn is_end_stream(&self) -> bool {
171        self.body().is_end_stream()
172    }
173
174    fn size_hint(&self) -> SizeHint {
175        self.body().size_hint()
176    }
177}
178
179impl<B: Body> Body for http::Response<B> {
180    type Data = B::Data;
181    type Error = B::Error;
182
183    fn poll_frame(
184        self: Pin<&mut Self>,
185        cx: &mut Context<'_>,
186    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
187        // SAFETY:
188        // A pin projection.
189        unsafe {
190            self.map_unchecked_mut(http::Response::body_mut)
191                .poll_frame(cx)
192        }
193    }
194
195    fn is_end_stream(&self) -> bool {
196        self.body().is_end_stream()
197    }
198
199    fn size_hint(&self) -> SizeHint {
200        self.body().size_hint()
201    }
202}
203
204impl Body for String {
205    type Data = Bytes;
206    type Error = Infallible;
207
208    fn poll_frame(
209        mut self: Pin<&mut Self>,
210        _cx: &mut Context<'_>,
211    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
212        if !self.is_empty() {
213            let s = std::mem::take(&mut *self);
214            Poll::Ready(Some(Ok(Frame::data(s.into_bytes().into()))))
215        } else {
216            Poll::Ready(None)
217        }
218    }
219
220    fn is_end_stream(&self) -> bool {
221        self.is_empty()
222    }
223
224    fn size_hint(&self) -> SizeHint {
225        SizeHint::with_exact(self.len() as u64)
226    }
227}
228
229#[cfg(test)]
230fn _assert_bounds() {
231    fn can_be_trait_object(_: &dyn Body<Data = std::io::Cursor<Vec<u8>>, Error = std::io::Error>) {}
232}