feat(matching): match header names case-insensitively#334
Merged
Conversation
HTTP header field names are case-insensitive (RFC 7230 §3.2), and Go's net/http canonicalizes incoming request header names, so a mock declaring "content-type" never matched a "Content-Type" request. Match header names case-insensitively via http.Header.Values, which canonicalizes only the lookup key — the declared casing is never altered. Header values and query-parameter names stay case-sensitive. Amends PRINCIPLES.md §3.4 accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Fixes #281.
Problem
HTTP header field names are case-insensitive (RFC 7230 §3.2), but Smocker matched them with an exact map lookup. Combined with Go's
net/http, which canonicalizes incoming request header names (content-type→Content-Type), a mock declaring a header in any non-canonical case (e.g.content-type) would never match — a real footgun.Fix
Header names are now matched case-insensitively via
http.Header.Values, which canonicalizes only the lookup key. The declared casing is never altered (stored mock keys and response headers keep their exact case — see §3.4). Header values and query-parameter names stay case-sensitive, preserving the "faithful, not lenient" intent of #179.PRINCIPLES.md§3.4 is amended to reflect this (names case-insensitive; values + query params case-sensitive; casing preserved on the wire, modulo net/http's own canonicalization of incoming request / upstream proxy headers).Verified
content-type↔Content-Typematch; header values stay case-sensitive; query-parameter names stay case-sensitive; an absent header still fails to match.Note: response headers declared in a mock are already returned with their exact case (#313); this PR only changes matching, not what's written on the wire.
🤖 Generated with Claude Code