mime: extend "builtinTypes" to include a more complete list of common types

Implement all agreed upon types, using IANA's listed media types to decide
when there is a disagreement in type.  Except in the case of `.wav` where
`audio/wav` is used.

Fixes #69530

Change-Id: Iec99a6ceb534073be83c8390f48799bec3e4cfc7
GitHub-Last-Rev: e314c5ec6d
GitHub-Pull-Request: golang/go#69533
Reviewed-on: https://go-review.googlesource.com/c/go/+/614376
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
Auto-Submit: Sean Liao <sean@liao.dev>
Reviewed-by: Sean Liao <sean@liao.dev>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
Aidan Welch 2025-09-25 21:00:45 +00:00 committed by Gopher Robot
parent 97da068774
commit 08afc50bea
2 changed files with 121 additions and 18 deletions

View file

@ -17,7 +17,7 @@ var (
mimeTypesLower sync.Map // map[string]string; ".z" => "application/x-compress"
// extensions maps from MIME type to list of lowercase file
// extensions: "image/jpeg" => [".jpg", ".jpeg"]
// extensions: "image/jpeg" => [".jfif", ".jpg", ".jpeg", ".pjp", ".pjpeg"]
extensionsMu sync.Mutex // Guards stores (but not loads) on extensions.
extensions sync.Map // map[string][]string; slice values are append-only.
)
@ -50,23 +50,82 @@ func setMimeTypes(lowerExt, mixExt map[string]string) {
}
}
// A type is listed here if both Firefox and Chrome included them in their own
// lists. In the case where they contradict they are deconflicted using IANA's
// listed media types https://www.iana.org/assignments/media-types/media-types.xhtml
//
// Chrome's MIME mappings to file extensions are defined at
// https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/net/base/mime_util.cc
//
// Firefox's MIME types can be found at
// https://github.com/mozilla-firefox/firefox/blob/main/netwerk/mime/nsMimeTypes.h
// and the mappings to file extensions at
// https://github.com/mozilla-firefox/firefox/blob/main/uriloader/exthandler/nsExternalHelperAppService.cpp
var builtinTypesLower = map[string]string{
".avif": "image/avif",
".css": "text/css; charset=utf-8",
".gif": "image/gif",
".htm": "text/html; charset=utf-8",
".html": "text/html; charset=utf-8",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".js": "text/javascript; charset=utf-8",
".json": "application/json",
".mjs": "text/javascript; charset=utf-8",
".pdf": "application/pdf",
".png": "image/png",
".svg": "image/svg+xml",
".wasm": "application/wasm",
".webp": "image/webp",
".xml": "text/xml; charset=utf-8",
".ai": "application/postscript",
".apk": "application/vnd.android.package-archive",
".apng": "image/apng",
".avif": "image/avif",
".bin": "application/octet-stream",
".bmp": "image/bmp",
".com": "application/octet-stream",
".css": "text/css; charset=utf-8",
".csv": "text/csv; charset=utf-8",
".doc": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
".ehtml": "text/html; charset=utf-8",
".eml": "message/rfc822",
".eps": "application/postscript",
".exe": "application/octet-stream",
".flac": "audio/flac",
".gif": "image/gif",
".gz": "application/gzip",
".htm": "text/html; charset=utf-8",
".html": "text/html; charset=utf-8",
".ico": "image/vnd.microsoft.icon",
".ics": "text/calendar; charset=utf-8",
".jfif": "image/jpeg",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".js": "text/javascript; charset=utf-8",
".json": "application/json",
".m4a": "audio/mp4",
".mjs": "text/javascript; charset=utf-8",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".oga": "audio/ogg",
".ogg": "audio/ogg",
".ogv": "video/ogg",
".opus": "audio/ogg",
".pdf": "application/pdf",
".pjp": "image/jpeg",
".pjpeg": "image/jpeg",
".png": "image/png",
".ppt": "application/vnd.ms-powerpoint",
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
".ps": "application/postscript",
".rdf": "application/rdf+xml",
".rtf": "application/rtf",
".shtml": "text/html; charset=utf-8",
".svg": "image/svg+xml",
".text": "text/plain; charset=utf-8",
".tif": "image/tiff",
".tiff": "image/tiff",
".txt": "text/plain; charset=utf-8",
".vtt": "text/vtt; charset=utf-8",
".wasm": "application/wasm",
".wav": "audio/wav",
".webm": "audio/webm",
".webp": "image/webp",
".xbl": "text/xml; charset=utf-8",
".xbm": "image/x-xbitmap",
".xht": "application/xhtml+xml",
".xhtml": "application/xhtml+xml",
".xls": "application/vnd.ms-excel",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".xml": "text/xml; charset=utf-8",
".xsl": "text/xml; charset=utf-8",
".zip": "application/zip",
}
var once sync.Once // guards initMime

