http_body_to_bytes/
lib.rs

1use bytes::{BufMut as _, Bytes};
2use http_body::Body as HttpBody;
3use http_body_util::BodyExt as _;
4
5pub async fn http_body_to_bytes<T>(body: T) -> Result<Bytes, T::Error>
6where
7    T: HttpBody,
8{
9    Ok(body.collect().await?.to_bytes())
10}
11
12pub async fn http_body_to_bytes_with_max_length<T>(
13    mut body: T,
14    max_length: usize,
15) -> Result<Bytes, Box<dyn std::error::Error + Send + Sync>>
16where
17    T: HttpBody + Unpin,
18{
19    let mut buf = Vec::with_capacity(max_length);
20    while let Some(Ok(frame)) = body.frame().await {
21        match frame.into_data() {
22            Ok(data) => buf.put(data),
23            Err(_frame) => {}
24        }
25        if buf.len() >= max_length {
26            return Ok(buf.into());
27        }
28    }
29    Ok(buf.into())
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    use core::convert::Infallible;
37
38    use http_body::Frame;
39    use http_body_util::{Full, StreamBody};
40
41    #[tokio::test]
42    async fn test_http_body_to_bytes() {
43        let body = Full::<Bytes>::from("foo");
44        assert_eq!(
45            http_body_to_bytes(body).await.unwrap(),
46            Bytes::copy_from_slice(b"foo")
47        );
48    }
49
50    #[tokio::test]
51    async fn test_http_body_to_bytes_with_max_length() {
52        let body = Full::<Bytes>::from("foobar");
53        assert_eq!(
54            http_body_to_bytes_with_max_length(body, 3).await.unwrap(),
55            Bytes::copy_from_slice(b"foobar")
56        );
57
58        let chunks: Vec<Result<_, Infallible>> = vec![
59            Ok(Frame::data(Bytes::from("hello"))),
60            Ok(Frame::data(Bytes::from(" "))),
61            Ok(Frame::data(Bytes::from("world"))),
62        ];
63        let body = StreamBody::new(futures_util::stream::iter(chunks));
64        assert_eq!(
65            http_body_to_bytes_with_max_length(body, 3).await.unwrap(),
66            Bytes::copy_from_slice(b"hello")
67        );
68
69        let chunks: Vec<Result<_, Infallible>> = vec![
70            Ok(Frame::data(Bytes::from("fo"))),
71            Ok(Frame::data(Bytes::from("o"))),
72            Ok(Frame::data(Bytes::from("bar"))),
73        ];
74        let body = StreamBody::new(futures_util::stream::iter(chunks));
75        assert_eq!(
76            http_body_to_bytes_with_max_length(body, 3).await.unwrap(),
77            Bytes::copy_from_slice(b"foo")
78        );
79    }
80}