Skip to main content

http_body_util/
channel.rs

1//! A body backed by a channel.
2
3use std::{
4    fmt::Display,
5    pin::Pin,
6    task::{Context, Poll},
7};
8
9use bytes::Buf;
10use http::HeaderMap;
11use http_body::{Body, Frame};
12use pin_project_lite::pin_project;
13use tokio::sync::{mpsc, oneshot};
14
15pin_project! {
16    /// A body backed by a channel.
17    pub struct Channel<D, E = std::convert::Infallible> {
18        rx_frame: mpsc::Receiver<Frame<D>>,
19        #[pin]
20        rx_error: oneshot::Receiver<E>,
21    }
22}
23
24impl<D, E> Channel<D, E> {
25    /// Create a new channel body.
26    ///
27    /// The channel will buffer up to the provided number of messages. Once the buffer is full,
28    /// attempts to send new messages will wait until a message is received from the channel. The
29    /// provided buffer capacity must be at least 1.
30    pub fn new(buffer: usize) -> (Sender<D, E>, Self) {
31        let (tx_frame, rx_frame) = mpsc::channel(buffer);
32        let (tx_error, rx_error) = oneshot::channel();
33        (Sender { tx_frame, tx_error }, Self { rx_frame, rx_error })
34    }
35}
36
37impl<D, E> Body for Channel<D, E>
38where
39    D: Buf,
40{
41    type Data = D;
42    type Error = E;
43
44    fn poll_frame(
45        self: Pin<&mut Self>,
46        cx: &mut Context<'_>,
47    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
48        let this = self.project();
49
50        match this.rx_frame.poll_recv(cx) {
51            Poll::Ready(frame @ Some(_)) => return Poll::Ready(frame.map(Ok)),
52            Poll::Ready(None) | Poll::Pending => {}
53        }
54
55        use core::future::Future;
56        match this.rx_error.poll(cx) {
57            Poll::Ready(Ok(error)) => return Poll::Ready(Some(Err(error))),
58            Poll::Ready(Err(_)) => return Poll::Ready(None),
59            Poll::Pending => {}
60        }
61
62        Poll::Pending
63    }
64}
65
66impl<D, E: std::fmt::Debug> std::fmt::Debug for Channel<D, E> {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.debug_struct("Channel")
69            .field("rx_frame", &self.rx_frame)
70            .field("rx_error", &self.rx_error)
71            .finish()
72    }
73}
74
75/// A sender half created through [`Channel::new`].
76pub struct Sender<D, E = std::convert::Infallible> {
77    tx_frame: mpsc::Sender<Frame<D>>,
78    tx_error: oneshot::Sender<E>,
79}
80
81impl<D, E> Sender<D, E> {
82    /// Send a frame on the channel.
83    pub async fn send(&mut self, frame: Frame<D>) -> Result<(), SendError> {
84        self.tx_frame.send(frame).await.map_err(|_| SendError)
85    }
86
87    /// Send data on data channel.
88    pub async fn send_data(&mut self, buf: D) -> Result<(), SendError> {
89        self.send(Frame::data(buf)).await
90    }
91
92    /// Send trailers on trailers channel.
93    pub async fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), SendError> {
94        self.send(Frame::trailers(trailers)).await
95    }
96
97    /// Attempts to send a frame on this channel.
98    ///
99    /// This function returns the unsent frame back as an `Err(_)` if the channel could not
100    /// (currently) accept another frame.
101    ///
102    /// # Note
103    ///
104    /// This is mostly useful for when trying to send a frame from outside of an asynchronous
105    /// context. If in an async context, prefer [`Sender::send_data()`] instead.
106    pub fn try_send(&mut self, frame: Frame<D>) -> Result<(), Frame<D>> {
107        let Self {
108            tx_frame,
109            tx_error: _,
110        } = self;
111
112        tx_frame
113            .try_send(frame)
114            .map_err(tokio::sync::mpsc::error::TrySendError::into_inner)
115    }
116
117    /// Returns the current capacity of the channel.
118    ///
119    /// The capacity goes down when [`Frame<T>`]s are sent. The capacity goes up when these frames
120    /// are received by the corresponding [`Channel<D, E>`]. This is distinct from
121    /// [`max_capacity()`][Self::max_capacity], which always returns the buffer capacity initially
122    /// specified when [`Channel::new()`][Channel::new] was called.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use bytes::Bytes;
128    /// use http_body_util::{BodyExt, channel::Channel};
129    /// use std::convert::Infallible;
130    ///
131    /// #[tokio::main]
132    /// async fn main() {
133    ///    let (mut tx, mut body) = Channel::<Bytes, Infallible>::new(4);
134    ///    assert_eq!(tx.capacity(), 4);
135    ///
136    ///    // Sending a value decreases the available capacity.
137    ///    tx.send_data(Bytes::from("Hel")).await.unwrap();
138    ///    assert_eq!(tx.capacity(), 3);
139    ///
140    ///    // Reading a value increases the available capacity.
141    ///    let _ = body.frame().await;
142    ///    assert_eq!(tx.capacity(), 4);
143    /// }
144    /// ```
145    pub fn capacity(&mut self) -> usize {
146        self.tx_frame.capacity()
147    }
148
149    /// Returns the maximum capacity of the channel.
150    ///
151    /// This function always returns the buffer capacity initially specified when
152    /// [`Channel::new()`][Channel::new] was called. This is distinct from
153    /// [`capacity()`][Self::capacity], which returns the currently available capacity.
154    ///
155    /// # Examples
156    ///
157    /// ```
158    /// use bytes::Bytes;
159    /// use http_body_util::{BodyExt, channel::Channel};
160    /// use std::convert::Infallible;
161    ///
162    /// #[tokio::main]
163    /// async fn main() {
164    ///    let (mut tx, mut body) = Channel::<Bytes, Infallible>::new(4);
165    ///    assert_eq!(tx.max_capacity(), 4);
166    ///
167    ///    // Sending a value buffers it, but does not affect the maximum capacity reported.
168    ///    tx.send_data(Bytes::from("Hel")).await.unwrap();
169    ///    assert_eq!(tx.max_capacity(), 4);
170    /// }
171    /// ```
172    pub fn max_capacity(&mut self) -> usize {
173        self.tx_frame.max_capacity()
174    }
175
176    /// Aborts the body in an abnormal fashion.
177    pub fn abort(self, error: E) {
178        self.tx_error.send(error).ok();
179    }
180}
181
182impl<D, E: std::fmt::Debug> std::fmt::Debug for Sender<D, E> {
183    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184        f.debug_struct("Sender")
185            .field("tx_frame", &self.tx_frame)
186            .field("tx_error", &self.tx_error)
187            .finish()
188    }
189}
190
191/// The error returned if [`Sender`] fails to send because the receiver is closed.
192#[derive(Debug)]
193#[non_exhaustive]
194pub struct SendError;
195
196impl Display for SendError {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        write!(f, "failed to send frame")
199    }
200}
201
202impl std::error::Error for SendError {}
203
204#[cfg(test)]
205mod tests {
206    use bytes::Bytes;
207    use http::{HeaderName, HeaderValue};
208
209    use crate::BodyExt;
210
211    use super::*;
212
213    #[tokio::test]
214    async fn empty() {
215        let (tx, body) = Channel::<Bytes>::new(1024);
216        drop(tx);
217
218        let collected = body.collect().await.unwrap();
219        assert!(collected.trailers().is_none());
220        assert!(collected.to_bytes().is_empty());
221    }
222
223    #[tokio::test]
224    async fn can_send_data() {
225        let (mut tx, body) = Channel::<Bytes>::new(1024);
226
227        tokio::spawn(async move {
228            tx.send_data(Bytes::from("Hel")).await.unwrap();
229            tx.send_data(Bytes::from("lo!")).await.unwrap();
230        });
231
232        let collected = body.collect().await.unwrap();
233        assert!(collected.trailers().is_none());
234        assert_eq!(collected.to_bytes(), "Hello!");
235    }
236
237    #[tokio::test]
238    async fn can_send_trailers() {
239        let (mut tx, body) = Channel::<Bytes>::new(1024);
240
241        tokio::spawn(async move {
242            let mut trailers = HeaderMap::new();
243            trailers.insert(
244                HeaderName::from_static("foo"),
245                HeaderValue::from_static("bar"),
246            );
247            tx.send_trailers(trailers).await.unwrap();
248        });
249
250        let collected = body.collect().await.unwrap();
251        assert_eq!(collected.trailers().unwrap()["foo"], "bar");
252        assert!(collected.to_bytes().is_empty());
253    }
254
255    #[tokio::test]
256    async fn can_send_both_data_and_trailers() {
257        let (mut tx, body) = Channel::<Bytes>::new(1024);
258
259        tokio::spawn(async move {
260            tx.send_data(Bytes::from("Hel")).await.unwrap();
261            tx.send_data(Bytes::from("lo!")).await.unwrap();
262            let mut trailers = HeaderMap::new();
263            trailers.insert(
264                HeaderName::from_static("foo"),
265                HeaderValue::from_static("bar"),
266            );
267            tx.send_trailers(trailers).await.unwrap();
268        });
269
270        let collected = body.collect().await.unwrap();
271        assert_eq!(collected.trailers().unwrap()["foo"], "bar");
272        assert_eq!(collected.to_bytes(), "Hello!");
273    }
274
275    #[tokio::test]
276    async fn try_send_works() {
277        let (mut tx, mut body) = Channel::<Bytes>::new(2);
278
279        // Send two messages, filling the channel's buffer.
280        tx.try_send(Frame::data(Bytes::from("one")))
281            .expect("can send one message");
282        tx.try_send(Frame::data(Bytes::from("two")))
283            .expect("can send two messages");
284
285        // Sending a value to a full channel should return it back to us.
286        match tx.try_send(Frame::data(Bytes::from("three"))) {
287            Err(frame) => assert_eq!(frame.into_data().unwrap(), "three"),
288            Ok(()) => panic!("synchronously sending a value to a full channel should fail"),
289        };
290
291        // Read the messages out of the body.
292        assert_eq!(
293            body.frame()
294                .await
295                .expect("yields result")
296                .expect("yields frame")
297                .into_data()
298                .expect("yields data"),
299            "one"
300        );
301        assert_eq!(
302            body.frame()
303                .await
304                .expect("yields result")
305                .expect("yields frame")
306                .into_data()
307                .expect("yields data"),
308            "two"
309        );
310
311        // Drop the body.
312        drop(body);
313
314        // Sending a value to a closed channel should return it back to us.
315        match tx.try_send(Frame::data(Bytes::from("closed"))) {
316            Err(frame) => assert_eq!(frame.into_data().unwrap(), "closed"),
317            Ok(()) => panic!("synchronously sending a value to a closed channel should fail"),
318        };
319    }
320
321    /// A stand-in for an error type, for unit tests.
322    type Error = &'static str;
323    /// An example error message.
324    const MSG: Error = "oh no";
325
326    #[tokio::test]
327    async fn aborts_before_trailers() {
328        let (mut tx, body) = Channel::<Bytes, Error>::new(1024);
329
330        tokio::spawn(async move {
331            tx.send_data(Bytes::from("Hel")).await.unwrap();
332            tx.send_data(Bytes::from("lo!")).await.unwrap();
333            tx.abort(MSG);
334        });
335
336        let err = body.collect().await.unwrap_err();
337        assert_eq!(err, MSG);
338    }
339
340    #[tokio::test]
341    async fn aborts_after_trailers() {
342        let (mut tx, body) = Channel::<Bytes, Error>::new(1024);
343
344        tokio::spawn(async move {
345            tx.send_data(Bytes::from("Hel")).await.unwrap();
346            tx.send_data(Bytes::from("lo!")).await.unwrap();
347            let mut trailers = HeaderMap::new();
348            trailers.insert(
349                HeaderName::from_static("foo"),
350                HeaderValue::from_static("bar"),
351            );
352            tx.send_trailers(trailers).await.unwrap();
353            tx.abort(MSG);
354        });
355
356        let err = body.collect().await.unwrap_err();
357        assert_eq!(err, MSG);
358    }
359}