View file

@ -208,7 +208,51 @@ func TestExtensionsByType2(t *testing.T) {
typ string
want []string
}{
{typ: "image/jpeg", want: []string{".jpeg", ".jpg"}},
{typ: "application/postscript", want: []string{".ai", ".eps", ".ps"}},
{typ: "application/vnd.android.package-archive", want: []string{".apk"}},
{typ: "image/apng", want: []string{".apng"}},
{typ: "image/avif", want: []string{".avif"}},
{typ: "application/octet-stream", want: []string{".bin", ".com", ".exe"}},
{typ: "image/bmp", want: []string{".bmp"}},
{typ: "text/css; charset=utf-8", want: []string{".css"}},
{typ: "text/csv; charset=utf-8", want: []string{".csv"}},
{typ: "application/msword", want: []string{".doc"}},
{typ: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", want: []string{".docx"}},
{typ: "text/html; charset=utf-8", want: []string{".ehtml", ".htm", ".html", ".shtml"}},
{typ: "message/rfc822", want: []string{".eml"}},
{typ: "audio/flac", want: []string{".flac"}},
{typ: "image/gif", want: []string{".gif"}},
{typ: "application/gzip", want: []string{".gz"}},
{typ: "image/vnd.microsoft.icon", want: []string{".ico"}},
{typ: "text/calendar; charset=utf-8", want: []string{".ics"}},
{typ: "image/jpeg", want: []string{".jfif", ".jpeg", ".jpg", ".pjp", ".pjpeg"}},
{typ: "text/javascript; charset=utf-8", want: []string{".js", ".mjs"}},
{typ: "application/json", want: []string{".json"}},
{typ: "audio/mp4", want: []string{".m4a"}},
{typ: "audio/mpeg", want: []string{".mp3"}},
{typ: "video/mp4", want: []string{".mp4"}},
{typ: "audio/ogg", want: []string{".oga", ".ogg", ".opus"}},
{typ: "video/ogg", want: []string{".ogv"}},
{typ: "application/pdf", want: []string{".pdf"}},
{typ: "image/png", want: []string{".png"}},
{typ: "application/vnd.ms-powerpoint", want: []string{".ppt"}},
{typ: "application/vnd.openxmlformats-officedocument.presentationml.presentation", want: []string{".pptx"}},
{typ: "application/rdf+xml", want: []string{".rdf"}},
{typ: "application/rtf", want: []string{".rtf"}},
{typ: "image/svg+xml", want: []string{".svg"}},
{typ: "text/plain; charset=utf-8", want: []string{".text", ".txt"}},
{typ: "image/tiff", want: []string{".tif", ".tiff"}},
{typ: "text/vtt; charset=utf-8", want: []string{".vtt"}},
{typ: "application/wasm", want: []string{".wasm"}},
{typ: "audio/wav", want: []string{".wav"}},
{typ: "audio/webm", want: []string{".webm"}},
{typ: "image/webp", want: []string{".webp"}},
{typ: "text/xml; charset=utf-8", want: []string{".xbl", ".xml", ".xsl"}},
{typ: "image/x-xbitmap", want: []string{".xbm"}},
{typ: "application/xhtml+xml", want: []string{".xht", ".xhtml"}},
{typ: "application/vnd.ms-excel", want: []string{".xls"}},
{typ: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", want: []string{".xlsx"}},
{typ: "application/zip", want: []string{".zip"}},
}
for _, tt := range tests {