diff --git a/cmd/server/main_test.go b/cmd/server/main_test.go index 368e149..2038b8e 100644 --- a/cmd/server/main_test.go +++ b/cmd/server/main_test.go @@ -76,6 +76,9 @@ func TestServeSPAServesAssetsImmutableAndBypassesAPIRoutes(t *testing.T) { if err := os.MkdirAll(filepath.Join(webDir, "assets"), 0o755); err != nil { t.Fatal(err) } + if err := os.MkdirAll(filepath.Join(webDir, "fonts"), 0o755); err != nil { + t.Fatal(err) + } if err := os.MkdirAll(filepath.Join(webDir, "brand"), 0o755); err != nil { t.Fatal(err) } @@ -85,6 +88,9 @@ func TestServeSPAServesAssetsImmutableAndBypassesAPIRoutes(t *testing.T) { if err := os.WriteFile(filepath.Join(webDir, "assets", "app.js"), []byte("console.log('ok')"), 0o644); err != nil { t.Fatal(err) } + if err := os.WriteFile(filepath.Join(webDir, "fonts", "geist-400.woff2"), []byte("wOF2-test-font"), 0o644); err != nil { + t.Fatal(err) + } if err := os.WriteFile(filepath.Join(webDir, "brand", "mebox-logo.svg"), []byte(""), 0o644); err != nil { t.Fatal(err) } @@ -105,6 +111,29 @@ func TestServeSPAServesAssetsImmutableAndBypassesAPIRoutes(t *testing.T) { t.Fatalf("asset Cache-Control = %q, want immutable", got) } + fontReq := httptest.NewRequest(http.MethodGet, "/fonts/geist-400.woff2", nil) + fontResp := httptest.NewRecorder() + router.ServeHTTP(fontResp, fontReq) + if fontResp.Code != http.StatusOK { + t.Fatalf("font status = %d, want 200", fontResp.Code) + } + if got := fontResp.Header().Get("Cache-Control"); !strings.Contains(got, "max-age=86400") { + t.Fatalf("font Cache-Control = %q, want max-age=86400", got) + } + if got := fontResp.Body.String(); got != "wOF2-test-font" { + t.Fatalf("font body = %q, want wOF2-test-font", got) + } + + missingFontReq := httptest.NewRequest(http.MethodGet, "/fonts/missing.woff2", nil) + missingFontResp := httptest.NewRecorder() + router.ServeHTTP(missingFontResp, missingFontReq) + if missingFontResp.Code != http.StatusNotFound { + t.Fatalf("missing font status = %d, want 404", missingFontResp.Code) + } + if strings.Contains(missingFontResp.Body.String(), "index") { + t.Fatalf("missing font should not serve SPA index: %q", missingFontResp.Body.String()) + } + brandReq := httptest.NewRequest(http.MethodGet, "/brand/mebox-logo.svg", nil) brandResp := httptest.NewRecorder() router.ServeHTTP(brandResp, brandReq) diff --git a/cmd/server/router.go b/cmd/server/router.go index fb387ba..a3ceb7a 100644 --- a/cmd/server/router.go +++ b/cmd/server/router.go @@ -59,6 +59,13 @@ func serveSPA(r *gin.Engine, root fs.FS) { c.Next() }) assets.GET("/*filepath", serveFSDir(root, "assets")) + fonts := r.Group("/fonts") + fonts.Use(middleware.GzipStatic()) + fonts.Use(func(c *gin.Context) { + c.Header("Cache-Control", "public, max-age=86400") + c.Next() + }) + fonts.GET("/*filepath", serveFSDir(root, "fonts")) brand := r.Group("/brand") brand.Use(func(c *gin.Context) { setNoCacheHeaders(c) @@ -70,11 +77,11 @@ func serveSPA(r *gin.Engine, root fs.FS) { r.GET(rootFile, serveFSFile(root, name)) r.HEAD(rootFile, serveFSFile(root, name)) } - r.NoRoute(middleware.GzipStatic(), func(c *gin.Context) { - if handler.TryHandleEmbyNormalizedRoute(c, r) { - return - } - path := c.Request.URL.Path + r.NoRoute(middleware.GzipStatic(), func(c *gin.Context) { + if handler.TryHandleEmbyNormalizedRoute(c, r) { + return + } + path := c.Request.URL.Path if shouldBypassSPAFallback(path) { c.Status(http.StatusNotFound) return