1 use bytes::{Buf, BufMut, Bytes};
2 
3 use super::HttpBody;
4 
5 /// Concatenate the buffers from a body into a single `Bytes` asynchronously.
6 ///
7 /// This may require copying the data into a single buffer. If you don't need
8 /// a contiguous buffer, prefer the [`aggregate`](crate::body::aggregate())
9 /// function.
10 ///
11 /// # Note
12 ///
13 /// Care needs to be taken if the remote is untrusted. The function doesn't implement any length
14 /// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the
15 /// `Content-Length` is a possibility, but it is not strictly mandated to be present.
16 ///
17 /// # Example
18 ///
19 /// ```
20 /// # #[cfg(all(feature = "client", feature = "tcp", any(feature = "http1", feature = "http2")))]
21 /// # async fn doc() -> hyper::Result<()> {
22 /// use hyper::{body::HttpBody};
23 ///
24 /// # let request = hyper::Request::builder()
25 /// #        .method(hyper::Method::POST)
26 /// #        .uri("http://httpbin.org/post")
27 /// #        .header("content-type", "application/json")
28 /// #        .body(hyper::Body::from(r#"{"library":"hyper"}"#)).unwrap();
29 /// # let client = hyper::Client::new();
30 /// let response = client.request(request).await?;
31 ///
32 /// const MAX_ALLOWED_RESPONSE_SIZE: u64 = 1024;
33 ///
34 /// let response_content_length = match response.body().size_hint().upper() {
35 ///     Some(v) => v,
36 ///     None => MAX_ALLOWED_RESPONSE_SIZE + 1 // Just to protect ourselves from a malicious response
37 /// };
38 ///
39 /// if response_content_length < MAX_ALLOWED_RESPONSE_SIZE {
40 ///     let body_bytes = hyper::body::to_bytes(response.into_body()).await?;
41 ///     println!("body: {:?}", body_bytes);
42 /// }
43 ///
44 /// # Ok(())
45 /// # }
46 /// ```
47 #[cfg_attr(
48     feature = "deprecated",
49     deprecated(
50         note = "This function has been replaced by a method on the `hyper::body::HttpBody` trait. Use `.collect().await?.to_bytes()` instead."
51     )
52 )]
53 #[cfg_attr(feature = "deprecated", allow(deprecated))]
to_bytes<T>(body: T) -> Result<Bytes, T::Error> where T: HttpBody,54 pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
55 where
56     T: HttpBody,
57 {
58     futures_util::pin_mut!(body);
59 
60     // If there's only 1 chunk, we can just return Buf::to_bytes()
61     let mut first = if let Some(buf) = body.data().await {
62         buf?
63     } else {
64         return Ok(Bytes::new());
65     };
66 
67     let second = if let Some(buf) = body.data().await {
68         buf?
69     } else {
70         return Ok(first.copy_to_bytes(first.remaining()));
71     };
72 
73     // Don't pre-emptively reserve *too* much.
74     let rest = (body.size_hint().lower() as usize).min(1024 * 16);
75     let cap = first
76         .remaining()
77         .saturating_add(second.remaining())
78         .saturating_add(rest);
79     // With more than 1 buf, we gotta flatten into a Vec first.
80     let mut vec = Vec::with_capacity(cap);
81     vec.put(first);
82     vec.put(second);
83 
84     while let Some(buf) = body.data().await {
85         vec.put(buf?);
86     }
87 
88     Ok(vec.into())
89 }
90