internal/devserver/mime.go

package devserver

import "strings"

// mimeByExt maps common extensions to content types. The Go standard
// library has its own map, but it's notoriously inconsistent across
// platforms (the system mime.types file gets involved), and I want the
// dev server to behave identically everywhere.
var mimeByExt = map[string]string{
	".html":  "text/html; charset=utf-8",
	".htm":   "text/html; charset=utf-8",
	".css":   "text/css; charset=utf-8",
	".js":    "application/javascript; charset=utf-8",
	".mjs":   "application/javascript; charset=utf-8",
	".json":  "application/json; charset=utf-8",
	".xml":   "application/xml; charset=utf-8",
	".rss":   "application/rss+xml; charset=utf-8",
	".atom":  "application/atom+xml; charset=utf-8",
	".txt":   "text/plain; charset=utf-8",
	".md":    "text/markdown; charset=utf-8",
	".svg":   "image/svg+xml",
	".png":   "image/png",
	".jpg":   "image/jpeg",
	".jpeg":  "image/jpeg",
	".gif":   "image/gif",
	".webp":  "image/webp",
	".ico":   "image/x-icon",
	".woff":  "font/woff",
	".woff2": "font/woff2",
	".ttf":   "font/ttf",
	".otf":   "font/otf",
	".pdf":   "application/pdf",
}

// MimeType returns the content type for ext (which should include the
// leading dot). Returns "" when the extension is unknown.
func MimeType(ext string) string {
	return mimeByExt[strings.ToLower(ext)]
}

// RegisterMime lets callers extend the table. Returns true if the
// extension was newly registered.
func RegisterMime(ext, contentType string) bool {
	ext = strings.ToLower(ext)
	if _, ok := mimeByExt[ext]; ok {
		return false
	}
	mimeByExt[ext] = contentType
	return true
}

// KnownExtensions returns every registered extension. Order is unspecified.
func KnownExtensions() []string {
	out := make([]string, 0, len(mimeByExt))
	for k := range mimeByExt {
		out = append(out, k)
	}
	return out
}