1use bytes::{Buf, BufMut, Bytes};
2
3use 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))]
54pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
55where
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