UI files: ETag and revalidation on each load
The embedded UI was served without any cache header, so a browser or a proxy could keep an old app.js after an update (seen with the API token display). Each file now has an ETag (hash of its content, computed at startup); the page, app.js and style.css are sent with "no-cache", so each load costs a 304 without body until the next version. Fonts are cached for 30 days. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
367420961e
commit
3e703c8792
5 files changed
+89
-1
No files matched your search
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
)
|
||||
|
||||
func TestStaticFilesCache(t *testing.T) {
|
||||
h := staticFiles(fstest.MapFS{
|
||||
"index.html": {Data: []byte("<p>v1</p>")},
|
||||
"app.js": {Data: []byte("v1")},
|
||||
"fonts/mono.woff2": {Data: []byte("font")},
|
||||
})
|
||||
get := func(path, etag string) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest("GET", path, nil)
|
||||
if etag != "" {
|
||||
req.Header.Set("If-None-Match", etag)
|
||||
}
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
rec := get("/app.js", "")
|
||||
tag := rec.Header().Get("ETag")
|
||||
if rec.Code != http.StatusOK || tag == "" || rec.Header().Get("Cache-Control") != "no-cache" {
|
||||
t.Fatalf("app.js: %d, ETag %q, Cache-Control %q", rec.Code, tag, rec.Header().Get("Cache-Control"))
|
||||
}
|
||||
if rec := get("/app.js", tag); rec.Code != http.StatusNotModified || rec.Body.Len() != 0 {
|
||||
t.Fatalf("revalidation: %d with %d bytes, want 304 without body", rec.Code, rec.Body.Len())
|
||||
}
|
||||
if rec := get("/app.js", `"old"`); rec.Code != http.StatusOK || rec.Body.String() != "v1" {
|
||||
t.Fatalf("stale ETag: %d %q", rec.Code, rec.Body)
|
||||
}
|
||||
if rec := get("/", ""); rec.Code != http.StatusOK || rec.Header().Get("ETag") == "" || rec.Header().Get("Cache-Control") != "no-cache" {
|
||||
t.Fatalf("index: %d %v", rec.Code, rec.Header())
|
||||
}
|
||||
if rec := get("/fonts/mono.woff2", ""); rec.Header().Get("Cache-Control") != "public, max-age=2592000" {
|
||||
t.Fatalf("font Cache-Control %q", rec.Header().Get("Cache-Control"))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user