hyperium / hyperium/http-body

Feature Proposal: Add `try_clone` method to `Body` trait

Open
#158 9 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
173
Forks
69
Avg merge
6d 15h
Merged PRs (30d)
4

Description

Description

When building HTTP clients with tower, tower-http, http-body, we often need to reuse the body data—most commonly for:

  • Retrying requests after transient errors
  • Following 3xx redirects
  • Others...

It is awkward now when working with something like tower::retry, because any middleware is free to wrap the original body in a new type that does not implement Clone.
Once the concrete type is erased (e.g. BoxBody), it forces users to add an extra warpper (“clone adapter”) to make it compile, or to buffer the entire body data, neither of which is ideal.


Proposal

Add a default method to the Body trait:

/// Try to clone this body if the underlying implementation supports it.
///
/// Returns `Some(cloned)` if the entire body can be reproduced verbatim, `None` otherwise.
///
/// Implementations that wrap another body must delegate this call so that the capability is preserved through arbitrary middleware.
fn try_clone(&self) -> Option<Self>
where
    Self: Sized,
{
    None
}
  • No breaking change—every existing type continues to compile, and works as before.
  • Middleware that only wrap the inner body can forward the call in one line.
  • Retry/redirect policies can attempt try_clone() first and only fall back to buffering when it returns None, keeping the fast path zero-copy.

Alternatives considered

rewind() would also work, which reset the body stream to begining. it good for seekable I/O like files maybe.

/// Return value tell is if rewind success.
///
/// For example: body construct from short `String`, `Vec<u8>`, `Bytes`,... always return true, and retry goes on.
/// body construct from channel/stream, return false, so that retry can not continue.
fn rewind(&mut self) -> bool {
    false
}

However, I believe try_clone is more general and the better choice.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue identifies the Body trait as the entry point; read its current definition and implementations, then inspect the retry and redirect use cases named here. Confirm the API shape, delegation expectations, and coverage needed for successful cloning versus unsupported bodies before considering the proposal complete.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.