shared_http_body

Crates.ioshared_http_body
lib.rsshared_http_body
version0.1.6
created_at2025-11-21 04:29:35.310118+00
updated_at2025-12-13 02:49:30.396663+00
descriptionA library for creating shareable HTTP bodies that can be cloned and consumed by multiple consumers
homepage
repositoryhttps://github.com/ankurmittal/shared-http-body-rs
max_upload_size
id1943122
size63,800
Ankur Mittal (ankurmittal)

documentation

https://docs.rs/shared_http_body

README

shared_http_body

Crates.io Documentation License: Apache 2.0 codecov

A Rust library for creating shareable HTTP bodies that can be cloned and consumed by multiple tasks.

Overview

shared_http_body provides SharedBody, which allows you to create an HTTP body that can be cloned and shared across multiple consumers. All clones share the same underlying body state, so clones created at the same time will see the same frames, while clones created after partial consumption will only see the remaining frames.

Quick Example

use shared_http_body::SharedBodyExt;
use http_body_util::{BodyExt, StreamBody};
use http_body::Frame;
use bytes::Bytes;
use futures_util::stream;

#[tokio::main]
async fn main() {
    // Create a body from a stream of frames
    let chunks = vec!["hello", "world"];
    let stream = stream::iter(
        chunks.into_iter()
            .map(|s| Ok::<_, std::convert::Infallible>(Frame::data(Bytes::from(s))))
    );
    let body = StreamBody::new(stream);
    
    let shared_body = body.into_shared();

    // Clone the body for multiple consumers
    let consumer1 = shared_body.clone();
    let consumer2 = shared_body.clone();

    // Both consumers will receive all frames
    let (result1, result2) = tokio::join!(
        consumer1.collect().map(|r| r.unwrap().to_bytes()),
        consumer2.collect().map(|r| r.unwrap().to_bytes())
    );

    assert_eq!(result1, Bytes::from("helloworld"));
    assert_eq!(result2, Bytes::from("helloworld"));
    println!("Both consumers got: {:?}", result1);
}

Key Features

  • Cloneable HTTP bodies: Create multiple consumers from a single body
  • Thread-safe: Send + Sync - clones can be moved across threads
  • Efficient sharing: Frames are cloned only when consumed by each clone
  • Works with any Unpin body: Compatible with most HTTP body types
  • Preserves HTTP semantics: Maintains size_hint() and is_end_stream() behavior
  • Convenient extension trait: Use .into_shared() on any body via SharedBodyExt

Use Cases

Common scenarios where cloning HTTP bodies is useful:

  • Dark Forwarding — Clone the body to send it to a secondary destination for testing in production or shadow traffic analysis.
  • Request Retries — Keep a clone of the request body for retry attempts on failure.
  • Request/Response Logging — Clone the body to log it while still forwarding to the handler.

Requirements

  • The underlying body must implement Unpin
  • Body data type (Body::Data) must implement Clone
  • Body error type (Body::Error) must implement Clone
  • For thread safety, the body and its data/error types must be Send + Sync

How It Works

SharedBody uses futures_util::future::Shared internally to share the state of frame consumption across clones. Each frame is wrapped in a ClonableFrame that can clone both data frames and trailer frames. This allows multiple consumers to independently consume the same body without interference.

License

Licensed under the Apache License, Version 2.0.

Commit count: 0

cargo fmt