Conversation
`HeaderCaseMap` was internal, so a message could only carry the original casing of names hyper itself had parsed, and only with `preserve_header_case` turned on. A client that has to write a name the way some other program writes it, because a server compares the bytes it receives, had no way to say so: `http::HeaderName` lowercases the name, and the HTTP/1 encoder writes that lowercased name, so the request no longer matches the client being imitated. Names such as `TE` next to a lowercased `sec-ch-ua`, or a title-cased `Sec-Fetch-Site`, are sent in the casing a browser sends them by. The type is public now, with a `Default` impl and a public `append` that records the spelling a name was written with. Putting the map into a message's extensions makes the HTTP/1 encoder write the spellings it holds, and write the lowercased `HeaderName` for a name the map does not mention, which is the behavior it already had for messages hyper parsed. No public way to read the spellings back is added here; that part of the design is still open. Refs: hyperium#2695
Runnin4ik
force-pushed
the
ext-public-header-case-map
branch
from
September 25, 2026 01:47
96d4e2e to
a04dd36
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Exposes
hyper::ext::HeaderCaseMap, which waspub(crate), so that a client can write an HTTP/1.1 request with the original casing of its header names.http::HeaderNamelowercases the name, and hyper's HTTP/1 encoder writes that lowercased name, so a client that has to speak to a server which compares the bytes it receives had no supported way to do it. That is the fingerprinting/impersonation case: the request has to carry what a browser sends, down to the casing, e.g.TE: trailers, or a lowercasedsec-ch-uaright next to a title-casedSec-Fetch-Site.HeaderCaseMapalready holds exactly this information for messages hyper itself parsed withpreserve_header_case; this makes the type public and gives it a public way to be built, so it can be put into a request's extensions:The encoder writes the spellings the map holds, and falls back to the lowercased
HeaderNamefor a name it does not mention, which is the behavior it already had for messages hyper parsed.Scope notes:
appendis the minimal public constructor: the lowercasedHeaderNameto look the entry up by, and theBytesto write. Its documentation states that the bytes must spell that name, since they go to the wire verbatim. There is deliberately no public read access yet — that half of the design (cased-name types, validation, round-tripping, as discussed on Original Header Cases API #2695) is still open, and can be added later without changing what is here.default()moves out of the inherent impl into a publicimpl Default, so the empty map is built the idiomatic way.insert— the writer the parser and the C API use — stayspub(crate), which leavesappendas the only public constructor.Refs #2695. This is the minimal exposure suggested in #2695 (comment).
Related: #3971 ("Add header casing public API") explores the same design space from the other direction — it switches the map's value type from
BytestoStringfor validation, but leaves the type and all of its methodspub(crate), so it does not expose anything yet — and is parked behind the proposal process that #4131 (HIP-0001, merged) set up. If that work is the better path, I am happy to rebase this behind it or close it; this is posted as the minimal-methods version to have something concrete to review on the implementation side.Checked locally on this branch, since GitHub reports no checks on it (the first-time-contributor approval gate rather than a failure):
cargo test --features full— 117 unit tests and 15 doctests pass, 0 failed, the two tests above and the documentation example among them;cargo fmt --checkclean.User-facing asks this answers: #1492 ("Headers are lower-cased when sent and no option to disable this feature").