package policies import ( "mime" "path" "strings" "sync" ) // DefaultMIMEResolver implements a MIME type resolver using Go's standard mime package // and a set of common web file type mappings. type DefaultMIMEResolver struct { customTypes map[string]string mu sync.RWMutex } // NewDefaultMIMEResolver creates a new DefaultMIMEResolver with common web MIME types. func NewDefaultMIMEResolver() *DefaultMIMEResolver { resolver := &DefaultMIMEResolver{ customTypes: make(map[string]string), } // JavaScript & TypeScript resolver.RegisterMIMEType(".js", "application/javascript") resolver.RegisterMIMEType(".mjs", "application/javascript") resolver.RegisterMIMEType(".cjs", "application/javascript") resolver.RegisterMIMEType(".ts", "text/typescript") resolver.RegisterMIMEType(".tsx", "text/tsx") resolver.RegisterMIMEType(".jsx", "text/jsx") // CSS & Styling resolver.RegisterMIMEType(".css", "text/css") resolver.RegisterMIMEType(".scss", "text/x-scss") resolver.RegisterMIMEType(".sass", "text/x-sass") resolver.RegisterMIMEType(".less", "text/x-less") // HTML & XML resolver.RegisterMIMEType(".html", "text/html") resolver.RegisterMIMEType(".htm", "text/html") resolver.RegisterMIMEType(".xml", "application/xml") resolver.RegisterMIMEType(".xhtml", "application/xhtml+xml") // Images - Raster resolver.RegisterMIMEType(".png", "image/png") resolver.RegisterMIMEType(".jpg", "image/jpeg") resolver.RegisterMIMEType(".jpeg", "image/jpeg") resolver.RegisterMIMEType(".gif", "image/gif") resolver.RegisterMIMEType(".webp", "image/webp") resolver.RegisterMIMEType(".avif", "image/avif") resolver.RegisterMIMEType(".bmp", "image/bmp") resolver.RegisterMIMEType(".tiff", "image/tiff") resolver.RegisterMIMEType(".tif", "image/tiff") resolver.RegisterMIMEType(".ico", "image/x-icon") resolver.RegisterMIMEType(".cur", "image/x-icon") // Images - Vector resolver.RegisterMIMEType(".svg", "image/svg+xml") resolver.RegisterMIMEType(".svgz", "image/svg+xml") // Fonts resolver.RegisterMIMEType(".woff", "font/woff") resolver.RegisterMIMEType(".woff2", "font/woff2") resolver.RegisterMIMEType(".ttf", "font/ttf") resolver.RegisterMIMEType(".otf", "font/otf") resolver.RegisterMIMEType(".eot", "application/vnd.ms-fontobject") // Audio resolver.RegisterMIMEType(".mp3", "audio/mpeg") resolver.RegisterMIMEType(".wav", "audio/wav") resolver.RegisterMIMEType(".ogg", "audio/ogg") resolver.RegisterMIMEType(".oga", "audio/ogg") resolver.RegisterMIMEType(".m4a", "audio/mp4") resolver.RegisterMIMEType(".aac", "audio/aac") resolver.RegisterMIMEType(".flac", "audio/flac") resolver.RegisterMIMEType(".opus", "audio/opus") resolver.RegisterMIMEType(".weba", "audio/webm") // Video resolver.RegisterMIMEType(".mp4", "video/mp4") resolver.RegisterMIMEType(".webm", "video/webm") resolver.RegisterMIMEType(".ogv", "video/ogg") resolver.RegisterMIMEType(".avi", "video/x-msvideo") resolver.RegisterMIMEType(".mpeg", "video/mpeg") resolver.RegisterMIMEType(".mpg", "video/mpeg") resolver.RegisterMIMEType(".mov", "video/quicktime") resolver.RegisterMIMEType(".wmv", "video/x-ms-wmv") resolver.RegisterMIMEType(".flv", "video/x-flv") resolver.RegisterMIMEType(".mkv", "video/x-matroska") resolver.RegisterMIMEType(".m4v", "video/mp4") // Data & Configuration resolver.RegisterMIMEType(".json", "application/json") resolver.RegisterMIMEType(".xml", "application/xml") resolver.RegisterMIMEType(".yml", "application/yaml") resolver.RegisterMIMEType(".yaml", "application/yaml") resolver.RegisterMIMEType(".toml", "application/toml") resolver.RegisterMIMEType(".ini", "text/plain") resolver.RegisterMIMEType(".conf", "text/plain") resolver.RegisterMIMEType(".config", "text/plain") // Documents resolver.RegisterMIMEType(".pdf", "application/pdf") resolver.RegisterMIMEType(".doc", "application/msword") resolver.RegisterMIMEType(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document") resolver.RegisterMIMEType(".xls", "application/vnd.ms-excel") resolver.RegisterMIMEType(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") resolver.RegisterMIMEType(".ppt", "application/vnd.ms-powerpoint") resolver.RegisterMIMEType(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation") resolver.RegisterMIMEType(".odt", "application/vnd.oasis.opendocument.text") resolver.RegisterMIMEType(".ods", "application/vnd.oasis.opendocument.spreadsheet") resolver.RegisterMIMEType(".odp", "application/vnd.oasis.opendocument.presentation") // Archives resolver.RegisterMIMEType(".zip", "application/zip") resolver.RegisterMIMEType(".tar", "application/x-tar") resolver.RegisterMIMEType(".gz", "application/gzip") resolver.RegisterMIMEType(".bz2", "application/x-bzip2") resolver.RegisterMIMEType(".7z", "application/x-7z-compressed") resolver.RegisterMIMEType(".rar", "application/vnd.rar") // Text files resolver.RegisterMIMEType(".txt", "text/plain") resolver.RegisterMIMEType(".md", "text/markdown") resolver.RegisterMIMEType(".markdown", "text/markdown") resolver.RegisterMIMEType(".csv", "text/csv") resolver.RegisterMIMEType(".log", "text/plain") // Source code (for syntax highlighting in browsers) resolver.RegisterMIMEType(".c", "text/x-c") resolver.RegisterMIMEType(".cpp", "text/x-c++") resolver.RegisterMIMEType(".h", "text/x-c") resolver.RegisterMIMEType(".hpp", "text/x-c++") resolver.RegisterMIMEType(".go", "text/x-go") resolver.RegisterMIMEType(".py", "text/x-python") resolver.RegisterMIMEType(".java", "text/x-java") resolver.RegisterMIMEType(".rs", "text/x-rust") resolver.RegisterMIMEType(".rb", "text/x-ruby") resolver.RegisterMIMEType(".php", "text/x-php") resolver.RegisterMIMEType(".sh", "text/x-shellscript") resolver.RegisterMIMEType(".bash", "text/x-shellscript") resolver.RegisterMIMEType(".sql", "text/x-sql") resolver.RegisterMIMEType(".template.sql", "text/plain") resolver.RegisterMIMEType(".upg", "text/plain") // Web Assembly resolver.RegisterMIMEType(".wasm", "application/wasm") // Manifest & Service Worker resolver.RegisterMIMEType(".webmanifest", "application/manifest+json") resolver.RegisterMIMEType(".manifest", "text/cache-manifest") // 3D Models resolver.RegisterMIMEType(".gltf", "model/gltf+json") resolver.RegisterMIMEType(".glb", "model/gltf-binary") resolver.RegisterMIMEType(".obj", "model/obj") resolver.RegisterMIMEType(".stl", "model/stl") // Other common web assets resolver.RegisterMIMEType(".map", "application/json") // Source maps resolver.RegisterMIMEType(".swf", "application/x-shockwave-flash") resolver.RegisterMIMEType(".apk", "application/vnd.android.package-archive") resolver.RegisterMIMEType(".dmg", "application/x-apple-diskimage") resolver.RegisterMIMEType(".exe", "application/x-msdownload") resolver.RegisterMIMEType(".iso", "application/x-iso9660-image") return resolver } // GetMIMEType returns the MIME type for the given file path. // It first checks custom registered types, then falls back to Go's mime.TypeByExtension. func (r *DefaultMIMEResolver) GetMIMEType(filePath string) string { ext := strings.ToLower(path.Ext(filePath)) // Check custom types first r.mu.RLock() if mimeType, ok := r.customTypes[ext]; ok { r.mu.RUnlock() return mimeType } r.mu.RUnlock() // Fall back to standard library if mimeType := mime.TypeByExtension(ext); mimeType != "" { return mimeType } // Return empty string if unknown return "" } // RegisterMIMEType registers a custom MIME type for the given file extension. func (r *DefaultMIMEResolver) RegisterMIMEType(extension, mimeType string) { if !strings.HasPrefix(extension, ".") { extension = "." + extension } r.mu.Lock() r.customTypes[strings.ToLower(extension)] = mimeType r.mu.Unlock() } // ConfigurableMIMEResolver implements a MIME type resolver with user-defined mappings only. // It does not use any default mappings. type ConfigurableMIMEResolver struct { types map[string]string mu sync.RWMutex } // NewConfigurableMIMEResolver creates a new ConfigurableMIMEResolver with the given mappings. func NewConfigurableMIMEResolver(types map[string]string) *ConfigurableMIMEResolver { resolver := &ConfigurableMIMEResolver{ types: make(map[string]string), } for ext, mimeType := range types { resolver.RegisterMIMEType(ext, mimeType) } return resolver } // GetMIMEType returns the MIME type for the given file path. func (r *ConfigurableMIMEResolver) GetMIMEType(filePath string) string { ext := strings.ToLower(path.Ext(filePath)) r.mu.RLock() defer r.mu.RUnlock() if mimeType, ok := r.types[ext]; ok { return mimeType } return "" } // RegisterMIMEType registers a MIME type for the given file extension. func (r *ConfigurableMIMEResolver) RegisterMIMEType(extension, mimeType string) { if !strings.HasPrefix(extension, ".") { extension = "." + extension } r.mu.Lock() r.types[strings.ToLower(extension)] = mimeType r.mu.Unlock() }