From eaf9cf06c07665cffd8d9260447321bffb1ed710 Mon Sep 17 00:00:00 2001
From: "coderabbitai[bot]"
<136622811+coderabbitai[bot]@users.noreply.github.com>
Date: Fri, 5 Jun 2026 11:02:32 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20CodeRabbit=20Chat:=20Implement?=
=?UTF-8?q?=20requested=20code=20changes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
internal/handler/cors_test.go | 36 +++++++++++++++++++++++++++++++++++
internal/handler/static.go | 8 +++++---
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/internal/handler/cors_test.go b/internal/handler/cors_test.go
index 0961e01e..05dd3941 100644
--- a/internal/handler/cors_test.go
+++ b/internal/handler/cors_test.go
@@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"testing"
+ "testing/fstest"
)
func TestParseCORSOrigins(t *testing.T) {
@@ -167,6 +168,41 @@ func TestCORSMiddlewareVaryOriginForDisallowedOrigin(t *testing.T) {
}
}
+func TestCORSMiddlewareVaryPreservedThroughStaticHandler(t *testing.T) {
+ // Regression test: serveFromCache used to call w.Header().Set("Vary",
+ // "Accept-Encoding") which silently dropped the "Origin" entry that
+ // CORSMiddleware had already added. After the fix (Set → Add) both
+ // values must appear in the response Vary header for an allowed origin
+ // requesting a static file.
+ const index = "
test"
+ prev := StaticFS
+ StaticFS = fstest.MapFS{
+ "index.html": &fstest.MapFile{Data: []byte(index)},
+ }
+ defer func() { StaticFS = prev }()
+
+ staticHandler := NewStaticHandler()
+ h := CORSMiddleware(ParseCORSOrigins("https://ui.example.com"), staticHandler)
+
+ req := httptest.NewRequest(http.MethodGet, "/", nil)
+ req.Header.Set("Origin", "https://ui.example.com")
+ rec := httptest.NewRecorder()
+ h.ServeHTTP(rec, req)
+
+ if rec.Code != http.StatusOK {
+ t.Fatalf("expected 200 from static handler, got %d", rec.Code)
+ }
+ vary := rec.Header().Values("Vary")
+ for _, want := range []string{"Origin", "Accept-Encoding"} {
+ if !containsStr(vary, want) {
+ t.Fatalf("static handler response Vary=%v missing %q — CORSMiddleware Vary was overwritten", vary, want)
+ }
+ }
+ if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "https://ui.example.com" {
+ t.Fatalf("Allow-Origin=%q, want reflected origin", got)
+ }
+}
+
func containsStr(s []string, want string) bool {
for _, v := range s {
if v == want {
diff --git a/internal/handler/static.go b/internal/handler/static.go
index b5fc6744..2130a86f 100644
--- a/internal/handler/static.go
+++ b/internal/handler/static.go
@@ -197,12 +197,14 @@ func serveFromCache(w http.ResponseWriter, r *http.Request, cached *staticFileCa
// Set content type
w.Header().Set("Content-Type", cached.contentType)
- // Always set Vary header to ensure caches differentiate by Accept-Encoding
- w.Header().Set("Vary", "Accept-Encoding")
+ // Add Accept-Encoding to Vary so caches differentiate by encoding. Use Add
+ // (not Set) to preserve any Vary values already written by upstream
+ // middleware (e.g. "Origin" from CORSMiddleware).
+ w.Header().Add("Vary", "Accept-Encoding")
// Check if client accepts gzip and we have gzipped content
if cached.gzipped != nil && strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
- w.Header().Set("Content-Encoding", "gzip")
+
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(cached.gzipped)))
w.WriteHeader(http.StatusOK)
w.Write(cached.gzipped)