From a5ce17c3e0b770c05dc5ca50c67024a40b8f2715 Mon Sep 17 00:00:00 2001 From: Vemund Gaukstad Date: Fri, 25 Aug 2023 17:30:59 +0200 Subject: [PATCH 1/4] Rewrite of MimeTypeMap to support matching file extensions to mimetype aliases. Example: zip files can be application/zip, application/zip-compressed or application/x-zip-compressed --- .../Controllers/ResourceController.cs | 12 +- .../DataRestrictionValidation.cs | 6 +- src/Altinn.App.Core/Helpers/MimeTypeMap.cs | 1292 ++++++++--------- src/Altinn.App.Core/Models/MimeType.cs | 91 ++ .../Helpers/MimeTypeMapTests.cs | 70 + .../Models/MimeTypeTests.cs | 72 + 6 files changed, 848 insertions(+), 695 deletions(-) create mode 100644 src/Altinn.App.Core/Models/MimeType.cs create mode 100644 test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs create mode 100644 test/Altinn.App.Core.Tests/Models/MimeTypeTests.cs diff --git a/src/Altinn.App.Api/Controllers/ResourceController.cs b/src/Altinn.App.Api/Controllers/ResourceController.cs index bbe7adb2a..10761ef64 100644 --- a/src/Altinn.App.Api/Controllers/ResourceController.cs +++ b/src/Altinn.App.Api/Controllers/ResourceController.cs @@ -50,7 +50,7 @@ public IActionResult Index(string org, string app, string id) if (fileContent != null) { - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower())); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower()).ToString()); } if (id == _appSettings.RuleConfigurationJSONFileName || id == _appSettings.RuleHandlerFileName) @@ -75,7 +75,7 @@ public IActionResult GetRuntimeResource(string id) if (fileContent != null) { - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower())); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower()).ToString()); } return StatusCode(404); @@ -99,14 +99,14 @@ public IActionResult GetTextResources(string org, string app) byte[] fileContent = _appResourceService.GetText(org, app, id); if (fileContent != null) { - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower())); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower()).ToString()); } id = $"resource.{defaultLang}.json"; fileContent = _appResourceService.GetText(org, app, id); if (fileContent != null) { - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower())); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(Path.GetExtension(id).ToLower()).ToString()); } return StatusCode(404); @@ -226,7 +226,7 @@ public ActionResult GetRulehandler(string org, string app, string id) byte[] fileContent = _appResourceService.GetRuleHandlerForSet(id); if (fileContent != null) { - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(".ts")); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(".ts").ToString()); } return NoContent(); @@ -249,7 +249,7 @@ public ActionResult GetRuleConfiguration(string org, string app, string id) return NoContent(); } - return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(".json")); + return new FileContentResult(fileContent, MimeTypeMap.GetMimeType(".json").ToString()); } /// diff --git a/src/Altinn.App.Api/Helpers/RequestHandling/DataRestrictionValidation.cs b/src/Altinn.App.Api/Helpers/RequestHandling/DataRestrictionValidation.cs index f7e0237dc..81c7a4f95 100644 --- a/src/Altinn.App.Api/Helpers/RequestHandling/DataRestrictionValidation.cs +++ b/src/Altinn.App.Api/Helpers/RequestHandling/DataRestrictionValidation.cs @@ -82,7 +82,7 @@ public static (bool Success, List Errors) CompliesWithDataRestr } string filetype = splitFilename[splitFilename.Length - 1]; - string mimeType = MimeTypeMap.GetMimeType(filetype); + var mimeType = MimeTypeMap.GetMimeType(filetype); if (!request.Headers.TryGetValue("Content-Type", out StringValues contentType)) { @@ -97,7 +97,7 @@ public static (bool Success, List Errors) CompliesWithDataRestr } // Verify that file mime type matches content type in request - if (!contentType.Equals("application/octet-stream") && !mimeType.Equals(contentType, StringComparison.InvariantCultureIgnoreCase)) + if (!contentType.Equals("application/octet-stream") && !mimeType.Equals(contentType)) { errors.Add(new ValidationIssue { @@ -110,7 +110,7 @@ public static (bool Success, List Errors) CompliesWithDataRestr } // Verify that file mime type is an allowed content-type - if (!dataType.AllowedContentTypes.Contains(mimeType, StringComparer.InvariantCultureIgnoreCase) && !dataType.AllowedContentTypes.Contains("application/octet-stream")) + if (!dataType.AllowedContentTypes.Contains(contentType.ToString(), StringComparer.InvariantCultureIgnoreCase) && !dataType.AllowedContentTypes.Contains("application/octet-stream")) { errors.Add(new ValidationIssue { diff --git a/src/Altinn.App.Core/Helpers/MimeTypeMap.cs b/src/Altinn.App.Core/Helpers/MimeTypeMap.cs index 4f221ec22..c5feb65f1 100644 --- a/src/Altinn.App.Core/Helpers/MimeTypeMap.cs +++ b/src/Altinn.App.Core/Helpers/MimeTypeMap.cs @@ -1,3 +1,5 @@ +using Altinn.App.Core.Models; + namespace Altinn.App.Core.Helpers { /// @@ -5,11 +7,11 @@ namespace Altinn.App.Core.Helpers /// public static class MimeTypeMap { - private static readonly Lazy> _mappings = new Lazy>(BuildMappings); + private static readonly Lazy> _mappings = new Lazy>(BuildMappings); - private static IDictionary BuildMappings() + private static IDictionary BuildMappings() { - var mappings = new Dictionary(StringComparer.OrdinalIgnoreCase) + var mappings = new Dictionary(StringComparer.OrdinalIgnoreCase) { #region Big freaking list of mime types @@ -28,664 +30,607 @@ private static IDictionary BuildMappings() // // Some added based on http://www.iana.org/assignments/media-types/media-types.xhtml // which lists mime types, but not extensions - { ".323", "text/h323" }, - { ".3g2", "video/3gpp2" }, - { ".3gp", "video/3gpp" }, - { ".3gp2", "video/3gpp2" }, - { ".3gpp", "video/3gpp" }, - { ".7z", "application/x-7z-compressed" }, - { ".aa", "audio/audible" }, - { ".AAC", "audio/aac" }, - { ".aaf", "application/octet-stream" }, - { ".aax", "audio/vnd.audible.aax" }, - { ".ac3", "audio/ac3" }, - { ".aca", "application/octet-stream" }, - { ".accda", "application/msaccess.addin" }, - { ".accdb", "application/msaccess" }, - { ".accdc", "application/msaccess.cab" }, - { ".accde", "application/msaccess" }, - { ".accdr", "application/msaccess.runtime" }, - { ".accdt", "application/msaccess" }, - { ".accdw", "application/msaccess.webapplication" }, - { ".accft", "application/msaccess.ftemplate" }, - { ".acx", "application/internet-property-stream" }, - { ".AddIn", "text/xml" }, - { ".ade", "application/msaccess" }, - { ".adobebridge", "application/x-bridge-url" }, - { ".adp", "application/msaccess" }, - { ".ADT", "audio/vnd.dlna.adts" }, - { ".ADTS", "audio/aac" }, - { ".afm", "application/octet-stream" }, - { ".ai", "application/postscript" }, - { ".aif", "audio/aiff" }, - { ".aifc", "audio/aiff" }, - { ".aiff", "audio/aiff" }, - { ".air", "application/vnd.adobe.air-application-installer-package+zip" }, - { ".amc", "application/mpeg" }, - { ".anx", "application/annodex" }, - { ".apk", "application/vnd.android.package-archive" }, - { ".application", "application/x-ms-application" }, - { ".art", "image/x-jg" }, - { ".asa", "application/xml" }, - { ".asax", "application/xml" }, - { ".ascx", "application/xml" }, - { ".asd", "application/octet-stream" }, - { ".asf", "video/x-ms-asf" }, - { ".ashx", "application/xml" }, - { ".asi", "application/octet-stream" }, - { ".asm", "text/plain" }, - { ".asmx", "application/xml" }, - { ".aspx", "application/xml" }, - { ".asr", "video/x-ms-asf" }, - { ".asx", "video/x-ms-asf" }, - { ".atom", "application/atom+xml" }, - { ".au", "audio/basic" }, - { ".avi", "video/x-msvideo" }, - { ".axa", "audio/annodex" }, - { ".axs", "application/olescript" }, - { ".axv", "video/annodex" }, - { ".bas", "text/plain" }, - { ".bcpio", "application/x-bcpio" }, - { ".bin", "application/octet-stream" }, - { ".bmp", "image/bmp" }, - { ".c", "text/plain" }, - { ".cab", "application/octet-stream" }, - { ".caf", "audio/x-caf" }, - { ".calx", "application/vnd.ms-office.calx" }, - { ".cat", "application/vnd.ms-pki.seccat" }, - { ".cc", "text/plain" }, - { ".cd", "text/plain" }, - { ".cdda", "audio/aiff" }, - { ".cdf", "application/x-cdf" }, - { ".cer", "application/x-x509-ca-cert" }, - { ".cfg", "text/plain" }, - { ".chm", "application/octet-stream" }, - { ".class", "application/x-java-applet" }, - { ".clp", "application/x-msclip" }, - { ".cmd", "text/plain" }, - { ".cmx", "image/x-cmx" }, - { ".cnf", "text/plain" }, - { ".cod", "image/cis-cod" }, - { ".config", "application/xml" }, - { ".contact", "text/x-ms-contact" }, - { ".coverage", "application/xml" }, - { ".cpio", "application/x-cpio" }, - { ".cpp", "text/plain" }, - { ".crd", "application/x-mscardfile" }, - { ".crl", "application/pkix-crl" }, - { ".crt", "application/x-x509-ca-cert" }, - { ".cs", "text/plain" }, - { ".csdproj", "text/plain" }, - { ".csh", "application/x-csh" }, - { ".csproj", "text/plain" }, - { ".css", "text/css" }, - { ".csv", "text/csv" }, - { ".cur", "application/octet-stream" }, - { ".cxx", "text/plain" }, - { ".dat", "application/octet-stream" }, - { ".datasource", "application/xml" }, - { ".dbproj", "text/plain" }, - { ".dcr", "application/x-director" }, - { ".def", "text/plain" }, - { ".deploy", "application/octet-stream" }, - { ".der", "application/x-x509-ca-cert" }, - { ".dgml", "application/xml" }, - { ".dib", "image/bmp" }, - { ".dif", "video/x-dv" }, - { ".dir", "application/x-director" }, - { ".disco", "text/xml" }, - { ".divx", "video/divx" }, - { ".dll", "application/x-msdownload" }, - { ".dll.config", "text/xml" }, - { ".dlm", "text/dlm" }, - { ".doc", "application/msword" }, - { ".docm", "application/vnd.ms-word.document.macroEnabled.12" }, - { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" }, - { ".dot", "application/msword" }, - { ".dotm", "application/vnd.ms-word.template.macroEnabled.12" }, - { ".dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" }, - { ".dsp", "application/octet-stream" }, - { ".dsw", "text/plain" }, - { ".dtd", "text/xml" }, - { ".dtsConfig", "text/xml" }, - { ".dv", "video/x-dv" }, - { ".dvi", "application/x-dvi" }, - { ".dwf", "drawing/x-dwf" }, - { ".dwp", "application/octet-stream" }, - { ".dxr", "application/x-director" }, - { ".eml", "message/rfc822" }, - { ".emz", "application/octet-stream" }, - { ".eot", "application/vnd.ms-fontobject" }, - { ".eps", "application/postscript" }, - { ".etl", "application/etl" }, - { ".etx", "text/x-setext" }, - { ".evy", "application/envoy" }, - { ".exe", "application/octet-stream" }, - { ".exe.config", "text/xml" }, - { ".fdf", "application/vnd.fdf" }, - { ".fif", "application/fractals" }, - { ".filters", "application/xml" }, - { ".fla", "application/octet-stream" }, - { ".flac", "audio/flac" }, - { ".flr", "x-world/x-vrml" }, - { ".flv", "video/x-flv" }, - { ".fsscript", "application/fsharp-script" }, - { ".fsx", "application/fsharp-script" }, - { ".generictest", "application/xml" }, - { ".gif", "image/gif" }, - { ".gpx", "application/gpx+xml" }, - { ".group", "text/x-ms-group" }, - { ".gsm", "audio/x-gsm" }, - { ".gtar", "application/x-gtar" }, - { ".gz", "application/x-gzip" }, - { ".h", "text/plain" }, - { ".hdf", "application/x-hdf" }, - { ".hdml", "text/x-hdml" }, - { ".hhc", "application/x-oleobject" }, - { ".hhk", "application/octet-stream" }, - { ".hhp", "application/octet-stream" }, - { ".hlp", "application/winhlp" }, - { ".hpp", "text/plain" }, - { ".hqx", "application/mac-binhex40" }, - { ".hta", "application/hta" }, - { ".htc", "text/x-component" }, - { ".htm", "text/html" }, - { ".html", "text/html" }, - { ".htt", "text/webviewhtml" }, - { ".hxa", "application/xml" }, - { ".hxc", "application/xml" }, - { ".hxd", "application/octet-stream" }, - { ".hxe", "application/xml" }, - { ".hxf", "application/xml" }, - { ".hxh", "application/octet-stream" }, - { ".hxi", "application/octet-stream" }, - { ".hxk", "application/xml" }, - { ".hxq", "application/octet-stream" }, - { ".hxr", "application/octet-stream" }, - { ".hxs", "application/octet-stream" }, - { ".hxt", "text/html" }, - { ".hxv", "application/xml" }, - { ".hxw", "application/octet-stream" }, - { ".hxx", "text/plain" }, - { ".i", "text/plain" }, - { ".ico", "image/x-icon" }, - { ".ics", "application/octet-stream" }, - { ".idl", "text/plain" }, - { ".ief", "image/ief" }, - { ".iii", "application/x-iphone" }, - { ".inc", "text/plain" }, - { ".inf", "application/octet-stream" }, - { ".ini", "text/plain" }, - { ".inl", "text/plain" }, - { ".ins", "application/x-internet-signup" }, - { ".ipa", "application/x-itunes-ipa" }, - { ".ipg", "application/x-itunes-ipg" }, - { ".ipproj", "text/plain" }, - { ".ipsw", "application/x-itunes-ipsw" }, - { ".iqy", "text/x-ms-iqy" }, - { ".isp", "application/x-internet-signup" }, - { ".ite", "application/x-itunes-ite" }, - { ".itlp", "application/x-itunes-itlp" }, - { ".itms", "application/x-itunes-itms" }, - { ".itpc", "application/x-itunes-itpc" }, - { ".IVF", "video/x-ivf" }, - { ".jar", "application/java-archive" }, - { ".java", "application/octet-stream" }, - { ".jck", "application/liquidmotion" }, - { ".jcz", "application/liquidmotion" }, - { ".jfif", "image/pjpeg" }, - { ".jnlp", "application/x-java-jnlp-file" }, - { ".jpb", "application/octet-stream" }, - { ".jpe", "image/jpeg" }, - { ".jpeg", "image/jpeg" }, - { ".jpg", "image/jpeg" }, - { ".js", "application/javascript" }, - { ".json", "application/json" }, - { ".jsx", "text/jscript" }, - { ".jsxbin", "text/plain" }, - { ".latex", "application/x-latex" }, - { ".library-ms", "application/windows-library+xml" }, - { ".lit", "application/x-ms-reader" }, - { ".loadtest", "application/xml" }, - { ".lpk", "application/octet-stream" }, - { ".lsf", "video/x-la-asf" }, - { ".lst", "text/plain" }, - { ".lsx", "video/x-la-asf" }, - { ".lzh", "application/octet-stream" }, - { ".m13", "application/x-msmediaview" }, - { ".m14", "application/x-msmediaview" }, - { ".m1v", "video/mpeg" }, - { ".m2t", "video/vnd.dlna.mpeg-tts" }, - { ".m2ts", "video/vnd.dlna.mpeg-tts" }, - { ".m2v", "video/mpeg" }, - { ".m3u", "audio/x-mpegurl" }, - { ".m3u8", "audio/x-mpegurl" }, - { ".m4a", "audio/m4a" }, - { ".m4b", "audio/m4b" }, - { ".m4p", "audio/m4p" }, - { ".m4r", "audio/x-m4r" }, - { ".m4v", "video/x-m4v" }, - { ".mac", "image/x-macpaint" }, - { ".mak", "text/plain" }, - { ".man", "application/x-troff-man" }, - { ".manifest", "application/x-ms-manifest" }, - { ".map", "text/plain" }, - { ".master", "application/xml" }, - { ".mda", "application/msaccess" }, - { ".mdb", "application/x-msaccess" }, - { ".mde", "application/msaccess" }, - { ".mdp", "application/octet-stream" }, - { ".me", "application/x-troff-me" }, - { ".mfp", "application/x-shockwave-flash" }, - { ".mht", "message/rfc822" }, - { ".mhtml", "message/rfc822" }, - { ".mid", "audio/mid" }, - { ".midi", "audio/mid" }, - { ".mix", "application/octet-stream" }, - { ".mk", "text/plain" }, - { ".mmf", "application/x-smaf" }, - { ".mno", "text/xml" }, - { ".mny", "application/x-msmoney" }, - { ".mod", "video/mpeg" }, - { ".mov", "video/quicktime" }, - { ".movie", "video/x-sgi-movie" }, - { ".mp2", "video/mpeg" }, - { ".mp2v", "video/mpeg" }, - { ".mp3", "audio/mpeg" }, - { ".mp4", "video/mp4" }, - { ".mp4v", "video/mp4" }, - { ".mpa", "video/mpeg" }, - { ".mpe", "video/mpeg" }, - { ".mpeg", "video/mpeg" }, - { ".mpf", "application/vnd.ms-mediapackage" }, - { ".mpg", "video/mpeg" }, - { ".mpp", "application/vnd.ms-project" }, - { ".mpv2", "video/mpeg" }, - { ".mqv", "video/quicktime" }, - { ".ms", "application/x-troff-ms" }, - { ".msi", "application/octet-stream" }, - { ".mso", "application/octet-stream" }, - { ".mts", "video/vnd.dlna.mpeg-tts" }, - { ".mtx", "application/xml" }, - { ".mvb", "application/x-msmediaview" }, - { ".mvc", "application/x-miva-compiled" }, - { ".mxp", "application/x-mmxp" }, - { ".nc", "application/x-netcdf" }, - { ".nsc", "video/x-ms-asf" }, - { ".nws", "message/rfc822" }, - { ".ocx", "application/octet-stream" }, - { ".oda", "application/oda" }, - { ".odb", "application/vnd.oasis.opendocument.database" }, - { ".odc", "application/vnd.oasis.opendocument.chart" }, - { ".odf", "application/vnd.oasis.opendocument.formula" }, - { ".odg", "application/vnd.oasis.opendocument.graphics" }, - { ".odh", "text/plain" }, - { ".odi", "application/vnd.oasis.opendocument.image" }, - { ".odl", "text/plain" }, - { ".odm", "application/vnd.oasis.opendocument.text-master" }, - { ".odp", "application/vnd.oasis.opendocument.presentation" }, - { ".ods", "application/vnd.oasis.opendocument.spreadsheet" }, - { ".odt", "application/vnd.oasis.opendocument.text" }, - { ".oga", "audio/ogg" }, - { ".ogg", "audio/ogg" }, - { ".ogv", "video/ogg" }, - { ".ogx", "application/ogg" }, - { ".one", "application/onenote" }, - { ".onea", "application/onenote" }, - { ".onepkg", "application/onenote" }, - { ".onetmp", "application/onenote" }, - { ".onetoc", "application/onenote" }, - { ".onetoc2", "application/onenote" }, - { ".opus", "audio/ogg" }, - { ".orderedtest", "application/xml" }, - { ".osdx", "application/opensearchdescription+xml" }, - { ".otf", "application/font-sfnt" }, - { ".otg", "application/vnd.oasis.opendocument.graphics-template" }, - { ".oth", "application/vnd.oasis.opendocument.text-web" }, - { ".otp", "application/vnd.oasis.opendocument.presentation-template" }, - { ".ots", "application/vnd.oasis.opendocument.spreadsheet-template" }, - { ".ott", "application/vnd.oasis.opendocument.text-template" }, - { ".oxt", "application/vnd.openofficeorg.extension" }, - { ".p10", "application/pkcs10" }, - { ".p12", "application/x-pkcs12" }, - { ".p7b", "application/x-pkcs7-certificates" }, - { ".p7c", "application/pkcs7-mime" }, - { ".p7m", "application/pkcs7-mime" }, - { ".p7r", "application/x-pkcs7-certreqresp" }, - { ".p7s", "application/pkcs7-signature" }, - { ".pbm", "image/x-portable-bitmap" }, - { ".pcast", "application/x-podcast" }, - { ".pct", "image/pict" }, - { ".pcx", "application/octet-stream" }, - { ".pcz", "application/octet-stream" }, - { ".pdf", "application/pdf" }, - { ".pfb", "application/octet-stream" }, - { ".pfm", "application/octet-stream" }, - { ".pfx", "application/x-pkcs12" }, - { ".pgm", "image/x-portable-graymap" }, - { ".pic", "image/pict" }, - { ".pict", "image/pict" }, - { ".pkgdef", "text/plain" }, - { ".pkgundef", "text/plain" }, - { ".pko", "application/vnd.ms-pki.pko" }, - { ".pls", "audio/scpls" }, - { ".pma", "application/x-perfmon" }, - { ".pmc", "application/x-perfmon" }, - { ".pml", "application/x-perfmon" }, - { ".pmr", "application/x-perfmon" }, - { ".pmw", "application/x-perfmon" }, - { ".png", "image/png" }, - { ".pnm", "image/x-portable-anymap" }, - { ".pnt", "image/x-macpaint" }, - { ".pntg", "image/x-macpaint" }, - { ".pnz", "image/png" }, - { ".pot", "application/vnd.ms-powerpoint" }, - { ".potm", "application/vnd.ms-powerpoint.template.macroEnabled.12" }, - { ".potx", "application/vnd.openxmlformats-officedocument.presentationml.template" }, - { ".ppa", "application/vnd.ms-powerpoint" }, - { ".ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12" }, - { ".ppm", "image/x-portable-pixmap" }, - { ".pps", "application/vnd.ms-powerpoint" }, - { ".ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" }, - { ".ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" }, - { ".ppt", "application/vnd.ms-powerpoint" }, - { ".pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12" }, - { ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" }, - { ".prf", "application/pics-rules" }, - { ".prm", "application/octet-stream" }, - { ".prx", "application/octet-stream" }, - { ".ps", "application/postscript" }, - { ".psc1", "application/PowerShell" }, - { ".psd", "application/octet-stream" }, - { ".psess", "application/xml" }, - { ".psm", "application/octet-stream" }, - { ".psp", "application/octet-stream" }, - { ".pub", "application/x-mspublisher" }, - { ".pwz", "application/vnd.ms-powerpoint" }, - { ".qht", "text/x-html-insertion" }, - { ".qhtm", "text/x-html-insertion" }, - { ".qt", "video/quicktime" }, - { ".qti", "image/x-quicktime" }, - { ".qtif", "image/x-quicktime" }, - { ".qtl", "application/x-quicktimeplayer" }, - { ".qxd", "application/octet-stream" }, - { ".ra", "audio/x-pn-realaudio" }, - { ".ram", "audio/x-pn-realaudio" }, - { ".rar", "application/x-rar-compressed" }, - { ".ras", "image/x-cmu-raster" }, - { ".rat", "application/rat-file" }, - { ".rc", "text/plain" }, - { ".rc2", "text/plain" }, - { ".rct", "text/plain" }, - { ".rdlc", "application/xml" }, - { ".reg", "text/plain" }, - { ".resx", "application/xml" }, - { ".rf", "image/vnd.rn-realflash" }, - { ".rgb", "image/x-rgb" }, - { ".rgs", "text/plain" }, - { ".rm", "application/vnd.rn-realmedia" }, - { ".rmi", "audio/mid" }, - { ".rmp", "application/vnd.rn-rn_music_package" }, - { ".roff", "application/x-troff" }, - { ".rpm", "audio/x-pn-realaudio-plugin" }, - { ".rqy", "text/x-ms-rqy" }, - { ".rtf", "application/rtf" }, - { ".rtx", "text/richtext" }, - { ".ruleset", "application/xml" }, - { ".s", "text/plain" }, - { ".safariextz", "application/x-safari-safariextz" }, - { ".scd", "application/x-msschedule" }, - { ".scr", "text/plain" }, - { ".sct", "text/scriptlet" }, - { ".sd2", "audio/x-sd2" }, - { ".sdp", "application/sdp" }, - { ".sea", "application/octet-stream" }, - { ".searchConnector-ms", "application/windows-search-connector+xml" }, - { ".setpay", "application/set-payment-initiation" }, - { ".setreg", "application/set-registration-initiation" }, - { ".settings", "application/xml" }, - { ".sgimb", "application/x-sgimb" }, - { ".sgml", "text/sgml" }, - { ".sh", "application/x-sh" }, - { ".shar", "application/x-shar" }, - { ".shtml", "text/html" }, - { ".sit", "application/x-stuffit" }, - { ".sitemap", "application/xml" }, - { ".skin", "application/xml" }, - { ".sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12" }, - { ".sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide" }, - { ".slk", "application/vnd.ms-excel" }, - { ".sln", "text/plain" }, - { ".slupkg-ms", "application/x-ms-license" }, - { ".smd", "audio/x-smd" }, - { ".smi", "application/octet-stream" }, - { ".smx", "audio/x-smd" }, - { ".smz", "audio/x-smd" }, - { ".snd", "audio/basic" }, - { ".snippet", "application/xml" }, - { ".snp", "application/octet-stream" }, - { ".sol", "text/plain" }, - { ".sor", "text/plain" }, - { ".spc", "application/x-pkcs7-certificates" }, - { ".spl", "application/futuresplash" }, - { ".spx", "audio/ogg" }, - { ".src", "application/x-wais-source" }, - { ".srf", "text/plain" }, - { ".SSISDeploymentManifest", "text/xml" }, - { ".ssm", "application/streamingmedia" }, - { ".sst", "application/vnd.ms-pki.certstore" }, - { ".stl", "application/vnd.ms-pki.stl" }, - { ".sv4cpio", "application/x-sv4cpio" }, - { ".sv4crc", "application/x-sv4crc" }, - { ".svc", "application/xml" }, - { ".svg", "image/svg+xml" }, - { ".swf", "application/x-shockwave-flash" }, - { ".step", "application/step" }, - { ".stp", "application/step" }, - { ".t", "application/x-troff" }, - { ".tar", "application/x-tar" }, - { ".tcl", "application/x-tcl" }, - { ".testrunconfig", "application/xml" }, - { ".testsettings", "application/xml" }, - { ".tex", "application/x-tex" }, - { ".texi", "application/x-texinfo" }, - { ".texinfo", "application/x-texinfo" }, - { ".tgz", "application/x-compressed" }, - { ".thmx", "application/vnd.ms-officetheme" }, - { ".thn", "application/octet-stream" }, - { ".tif", "image/tiff" }, - { ".tiff", "image/tiff" }, - { ".tlh", "text/plain" }, - { ".tli", "text/plain" }, - { ".toc", "application/octet-stream" }, - { ".tr", "application/x-troff" }, - { ".trm", "application/x-msterminal" }, - { ".trx", "application/xml" }, - { ".ts", "video/vnd.dlna.mpeg-tts" }, - { ".tsv", "text/tab-separated-values" }, - { ".ttf", "application/font-sfnt" }, - { ".tts", "video/vnd.dlna.mpeg-tts" }, - { ".txt", "text/plain" }, - { ".u32", "application/octet-stream" }, - { ".uls", "text/iuls" }, - { ".user", "text/plain" }, - { ".ustar", "application/x-ustar" }, - { ".vb", "text/plain" }, - { ".vbdproj", "text/plain" }, - { ".vbk", "video/mpeg" }, - { ".vbproj", "text/plain" }, - { ".vbs", "text/vbscript" }, - { ".vcf", "text/x-vcard" }, - { ".vcproj", "application/xml" }, - { ".vcs", "text/plain" }, - { ".vcxproj", "application/xml" }, - { ".vddproj", "text/plain" }, - { ".vdp", "text/plain" }, - { ".vdproj", "text/plain" }, - { ".vdx", "application/vnd.ms-visio.viewer" }, - { ".vml", "text/xml" }, - { ".vscontent", "application/xml" }, - { ".vsct", "text/xml" }, - { ".vsd", "application/vnd.visio" }, - { ".vsi", "application/ms-vsi" }, - { ".vsix", "application/vsix" }, - { ".vsixlangpack", "text/xml" }, - { ".vsixmanifest", "text/xml" }, - { ".vsmdi", "application/xml" }, - { ".vspscc", "text/plain" }, - { ".vss", "application/vnd.visio" }, - { ".vsscc", "text/plain" }, - { ".vssettings", "text/xml" }, - { ".vssscc", "text/plain" }, - { ".vst", "application/vnd.visio" }, - { ".vstemplate", "text/xml" }, - { ".vsto", "application/x-ms-vsto" }, - { ".vsw", "application/vnd.visio" }, - { ".vsx", "application/vnd.visio" }, - { ".vtx", "application/vnd.visio" }, - { ".wav", "audio/wav" }, - { ".wave", "audio/wav" }, - { ".wax", "audio/x-ms-wax" }, - { ".wbk", "application/msword" }, - { ".wbmp", "image/vnd.wap.wbmp" }, - { ".wcm", "application/vnd.ms-works" }, - { ".wdb", "application/vnd.ms-works" }, - { ".wdp", "image/vnd.ms-photo" }, - { ".webarchive", "application/x-safari-webarchive" }, - { ".webm", "video/webm" }, - { ".webp", "image/webp" }, /* https://en.wikipedia.org/wiki/WebP */ - { ".webtest", "application/xml" }, - { ".wiq", "application/xml" }, - { ".wiz", "application/msword" }, - { ".wks", "application/vnd.ms-works" }, - { ".WLMP", "application/wlmoviemaker" }, - { ".wlpginstall", "application/x-wlpg-detect" }, - { ".wlpginstall3", "application/x-wlpg3-detect" }, - { ".wm", "video/x-ms-wm" }, - { ".wma", "audio/x-ms-wma" }, - { ".wmd", "application/x-ms-wmd" }, - { ".wmf", "application/x-msmetafile" }, - { ".wml", "text/vnd.wap.wml" }, - { ".wmlc", "application/vnd.wap.wmlc" }, - { ".wmls", "text/vnd.wap.wmlscript" }, - { ".wmlsc", "application/vnd.wap.wmlscriptc" }, - { ".wmp", "video/x-ms-wmp" }, - { ".wmv", "video/x-ms-wmv" }, - { ".wmx", "video/x-ms-wmx" }, - { ".wmz", "application/x-ms-wmz" }, - { ".woff", "application/font-woff" }, - { ".wpl", "application/vnd.ms-wpl" }, - { ".wps", "application/vnd.ms-works" }, - { ".wri", "application/x-mswrite" }, - { ".wrl", "x-world/x-vrml" }, - { ".wrz", "x-world/x-vrml" }, - { ".wsc", "text/scriptlet" }, - { ".wsdl", "text/xml" }, - { ".wvx", "video/x-ms-wvx" }, - { ".x", "application/directx" }, - { ".xaf", "x-world/x-vrml" }, - { ".xaml", "application/xaml+xml" }, - { ".xap", "application/x-silverlight-app" }, - { ".xbap", "application/x-ms-xbap" }, - { ".xbm", "image/x-xbitmap" }, - { ".xdr", "text/plain" }, - { ".xht", "application/xhtml+xml" }, - { ".xhtml", "application/xhtml+xml" }, - { ".xla", "application/vnd.ms-excel" }, - { ".xlam", "application/vnd.ms-excel.addin.macroEnabled.12" }, - { ".xlc", "application/vnd.ms-excel" }, - { ".xld", "application/vnd.ms-excel" }, - { ".xlk", "application/vnd.ms-excel" }, - { ".xll", "application/vnd.ms-excel" }, - { ".xlm", "application/vnd.ms-excel" }, - { ".xls", "application/vnd.ms-excel" }, - { ".xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" }, - { ".xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" }, - { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }, - { ".xlt", "application/vnd.ms-excel" }, - { ".xltm", "application/vnd.ms-excel.template.macroEnabled.12" }, - { ".xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" }, - { ".xlw", "application/vnd.ms-excel" }, - { ".xml", "text/xml" }, - { ".xmta", "application/xml" }, - { ".xof", "x-world/x-vrml" }, - { ".XOML", "text/plain" }, - { ".xpm", "image/x-xpixmap" }, - { ".xps", "application/vnd.ms-xpsdocument" }, - { ".xrm-ms", "text/xml" }, - { ".xsc", "application/xml" }, - { ".xsd", "text/xml" }, - { ".xsf", "text/xml" }, - { ".xsl", "text/xml" }, - { ".xslt", "text/xml" }, - { ".xsn", "application/octet-stream" }, - { ".xss", "application/xml" }, - { ".xspf", "application/xspf+xml" }, - { ".xtp", "application/octet-stream" }, - { ".xwd", "image/x-xwindowdump" }, - { ".z", "application/x-compress" }, - { ".zip", "application/zip" }, - { "application/fsharp-script", ".fsx" }, - { "application/msaccess", ".adp" }, - { "application/msword", ".doc" }, - { "application/octet-stream", ".bin" }, - { "application/onenote", ".one" }, - { "application/postscript", ".eps" }, - { "application/step", ".step" }, - { "application/vnd.ms-excel", ".xls" }, - { "application/vnd.ms-powerpoint", ".ppt" }, - { "application/vnd.ms-works", ".wks" }, - { "application/vnd.visio", ".vsd" }, - { "application/x-director", ".dir" }, - { "application/x-shockwave-flash", ".swf" }, - { "application/x-x509-ca-cert", ".cer" }, - { "application/x-zip-compressed", ".zip" }, - { "application/xhtml+xml", ".xhtml" }, - { "application/xml", ".xml" }, // anomoly, .xml -> text/xml, but application/xml -> many thingss, but all are xml, so safest is .xml - { "audio/aac", ".AAC" }, - { "audio/aiff", ".aiff" }, - { "audio/basic", ".snd" }, - { "audio/mid", ".midi" }, - { "audio/wav", ".wav" }, - { "audio/x-m4a", ".m4a" }, - { "audio/x-mpegurl", ".m3u" }, - { "audio/x-pn-realaudio", ".ra" }, - { "audio/x-smd", ".smd" }, - { "image/bmp", ".bmp" }, - { "image/jpeg", ".jpg" }, - { "image/pict", ".pic" }, - { "image/png", ".png" }, - { "image/tiff", ".tiff" }, - { "image/x-macpaint", ".mac" }, - { "image/x-quicktime", ".qti" }, - { "message/rfc822", ".eml" }, - { "text/html", ".html" }, - { "text/plain", ".txt" }, - { "text/scriptlet", ".wsc" }, - { "text/xml", ".xml" }, - { "video/3gpp", ".3gp" }, - { "video/3gpp2", ".3gp2" }, - { "video/mp4", ".mp4" }, - { "video/mpeg", ".mpg" }, - { "video/quicktime", ".mov" }, - { "video/vnd.dlna.mpeg-tts", ".m2t" }, - { "video/x-dv", ".dv" }, - { "video/x-la-asf", ".lsf" }, - { "video/x-ms-asf", ".asf" }, - { "x-world/x-vrml", ".xof" }, + { ".323", new("text/h323") }, + { ".3g2", new("video/3gpp2") }, + { ".3gp", new("video/3gpp", "audio/3gpp") }, + { ".3gp2", new("video/3gpp2") }, + { ".3gpp", new("video/3gpp") }, + { ".7z", new("application/x-7z-compressed") }, + { ".aa", new("audio/audible") }, + { ".AAC", new("audio/aac") }, + { ".aaf", new("application/octet-stream") }, + { ".aax", new("audio/vnd.audible.aax") }, + { ".ac3", new("audio/ac3") }, + { ".aca", new("application/octet-stream") }, + { ".accda", new("application/msaccess.addin") }, + { ".accdb", new("application/msaccess") }, + { ".accdc", new("application/msaccess.cab") }, + { ".accde", new("application/msaccess") }, + { ".accdr", new("application/msaccess.runtime") }, + { ".accdt", new("application/msaccess") }, + { ".accdw", new("application/msaccess.webapplication") }, + { ".accft", new("application/msaccess.ftemplate") }, + { ".acx", new("application/internet-property-stream") }, + { ".AddIn", new("text/xml") }, + { ".ade", new("application/msaccess") }, + { ".adobebridge", new("application/x-bridge-url") }, + { ".adp", new("application/msaccess") }, + { ".ADT", new("audio/vnd.dlna.adts") }, + { ".ADTS", new("audio/aac") }, + { ".afm", new("application/octet-stream") }, + { ".ai", new("application/postscript") }, + { ".aif", new("audio/aiff") }, + { ".aifc", new("audio/aiff") }, + { ".aiff", new("audio/aiff") }, + { ".air", new("application/vnd.adobe.air-application-installer-package+zip") }, + { ".amc", new("application/mpeg") }, + { ".anx", new("application/annodex") }, + { ".apk", new("application/vnd.android.package-archive") }, + { ".application", new("application/x-ms-application") }, + { ".art", new("image/x-jg") }, + { ".asa", new("application/xml") }, + { ".asax", new("application/xml") }, + { ".ascx", new("application/xml") }, + { ".asd", new("application/octet-stream") }, + { ".asf", new("video/x-ms-asf") }, + { ".ashx", new("application/xml") }, + { ".asi", new("application/octet-stream") }, + { ".asm", new("text/plain") }, + { ".asmx", new("application/xml") }, + { ".aspx", new("application/xml") }, + { ".asr", new("video/x-ms-asf") }, + { ".asx", new("video/x-ms-asf") }, + { ".atom", new("application/atom+xml") }, + { ".au", new("audio/basic") }, + { ".avi", new("video/x-msvideo") }, + { ".axa", new("audio/annodex") }, + { ".axs", new("application/olescript") }, + { ".axv", new("video/annodex") }, + { ".bas", new("text/plain") }, + { ".bcpio", new("application/x-bcpio") }, + { ".bin", new("application/octet-stream") }, + { ".bmp", new("image/bmp") }, + { ".c", new("text/plain") }, + { ".cab", new("application/octet-stream") }, + { ".caf", new("audio/x-caf") }, + { ".calx", new("application/vnd.ms-office.calx") }, + { ".cat", new("application/vnd.ms-pki.seccat") }, + { ".cc", new("text/plain") }, + { ".cd", new("text/plain") }, + { ".cdda", new("audio/aiff") }, + { ".cdf", new("application/x-cdf") }, + { ".cer", new("application/x-x509-ca-cert") }, + { ".cfg", new("text/plain") }, + { ".chm", new("application/octet-stream") }, + { ".class", new("application/x-java-applet") }, + { ".clp", new("application/x-msclip") }, + { ".cmd", new("text/plain") }, + { ".cmx", new("image/x-cmx") }, + { ".cnf", new("text/plain") }, + { ".cod", new("image/cis-cod") }, + { ".config", new("application/xml") }, + { ".contact", new("text/x-ms-contact") }, + { ".coverage", new("application/xml") }, + { ".cpio", new("application/x-cpio") }, + { ".cpp", new("text/plain") }, + { ".crd", new("application/x-mscardfile") }, + { ".crl", new("application/pkix-crl") }, + { ".crt", new("application/x-x509-ca-cert") }, + { ".cs", new("text/plain") }, + { ".csdproj", new("text/plain") }, + { ".csh", new("application/x-csh") }, + { ".csproj", new("text/plain") }, + { ".css", new("text/css") }, + { ".csv", new("text/csv") }, + { ".cur", new("application/octet-stream") }, + { ".cxx", new("text/plain") }, + { ".dat", new("application/octet-stream") }, + { ".datasource", new("application/xml") }, + { ".dbproj", new("text/plain") }, + { ".dcr", new("application/x-director") }, + { ".def", new("text/plain") }, + { ".deploy", new("application/octet-stream") }, + { ".der", new("application/x-x509-ca-cert") }, + { ".dgml", new("application/xml") }, + { ".dib", new("image/bmp") }, + { ".dif", new("video/x-dv") }, + { ".dir", new("application/x-director") }, + { ".disco", new("text/xml") }, + { ".divx", new("video/divx") }, + { ".dll", new("application/x-msdownload") }, + { ".dll.config", new("text/xml") }, + { ".dlm", new("text/dlm") }, + { ".doc", new("application/msword") }, + { ".docm", new("application/vnd.ms-word.document.macroEnabled.12") }, + { ".docx", new("application/vnd.openxmlformats-officedocument.wordprocessingml.document") }, + { ".dot", new("application/msword") }, + { ".dotm", new("application/vnd.ms-word.template.macroEnabled.12") }, + { ".dotx", new("application/vnd.openxmlformats-officedocument.wordprocessingml.template") }, + { ".dsp", new("application/octet-stream") }, + { ".dsw", new("text/plain") }, + { ".dtd", new("text/xml") }, + { ".dtsConfig", new("text/xml") }, + { ".dv", new("video/x-dv") }, + { ".dvi", new("application/x-dvi") }, + { ".dwf", new("drawing/x-dwf") }, + { ".dwp", new("application/octet-stream") }, + { ".dxr", new("application/x-director") }, + { ".eml", new("message/rfc822") }, + { ".emz", new("application/octet-stream") }, + { ".eot", new("application/vnd.ms-fontobject") }, + { ".eps", new("application/postscript") }, + { ".etl", new("application/etl") }, + { ".etx", new("text/x-setext") }, + { ".evy", new("application/envoy") }, + { ".exe", new("application/octet-stream") }, + { ".exe.config", new("text/xml") }, + { ".fdf", new("application/vnd.fdf") }, + { ".fif", new("application/fractals") }, + { ".filters", new("application/xml") }, + { ".fla", new("application/octet-stream") }, + { ".flac", new("audio/flac") }, + { ".flr", new("x-world/x-vrml") }, + { ".flv", new("video/x-flv") }, + { ".fsscript", new("application/fsharp-script") }, + { ".fsx", new("application/fsharp-script") }, + { ".generictest", new("application/xml") }, + { ".gif", new("image/gif") }, + { ".gpx", new("application/gpx+xml") }, + { ".group", new("text/x-ms-group") }, + { ".gsm", new("audio/x-gsm") }, + { ".gtar", new("application/x-gtar") }, + { ".gz", new("application/x-gzip") }, + { ".h", new("text/plain") }, + { ".hdf", new("application/x-hdf") }, + { ".hdml", new("text/x-hdml") }, + { ".hhc", new("application/x-oleobject") }, + { ".hhk", new("application/octet-stream") }, + { ".hhp", new("application/octet-stream") }, + { ".hlp", new("application/winhlp") }, + { ".hpp", new("text/plain") }, + { ".hqx", new("application/mac-binhex40") }, + { ".hta", new("application/hta") }, + { ".htc", new("text/x-component") }, + { ".htm", new("text/html") }, + { ".html", new("text/html") }, + { ".htt", new("text/webviewhtml") }, + { ".hxa", new("application/xml") }, + { ".hxc", new("application/xml") }, + { ".hxd", new("application/octet-stream") }, + { ".hxe", new("application/xml") }, + { ".hxf", new("application/xml") }, + { ".hxh", new("application/octet-stream") }, + { ".hxi", new("application/octet-stream") }, + { ".hxk", new("application/xml") }, + { ".hxq", new("application/octet-stream") }, + { ".hxr", new("application/octet-stream") }, + { ".hxs", new("application/octet-stream") }, + { ".hxt", new("text/html") }, + { ".hxv", new("application/xml") }, + { ".hxw", new("application/octet-stream") }, + { ".hxx", new("text/plain") }, + { ".i", new("text/plain") }, + { ".ico", new("image/x-icon") }, + { ".ics", new("application/octet-stream") }, + { ".idl", new("text/plain") }, + { ".ief", new("image/ief") }, + { ".iii", new("application/x-iphone") }, + { ".inc", new("text/plain") }, + { ".inf", new("application/octet-stream") }, + { ".ini", new("text/plain") }, + { ".inl", new("text/plain") }, + { ".ins", new("application/x-internet-signup") }, + { ".ipa", new("application/x-itunes-ipa") }, + { ".ipg", new("application/x-itunes-ipg") }, + { ".ipproj", new("text/plain") }, + { ".ipsw", new("application/x-itunes-ipsw") }, + { ".iqy", new("text/x-ms-iqy") }, + { ".isp", new("application/x-internet-signup") }, + { ".ite", new("application/x-itunes-ite") }, + { ".itlp", new("application/x-itunes-itlp") }, + { ".itms", new("application/x-itunes-itms") }, + { ".itpc", new("application/x-itunes-itpc") }, + { ".IVF", new("video/x-ivf") }, + { ".jar", new("application/java-archive") }, + { ".java", new("application/octet-stream") }, + { ".jck", new("application/liquidmotion") }, + { ".jcz", new("application/liquidmotion") }, + { ".jfif", new("image/pjpeg") }, + { ".jnlp", new("application/x-java-jnlp-file") }, + { ".jpb", new("application/octet-stream") }, + { ".jpe", new("image/jpeg") }, + { ".jpeg", new("image/jpeg") }, + { ".jpg", new("image/jpeg") }, + { ".js", new("application/javascript") }, + { ".json", new("application/json") }, + { ".jsx", new("text/jscript") }, + { ".jsxbin", new("text/plain") }, + { ".latex", new("application/x-latex") }, + { ".library-ms", new("application/windows-library+xml") }, + { ".lit", new("application/x-ms-reader") }, + { ".loadtest", new("application/xml") }, + { ".lpk", new("application/octet-stream") }, + { ".lsf", new("video/x-la-asf") }, + { ".lst", new("text/plain") }, + { ".lsx", new("video/x-la-asf") }, + { ".lzh", new("application/octet-stream") }, + { ".m13", new("application/x-msmediaview") }, + { ".m14", new("application/x-msmediaview") }, + { ".m1v", new("video/mpeg") }, + { ".m2t", new("video/vnd.dlna.mpeg-tts") }, + { ".m2ts", new("video/vnd.dlna.mpeg-tts") }, + { ".m2v", new("video/mpeg") }, + { ".m3u", new("audio/x-mpegurl") }, + { ".m3u8", new("audio/x-mpegurl") }, + { ".m4a", new("audio/m4a") }, + { ".m4b", new("audio/m4b") }, + { ".m4p", new("audio/m4p") }, + { ".m4r", new("audio/x-m4r") }, + { ".m4v", new("video/x-m4v") }, + { ".mac", new("image/x-macpaint") }, + { ".mak", new("text/plain") }, + { ".man", new("application/x-troff-man") }, + { ".manifest", new("application/x-ms-manifest") }, + { ".map", new("text/plain") }, + { ".master", new("application/xml") }, + { ".mda", new("application/msaccess") }, + { ".mdb", new("application/x-msaccess") }, + { ".mde", new("application/msaccess") }, + { ".mdp", new("application/octet-stream") }, + { ".me", new("application/x-troff-me") }, + { ".mfp", new("application/x-shockwave-flash") }, + { ".mht", new("message/rfc822") }, + { ".mhtml", new("message/rfc822") }, + { ".mid", new("audio/mid") }, + { ".midi", new("audio/mid") }, + { ".mix", new("application/octet-stream") }, + { ".mk", new("text/plain") }, + { ".mmf", new("application/x-smaf") }, + { ".mno", new("text/xml") }, + { ".mny", new("application/x-msmoney") }, + { ".mod", new("video/mpeg") }, + { ".mov", new("video/quicktime") }, + { ".movie", new("video/x-sgi-movie") }, + { ".mp2", new("video/mpeg") }, + { ".mp2v", new("video/mpeg") }, + { ".mp3", new("audio/mpeg") }, + { ".mp4", new("video/mp4") }, + { ".mp4v", new("video/mp4") }, + { ".mpa", new("video/mpeg") }, + { ".mpe", new("video/mpeg") }, + { ".mpeg", new("video/mpeg") }, + { ".mpf", new("application/vnd.ms-mediapackage") }, + { ".mpg", new("video/mpeg") }, + { ".mpp", new("application/vnd.ms-project") }, + { ".mpv2", new("video/mpeg") }, + { ".mqv", new("video/quicktime") }, + { ".ms", new("application/x-troff-ms") }, + { ".msi", new("application/octet-stream") }, + { ".mso", new("application/octet-stream") }, + { ".mts", new("video/vnd.dlna.mpeg-tts") }, + { ".mtx", new("application/xml") }, + { ".mvb", new("application/x-msmediaview") }, + { ".mvc", new("application/x-miva-compiled") }, + { ".mxp", new("application/x-mmxp") }, + { ".nc", new("application/x-netcdf") }, + { ".nsc", new("video/x-ms-asf") }, + { ".nws", new("message/rfc822") }, + { ".ocx", new("application/octet-stream") }, + { ".oda", new("application/oda") }, + { ".odb", new("application/vnd.oasis.opendocument.database") }, + { ".odc", new("application/vnd.oasis.opendocument.chart") }, + { ".odf", new("application/vnd.oasis.opendocument.formula") }, + { ".odg", new("application/vnd.oasis.opendocument.graphics") }, + { ".odh", new("text/plain") }, + { ".odi", new("application/vnd.oasis.opendocument.image") }, + { ".odl", new("text/plain") }, + { ".odm", new("application/vnd.oasis.opendocument.text-master") }, + { ".odp", new("application/vnd.oasis.opendocument.presentation") }, + { ".ods", new("application/vnd.oasis.opendocument.spreadsheet") }, + { ".odt", new("application/vnd.oasis.opendocument.text") }, + { ".oga", new("audio/ogg") }, + { ".ogg", new("audio/ogg") }, + { ".ogv", new("video/ogg") }, + { ".ogx", new("application/ogg") }, + { ".one", new("application/onenote") }, + { ".onea", new("application/onenote") }, + { ".onepkg", new("application/onenote") }, + { ".onetmp", new("application/onenote") }, + { ".onetoc", new("application/onenote") }, + { ".onetoc2", new("application/onenote") }, + { ".opus", new("audio/ogg") }, + { ".orderedtest", new("application/xml") }, + { ".osdx", new("application/opensearchdescription+xml") }, + { ".otf", new("application/font-sfnt") }, + { ".otg", new("application/vnd.oasis.opendocument.graphics-template") }, + { ".oth", new("application/vnd.oasis.opendocument.text-web") }, + { ".otp", new("application/vnd.oasis.opendocument.presentation-template") }, + { ".ots", new("application/vnd.oasis.opendocument.spreadsheet-template") }, + { ".ott", new("application/vnd.oasis.opendocument.text-template") }, + { ".oxt", new("application/vnd.openofficeorg.extension") }, + { ".p10", new("application/pkcs10") }, + { ".p12", new("application/x-pkcs12") }, + { ".p7b", new("application/x-pkcs7-certificates") }, + { ".p7c", new("application/pkcs7-mime") }, + { ".p7m", new("application/pkcs7-mime") }, + { ".p7r", new("application/x-pkcs7-certreqresp") }, + { ".p7s", new("application/pkcs7-signature") }, + { ".pbm", new("image/x-portable-bitmap") }, + { ".pcast", new("application/x-podcast") }, + { ".pct", new("image/pict") }, + { ".pcx", new("application/octet-stream") }, + { ".pcz", new("application/octet-stream") }, + { ".pdf", new("application/pdf") }, + { ".pfb", new("application/octet-stream") }, + { ".pfm", new("application/octet-stream") }, + { ".pfx", new("application/x-pkcs12") }, + { ".pgm", new("image/x-portable-graymap") }, + { ".pic", new("image/pict") }, + { ".pict", new("image/pict") }, + { ".pkgdef", new("text/plain") }, + { ".pkgundef", new("text/plain") }, + { ".pko", new("application/vnd.ms-pki.pko") }, + { ".pls", new("audio/scpls") }, + { ".pma", new("application/x-perfmon") }, + { ".pmc", new("application/x-perfmon") }, + { ".pml", new("application/x-perfmon") }, + { ".pmr", new("application/x-perfmon") }, + { ".pmw", new("application/x-perfmon") }, + { ".png", new("image/png") }, + { ".pnm", new("image/x-portable-anymap") }, + { ".pnt", new("image/x-macpaint") }, + { ".pntg", new("image/x-macpaint") }, + { ".pnz", new("image/png") }, + { ".pot", new("application/vnd.ms-powerpoint") }, + { ".potm", new("application/vnd.ms-powerpoint.template.macroEnabled.12") }, + { ".potx", new("application/vnd.openxmlformats-officedocument.presentationml.template") }, + { ".ppa", new("application/vnd.ms-powerpoint") }, + { ".ppam", new("application/vnd.ms-powerpoint.addin.macroEnabled.12") }, + { ".ppm", new("image/x-portable-pixmap") }, + { ".pps", new("application/vnd.ms-powerpoint") }, + { ".ppsm", new("application/vnd.ms-powerpoint.slideshow.macroEnabled.12") }, + { ".ppsx", new("application/vnd.openxmlformats-officedocument.presentationml.slideshow") }, + { ".ppt", new("application/vnd.ms-powerpoint") }, + { ".pptm", new("application/vnd.ms-powerpoint.presentation.macroEnabled.12") }, + { ".pptx", new("application/vnd.openxmlformats-officedocument.presentationml.presentation") }, + { ".prf", new("application/pics-rules") }, + { ".prm", new("application/octet-stream") }, + { ".prx", new("application/octet-stream") }, + { ".ps", new("application/postscript") }, + { ".psc1", new("application/PowerShell") }, + { ".psd", new("application/octet-stream") }, + { ".psess", new("application/xml") }, + { ".psm", new("application/octet-stream") }, + { ".psp", new("application/octet-stream") }, + { ".pub", new("application/x-mspublisher") }, + { ".pwz", new("application/vnd.ms-powerpoint") }, + { ".qht", new("text/x-html-insertion") }, + { ".qhtm", new("text/x-html-insertion") }, + { ".qt", new("video/quicktime") }, + { ".qti", new("image/x-quicktime") }, + { ".qtif", new("image/x-quicktime") }, + { ".qtl", new("application/x-quicktimeplayer") }, + { ".qxd", new("application/octet-stream") }, + { ".ra", new("audio/x-pn-realaudio") }, + { ".ram", new("audio/x-pn-realaudio") }, + { ".rar", new("application/x-rar-compressed") }, + { ".ras", new("image/x-cmu-raster") }, + { ".rat", new("application/rat-file") }, + { ".rc", new("text/plain") }, + { ".rc2", new("text/plain") }, + { ".rct", new("text/plain") }, + { ".rdlc", new("application/xml") }, + { ".reg", new("text/plain") }, + { ".resx", new("application/xml") }, + { ".rf", new("image/vnd.rn-realflash") }, + { ".rgb", new("image/x-rgb") }, + { ".rgs", new("text/plain") }, + { ".rm", new("application/vnd.rn-realmedia") }, + { ".rmi", new("audio/mid") }, + { ".rmp", new("application/vnd.rn-rn_music_package") }, + { ".roff", new("application/x-troff") }, + { ".rpm", new("audio/x-pn-realaudio-plugin") }, + { ".rqy", new("text/x-ms-rqy") }, + { ".rtf", new("application/rtf") }, + { ".rtx", new("text/richtext") }, + { ".ruleset", new("application/xml") }, + { ".s", new("text/plain") }, + { ".safariextz", new("application/x-safari-safariextz") }, + { ".scd", new("application/x-msschedule") }, + { ".scr", new("text/plain") }, + { ".sct", new("text/scriptlet") }, + { ".sd2", new("audio/x-sd2") }, + { ".sdp", new("application/sdp") }, + { ".sea", new("application/octet-stream") }, + { ".searchConnector-ms", new("application/windows-search-connector+xml") }, + { ".setpay", new("application/set-payment-initiation") }, + { ".setreg", new("application/set-registration-initiation") }, + { ".settings", new("application/xml") }, + { ".sgimb", new("application/x-sgimb") }, + { ".sgml", new("text/sgml") }, + { ".sh", new("application/x-sh") }, + { ".shar", new("application/x-shar") }, + { ".shtml", new("text/html") }, + { ".sit", new("application/x-stuffit") }, + { ".sitemap", new("application/xml") }, + { ".skin", new("application/xml") }, + { ".sldm", new("application/vnd.ms-powerpoint.slide.macroEnabled.12") }, + { ".sldx", new("application/vnd.openxmlformats-officedocument.presentationml.slide") }, + { ".slk", new("application/vnd.ms-excel") }, + { ".sln", new("text/plain") }, + { ".slupkg-ms", new("application/x-ms-license") }, + { ".smd", new("audio/x-smd") }, + { ".smi", new("application/octet-stream") }, + { ".smx", new("audio/x-smd") }, + { ".smz", new("audio/x-smd") }, + { ".snd", new("audio/basic") }, + { ".snippet", new("application/xml") }, + { ".snp", new("application/octet-stream") }, + { ".sol", new("text/plain") }, + { ".sor", new("text/plain") }, + { ".spc", new("application/x-pkcs7-certificates") }, + { ".spl", new("application/futuresplash") }, + { ".spx", new("audio/ogg") }, + { ".src", new("application/x-wais-source") }, + { ".srf", new("text/plain") }, + { ".SSISDeploymentManifest", new("text/xml") }, + { ".ssm", new("application/streamingmedia") }, + { ".sst", new("application/vnd.ms-pki.certstore") }, + { ".stl", new("application/vnd.ms-pki.stl") }, + { ".sv4cpio", new("application/x-sv4cpio") }, + { ".sv4crc", new("application/x-sv4crc") }, + { ".svc", new("application/xml") }, + { ".svg", new("image/svg+xml") }, + { ".swf", new("application/x-shockwave-flash") }, + { ".step", new("application/step") }, + { ".stp", new("application/step") }, + { ".t", new("application/x-troff") }, + { ".tar", new("application/x-tar") }, + { ".tcl", new("application/x-tcl") }, + { ".testrunconfig", new("application/xml") }, + { ".testsettings", new("application/xml") }, + { ".tex", new("application/x-tex") }, + { ".texi", new("application/x-texinfo") }, + { ".texinfo", new("application/x-texinfo") }, + { ".tgz", new("application/x-compressed") }, + { ".thmx", new("application/vnd.ms-officetheme") }, + { ".thn", new("application/octet-stream") }, + { ".tif", new("image/tiff") }, + { ".tiff", new("image/tiff") }, + { ".tlh", new("text/plain") }, + { ".tli", new("text/plain") }, + { ".toc", new("application/octet-stream") }, + { ".tr", new("application/x-troff") }, + { ".trm", new("application/x-msterminal") }, + { ".trx", new("application/xml") }, + { ".ts", new("video/vnd.dlna.mpeg-tts") }, + { ".tsv", new("text/tab-separated-values") }, + { ".ttf", new("application/font-sfnt") }, + { ".tts", new("video/vnd.dlna.mpeg-tts") }, + { ".txt", new("text/plain") }, + { ".u32", new("application/octet-stream") }, + { ".uls", new("text/iuls") }, + { ".user", new("text/plain") }, + { ".ustar", new("application/x-ustar") }, + { ".vb", new("text/plain") }, + { ".vbdproj", new("text/plain") }, + { ".vbk", new("video/mpeg") }, + { ".vbproj", new("text/plain") }, + { ".vbs", new("text/vbscript") }, + { ".vcf", new("text/x-vcard") }, + { ".vcproj", new("application/xml") }, + { ".vcs", new("text/plain") }, + { ".vcxproj", new("application/xml") }, + { ".vddproj", new("text/plain") }, + { ".vdp", new("text/plain") }, + { ".vdproj", new("text/plain") }, + { ".vdx", new("application/vnd.ms-visio.viewer") }, + { ".vml", new("text/xml") }, + { ".vscontent", new("application/xml") }, + { ".vsct", new("text/xml") }, + { ".vsd", new("application/vnd.visio") }, + { ".vsi", new("application/ms-vsi") }, + { ".vsix", new("application/vsix") }, + { ".vsixlangpack", new("text/xml") }, + { ".vsixmanifest", new("text/xml") }, + { ".vsmdi", new("application/xml") }, + { ".vspscc", new("text/plain") }, + { ".vss", new("application/vnd.visio") }, + { ".vsscc", new("text/plain") }, + { ".vssettings", new("text/xml") }, + { ".vssscc", new("text/plain") }, + { ".vst", new("application/vnd.visio") }, + { ".vstemplate", new("text/xml") }, + { ".vsto", new("application/x-ms-vsto") }, + { ".vsw", new("application/vnd.visio") }, + { ".vsx", new("application/vnd.visio") }, + { ".vtx", new("application/vnd.visio") }, + { ".wav", new("audio/wav") }, + { ".wave", new("audio/wav") }, + { ".wax", new("audio/x-ms-wax") }, + { ".wbk", new("application/msword") }, + { ".wbmp", new("image/vnd.wap.wbmp") }, + { ".wcm", new("application/vnd.ms-works") }, + { ".wdb", new("application/vnd.ms-works") }, + { ".wdp", new("image/vnd.ms-photo") }, + { ".webarchive", new("application/x-safari-webarchive") }, + { ".webm", new("video/webm") }, + { ".webp", new("image/webp") }, /* https://en.wikipedia.org/wiki/WebP */ + { ".webtest", new("application/xml") }, + { ".wiq", new("application/xml") }, + { ".wiz", new("application/msword") }, + { ".wks", new("application/vnd.ms-works") }, + { ".WLMP", new("application/wlmoviemaker") }, + { ".wlpginstall", new("application/x-wlpg-detect") }, + { ".wlpginstall3", new("application/x-wlpg3-detect") }, + { ".wm", new("video/x-ms-wm") }, + { ".wma", new("audio/x-ms-wma") }, + { ".wmd", new("application/x-ms-wmd") }, + { ".wmf", new("application/x-msmetafile") }, + { ".wml", new("text/vnd.wap.wml") }, + { ".wmlc", new("application/vnd.wap.wmlc") }, + { ".wmls", new("text/vnd.wap.wmlscript") }, + { ".wmlsc", new("application/vnd.wap.wmlscriptc") }, + { ".wmp", new("video/x-ms-wmp") }, + { ".wmv", new("video/x-ms-wmv") }, + { ".wmx", new("video/x-ms-wmx") }, + { ".wmz", new("application/x-ms-wmz") }, + { ".woff", new("application/font-woff") }, + { ".wpl", new("application/vnd.ms-wpl") }, + { ".wps", new("application/vnd.ms-works") }, + { ".wri", new("application/x-mswrite") }, + { ".wrl", new("x-world/x-vrml") }, + { ".wrz", new("x-world/x-vrml") }, + { ".wsc", new("text/scriptlet") }, + { ".wsdl", new("text/xml") }, + { ".wvx", new("video/x-ms-wvx") }, + { ".x", new("application/directx") }, + { ".xaf", new("x-world/x-vrml") }, + { ".xaml", new("application/xaml+xml") }, + { ".xap", new("application/x-silverlight-app") }, + { ".xbap", new("application/x-ms-xbap") }, + { ".xbm", new("image/x-xbitmap") }, + { ".xdr", new("text/plain") }, + { ".xht", new("application/xhtml+xml") }, + { ".xhtml", new("application/xhtml+xml") }, + { ".xla", new("application/vnd.ms-excel") }, + { ".xlam", new("application/vnd.ms-excel.addin.macroEnabled.12") }, + { ".xlc", new("application/vnd.ms-excel") }, + { ".xld", new("application/vnd.ms-excel") }, + { ".xlk", new("application/vnd.ms-excel") }, + { ".xll", new("application/vnd.ms-excel") }, + { ".xlm", new("application/vnd.ms-excel") }, + { ".xls", new("application/vnd.ms-excel") }, + { ".xlsb", new("application/vnd.ms-excel.sheet.binary.macroEnabled.12") }, + { ".xlsm", new("application/vnd.ms-excel.sheet.macroEnabled.12") }, + { ".xlsx", new("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") }, + { ".xlt", new("application/vnd.ms-excel") }, + { ".xltm", new("application/vnd.ms-excel.template.macroEnabled.12") }, + { ".xltx", new("application/vnd.openxmlformats-officedocument.spreadsheetml.template") }, + { ".xlw", new("application/vnd.ms-excel") }, + { ".xml", new("application/xml", "text/xml") }, + { ".xmta", new("application/xml") }, + { ".xof", new("x-world/x-vrml") }, + { ".XOML", new("text/plain") }, + { ".xpm", new("image/x-xpixmap") }, + { ".xps", new("application/vnd.ms-xpsdocument") }, + { ".xrm-ms", new("text/xml") }, + { ".xsc", new("application/xml") }, + { ".xsd", new("text/xml") }, + { ".xsf", new("text/xml") }, + { ".xsl", new("text/xml") }, + { ".xslt", new("text/xml") }, + { ".xsn", new("application/octet-stream") }, + { ".xss", new("application/xml") }, + { ".xspf", new("application/xspf+xml") }, + { ".xtp", new("application/octet-stream") }, + { ".xwd", new("image/x-xwindowdump") }, + { ".z", new("application/x-compress") }, + { ".zip", new("application/zip", "application/x-zip-compressed", "application/zip-compressed") } + #endregion }; - var cache = mappings.ToList(); // need ToList() to avoid modifying while still enumerating - - foreach (var mapping in cache) - { - if (!mappings.ContainsKey(mapping.Value)) - { - mappings.Add(mapping.Value, mapping.Key); - } - } - return mappings; } @@ -694,11 +639,11 @@ private static IDictionary BuildMappings() /// /// the file extension /// The mime type - public static string GetMimeType(string extension) + public static MimeType GetMimeType(string extension) { if (extension == null) { - throw new ArgumentNullException("extension"); + throw new ArgumentNullException(nameof(extension)); } if (!extension.StartsWith(".")) @@ -706,32 +651,7 @@ public static string GetMimeType(string extension) extension = "." + extension; } - return _mappings.Value.TryGetValue(extension, out string? mime) ? mime : "application/octet-stream"; - } - - /// - /// Get the file extension based on the mime type - /// - /// the mime type of the file - /// The file extention based on the mime type - public static string GetExtension(string mimeType) - { - if (mimeType == null) - { - throw new ArgumentNullException("mimeType"); - } - - if (mimeType.StartsWith(".")) - { - throw new ArgumentException("Requested mime type is not valid: " + mimeType); - } - - if (_mappings.Value.TryGetValue(mimeType, out string? extension)) - { - return extension; - } - - throw new ArgumentException("Requested mime type is not registered: " + mimeType); + return _mappings.Value.TryGetValue(extension, out MimeType? mime) ? mime : new MimeType("application/octet-stream"); } } } diff --git a/src/Altinn.App.Core/Models/MimeType.cs b/src/Altinn.App.Core/Models/MimeType.cs new file mode 100644 index 000000000..6f3e25d52 --- /dev/null +++ b/src/Altinn.App.Core/Models/MimeType.cs @@ -0,0 +1,91 @@ +using System.Collections; +using Microsoft.Extensions.Primitives; + +namespace Altinn.App.Core.Models; + +/// +/// MimeType class for handling mime types and aliases +/// +public class MimeType +{ + /// + /// The mime type + /// + public string Type { get; } + /// + /// The aliases for the mime type + /// + public IEnumerable Aliases { get; } + + /// + /// Create a new instance of + /// + /// The mime type + /// The aliases for the mime type + public MimeType(string type, params string[] aliases) + { + Type = type; + Aliases = aliases; + } + + /// + /// Check if the mime type matches the given string + /// + /// String representation of the mime type + /// to use for checking equality to type. Default: + /// to use for checking equality to aliases. Default: + /// true if type or any aliases matches the string in mimeType + public bool IsMatch(string mimeType, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase, IEqualityComparer? comparer = null) + { + if (Type.Equals(mimeType, comparisonType)) + { + return true; + } + + return Aliases.Contains(mimeType, comparer ?? StringComparer.InvariantCultureIgnoreCase); + } + + /// + /// Returns the string representation of the mime type + /// + /// + public override string ToString() + { + return Type; + } + + /// + /// Check if the mime type matches the given object + /// + /// + /// + private bool Equals(MimeType? other) + { + return other != null && Type == other.Type && Aliases.SequenceEqual(other.Aliases); + } + + + /// + /// Check if the mime type matches the given object + /// Supported types are: + /// + /// + /// + /// + /// The object to check for equality against. See list of supported types + /// to use for checking equality to type. Default: + /// to use for checking equality to aliases. Default: + /// true if type or any aliases matches + public bool Equals(object? obj, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase, IEqualityComparer? comparer = null) + { + if (obj is null) return false; + + return obj switch + { + string s => IsMatch(s, comparisonType, comparer), + StringValues s => IsMatch(s.ToString(), comparisonType, comparer), + MimeType m => Equals(m), + _ => false + }; + } +} \ No newline at end of file diff --git a/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs b/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs new file mode 100644 index 000000000..7c39c8b47 --- /dev/null +++ b/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs @@ -0,0 +1,70 @@ +using Altinn.App.Core.Helpers; +using Altinn.App.Core.Models; +using FluentAssertions; +using Xunit; + +namespace Altinn.App.Core.Tests.Helpers; + +public class MimeTypeMapTests +{ + [Fact] + public void GetMimeType_ShouldReturnCorrectMimeType_for_pdf() + { + // Arrange + string extension = ".pdf"; + + // Act + var mimeType = MimeTypeMap.GetMimeType(extension); + + // Assert + mimeType.ToString().Should().BeEquivalentTo("application/pdf"); + } + + [Fact] + public void GetMimeType_ShouldReturnCorrectMimeType_for_pdf_without_leading_dot() + { + // Arrange + string extension = "pdf"; + + // Act + var mimeType = MimeTypeMap.GetMimeType(extension); + + // Assert + mimeType.ToString().Should().BeEquivalentTo("application/pdf"); + } + + [Fact] + public void GetMimeType_ShouldReturnCorrectMimeType_for_zip() + { + // Arrange + string extension = ".zip"; + + // Act + var mimeType = MimeTypeMap.GetMimeType(extension); + + // Assert + mimeType.ToString().Should().BeEquivalentTo("application/zip"); + } + + [Fact] + public void GetMimeType_ShouldReturnCorrectMimeType_matching_x_zip_compressed() + { + // Arrange + string extension = ".zip"; + + // Act + var mimeType = MimeTypeMap.GetMimeType(extension); + + // Assert + mimeType.IsMatch("application/zip").Should().BeTrue(); + mimeType.IsMatch("application/x-zip-compressed").Should().BeTrue(); + mimeType.IsMatch("application/pdf").Should().BeFalse(); + } + + [Fact] + public void GetMimeType_throws_ArgumentNullException_if_extension_null() + { + Action act = () => MimeTypeMap.GetMimeType(null); + act.Should().Throw(); + } +} diff --git a/test/Altinn.App.Core.Tests/Models/MimeTypeTests.cs b/test/Altinn.App.Core.Tests/Models/MimeTypeTests.cs new file mode 100644 index 000000000..fb74878e6 --- /dev/null +++ b/test/Altinn.App.Core.Tests/Models/MimeTypeTests.cs @@ -0,0 +1,72 @@ +using Altinn.App.Core.Models; +using FluentAssertions; +using Microsoft.Extensions.Primitives; +using Xunit; + +namespace Altinn.App.Core.Tests.Models; + +public class MimeTypeTests +{ + [Fact] + public void Equals_matches_string_to_type() + { + var mimeType = new MimeType("application/pdf"); + mimeType.Equals("application/pdf").Should().BeTrue(); + } + + [Fact] + public void Equals_not_matches_string_to_type_no_aliases() + { + var mimeType = new MimeType("application/pdf"); + mimeType.Equals("application/zip").Should().BeFalse(); + } + + [Fact] + public void Equals_matches_string_to_alias() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals("application/x-zip-compressed").Should().BeTrue(); + } + + [Fact] + public void Equals_matches_stringvalues_to_type() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(new StringValues("application/zip")).Should().BeTrue(); + } + + [Fact] + public void Equals_matches_mimetype_when_type_and_alias_equal() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(new MimeType("application/zip", "application/x-zip-compressed")).Should().BeTrue(); + } + + [Fact] + public void Equals_not_matches_mimetype_when_type_not_equal() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(new MimeType("application/x-zip-compressed", "application/x-zip-compressed")).Should().BeFalse(); + } + + [Fact] + public void Equals_not_matches_mimetype_when_alias_not_equal() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(new MimeType("application/zip")).Should().BeFalse(); + } + + [Fact] + public void Equals_returns_false_when_object_is_null() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(null).Should().BeFalse(); + } + + [Fact] + public void Equals_returns_false_when_unknown_object() + { + var mimeType = new MimeType("application/zip", "application/x-zip-compressed"); + mimeType.Equals(1).Should().BeFalse(); + } +} \ No newline at end of file From 91e84a74fea8200f34f6c80c69ec5e07d923a361 Mon Sep 17 00:00:00 2001 From: Vemund Gaukstad Date: Sat, 26 Aug 2023 08:52:57 +0200 Subject: [PATCH 2/4] Test to cover case where fileextension not found in map --- test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs b/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs index 7c39c8b47..78b330014 100644 --- a/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs +++ b/test/Altinn.App.Core.Tests/Helpers/MimeTypeMapTests.cs @@ -67,4 +67,11 @@ public void GetMimeType_throws_ArgumentNullException_if_extension_null() Action act = () => MimeTypeMap.GetMimeType(null); act.Should().Throw(); } + + [Fact] + public void GetMimeType_returns_octetstream_for_unknown_fileextension() + { + var mimetype = MimeTypeMap.GetMimeType(".unknown"); + mimetype.Should().BeEquivalentTo(new MimeType("application/octet-stream")); + } } From 0b1f25fce468290c65da38140f61bcc3cfdaa6d9 Mon Sep 17 00:00:00 2001 From: Vemund Gaukstad Date: Sat, 26 Aug 2023 08:54:43 +0200 Subject: [PATCH 3/4] remove misleading comment --- src/Altinn.App.Core/Helpers/MimeTypeMap.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Altinn.App.Core/Helpers/MimeTypeMap.cs b/src/Altinn.App.Core/Helpers/MimeTypeMap.cs index c5feb65f1..a05e9de1f 100644 --- a/src/Altinn.App.Core/Helpers/MimeTypeMap.cs +++ b/src/Altinn.App.Core/Helpers/MimeTypeMap.cs @@ -3,7 +3,7 @@ namespace Altinn.App.Core.Helpers { /// - /// MimeTypeMap from https://github.com/samuelneff/MimeTypeMap + /// MimeTypeMap based on https://github.com/samuelneff/MimeTypeMap /// public static class MimeTypeMap { @@ -15,21 +15,6 @@ private static IDictionary BuildMappings() { #region Big freaking list of mime types - // maps both ways, - // extension -> mime type - // and - // mime type -> extension - // - // any mime types on left side not pre-loaded on right side, are added automatically - // some mime types can map to multiple extensions, so to get a deterministic mapping, - // add those to the dictionary specifcially - // - // combination of values from Windows 7 Registry and - // from C:\Windows\System32\inetsrv\config\applicationHost.config - // some added, including .7z and .dat - // - // Some added based on http://www.iana.org/assignments/media-types/media-types.xhtml - // which lists mime types, but not extensions { ".323", new("text/h323") }, { ".3g2", new("video/3gpp2") }, { ".3gp", new("video/3gpp", "audio/3gpp") }, From b145e1214434c0b8368d21730e79d1429d613e29 Mon Sep 17 00:00:00 2001 From: Vemund Gaukstad Date: Sat, 26 Aug 2023 08:56:51 +0200 Subject: [PATCH 4/4] Fix codeQL warning --- src/Altinn.App.Core/Models/MimeType.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Altinn.App.Core/Models/MimeType.cs b/src/Altinn.App.Core/Models/MimeType.cs index 6f3e25d52..598170c7d 100644 --- a/src/Altinn.App.Core/Models/MimeType.cs +++ b/src/Altinn.App.Core/Models/MimeType.cs @@ -59,7 +59,7 @@ public override string ToString() /// /// /// - private bool Equals(MimeType? other) + private bool MimeTypeEquals(MimeType? other) { return other != null && Type == other.Type && Aliases.SequenceEqual(other.Aliases); } @@ -84,7 +84,7 @@ public bool Equals(object? obj, StringComparison comparisonType = StringComparis { string s => IsMatch(s, comparisonType, comparer), StringValues s => IsMatch(s.ToString(), comparisonType, comparer), - MimeType m => Equals(m), + MimeType m => MimeTypeEquals(m), _ => false }; }