From 3be8dabc89315f2f2a40855efe0a4d6e9e7acc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 30 Jul 2026 12:40:35 +0200 Subject: [PATCH] caddyhttp: use canonical header key casing to avoid re-canonicalization (#7911) Header.Get/Set re-canonicalize and allocate whenever the passed key isn't already in canonical MIME header form. Sec-WebSocket-Key, WWW-Authenticate, and content-type all miss the fast path; switch to their canonical forms (Sec-Websocket-Key, Www-Authenticate, Content-Type). Enable the canonicalheader linter to catch future regressions, excluded in test files since those already use non-canonical casing in several places without a perf-sensitive path behind them. --- .golangci.yml | 4 ++++ modules/caddyhttp/caddyauth/basicauth.go | 2 +- modules/caddyhttp/encode/encode.go | 2 +- modules/caddyhttp/matchers.go | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e800788f5..40f017b6c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,6 +19,7 @@ linters: - asciicheck - bidichk - bodyclose + - canonicalheader - decorder - dogsled - dupl @@ -97,6 +98,9 @@ linters: - linters: - errcheck path: _test\.go + - linters: + - canonicalheader + path: _test\.go paths: - third_party$ - builtin$ diff --git a/modules/caddyhttp/caddyauth/basicauth.go b/modules/caddyhttp/caddyauth/basicauth.go index 4152d7908..348e23af7 100644 --- a/modules/caddyhttp/caddyauth/basicauth.go +++ b/modules/caddyhttp/caddyauth/basicauth.go @@ -212,7 +212,7 @@ func (hba HTTPBasicAuth) promptForCredentials(w http.ResponseWriter, err error) if realm == "" { realm = "restricted" } - w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm)) + w.Header().Set("Www-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm)) return User{}, false, err } diff --git a/modules/caddyhttp/encode/encode.go b/modules/caddyhttp/encode/encode.go index 8a4ac2b23..ebf028458 100644 --- a/modules/caddyhttp/encode/encode.go +++ b/modules/caddyhttp/encode/encode.go @@ -499,10 +499,10 @@ func hasVaryValue(hdr http.Header, target string) bool { // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html. func AcceptedEncodings(r *http.Request, preferredOrder []string) []string { acceptEncHeader := r.Header.Get("Accept-Encoding") - websocketKey := r.Header.Get("Sec-WebSocket-Key") if acceptEncHeader == "" { return []string{} } + websocketKey := r.Header.Get("Sec-Websocket-Key") prefs := []encodingPreference{} diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index 49f088ad5..d084af825 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -1368,7 +1368,7 @@ func (m MatchProtocol) Match(r *http.Request) bool { func (m MatchProtocol) MatchWithError(r *http.Request) (bool, error) { switch string(m) { case "grpc": - return strings.HasPrefix(r.Header.Get("content-type"), "application/grpc"), nil + return strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc"), nil case "https": return r.TLS != nil, nil case "http":