httputil: add Vary: Accept-Encoding and fix compression headers (#17466)
Some checks failed
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Build Prometheus for common architectures (push) Waiting to run
CI / Build Prometheus for all architectures (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Push README to Docker Hub / Push README to Docker Hub (push) Has been cancelled
Push README to Docker Hub / Push README to quay.io (push) Has been cancelled

- Emit `Vary: Accept-Encoding` in newCompressedResponseWriter so shared caches
  key responses by content-coding. This prevents cache poisoning and
  undecodable bytes when a compressed variant is cached and later served to a
  client that didn't advertise support. (RFC 9110 §12.5.5 "Vary";
  RFC 9111 §4.1 cache key & Vary)

- When selecting gzip/deflate, set `Content-Encoding` and delete any existing
  `Content-Length` so Go's net/http can frame the message correctly
  (chunked for HTTP/1.1; implicit for HTTP/2+). This avoids stale length
  mismatches and related proxy/client issues.

Signed-off-by: Joshua Rogers <MegaManSec@users.noreply.github.com>
This commit is contained in:
Joshua Rogers 2025-12-21 17:15:35 +08:00 committed by GitHub
parent b34e3410f3
commit a155ad55a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -56,6 +56,7 @@ func (c *compressedResponseWriter) Close() {
// Constructs a new compressedResponseWriter based on client request headers.
func newCompressedResponseWriter(writer http.ResponseWriter, req *http.Request) *compressedResponseWriter {
writer.Header().Add("Vary", acceptEncodingHeader)
raw := req.Header.Get(acceptEncodingHeader)
var (
encoding string
@ -65,13 +66,17 @@ func newCompressedResponseWriter(writer http.ResponseWriter, req *http.Request)
encoding, raw, commaFound = strings.Cut(raw, ",")
switch strings.TrimSpace(encoding) {
case gzipEncoding:
writer.Header().Set(contentEncodingHeader, gzipEncoding)
h := writer.Header()
h.Del("Content-Length") // avoid stale length after compression
h.Set(contentEncodingHeader, gzipEncoding)
return &compressedResponseWriter{
ResponseWriter: writer,
writer: gzip.NewWriter(writer),
}
case deflateEncoding:
writer.Header().Set(contentEncodingHeader, deflateEncoding)
h := writer.Header()
h.Del("Content-Length")
h.Set(contentEncodingHeader, deflateEncoding)
return &compressedResponseWriter{
ResponseWriter: writer,
writer: zlib.NewWriter(writer),