encode: prioritize zstd and br over gzip in content negotiation (#7772)
Tests / test (s390x on IBM Z) (push) Has been skipped
Tests / goreleaser-check (push) Has been skipped
Cross-Build / build (~1.26.0, 1.26, aix) (push) Successful in 2m10s
Tests / test (./cmd/caddy/caddy, ~1.26.0, ubuntu-latest, 0, 1.26, linux) (push) Failing after 3m19s
Cross-Build / build (~1.26.0, 1.26, darwin) (push) Successful in 1m48s
Cross-Build / build (~1.26.0, 1.26, dragonfly) (push) Successful in 1m30s
Cross-Build / build (~1.26.0, 1.26, freebsd) (push) Successful in 1m49s
Cross-Build / build (~1.26.0, 1.26, linux) (push) Successful in 1m46s
Cross-Build / build (~1.26.0, 1.26, illumos) (push) Successful in 3m3s
Cross-Build / build (~1.26.0, 1.26, netbsd) (push) Successful in 1m48s
Cross-Build / build (~1.26.0, 1.26, solaris) (push) Successful in 2m0s
Cross-Build / build (~1.26.0, 1.26, windows) (push) Successful in 1m7s
Cross-Build / build (~1.26.0, 1.26, openbsd) (push) Successful in 3m6s
Lint / dependency-review (push) Failing after 36s
Lint / govulncheck (push) Successful in 1m41s
Lint / lint (ubuntu-latest, linux) (push) Successful in 2m42s
OpenSSF Scorecard supply-chain security / Scorecard analysis (push) Failing after 6m31s
Tests / test (./cmd/caddy/caddy, ~1.26.0, macos-14, 0, 1.26, mac) (push) Has been cancelled
Tests / test (./cmd/caddy/caddy.exe, ~1.26.0, windows-latest, True, 1.26, windows) (push) Has been cancelled
Lint / lint (macos-14, mac) (push) Has been cancelled
Lint / lint (windows-latest, windows) (push) Has been cancelled

* fix(encode): prioritize zstd and br over gzip in content negotiation

* test(encode): update unit tests to reflect new default priority ties

* fix(encode): move default preferences to dynamic encode handler and restore generic negotiation helper

* test(encode): call real Provision function in served-response test

* test(encode): rename served-response test to TestServeHTTPDefaultEncodingPreference

* refactor(encode): use slices.SortStableFunc and httptest.NewRecorder as recommended

* refactor(encode): simplify sorting with cmp.Compare and check request error in test

* test(encode): fix variable redeclaration in TestServeHTTPDefaultEncodingPreference

Fix 'no new variables on left side of :=' error by changing 'err :=' to 'err ='
on line 347, since err was already declared on line 332.

This fixes the build failure in the encode module tests.
This commit is contained in:
Muhammad Syafri, S.Kom
2026-05-29 02:26:19 +07:00
committed by GitHub
parent 86121c860f
commit 03e08ee6a9
2 changed files with 88 additions and 5 deletions
+75
View File
@@ -1,10 +1,16 @@
package encode
import (
"context"
"io"
"net/http"
"net/http/httptest"
"slices"
"sync"
"testing"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)
func BenchmarkOpenResponseWriter(b *testing.B) {
@@ -295,3 +301,72 @@ func TestIsEncodeAllowed(t *testing.T) {
})
}
}
type mockEncoder struct{}
func (mockEncoder) Write(p []byte) (n int, err error) { return len(p), nil }
func (mockEncoder) Close() error { return nil }
func (mockEncoder) Reset(w io.Writer) {}
func (mockEncoder) Flush() error { return nil }
func TestServeHTTPDefaultEncodingPreference(t *testing.T) {
enc := new(Encode)
enc.MinLength = 1 // compress everything
enc.writerPools = map[string]*sync.Pool{
"gzip": {
New: func() any { return mockEncoder{} },
},
"zstd": {
New: func() any { return mockEncoder{} },
},
}
// Call Provision() with a valid caddy.Context to exercise the real path
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
defer cancel()
if err := enc.Provision(ctx); err != nil {
t.Fatalf("Provision failed: %v", err)
}
// Test default preference: zstd preferred over gzip
r, err := http.NewRequest("GET", "/", nil)
if err != nil {
t.Fatalf("error creating request: %v", err)
}
r.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd")
w := httptest.NewRecorder()
w.Header().Set("Content-Type", "text/plain")
next := caddyhttp.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
w.WriteHeader(http.StatusOK)
_, err := w.Write([]byte("Hello, world! This is a long enough string to satisfy min length if it wasn't 1."))
return err
})
err = enc.ServeHTTP(w, r, next)
if err != nil {
t.Fatalf("ServeHTTP returned error: %v", err)
}
// ETag suffix or Content-Encoding header should reflect zstd
contentEncoding := w.Header().Get("Content-Encoding")
if contentEncoding != "zstd" {
t.Errorf("Expected Content-Encoding to be 'zstd' by default, got '%s'", contentEncoding)
}
// Test explicit user preference: gzip over zstd
enc.Prefer = []string{"gzip", "zstd"}
w2 := httptest.NewRecorder()
w2.Header().Set("Content-Type", "text/plain")
err = enc.ServeHTTP(w2, r, next)
if err != nil {
t.Fatalf("ServeHTTP returned error: %v", err)
}
contentEncoding2 := w2.Header().Get("Content-Encoding")
if contentEncoding2 != "gzip" {
t.Errorf("Expected Content-Encoding to be 'gzip' when explicitly preferred, got '%s'", contentEncoding2)
}
}