use bytes::{Buf, BufMut, Bytes}; use super::HttpBody; /// Concatenate the buffers from a body into a single `Bytes` asynchronously. /// /// This may require copying the data into a single buffer. If you don't need /// a contiguous buffer, prefer the [`aggregate`](crate::body::aggregate()) /// function. /// /// # Note /// /// Care needs to be taken if the remote is untrusted. The function doesn't implement any length /// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the /// `Content-Length` is a possibility, but it is not strictly mandated to be present. /// /// # Example /// /// ``` /// # #[cfg(all(feature = "client", feature = "tcp", any(feature = "http1", feature = "http2")))] /// # async fn doc() -> hyper::Result<()> { /// use hyper::{body::HttpBody}; /// /// # let request = hyper::Request::builder() /// # .method(hyper::Method::POST) /// # .uri("http://httpbin.org/post") /// # .header("content-type", "application/json") /// # .body(hyper::Body::from(r#"{"library":"hyper"}"#)).unwrap(); /// # let client = hyper::Client::new(); /// let response = client.request(request).await?; /// /// const MAX_ALLOWED_RESPONSE_SIZE: u64 = 1024; /// /// let response_content_length = match response.body().size_hint().upper() { /// Some(v) => v, /// None => MAX_ALLOWED_RESPONSE_SIZE + 1 // Just to protect ourselves from a malicious response /// }; /// /// if response_content_length < MAX_ALLOWED_RESPONSE_SIZE { /// let body_bytes = hyper::body::to_bytes(response.into_body()).await?; /// println!("body: {:?}", body_bytes); /// } /// /// # Ok(()) /// # } /// ``` pub async fn to_bytes(body: T) -> Result where T: HttpBody, { futures_util::pin_mut!(body); // If there's only 1 chunk, we can just return Buf::to_bytes() let mut first = if let Some(buf) = body.data().await { buf? } else { return Ok(Bytes::new()); }; let second = if let Some(buf) = body.data().await { buf? } else { return Ok(first.copy_to_bytes(first.remaining())); }; // Don't pre-emptively reserve *too* much. let rest = (body.size_hint().lower() as usize).min(1024 * 16); let cap = first .remaining() .saturating_add(second.remaining()) .saturating_add(rest); // With more than 1 buf, we gotta flatten into a Vec first. let mut vec = Vec::with_capacity(cap); vec.put(first); vec.put(second); while let Some(buf) = body.data().await { vec.put(buf?); } Ok(vec.into()) }