Match header field names case-insensitively in the default header_matcher - #805
Open
chuenchen309 wants to merge 2 commits into
Open
Match header field names case-insensitively in the default header_matcher#805chuenchen309 wants to merge 2 commits into
chuenchen309 wants to merge 2 commits into
Conversation
…cher
HTTP header names are case-insensitive and requests stores request.headers
as a CaseInsensitiveDict, but the default (strict_match=False) path rebuilt
them into a plain dict keyed by the request's original casing with a
case-sensitive `k in headers` filter. Any casing difference dropped the
header, so header_matcher({"X-Custom": ...}) failed to match a request
sending "x-custom" (and vice versa), with a misleading "{} doesn't match"
reason. strict_match=True kept the CaseInsensitiveDict and already matched
case-insensitively, so the default path was the outlier.
Key the filtered dict by the matcher's names using CaseInsensitiveDict
membership so the case-insensitive lookup survives.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
markstory
reviewed
Jul 21, 2026
Comment on lines
+873
to
+874
| resp = requests.get(url, headers={"x-custom": "token"}) | ||
| assert_response(resp, body='{"success": true}', content_type="application/json") |
Member
There was a problem hiding this comment.
Could there also be a test that covers case-mismatch on strict_match=True? There isn't a test for that scenario right now.
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.
HTTP header field names are case-insensitive, and
requestsstoresrequest.headersas aCaseInsensitiveDict. But the defaultheader_matcher(strict_match=False) rebuilds them into a plain dict keyed by the request's original casing, filtered with a case-sensitivek in headers:So any casing difference drops the header and the match fails — with a misleading
{} doesn't matchreason:strict_match=Truekeeps theCaseInsensitiveDictand already matches case-insensitively, so the default path was the odd one out. It matters in practice because HTTP/2 mandates lowercase header names, so client code (or a recorded cassette) can easily sendcontent-typewhere the matcher spec writesContent-Type.The fix keys the filtered dict by the matcher's names, using
CaseInsensitiveDictmembership so the case-insensitive lookup survives. Value comparisons, missing-header detection, andstrict_match=Trueare unchanged; the full suite stays green.Disclosure: found and written by an AI coding agent (Claude Code) running autonomously on this account; the human account holder reviews every change and is accountable for it. The verification is real and re-runnable from the diff.