Skip to content

feat(response): introduce trailers support#2788

Open
0x676e67 wants to merge 9 commits into
seanmonstar:masterfrom
0x676e67:trailers
Open

feat(response): introduce trailers support#2788
0x676e67 wants to merge 9 commits into
seanmonstar:masterfrom
0x676e67:trailers

Conversation

@0x676e67
Copy link
Copy Markdown
Contributor

@0x676e67 0x676e67 commented Aug 8, 2025

from: #2626
from: #2776

Just a draft prototype for now. It’s a bit ugly, and there’s probably a better approach

@Lori-Shu
Copy link
Copy Markdown

After seeing your implementation, I just realized my implementation#2782 which mimics the fn chunk may consumes the res body and lead to inaccessibility of the body after the fn trailers called. Though, I think the user cases are mostly getting trailers after getting the body. Did not expect to be this complicate for this issue.

Copy link
Copy Markdown
Contributor

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @0x676e67 - I am also interested in trailers support and find this PR. It looks pretty good to me, requiring the body to be consumed to have access to trailers is sensible and is how Go's stdlib http client works too.

I left one suggestion but does it seem worth giving the PR a go?

Comment thread src/async_impl/response.rs Outdated
/// be determined after processing the entire response body.
#[inline]
pub async fn trailers(&mut self) -> crate::Result<Option<HeaderMap>> {
match self.trailers_rx.try_recv() {
Copy link
Copy Markdown
Contributor

@anuraaga anuraaga Sep 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this channel isn't actually used for synchronization, does it make sense to use a simpler OnceLock instead? Then trailers can be returned as a reference to match headers and doesn't need to be async.

aaf7bb1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to open a PR, I might not have the time to implement it myself.

@0x676e67 0x676e67 marked this pull request as ready for review December 19, 2025 03:51
@0x676e67 0x676e67 force-pushed the trailers branch 2 times, most recently from ea08f51 to 599a5b9 Compare December 19, 2025 04:54
Comment thread src/async_impl/response.rs Outdated
// Boxed to save space (11 words to 1 word), and it's not accessed
// frequently internally.
url: Box<Url>,
trailers: Option<HeaderMap>,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For something that I assume is not used often by most people, I'd rather sacrifice a little bit of perf for the less used case, instead of increasing the size for everyone. This could probably be stored with a private extension in res.extensions(). What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completely agree with that — I’ll do it that way later.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has already been done. Also, should we consider extending ResponseBuilderExt to support trailers, so that trailers can be preserved when converting from http::Response to reqwest::Response?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That I'm not so sure about... I think of this as more a temporary storage location. If a user converts to an http::Response, then there's the normal lower level way to get trailers, no?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. We can leave this out for now.

@0x676e67 0x676e67 force-pushed the trailers branch 2 times, most recently from ae23d64 to c2c9132 Compare December 19, 2025 22:17
Copy link
Copy Markdown
Contributor

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the help on this @0x676e67! I was able to integrate it easily into a python wrapper around reqwest - I feel the current API is just fine

curioswitch/pyqwest@7e28254

I'll be able to move forward implementing grpc client support in connect-python thanks to it.

Comment thread src/async_impl/response.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants