Skip to main content

actix_http/body/
message_body.rs

1//! [`MessageBody`] trait and foreign implementations.
2
3use std::{
4    convert::Infallible,
5    error::Error as StdError,
6    mem,
7    pin::Pin,
8    task::{Context, Poll},
9};
10
11use bytes::{Bytes, BytesMut};
12use futures_core::ready;
13use pin_project_lite::pin_project;
14
15use super::{BodySize, BoxBody};
16
17/// An interface for types that can be used as a response body.
18///
19/// It is not usually necessary to create custom body types, this trait is already [implemented for
20/// a large number of sensible body types](#foreign-impls) including:
21/// - Empty body: `()`
22/// - Text-based: `String`, `&'static str`, [`ByteString`](https://docs.rs/bytestring/1).
23/// - Byte-based: `Bytes`, `BytesMut`, `Vec<u8>`, `&'static [u8]`;
24/// - Streams: [`BodyStream`](super::BodyStream), [`SizedStream`](super::SizedStream)
25///
26/// # Examples
27/// ```
28/// # use std::convert::Infallible;
29/// # use std::task::{Poll, Context};
30/// # use std::pin::Pin;
31/// # use bytes::Bytes;
32/// # use actix_http::body::{BodySize, MessageBody};
33/// struct Repeat {
34///     chunk: String,
35///     n_times: usize,
36/// }
37///
38/// impl MessageBody for Repeat {
39///     type Error = Infallible;
40///
41///     fn size(&self) -> BodySize {
42///         BodySize::Sized((self.chunk.len() * self.n_times) as u64)
43///     }
44///
45///     fn poll_next(
46///         self: Pin<&mut Self>,
47///         _cx: &mut Context<'_>,
48///     ) -> Poll<Option<Result<Bytes, Self::Error>>> {
49///         let payload_string = self.chunk.repeat(self.n_times);
50///         let payload_bytes = Bytes::from(payload_string);
51///         Poll::Ready(Some(Ok(payload_bytes)))
52///     }
53/// }
54/// ```
55pub trait MessageBody {
56    /// The type of error that will be returned if streaming body fails.
57    ///
58    /// Since it is not appropriate to generate a response mid-stream, it only requires `Error` for
59    /// internal use and logging.
60    type Error: Into<Box<dyn StdError>>;
61
62    /// Body size hint.
63    ///
64    /// If [`BodySize::None`] is returned, optimizations that skip reading the body are allowed.
65    fn size(&self) -> BodySize;
66
67    /// Attempt to pull out the next chunk of body bytes.
68    ///
69    /// # Return Value
70    /// Similar to the `Stream` interface, there are several possible return values, each indicating
71    /// a distinct state:
72    /// - `Poll::Pending` means that this body's next chunk is not ready yet. Implementations must
73    ///   ensure that the current task will be notified when the next chunk may be ready.
74    /// - `Poll::Ready(Some(val))` means that the body has successfully produced a chunk, `val`,
75    ///   and may produce further values on subsequent `poll_next` calls.
76    /// - `Poll::Ready(None)` means that the body is complete, and `poll_next` should not be
77    ///   invoked again.
78    ///
79    /// # Panics
80    /// Once a body is complete (i.e., `poll_next` returned `Ready(None)`), calling its `poll_next`
81    /// method again may panic, block forever, or cause other kinds of problems; this trait places
82    /// no requirements on the effects of such a call. However, as the `poll_next` method is not
83    /// marked unsafe, Rust’s usual rules apply: calls must never cause UB, regardless of its state.
84    fn poll_next(
85        self: Pin<&mut Self>,
86        cx: &mut Context<'_>,
87    ) -> Poll<Option<Result<Bytes, Self::Error>>>;
88
89    /// Try to convert into the complete chunk of body bytes.
90    ///
91    /// Override this method if the complete body can be trivially extracted. This is useful for
92    /// optimizations where `poll_next` calls can be avoided.
93    ///
94    /// Body types with [`BodySize::None`] are allowed to return empty `Bytes`. Although, if calling
95    /// this method, it is recommended to check `size` first and return early.
96    ///
97    /// # Errors
98    /// The default implementation will error and return the original type back to the caller for
99    /// further use.
100    #[inline]
101    fn try_into_bytes(self) -> Result<Bytes, Self>
102    where
103        Self: Sized,
104    {
105        Err(self)
106    }
107
108    /// Wraps this body into a `BoxBody`.
109    ///
110    /// No-op when called on a `BoxBody`, meaning there is no risk of double boxing when calling
111    /// this on a generic `MessageBody`. Prefer this over [`BoxBody::new`] when a boxed body
112    /// is required.
113    #[inline]
114    fn boxed(self) -> BoxBody
115    where
116        Self: Sized + 'static,
117    {
118        BoxBody::new(self)
119    }
120}
121
122mod foreign_impls {
123    use std::{borrow::Cow, ops::DerefMut};
124
125    use super::*;
126
127    impl<B> MessageBody for &mut B
128    where
129        B: MessageBody + Unpin + ?Sized,
130    {
131        type Error = B::Error;
132
133        fn size(&self) -> BodySize {
134            (**self).size()
135        }
136
137        fn poll_next(
138            mut self: Pin<&mut Self>,
139            cx: &mut Context<'_>,
140        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
141            Pin::new(&mut **self).poll_next(cx)
142        }
143    }
144
145    impl MessageBody for Infallible {
146        type Error = Infallible;
147
148        fn size(&self) -> BodySize {
149            match *self {}
150        }
151
152        fn poll_next(
153            self: Pin<&mut Self>,
154            _cx: &mut Context<'_>,
155        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
156            match *self {}
157        }
158    }
159
160    impl MessageBody for () {
161        type Error = Infallible;
162
163        #[inline]
164        fn size(&self) -> BodySize {
165            BodySize::Sized(0)
166        }
167
168        #[inline]
169        fn poll_next(
170            self: Pin<&mut Self>,
171            _cx: &mut Context<'_>,
172        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
173            Poll::Ready(None)
174        }
175
176        #[inline]
177        fn try_into_bytes(self) -> Result<Bytes, Self> {
178            Ok(Bytes::new())
179        }
180    }
181
182    impl<B> MessageBody for Box<B>
183    where
184        B: MessageBody + Unpin + ?Sized,
185    {
186        type Error = B::Error;
187
188        #[inline]
189        fn size(&self) -> BodySize {
190            self.as_ref().size()
191        }
192
193        #[inline]
194        fn poll_next(
195            self: Pin<&mut Self>,
196            cx: &mut Context<'_>,
197        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
198            Pin::new(self.get_mut().as_mut()).poll_next(cx)
199        }
200    }
201
202    impl<T, B> MessageBody for Pin<T>
203    where
204        T: DerefMut<Target = B> + Unpin,
205        B: MessageBody + ?Sized,
206    {
207        type Error = B::Error;
208
209        #[inline]
210        fn size(&self) -> BodySize {
211            self.as_ref().size()
212        }
213
214        #[inline]
215        fn poll_next(
216            self: Pin<&mut Self>,
217            cx: &mut Context<'_>,
218        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
219            self.get_mut().as_mut().poll_next(cx)
220        }
221    }
222
223    impl MessageBody for &'static [u8] {
224        type Error = Infallible;
225
226        #[inline]
227        fn size(&self) -> BodySize {
228            BodySize::Sized(self.len() as u64)
229        }
230
231        #[inline]
232        fn poll_next(
233            self: Pin<&mut Self>,
234            _cx: &mut Context<'_>,
235        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
236            if self.is_empty() {
237                Poll::Ready(None)
238            } else {
239                Poll::Ready(Some(Ok(Bytes::from_static(mem::take(self.get_mut())))))
240            }
241        }
242
243        #[inline]
244        fn try_into_bytes(self) -> Result<Bytes, Self> {
245            Ok(Bytes::from_static(self))
246        }
247    }
248
249    impl MessageBody for Bytes {
250        type Error = Infallible;
251
252        #[inline]
253        fn size(&self) -> BodySize {
254            BodySize::Sized(self.len() as u64)
255        }
256
257        #[inline]
258        fn poll_next(
259            self: Pin<&mut Self>,
260            _cx: &mut Context<'_>,
261        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
262            if self.is_empty() {
263                Poll::Ready(None)
264            } else {
265                Poll::Ready(Some(Ok(mem::take(self.get_mut()))))
266            }
267        }
268
269        #[inline]
270        fn try_into_bytes(self) -> Result<Bytes, Self> {
271            Ok(self)
272        }
273    }
274
275    impl MessageBody for BytesMut {
276        type Error = Infallible;
277
278        #[inline]
279        fn size(&self) -> BodySize {
280            BodySize::Sized(self.len() as u64)
281        }
282
283        #[inline]
284        fn poll_next(
285            self: Pin<&mut Self>,
286            _cx: &mut Context<'_>,
287        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
288            if self.is_empty() {
289                Poll::Ready(None)
290            } else {
291                Poll::Ready(Some(Ok(mem::take(self.get_mut()).freeze())))
292            }
293        }
294
295        #[inline]
296        fn try_into_bytes(self) -> Result<Bytes, Self> {
297            Ok(self.freeze())
298        }
299    }
300
301    impl MessageBody for Vec<u8> {
302        type Error = Infallible;
303
304        #[inline]
305        fn size(&self) -> BodySize {
306            BodySize::Sized(self.len() as u64)
307        }
308
309        #[inline]
310        fn poll_next(
311            self: Pin<&mut Self>,
312            _cx: &mut Context<'_>,
313        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
314            if self.is_empty() {
315                Poll::Ready(None)
316            } else {
317                Poll::Ready(Some(Ok(mem::take(self.get_mut()).into())))
318            }
319        }
320
321        #[inline]
322        fn try_into_bytes(self) -> Result<Bytes, Self> {
323            Ok(Bytes::from(self))
324        }
325    }
326
327    impl MessageBody for Cow<'static, [u8]> {
328        type Error = Infallible;
329
330        #[inline]
331        fn size(&self) -> BodySize {
332            BodySize::Sized(self.len() as u64)
333        }
334
335        #[inline]
336        fn poll_next(
337            self: Pin<&mut Self>,
338            _cx: &mut Context<'_>,
339        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
340            if self.is_empty() {
341                Poll::Ready(None)
342            } else {
343                let bytes = match mem::take(self.get_mut()) {
344                    Cow::Borrowed(b) => Bytes::from_static(b),
345                    Cow::Owned(b) => Bytes::from(b),
346                };
347                Poll::Ready(Some(Ok(bytes)))
348            }
349        }
350
351        #[inline]
352        fn try_into_bytes(self) -> Result<Bytes, Self> {
353            match self {
354                Cow::Borrowed(b) => Ok(Bytes::from_static(b)),
355                Cow::Owned(b) => Ok(Bytes::from(b)),
356            }
357        }
358    }
359
360    impl MessageBody for &'static str {
361        type Error = Infallible;
362
363        #[inline]
364        fn size(&self) -> BodySize {
365            BodySize::Sized(self.len() as u64)
366        }
367
368        #[inline]
369        fn poll_next(
370            self: Pin<&mut Self>,
371            _cx: &mut Context<'_>,
372        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
373            if self.is_empty() {
374                Poll::Ready(None)
375            } else {
376                let string = mem::take(self.get_mut());
377                let bytes = Bytes::from_static(string.as_bytes());
378                Poll::Ready(Some(Ok(bytes)))
379            }
380        }
381
382        #[inline]
383        fn try_into_bytes(self) -> Result<Bytes, Self> {
384            Ok(Bytes::from_static(self.as_bytes()))
385        }
386    }
387
388    impl MessageBody for String {
389        type Error = Infallible;
390
391        #[inline]
392        fn size(&self) -> BodySize {
393            BodySize::Sized(self.len() as u64)
394        }
395
396        #[inline]
397        fn poll_next(
398            self: Pin<&mut Self>,
399            _cx: &mut Context<'_>,
400        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
401            if self.is_empty() {
402                Poll::Ready(None)
403            } else {
404                let string = mem::take(self.get_mut());
405                Poll::Ready(Some(Ok(Bytes::from(string))))
406            }
407        }
408
409        #[inline]
410        fn try_into_bytes(self) -> Result<Bytes, Self> {
411            Ok(Bytes::from(self))
412        }
413    }
414
415    impl MessageBody for Cow<'static, str> {
416        type Error = Infallible;
417
418        #[inline]
419        fn size(&self) -> BodySize {
420            BodySize::Sized(self.len() as u64)
421        }
422
423        #[inline]
424        fn poll_next(
425            self: Pin<&mut Self>,
426            _cx: &mut Context<'_>,
427        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
428            if self.is_empty() {
429                Poll::Ready(None)
430            } else {
431                let bytes = match mem::take(self.get_mut()) {
432                    Cow::Borrowed(s) => Bytes::from_static(s.as_bytes()),
433                    Cow::Owned(s) => Bytes::from(s.into_bytes()),
434                };
435                Poll::Ready(Some(Ok(bytes)))
436            }
437        }
438
439        #[inline]
440        fn try_into_bytes(self) -> Result<Bytes, Self> {
441            match self {
442                Cow::Borrowed(s) => Ok(Bytes::from_static(s.as_bytes())),
443                Cow::Owned(s) => Ok(Bytes::from(s.into_bytes())),
444            }
445        }
446    }
447
448    impl MessageBody for bytestring::ByteString {
449        type Error = Infallible;
450
451        #[inline]
452        fn size(&self) -> BodySize {
453            BodySize::Sized(self.len() as u64)
454        }
455
456        #[inline]
457        fn poll_next(
458            self: Pin<&mut Self>,
459            _cx: &mut Context<'_>,
460        ) -> Poll<Option<Result<Bytes, Self::Error>>> {
461            if self.is_empty() {
462                Poll::Ready(None)
463            } else {
464                let string = mem::take(self.get_mut());
465                Poll::Ready(Some(Ok(string.into_bytes())))
466            }
467        }
468
469        #[inline]
470        fn try_into_bytes(self) -> Result<Bytes, Self> {
471            Ok(self.into_bytes())
472        }
473    }
474}
475
476pin_project! {
477    pub(crate) struct MessageBodyMapErr<B, F> {
478        #[pin]
479        body: B,
480        mapper: Option<F>,
481    }
482}
483
484impl<B, F, E> MessageBodyMapErr<B, F>
485where
486    B: MessageBody,
487    F: FnOnce(B::Error) -> E,
488{
489    pub(crate) fn new(body: B, mapper: F) -> Self {
490        Self {
491            body,
492            mapper: Some(mapper),
493        }
494    }
495}
496
497impl<B, F, E> MessageBody for MessageBodyMapErr<B, F>
498where
499    B: MessageBody,
500    F: FnOnce(B::Error) -> E,
501    E: Into<Box<dyn StdError>>,
502{
503    type Error = E;
504
505    #[inline]
506    fn size(&self) -> BodySize {
507        self.body.size()
508    }
509
510    fn poll_next(
511        mut self: Pin<&mut Self>,
512        cx: &mut Context<'_>,
513    ) -> Poll<Option<Result<Bytes, Self::Error>>> {
514        let this = self.as_mut().project();
515
516        match ready!(this.body.poll_next(cx)) {
517            Some(Err(err)) => {
518                let f = self.as_mut().project().mapper.take().unwrap();
519                let mapped_err = (f)(err);
520                Poll::Ready(Some(Err(mapped_err)))
521            }
522            Some(Ok(val)) => Poll::Ready(Some(Ok(val))),
523            None => Poll::Ready(None),
524        }
525    }
526
527    #[inline]
528    fn try_into_bytes(self) -> Result<Bytes, Self> {
529        let Self { body, mapper } = self;
530        body.try_into_bytes().map_err(|body| Self { body, mapper })
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use actix_rt::pin;
537    use actix_utils::future::poll_fn;
538    use futures_util::stream;
539
540    use super::*;
541    use crate::body::{self, EitherBody};
542
543    macro_rules! assert_poll_next {
544        ($pin:expr, $exp:expr) => {
545            assert_eq!(
546                poll_fn(|cx| $pin.as_mut().poll_next(cx))
547                    .await
548                    .unwrap() // unwrap option
549                    .unwrap(), // unwrap result
550                $exp
551            );
552        };
553    }
554
555    macro_rules! assert_poll_next_none {
556        ($pin:expr) => {
557            assert!(poll_fn(|cx| $pin.as_mut().poll_next(cx)).await.is_none());
558        };
559    }
560
561    #[allow(unused_allocation)] // triggered by `Box::new(()).size()`
562    #[actix_rt::test]
563    async fn boxing_equivalence() {
564        assert_eq!(().size(), BodySize::Sized(0));
565        assert_eq!(().size(), Box::new(()).size());
566        assert_eq!(().size(), Box::pin(()).size());
567
568        let pl = Box::new(());
569        pin!(pl);
570        assert_poll_next_none!(pl);
571
572        let mut pl = Box::pin(());
573        assert_poll_next_none!(pl);
574    }
575
576    #[actix_rt::test]
577    async fn mut_equivalence() {
578        assert_eq!(().size(), BodySize::Sized(0));
579        assert_eq!(().size(), (&(&mut ())).size());
580
581        let pl = &mut ();
582        pin!(pl);
583        assert_poll_next_none!(pl);
584
585        let pl = &mut Box::new(());
586        pin!(pl);
587        assert_poll_next_none!(pl);
588
589        let mut body = body::SizedStream::new(
590            8,
591            stream::iter([
592                Ok::<_, std::io::Error>(Bytes::from("1234")),
593                Ok(Bytes::from("5678")),
594            ]),
595        );
596        let body = &mut body;
597        assert_eq!(body.size(), BodySize::Sized(8));
598        pin!(body);
599        assert_poll_next!(body, Bytes::from_static(b"1234"));
600        assert_poll_next!(body, Bytes::from_static(b"5678"));
601        assert_poll_next_none!(body);
602    }
603
604    #[allow(clippy::let_unit_value)]
605    #[actix_rt::test]
606    async fn test_unit() {
607        let pl = ();
608        assert_eq!(pl.size(), BodySize::Sized(0));
609        pin!(pl);
610        assert_poll_next_none!(pl);
611    }
612
613    #[actix_rt::test]
614    async fn test_static_str() {
615        assert_eq!("".size(), BodySize::Sized(0));
616        assert_eq!("test".size(), BodySize::Sized(4));
617
618        let pl = "test";
619        pin!(pl);
620        assert_poll_next!(pl, Bytes::from("test"));
621    }
622
623    #[actix_rt::test]
624    async fn test_static_bytes() {
625        assert_eq!(b"".as_ref().size(), BodySize::Sized(0));
626        assert_eq!(b"test".as_ref().size(), BodySize::Sized(4));
627
628        let pl = b"test".as_ref();
629        pin!(pl);
630        assert_poll_next!(pl, Bytes::from("test"));
631    }
632
633    #[actix_rt::test]
634    async fn test_vec() {
635        assert_eq!(vec![0; 0].size(), BodySize::Sized(0));
636        assert_eq!(Vec::from("test").size(), BodySize::Sized(4));
637
638        let pl = Vec::from("test");
639        pin!(pl);
640        assert_poll_next!(pl, Bytes::from("test"));
641    }
642
643    #[actix_rt::test]
644    async fn test_bytes() {
645        assert_eq!(Bytes::new().size(), BodySize::Sized(0));
646        assert_eq!(Bytes::from_static(b"test").size(), BodySize::Sized(4));
647
648        let pl = Bytes::from_static(b"test");
649        pin!(pl);
650        assert_poll_next!(pl, Bytes::from("test"));
651    }
652
653    #[actix_rt::test]
654    async fn test_bytes_mut() {
655        assert_eq!(BytesMut::new().size(), BodySize::Sized(0));
656        assert_eq!(BytesMut::from(b"test".as_ref()).size(), BodySize::Sized(4));
657
658        let pl = BytesMut::from("test");
659        pin!(pl);
660        assert_poll_next!(pl, Bytes::from("test"));
661    }
662
663    #[actix_rt::test]
664    async fn test_string() {
665        assert_eq!(String::new().size(), BodySize::Sized(0));
666        assert_eq!("test".to_owned().size(), BodySize::Sized(4));
667
668        let pl = "test".to_owned();
669        pin!(pl);
670        assert_poll_next!(pl, Bytes::from("test"));
671    }
672
673    #[actix_rt::test]
674    async fn test_byte_string() {
675        let pl = bytestring::ByteString::from_static("test");
676        assert_eq!(pl.size(), BodySize::Sized(4));
677        pin!(pl);
678        assert_poll_next!(pl, Bytes::from_static(b"test"));
679        assert_poll_next_none!(pl);
680    }
681
682    #[actix_rt::test]
683    async fn complete_body_combinators() {
684        let body = Bytes::from_static(b"test");
685        let body = BoxBody::new(body);
686        let body = EitherBody::<_, ()>::left(body);
687        let body = EitherBody::<(), _>::right(body);
688        // Do not support try_into_bytes:
689        // let body = Box::new(body);
690        // let body = Box::pin(body);
691
692        assert_eq!(body.try_into_bytes().unwrap(), Bytes::from("test"));
693    }
694
695    #[actix_rt::test]
696    async fn complete_body_combinators_poll() {
697        let body = Bytes::from_static(b"test");
698        let body = BoxBody::new(body);
699        let body = EitherBody::<_, ()>::left(body);
700        let body = EitherBody::<(), _>::right(body);
701        let mut body = body;
702
703        assert_eq!(body.size(), BodySize::Sized(4));
704        assert_poll_next!(Pin::new(&mut body), Bytes::from("test"));
705        assert_poll_next_none!(Pin::new(&mut body));
706    }
707
708    #[actix_rt::test]
709    async fn none_body_combinators() {
710        fn none_body() -> BoxBody {
711            let body = body::None;
712            let body = BoxBody::new(body);
713            let body = EitherBody::<_, ()>::left(body);
714            let body = EitherBody::<(), _>::right(body);
715            body.boxed()
716        }
717
718        assert_eq!(none_body().size(), BodySize::None);
719        assert_eq!(none_body().try_into_bytes().unwrap(), Bytes::new());
720        assert_poll_next_none!(Pin::new(&mut none_body()));
721    }
722
723    // down-casting used to be done with a method on MessageBody trait
724    // test is kept to demonstrate equivalence of Any trait
725    #[actix_rt::test]
726    async fn test_body_casting() {
727        let mut body = String::from("hello cast");
728        // let mut resp_body: &mut dyn MessageBody<Error = Error> = &mut body;
729        let resp_body: &mut dyn std::any::Any = &mut body;
730        let body = resp_body.downcast_ref::<String>().unwrap();
731        assert_eq!(body, "hello cast");
732        let body = &mut resp_body.downcast_mut::<String>().unwrap();
733        body.push('!');
734        let body = resp_body.downcast_ref::<String>().unwrap();
735        assert_eq!(body, "hello cast!");
736        let not_body = resp_body.downcast_ref::<()>();
737        assert!(not_body.is_none());
738    }
739
740    #[actix_rt::test]
741    async fn non_owning_to_bytes() {
742        let mut body = BoxBody::new(());
743        let bytes = body::to_bytes(&mut body).await.unwrap();
744        assert_eq!(bytes, Bytes::new());
745
746        let mut body = body::BodyStream::new(stream::iter([
747            Ok::<_, std::io::Error>(Bytes::from("1234")),
748            Ok(Bytes::from("5678")),
749        ]));
750        let bytes = body::to_bytes(&mut body).await.unwrap();
751        assert_eq!(bytes, Bytes::from_static(b"12345678"));
752    }
753}