Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ext): support non-canonical HTTP/1 reason phrases #2792

Merged

Conversation

acfoltzer
Copy link
Member

Add a new extension type hyper::ext::ReasonPhrase gated by a new feature flag http1_reason_phrase. When enabled, store any non-canonical reason phrases in this extension when parsing responses, and write this reason phrase instead of the canonical reason phrase when emitting responses.

Reason phrases are a disused corner of the spec that implementations ought to treat as opaque blobs of bytes. Unfortunately, real-world traffic sometimes does depend on being able to inspect and manipulate them.

My main outstanding question is: should this new feature flag be included in full? Excluding it means this patch also has to modify the CI configuration in order to run the client and server tests.

Copy link
Member Author

@acfoltzer acfoltzer left a comment

Choose a reason for hiding this comment

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

So the tricky question is: is this worth a feature flag? Here are the performance numbers for the cargo bench suite (red is with the new feature disabled, green is with it enabled): https://gist.github.com/acfoltzer/c64e92ac95c390cb1c08624ecf61bfdf

It looks to me like roughly a wash, though there's a fair amount of noise in the sample. The problem is that none of the existing benches use the custom reason phrase, so it's hard to see the overall effect that existing users of "full" might get if they're already receiving responses with non-canonical phrases.

From an API cleanliness perspective I would prefer rolling this extension into the existing "http1" flag, but I also don't want to be introducing undue surprises for users of client who are not currently having to bear the cost of either the comparison against the canonical reason phrase or the allocation to store a custom one when sighted.

src/ext/h1_reason_phrase.rs Outdated Show resolved Hide resolved
src/ffi/http_types.rs Show resolved Hide resolved
Comment on lines 362 to 371
#[cfg(feature = "http1_reason_phrase")]
let custom_reason_phrase = msg.head.extensions.get::<crate::ext::ReasonPhrase>();
#[cfg(not(feature = "http1_reason_phrase"))]
#[allow(non_upper_case_globals)]
const custom_reason_phrase: Option<()> = None;
Copy link
Member Author

Choose a reason for hiding this comment

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

Here's where it starts getting a bit messy. To reduce the overall cfgness of this code, I'm relying on const evaluation to ensure this does not have an effect on performance when the flag is not enabled.

@acfoltzer acfoltzer marked this pull request as ready for review March 23, 2022 01:19
@acfoltzer acfoltzer force-pushed the acfoltzer/http1_reason_phrase branch from a99c3a7 to e7be2e1 Compare March 23, 2022 01:31
Copy link
Member

@seanmonstar seanmonstar left a comment

Choose a reason for hiding this comment

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

Very good start, I appreciate the thoroughness of the docs and tests 🤩

Cargo.toml Outdated Show resolved Hide resolved
src/ext/h1_reason_phrase.rs Outdated Show resolved Hide resolved
src/ext/h1_reason_phrase.rs Outdated Show resolved Hide resolved
src/ext/h1_reason_phrase.rs Outdated Show resolved Hide resolved
src/ext/h1_reason_phrase.rs Outdated Show resolved Hide resolved
@acfoltzer acfoltzer requested a review from seanmonstar March 23, 2022 22:52
@seanmonstar
Copy link
Member

@acfoltzer was this waiting on anything else, or just another review from me?

@acfoltzer
Copy link
Member Author

@seanmonstar yep, though it looks like I'll need to fix some merge conflicts first. I'll try to get to that soon

Add a new extension type `hyper::ext::ReasonPhrase` gated by either the `ffi` or `http1` Cargo
features. When enabled, store any non-canonical reason phrases in this extension when parsing
responses, and write this reason phrase instead of the canonical reason phrase when emitting
responses.

Reason phrases are a disused corner of the spec that implementations ought to treat as opaque blobs
of bytes. Unfortunately, real-world traffic sometimes does depend on being able to inspect and
manipulate them.

Non-canonical reason phrases are checked for validity at runtime to prevent invalid and dangerous
characters from being emitted when writing responses. An `unsafe` escape hatch is present for hyper
itself to create reason phrases that have been parsed (and therefore implicitly validated) by
httparse.
@acfoltzer acfoltzer force-pushed the acfoltzer/http1_reason_phrase branch from 4ca1eee to 6ed3a7f Compare June 8, 2022 15:32
@acfoltzer
Copy link
Member Author

@seanmonstar rebased and squashed, incorporating the proposed change to fold this into the http1 feature rather than introducing an entirely new feature just for the reason phrases. I think it's ready for a final review.

@seanmonstar seanmonstar merged commit b2052a4 into hyperium:master Jun 8, 2022
@acfoltzer acfoltzer deleted the acfoltzer/http1_reason_phrase branch June 8, 2022 23:05
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.

2 participants