fix(mime): register application/manifest+json for .webmanifest (+ webp/avif); v1.7.1
Go's MIME table has no .webmanifest entry, so http.FileServer sniffed the PWA web app manifest as text/plain. mime.AddExtensionType at package load makes TypeByExtension authoritative. A correctness nit (the manifest spec parses by content and nosniff does not reject manifests), but a PWA server should label its manifest correctly.
This commit is contained in:
+18
-4
@@ -6,6 +6,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.nochebuena.dev/einherjar/contracts/logging"
|
||||
@@ -20,10 +21,11 @@ func newTestHandler(t *testing.T) http.Handler {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
for name, body := range map[string]string{
|
||||
"index.html": "<!doctype html><title>app</title>",
|
||||
"main.4f8a2b1c.js": "console.log(1)",
|
||||
"favicon.ico": "icon",
|
||||
"ngsw.json": "{}",
|
||||
"index.html": "<!doctype html><title>app</title>",
|
||||
"main.4f8a2b1c.js": "console.log(1)",
|
||||
"favicon.ico": "icon",
|
||||
"ngsw.json": "{}",
|
||||
"manifest.webmanifest": `{"name":"app"}`,
|
||||
} {
|
||||
if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -107,6 +109,18 @@ func TestFallback_RootServesIndex(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestManifestContentType(t *testing.T) {
|
||||
// Without the mime registration this is sniffed as text/plain; with it the
|
||||
// PWA manifest carries its registered type.
|
||||
rec := get(newTestHandler(t), "/manifest.webmanifest", "*/*")
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200", rec.Code)
|
||||
}
|
||||
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "application/manifest+json") {
|
||||
t.Errorf("Content-Type = %q, want application/manifest+json", ct)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsHashed(t *testing.T) {
|
||||
hashed := []string{"main.4f8a2b1c.js", "index-DkJf3x9a.js", "styles-4NDEUD5S.css", "app.a1b2c3d4.mjs"}
|
||||
plain := []string{"favicon.ico", "index.html", "logo.png", "about.js", "main.js", "vendor.css"}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package spa
|
||||
|
||||
import "mime"
|
||||
|
||||
// Go's built-in MIME table — and a container image without /etc/mime.types — has no
|
||||
// entry for these extensions, so http.FileServer falls back to content sniffing and
|
||||
// mislabels them. The one that matters for a PWA server is the web app manifest,
|
||||
// sniffed as text/plain instead of application/manifest+json. Registering the types
|
||||
// once at package load makes mime.TypeByExtension authoritative, so the correct
|
||||
// Content-Type is sent and no sniffing fallback runs.
|
||||
//
|
||||
// This is a correctness nit, not a fix for a live break: the manifest spec parses by
|
||||
// content (valid JSON) rather than declared type, so browsers accept it either way.
|
||||
// A PWA-focused server should still label it correctly. .webp/.avif get the same
|
||||
// treatment for the same reason.
|
||||
func init() {
|
||||
for ext, typ := range map[string]string{
|
||||
".webmanifest": "application/manifest+json",
|
||||
".webp": "image/webp",
|
||||
".avif": "image/avif",
|
||||
} {
|
||||
_ = mime.AddExtensionType(ext, typ)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user