http_body_util/
channel.rs1use 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 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 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
75pub 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 pub async fn send(&mut self, frame: Frame<D>) -> Result<(), SendError> {
84 self.tx_frame.send(frame).await.map_err(|_| SendError)
85 }
86
87 pub async fn send_data(&mut self, buf: D) -> Result<(), SendError> {
89 self.send(Frame::data(buf)).await
90 }
91
92 pub async fn send_trailers(&mut self, trailers: HeaderMap) -> Result<(), SendError> {
94 self.send(Frame::trailers(trailers)).await
95 }
96
97 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 pub fn capacity(&mut self) -> usize {
146 self.tx_frame.capacity()
147 }
148
149 pub fn max_capacity(&mut self) -> usize {
173 self.tx_frame.max_capacity()
174 }
175
176 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#[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 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 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 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(body);
313
314 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 type Error = &'static str;
323 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}