### Handling HTTP Request and Response Bodies Source: https://context7.com/hyperium/http-body/llms.txt Demonstrates how to interact with the Body trait implemented on http::Request and http::Response. This includes checking size hints and collecting body data into bytes. ```rust use bytes::Bytes; use http::{Request, Response, StatusCode}; use http_body::Body; use http_body_util::{Full, BodyExt}; #[tokio::main] async fn main() { // Create an HTTP request with a body let request = Request::builder() .method("POST") .uri("/api/data") .body(Full::new(Bytes::from(r#"{"key": "value"}"#))) .unwrap(); // Access body properties through the request assert_eq!(request.size_hint().exact(), Some(16)); assert!(!request.is_end_stream()); // Create an HTTP response with a body let response = Response::builder() .status(StatusCode::OK) .header("content-type", "application/json") .body(Full::new(Bytes::from(r#"{"status": "ok"}"#))) .unwrap(); // Collect response body let (parts, body) = response.into_parts(); let collected = body.collect().await.unwrap(); let body_bytes = collected.to_bytes(); assert_eq!(parts.status, StatusCode::OK); assert_eq!(body_bytes, r#"{"status": "ok"}"#); } ``` -------------------------------- ### Full Body: Creating and Using Single Data Chunks in Rust Source: https://context7.com/hyperium/http-body/llms.txt Demonstrates how to create and utilize the `Full` body type, which holds a single data chunk. It's suitable for small, complete payloads and shows creation from various types like Bytes, string slices, and byte arrays, along with methods for accessing data and checking stream status. ```rust use bytes::Bytes; use http_body::Body; use http_body_util::{Full, BodyExt}; #[tokio::main] async fn main() { // Create from various types let body1 = Full::new(Bytes::from("Hello")); let body2 = Full::from("Hello, World!"); let body3 = Full::from(vec![1u8, 2, 3, 4, 5]); let body4: Full = Full::from(b"static bytes".as_slice()); // Use the body let mut body = Full::new(Bytes::from("Hello, World!")); assert_eq!(body.size_hint().exact(), Some(13)); assert!(!body.is_end_stream()); // Read the single frame let frame = body.frame().await.unwrap().unwrap(); let data = frame.into_data().unwrap(); assert_eq!(data, Bytes::from("Hello, World!")); // Body is now exhausted assert!(body.is_end_stream()); assert!(body.frame().await.is_none()); // Access inner data without polling let body = Full::new(Bytes::from("test")); assert_eq!(body.into_inner(), Some(Bytes::from("test"))); } ``` -------------------------------- ### StreamBody: Creating HTTP Bodies from Streams in Rust Source: https://context7.com/hyperium/http-body/llms.txt Explains how to use `StreamBody` to wrap an asynchronous stream of frames, enabling the creation of HTTP bodies from sources like async iterators. It covers creating a body from frames, reading frames, and handling trailers. ```rust use bytes::Bytes; use http_body::Frame; use http_body_util::{StreamBody, BodyExt}; use futures_util::stream; use std::convert::Infallible; #[tokio::main] async fn main() { // Create a body from a stream of frames let chunks = vec![ Ok::<_, Infallible>(Frame::data(Bytes::from("Hello, "))), Ok(Frame::data(Bytes::from("World!"))), ]; let stream = stream::iter(chunks); let mut body = StreamBody::new(stream); // Read frames from the body let frame1 = body.frame().await.unwrap().unwrap(); assert_eq!(frame1.into_data().unwrap(), Bytes::from("Hello, ")); let frame2 = body.frame().await.unwrap().unwrap(); assert_eq!(frame2.into_data().unwrap(), Bytes::from("World!")); assert!(body.frame().await.is_none()); // Stream with trailers let mut trailers = http::HeaderMap::new(); trailers.insert("checksum", "abc123".parse().unwrap()); let frames = vec![ Ok::<_, Infallible>(Frame::data(Bytes::from("data"))), Ok(Frame::trailers(trailers)), ]; let body = StreamBody::new(stream::iter(frames)); let collected = body.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "data"); assert!(collected.trailers().is_some()); } ``` -------------------------------- ### HTTP Body SizeHint in Rust Source: https://context7.com/hyperium/http-body/llms.txt Explains the `http_body::SizeHint` struct in Rust, used to provide bounds on the remaining length of an HTTP body stream. It covers creating hints with exact sizes, setting lower and upper bounds, and combining hints. ```rust use http_body::SizeHint; // Create a size hint with exact size (lower == upper) let exact = SizeHint::with_exact(1024); assert_eq!(exact.lower(), 1024); assert_eq!(exact.upper(), Some(1024)); assert_eq!(exact.exact(), Some(1024)); // Create a size hint with bounds let mut hint = SizeHint::new(); hint.set_lower(100); hint.set_upper(500); assert_eq!(hint.lower(), 100); assert_eq!(hint.upper(), Some(500)); assert_eq!(hint.exact(), None); // Not exact because lower != upper // Add size hints together (useful for composed bodies) let hint1 = SizeHint::with_exact(100); let hint2 = SizeHint::with_exact(200); let combined = hint1 + hint2; assert_eq!(combined.exact(), Some(300)); ``` -------------------------------- ### Empty HTTP Body Implementation in Rust Source: https://context7.com/hyperium/http-body/llms.txt Shows how to use the `http_body_util::Empty` struct in Rust to represent an HTTP body with no data. This type immediately signals the end of the stream and is useful as a placeholder or for requests/responses without content. ```rust use bytes::Bytes; use http_body::Body; use http_body_util::{Empty, BodyExt}; #[tokio::main] async fn main() { // Create an empty body let mut body = Empty::::new(); // Check properties assert!(body.is_end_stream()); assert_eq!(body.size_hint().exact(), Some(0)); // Polling returns None immediately assert!(body.frame().await.is_none()); // Empty bodies are Copy and Clone let body2 = body; let body3 = body.clone(); } ``` -------------------------------- ### Add Trailers to Bodies Source: https://context7.com/hyperium/http-body/llms.txt The with_trailers combinator allows attaching a future to a body that resolves into trailers. This is useful for scenarios like content hashing where trailers are computed asynchronously. ```rust use bytes::Bytes; use http::HeaderMap; use http_body_util::{Full, BodyExt}; #[tokio::main] async fn main() { let (tx, rx) = tokio::sync::oneshot::channel::(); let body = Full::::from("Hello, World!") .with_trailers(async move { match rx.await { Ok(trailers) => Some(Ok(trailers)), Err(_) => None, } }); tokio::spawn(async move { let mut trailers = HeaderMap::new(); trailers.insert("x-content-hash", "sha256:abc123".parse().unwrap()); let _ = tx.send(trailers); }); let collected = body.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "Hello, World!"); assert!(collected.trailers().is_some()); } ``` -------------------------------- ### Channel Body: Asynchronous Communication for HTTP Bodies in Rust Source: https://context7.com/hyperium/http-body/llms.txt Details the `Channel` body type, which uses an asynchronous channel to send data from one task and consume it as an HTTP body in another. This is useful for dynamically generated responses and demonstrates sending data, trailers, and handling errors. ```rust use bytes::Bytes; use http::HeaderMap; use http_body_util::{BodyExt, channel::Channel}; use std::convert::Infallible; #[tokio::main] async fn main() { // Create a channel with buffer capacity let (mut tx, body) = Channel::::new(1024); // Spawn a task to send data tokio::spawn(async move { tx.send_data(Bytes::from("Hello, ")).await.unwrap(); tx.send_data(Bytes::from("World!")).await.unwrap(); // Optionally send trailers let mut trailers = HeaderMap::new(); trailers.insert("x-checksum", "abc123".parse().unwrap()); tx.send_trailers(trailers).await.unwrap(); // Sender is dropped here, signaling end of stream }); // Collect all data from the body let collected = body.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "Hello, World!"); assert_eq!(collected.trailers().unwrap()["x-checksum"], "abc123"); } #[tokio::main] async fn channel_with_error() { // Channel with custom error type let (mut tx, body) = Channel::::new(16); tokio::spawn(async move { tx.send_data(Bytes::from("partial data")).await.unwrap(); // Abort with an error tx.abort("connection reset"); }); let result = body.collect().await; assert_eq!(result.unwrap_err(), "connection reset"); } #[tokio::main] async fn channel_capacity() { let (mut tx, mut body) = Channel::::new(4); assert_eq!(tx.capacity(), 4); assert_eq!(tx.max_capacity(), 4); tx.send_data(Bytes::from("data")).await.unwrap(); assert_eq!(tx.capacity(), 3); // Reading increases capacity let _ = body.frame().await; assert_eq!(tx.capacity(), 4); } ``` -------------------------------- ### Implement Custom HTTP Body Trait in Rust Source: https://context7.com/hyperium/http-body/llms.txt Demonstrates how to implement the `http_body::Body` trait for a custom struct. This involves defining the data type, error type, and implementing `poll_frame`, `is_end_stream`, and `size_hint` methods for asynchronous frame-based streaming. ```rust use bytes::Bytes; use http_body::Body; use std::pin::Pin; use std::task::{Context, Poll}; // Implement a custom body type struct MyBody { data: Option, } impl Body for MyBody { type Data = Bytes; type Error = std::convert::Infallible; fn poll_frame( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll, Self::Error>>> { Poll::Ready(self.data.take().map(|d| Ok(http_body::Frame::data(d)))) } fn is_end_stream(&self) -> bool { self.data.is_none() } fn size_hint(&self) -> http_body::SizeHint { match &self.data { Some(data) => http_body::SizeHint::with_exact(data.len() as u64), None => http_body::SizeHint::with_exact(0), } } } // Usage let body = MyBody { data: Some(Bytes::from("Hello, World!")) }; assert_eq!(body.size_hint().exact(), Some(13)); assert!(!body.is_end_stream()); ``` -------------------------------- ### HTTP Body Frame Type in Rust Source: https://context7.com/hyperium/http-body/llms.txt Illustrates the usage of the `http_body::Frame` enum in Rust for representing data chunks or trailers within an HTTP body stream. It shows how to create, identify, and extract data from both data frames and trailer frames. ```rust use bytes::Bytes; use http::HeaderMap; use http_body::Frame; // Create a data frame let data_frame = Frame::data(Bytes::from("Hello, World!")); assert!(data_frame.is_data()); assert!(!data_frame.is_trailers()); // Extract data from the frame let data = data_frame.into_data().expect("should be data frame"); assert_eq!(data, Bytes::from("Hello, World!")); // Create a trailers frame let mut trailers = HeaderMap::new(); trailers.insert("content-md5", "abc123".parse().unwrap()); let trailer_frame: Frame = Frame::trailers(trailers); assert!(trailer_frame.is_trailers()); // Map frame data to a different type let frame = Frame::data(vec![1u8, 2, 3]); let mapped: Frame = frame.map_data(|v| Bytes::from(v)); assert_eq!(mapped.data_ref().unwrap().as_ref(), &[1, 2, 3]); ``` -------------------------------- ### Convert Bodies to Streams Source: https://context7.com/hyperium/http-body/llms.txt BodyStream and BodyDataStream convert HTTP bodies into asynchronous streams. BodyStream includes all frames including trailers, while BodyDataStream filters for data frames only. ```rust use bytes::Bytes; use http_body_util::{Full, BodyExt}; use http_body_util::{BodyStream, BodyDataStream}; use futures_util::StreamExt; #[tokio::main] async fn main() { let body = Full::new(Bytes::from("Hello")); let mut stream = BodyStream::new(body); let frame = stream.next().await.unwrap().unwrap(); assert!(frame.is_data()); assert_eq!(frame.into_data().unwrap(), "Hello"); assert!(stream.next().await.is_none()); let body = Full::new(Bytes::from("World")); let mut data_stream = BodyDataStream::new(body); let data = data_stream.next().await.unwrap().unwrap(); assert_eq!(data, "World"); assert!(data_stream.next().await.is_none()); } ``` -------------------------------- ### Create Sum Type Bodies with Either Source: https://context7.com/hyperium/http-body/llms.txt The Either type allows a body to be one of two different types, provided they share the same Data type. It is useful for functions that return different body implementations based on runtime conditions. ```rust use bytes::Bytes; use http_body_util::{BodyExt, Empty, Full, Either}; #[tokio::main] async fn main() { fn make_body(include_data: bool) -> Either, Empty> { if include_data { Either::Left(Full::new(Bytes::from("Hello!"))) } else { Either::Right(Empty::new()) } } let body = make_body(true); let collected = body.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "Hello!"); let body = make_body(false); let collected = body.collect().await.unwrap(); assert!(collected.to_bytes().is_empty()); let either: Either = Either::Left(42); assert_eq!(either.into_inner(), 42); } ``` -------------------------------- ### Implement Type-Erased Bodies with BoxBody Source: https://context7.com/hyperium/http-body/llms.txt BoxBody and UnsyncBoxBody provide trait-object based body implementations. These enable dynamic dispatch and the ability to store different body types in a single collection. ```rust use bytes::Bytes; use http_body_util::{BodyExt, Empty, Full}; use http_body_util::combinators::{BoxBody, UnsyncBoxBody}; #[tokio::main] async fn main() { let body1: BoxBody = Full::new(Bytes::from("one")).boxed(); let body2: BoxBody = Empty::new().boxed(); let mut bodies: Vec> = vec![body1, body2]; for body in &mut bodies { let collected = std::mem::take(body).collect().await.unwrap(); println!("Body bytes: {:?}", collected.to_bytes()); } let unsync_body: UnsyncBoxBody = Full::new(Bytes::from("unsync")).boxed_unsync(); let collected = unsync_body.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "unsync"); let default_body = BoxBody::::default(); assert!(default_body.is_end_stream()); } ``` -------------------------------- ### BodyExt: Manipulate and Stream HTTP Bodies in Rust Source: https://context7.com/hyperium/http-body/llms.txt The BodyExt trait extends HTTP body types with methods for frame manipulation, collection, mapping, error transformation, boxing for dynamic dispatch, and conversion to streams. It requires the `bytes` and `http_body_util` crates. Input is typically an `http_body::Body` implementation, and outputs vary based on the method used, such as `Collected`, `Stream`, or `BoxBody`. ```rust use bytes::Bytes; use http_body_util::{BodyExt, Full, Empty}; #[tokio::main] async fn main() { // frame() - Get next frame as a future let mut body = Full::new(Bytes::from("Hello")); let frame = body.frame().await.unwrap().unwrap(); assert_eq!(frame.into_data().unwrap(), "Hello"); // collect() - Collect all frames into Collected let body = Full::new(Bytes::from("Hello, World!")); let collected = body.collect().await.unwrap(); let bytes = collected.to_bytes(); assert_eq!(bytes, "Hello, World!"); // map_frame() - Transform frames let body = Full::new(Bytes::from("hello")); let mapped = body.map_frame(|frame| { frame.map_data(|data| { Bytes::from(data.to_ascii_uppercase()) }) }); let result = mapped.collect().await.unwrap().to_bytes(); assert_eq!(result, "HELLO"); // map_err() - Transform error types let body = Full::::new(Bytes::from("data")); let _mapped = body.map_err(|_: std::convert::Infallible| -> std::io::Error { std::io::Error::new(std::io::ErrorKind::Other, "error") }); // boxed() - Type-erase the body for dynamic dispatch let body1: http_body_util::combinators::BoxBody = Full::new(Bytes::from("one")).boxed(); let body2: http_body_util::combinators::BoxBody = Empty::new().boxed(); // Both can now be stored in the same collection let bodies = vec![body1, body2]; // into_stream() - Convert body to a Stream use futures_util::StreamExt; let body = Full::new(Bytes::from("streamed")); let mut stream = body.into_stream(); let frame = stream.next().await.unwrap().unwrap(); assert!(frame.is_data()); } ``` -------------------------------- ### Collected Body: Buffer and Access HTTP Body Data and Trailers in Rust Source: https://context7.com/hyperium/http-body/llms.txt The Collected struct, returned by `BodyExt::collect()`, buffers all data and trailer frames from an HTTP body. It can be converted into a `Bytes` object or used as a body itself. It requires `bytes`, `http_body_util`, `http`, and `futures_util` crates. The input is an `http_body::Body`, and the output is a `Collected` struct containing the body's content and trailers. ```rust use bytes::Bytes; use http::HeaderMap; use http_body::Frame; use http_body_util::{BodyExt, StreamBody}; use futures_util::stream; use std::convert::Infallible; #[tokio::main] async fn main() { // Create a body with multiple chunks and trailers let mut trailers = HeaderMap::new(); trailers.insert("x-checksum", "abc123".parse().unwrap()); let frames = vec![ Ok::<_, Infallible>(Frame::data(Bytes::from("Hello, "))), Ok(Frame::data(Bytes::from("World!"))), Ok(Frame::trailers(trailers)), ]; let body = StreamBody::new(stream::iter(frames)); // Collect the entire body let collected = body.collect().await.unwrap(); // Convert to bytes let bytes = collected.to_bytes(); assert_eq!(bytes, "Hello, World!"); // Collect again to access trailers (to_bytes consumes self) let frames2 = vec![ Ok::<_, Infallible>(Frame::data(Bytes::from("data"))), Ok(Frame::trailers({ let mut t = HeaderMap::new(); t.insert("trailer", "value".parse().unwrap()); t })), ]; let collected2 = StreamBody::new(stream::iter(frames2)).collect().await.unwrap(); // Access trailers assert_eq!(collected2.trailers().unwrap()["trailer"], "value"); // aggregate() returns an impl Buf for efficient reading let collected3 = StreamBody::new(stream::iter(vec![ Ok::<_, Infallible>(Frame::data(Bytes::from("buf"))), ])).collect().await.unwrap(); let buf = collected3.aggregate(); use bytes::Buf; assert_eq!(buf.remaining(), 3); } ``` -------------------------------- ### Limited Body: Enforce Content Length Limits for HTTP Bodies in Rust Source: https://context7.com/hyperium/http-body/llms.txt The Limited struct wraps an HTTP body and enforces a maximum content length, returning a `LengthLimitError` if the limit is exceeded. It requires the `http_body_util` crate. Input is an `http_body::Body` and a size limit, and the output is either a `Collected` body if within limits or a `LengthLimitError`. ```rust use bytes::Bytes; use http_body_util::{BodyExt, Full, Limited, LengthLimitError}; #[tokio::main] async fn main() { // Create a limited body with 100 byte limit let inner = Full::new(Bytes::from("Hello, World!")); let mut limited = Limited::new(inner, 100); // This succeeds because content is under limit let collected = limited.collect().await.unwrap(); assert_eq!(collected.to_bytes(), "Hello, World!"); // Create a body that exceeds the limit let large_data = Bytes::from("x".repeat(200)); let inner = Full::new(large_data); let limited = Limited::new(inner, 100); // This fails with LengthLimitError let result = limited.collect().await; assert!(result.is_err()); let err = result.unwrap_err(); assert!(err.downcast_ref::().is_some()); } ``` -------------------------------- ### Fuse HTTP Body Combinator Source: https://context7.com/hyperium/http-body/llms.txt The Fuse combinator ensures that a body returns None consistently after the first exhaustion or error. This prevents invalid re-polling of bodies that have already finished. ```rust use bytes::Bytes; use http_body_util::{Full, BodyExt}; #[tokio::main] async fn main() { let body = Full::new(Bytes::from("data")); let mut fused = body.fuse(); // Read the data let frame = fused.frame().await.unwrap().unwrap(); assert_eq!(frame.into_data().unwrap(), "data"); // After exhaustion, always returns None assert!(fused.frame().await.is_none()); assert!(fused.frame().await.is_none()); // Safe to poll again assert!(fused.frame().await.is_none()); // Still None } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.