Skip to content

fix(headers): OrigHeaderMap constructor drops header casing#557

Merged
0x676e67 merged 1 commit into0x676e67:mainfrom
tjaycodes4you:main
Apr 9, 2026
Merged

fix(headers): OrigHeaderMap constructor drops header casing#557
0x676e67 merged 1 commit into0x676e67:mainfrom
tjaycodes4you:main

Conversation

@tjaycodes4you
Copy link
Copy Markdown
Contributor

Fix: OrigHeaderMap constructor drops header casing

Problem

OrigHeaderMap(list) does not preserve the casing of header names passed to it.

For example:

OrigHeaderMap(['Host', 'User-Agent', 'Accept'])

sends host, user-agent, accept on the wire — all lowercase — despite the title-case input.

Root cause

In src/header.rs, the new() constructor converts each string to a HeaderName via
HeaderName::from_bytes() before inserting it into the map:

let name = match name
    .extract::<PyBackedStr>()
    .map(|n| HeaderName::from_bytes(n.as_bytes()))  // normalises to lowercase
{
    Ok(Ok(n)) => n,
    _ => continue,
};
headers.insert(name);  // inserts as Kind::Standard → lowercase on wire

HeaderName is always stored lowercase (per the HTTP spec's normalisation). When inserted
into OrigHeaderMap, it becomes Kind::Standard, whose as_ref() returns the lowercase
canonical form — so the original casing is permanently lost.

By contrast, the insert() method and the FromPyObject impl both use Bytes::from_owner()
which goes through Kind::Cased, preserving the exact bytes as given.

Fix

Change new() to use the same Bytes path as insert() and FromPyObject:

let name = match name.extract::<PyBackedStr>() {
    Ok(n) => Bytes::from_owner(n),
    _ => continue,
};
headers.insert(name);  // inserts as Kind::Cased → exact casing preserved on wire

Impact

Any code that constructs OrigHeaderMap via the constructor (e.g. OrigHeaderMap(['Host', 'X-Custom']))
now correctly preserves the supplied casing. The insert() method was already correct and is unaffected.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request simplifies the header name extraction logic in src/header.rs by directly converting PyBackedStr to Bytes. A suggestion was made to use a let-else statement instead of a match block to improve the readability of the extraction process.

@0x676e67 0x676e67 merged commit 3c55295 into 0x676e67:main Apr 9, 2026
32 checks passed
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