| // Copyright (c) 2016 The Rouille developers |
| // Licensed under the Apache License, Version 2.0 |
| // <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT |
| // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, |
| // at your option. All files in the project carrying such |
| // notice may not be copied, modified, or distributed except |
| // according to those terms. |
| |
| use std::fs; |
| use std::path::Path; |
| |
| use filetime; |
| use time; |
| |
| use Request; |
| use Response; |
| |
| /// Searches inside `path` for a file that matches the given request. If a file is found, |
| /// returns a `Response` that would serve this file if returned. If no file is found, a 404 |
| /// response is returned instead. |
| /// |
| /// The value of the `Content-Type` header of the response is guessed based on the file's |
| /// extension. If you wish so, you can modify that `Content-Type` by modifying the `Response` |
| /// object returned by this function. |
| /// |
| /// # Example |
| /// |
| /// In this example, a request made for example to `/test.txt` will return the file |
| /// `public/test.txt` (relative to the current working directory, which is usually the location |
| /// of the `Cargo.toml`) if it exists. |
| /// |
| /// ```no_run |
| /// rouille::start_server("localhost:8000", move |request| { |
| /// let response = rouille::match_assets(&request, "public"); |
| /// if response.is_success() { |
| /// return response; |
| /// } |
| /// |
| /// // ... |
| /// # panic!() |
| /// }); |
| /// ``` |
| /// |
| /// # Security |
| /// |
| /// Everything inside the directory that you pass as `path` is potentially accessible by any |
| /// client. **Do not use assume that client won't be able to guess the URL of a sensitive file**. |
| /// All sensitive files should require a login/password to be accessed. |
| /// |
| /// If you want to serve sensitive files, you are encouraged to put them in a different directory |
| /// than public files, and call `match_assets` once for public files and once for private files |
| /// after you checked the user's credentials. |
| /// Only call `match_assets` **after** you know that the user can have access to all the files |
| /// that can be served. |
| /// |
| /// If you manage the user's accesses per-file, use a white list of authorized files instead of a |
| /// black list of forbidden files. Files can potentially be accessed from multiple different URLs |
| /// and a black list may not cover everything. |
| /// |
| /// # Example with prefix |
| /// |
| /// Sometimes you want to add a prefix to the URL of your static files. To do that, you can use |
| /// the `remove_prefix` method on `Request`. |
| /// |
| /// ```no_run |
| /// rouille::start_server("localhost:8000", move |request| { |
| /// if let Some(request) = request.remove_prefix("/static") { |
| /// return rouille::match_assets(&request, "public"); |
| /// } |
| /// |
| /// // ... |
| /// # panic!() |
| /// }); |
| /// ``` |
| /// |
| /// In this example, a request made to `/static/test.txt` will return the file |
| /// `public/test.txt` if it exists. |
| /// |
| pub fn match_assets<P: ?Sized>(request: &Request, path: &P) -> Response |
| where P: AsRef<Path> |
| { |
| let path = path.as_ref(); |
| let path = match path.canonicalize() { |
| Ok(p) => p, |
| Err(_) => return Response::empty_404(), |
| }; |
| |
| // The potential location of the file on the disk. |
| let potential_file = { |
| let mut path = path.to_path_buf(); |
| for component in request.url().split('/') { |
| path.push(component); |
| } |
| path |
| }; |
| |
| // We try to canonicalize the file. If this fails, then the file doesn't exist. |
| let potential_file = match potential_file.canonicalize() { |
| Ok(f) => f, |
| Err(_) => return Response::empty_404(), |
| }; |
| |
| // Check that we're still within `path`. This should eliminate security issues with |
| // requests like `GET /../private_file`. |
| if !potential_file.starts_with(path) { |
| return Response::empty_404(); |
| } |
| |
| // Check that it's a file and not a directory. |
| match fs::metadata(&potential_file) { |
| Ok(ref m) if m.is_file() => (), |
| _ => return Response::empty_404(), |
| }; |
| |
| let extension = potential_file.extension().and_then(|s| s.to_str()); |
| |
| let file = match fs::File::open(&potential_file) { |
| Ok(f) => f, |
| Err(_) => return Response::empty_404(), |
| }; |
| |
| let etag: String = (fs::metadata(&potential_file) |
| .map(|meta| filetime::FileTime::from_last_modification_time(&meta).unix_seconds() as u64) |
| .unwrap_or(time::now().tm_nsec as u64) |
| ^ 0xd3f4_0305_c9f8_e911_u64).to_string(); |
| |
| Response::from_file(extension_to_mime_impl(extension), file) |
| .with_etag(request, etag) |
| .with_public_cache(3600) // TODO: is this a good idea? what if the file is private? |
| } |
| |
| /// Returns the mime type of a file based on its extension, or `application/octet-stream` if the |
| /// extension is unknown. |
| #[inline] |
| pub fn extension_to_mime(extension: &str) -> &'static str { |
| extension_to_mime_impl(Some(extension)) |
| } |
| |
| /// Returns the mime type of a file based on its extension. |
| fn extension_to_mime_impl(extension: Option<&str>) -> &'static str { |
| // List taken from https://github.com/cybergeek94/mime_guess/blob/master/src/mime_types.rs, |
| // itself taken from a dead link. |
| match extension { |
| Some("323") => "text/h323; charset=utf8", |
| Some("3g2") => "video/3gpp2", |
| Some("3gp") => "video/3gpp", |
| Some("3gp2") => "video/3gpp2", |
| Some("3gpp") => "video/3gpp", |
| Some("7z") => "application/x-7z-compressed", |
| Some("aa") => "audio/audible", |
| Some("aac") => "audio/aac", |
| Some("aaf") => "application/octet-stream", |
| Some("aax") => "audio/vnd.audible.aax", |
| Some("ac3") => "audio/ac3", |
| Some("aca") => "application/octet-stream", |
| Some("accda") => "application/msaccess.addin", |
| Some("accdb") => "application/msaccess", |
| Some("accdc") => "application/msaccess.cab", |
| Some("accde") => "application/msaccess", |
| Some("accdr") => "application/msaccess.runtime", |
| Some("accdt") => "application/msaccess", |
| Some("accdw") => "application/msaccess.webapplication", |
| Some("accft") => "application/msaccess.ftemplate", |
| Some("acx") => "application/internet-property-stream", |
| Some("addin") => "application/xml", |
| Some("ade") => "application/msaccess", |
| Some("adobebridge") => "application/x-bridge-url", |
| Some("adp") => "application/msaccess", |
| Some("adt") => "audio/vnd.dlna.adts", |
| Some("adts") => "audio/aac", |
| Some("afm") => "application/octet-stream", |
| Some("ai") => "application/postscript", |
| Some("aif") => "audio/x-aiff", |
| Some("aifc") => "audio/aiff", |
| Some("aiff") => "audio/aiff", |
| Some("air") => "application/vnd.adobe.air-application-installer-package+zip", |
| Some("amc") => "application/x-mpeg", |
| Some("application") => "application/x-ms-application", |
| Some("art") => "image/x-jg", |
| Some("asa") => "application/xml", |
| Some("asax") => "application/xml", |
| Some("ascx") => "application/xml", |
| Some("asd") => "application/octet-stream", |
| Some("asf") => "video/x-ms-asf", |
| Some("ashx") => "application/xml", |
| Some("asi") => "application/octet-stream", |
| Some("asm") => "text/plain; charset=utf8", |
| Some("asmx") => "application/xml", |
| Some("aspx") => "application/xml", |
| Some("asr") => "video/x-ms-asf", |
| Some("asx") => "video/x-ms-asf", |
| Some("atom") => "application/atom+xml", |
| Some("au") => "audio/basic", |
| Some("avi") => "video/x-msvideo", |
| Some("axs") => "application/olescript", |
| Some("bas") => "text/plain; charset=utf8", |
| Some("bcpio") => "application/x-bcpio", |
| Some("bin") => "application/octet-stream", |
| Some("bmp") => "image/bmp", |
| Some("c") => "text/plain; charset=utf8", |
| Some("cab") => "application/octet-stream", |
| Some("caf") => "audio/x-caf", |
| Some("calx") => "application/vnd.ms-office.calx", |
| Some("cat") => "application/vnd.ms-pki.seccat", |
| Some("cc") => "text/plain; charset=utf8", |
| Some("cd") => "text/plain; charset=utf8", |
| Some("cdda") => "audio/aiff", |
| Some("cdf") => "application/x-cdf", |
| Some("cer") => "application/x-x509-ca-cert", |
| Some("chm") => "application/octet-stream", |
| Some("class") => "application/x-java-applet", |
| Some("clp") => "application/x-msclip", |
| Some("cmx") => "image/x-cmx", |
| Some("cnf") => "text/plain; charset=utf8", |
| Some("cod") => "image/cis-cod", |
| Some("config") => "application/xml", |
| Some("contact") => "text/x-ms-contact; charset=utf8", |
| Some("coverage") => "application/xml", |
| Some("cpio") => "application/x-cpio", |
| Some("cpp") => "text/plain; charset=utf8", |
| Some("crd") => "application/x-mscardfile", |
| Some("crl") => "application/pkix-crl", |
| Some("crt") => "application/x-x509-ca-cert", |
| Some("cs") => "text/plain; charset=utf8", |
| Some("csdproj") => "text/plain; charset=utf8", |
| Some("csh") => "application/x-csh", |
| Some("csproj") => "text/plain; charset=utf8", |
| Some("css") => "text/css; charset=utf8", |
| Some("csv") => "text/csv; charset=utf8", |
| Some("cur") => "application/octet-stream", |
| Some("cxx") => "text/plain; charset=utf8", |
| Some("dat") => "application/octet-stream", |
| Some("datasource") => "application/xml", |
| Some("dbproj") => "text/plain; charset=utf8", |
| Some("dcr") => "application/x-director", |
| Some("def") => "text/plain; charset=utf8", |
| Some("deploy") => "application/octet-stream", |
| Some("der") => "application/x-x509-ca-cert", |
| Some("dgml") => "application/xml", |
| Some("dib") => "image/bmp", |
| Some("dif") => "video/x-dv", |
| Some("dir") => "application/x-director", |
| Some("disco") => "application/xml", |
| Some("dll") => "application/x-msdownload", |
| Some("dll.config") => "application/xml", |
| Some("dlm") => "text/dlm; charset=utf8", |
| Some("doc") => "application/msword", |
| Some("docm") => "application/vnd.ms-word.document.macroEnabled.12", |
| Some("docx") => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
| Some("dot") => "application/msword", |
| Some("dotm") => "application/vnd.ms-word.template.macroEnabled.12", |
| Some("dotx") => "application/vnd.openxmlformats-officedocument.wordprocessingml.template", |
| Some("dsp") => "application/octet-stream", |
| Some("dsw") => "text/plain; charset=utf8", |
| Some("dtd") => "application/xml", |
| Some("dtsConfig") => "application/xml", |
| Some("dv") => "video/x-dv", |
| Some("dvi") => "application/x-dvi", |
| Some("dwf") => "drawing/x-dwf", |
| Some("dwp") => "application/octet-stream", |
| Some("dxr") => "application/x-director", |
| Some("eml") => "message/rfc822", |
| Some("emz") => "application/octet-stream", |
| Some("eot") => "application/vnd.ms-fontobject", |
| Some("eps") => "application/postscript", |
| Some("etl") => "application/etl", |
| Some("etx") => "text/x-setext; charset=utf8", |
| Some("evy") => "application/envoy", |
| Some("exe") => "application/octet-stream", |
| Some("exe.config") => "application/xml", |
| Some("fdf") => "application/vnd.fdf", |
| Some("fif") => "application/fractals", |
| Some("filters") => "Application/xml", |
| Some("fla") => "application/octet-stream", |
| Some("flr") => "x-world/x-vrml", |
| Some("flv") => "video/x-flv", |
| Some("fsscript") => "application/fsharp-script", |
| Some("fsx") => "application/fsharp-script", |
| Some("generictest") => "application/xml", |
| Some("gif") => "image/gif", |
| Some("group") => "text/x-ms-group; charset=utf8", |
| Some("gsm") => "audio/x-gsm", |
| Some("gtar") => "application/x-gtar", |
| Some("gz") => "application/x-gzip", |
| Some("h") => "text/plain; charset=utf8", |
| Some("hdf") => "application/x-hdf", |
| Some("hdml") => "text/x-hdml; charset=utf8", |
| Some("hhc") => "application/x-oleobject", |
| Some("hhk") => "application/octet-stream", |
| Some("hhp") => "application/octet-stream", |
| Some("hlp") => "application/winhlp", |
| Some("hpp") => "text/plain; charset=utf8", |
| Some("hqx") => "application/mac-binhex40", |
| Some("hta") => "application/hta", |
| Some("htc") => "text/x-component; charset=utf8", |
| Some("htm") => "text/html; charset=utf8", |
| Some("html") => "text/html; charset=utf8", |
| Some("htt") => "text/webviewhtml; charset=utf8", |
| Some("hxa") => "application/xml", |
| Some("hxc") => "application/xml", |
| Some("hxd") => "application/octet-stream", |
| Some("hxe") => "application/xml", |
| Some("hxf") => "application/xml", |
| Some("hxh") => "application/octet-stream", |
| Some("hxi") => "application/octet-stream", |
| Some("hxk") => "application/xml", |
| Some("hxq") => "application/octet-stream", |
| Some("hxr") => "application/octet-stream", |
| Some("hxs") => "application/octet-stream", |
| Some("hxt") => "text/html; charset=utf8", |
| Some("hxv") => "application/xml", |
| Some("hxw") => "application/octet-stream", |
| Some("hxx") => "text/plain; charset=utf8", |
| Some("i") => "text/plain; charset=utf8", |
| Some("ico") => "image/x-icon", |
| Some("ics") => "application/octet-stream", |
| Some("idl") => "text/plain; charset=utf8", |
| Some("ief") => "image/ief", |
| Some("iii") => "application/x-iphone", |
| Some("inc") => "text/plain; charset=utf8", |
| Some("inf") => "application/octet-stream", |
| Some("inl") => "text/plain; charset=utf8", |
| Some("ins") => "application/x-internet-signup", |
| Some("ipa") => "application/x-itunes-ipa", |
| Some("ipg") => "application/x-itunes-ipg", |
| Some("ipproj") => "text/plain; charset=utf8", |
| Some("ipsw") => "application/x-itunes-ipsw", |
| Some("iqy") => "text/x-ms-iqy; charset=utf8", |
| Some("isp") => "application/x-internet-signup", |
| Some("ite") => "application/x-itunes-ite", |
| Some("itlp") => "application/x-itunes-itlp", |
| Some("itms") => "application/x-itunes-itms", |
| Some("itpc") => "application/x-itunes-itpc", |
| Some("ivf") => "video/x-ivf", |
| Some("jar") => "application/java-archive", |
| Some("java") => "application/octet-stream", |
| Some("jck") => "application/liquidmotion", |
| Some("jcz") => "application/liquidmotion", |
| Some("jfif") => "image/pjpeg", |
| Some("jnlp") => "application/x-java-jnlp-file", |
| Some("jpb") => "application/octet-stream", |
| Some("jpe") => "image/jpeg", |
| Some("jpeg") => "image/jpeg", |
| Some("jpg") => "image/jpeg", |
| Some("js") => "application/javascript", |
| Some("json") => "application/json", |
| Some("jsx") => "text/jscript; charset=utf8", |
| Some("jsxbin") => "text/plain; charset=utf8", |
| Some("latex") => "application/x-latex", |
| Some("library-ms") => "application/windows-library+xml", |
| Some("lit") => "application/x-ms-reader", |
| Some("loadtest") => "application/xml", |
| Some("lpk") => "application/octet-stream", |
| Some("lsf") => "video/x-la-asf", |
| Some("lst") => "text/plain; charset=utf8", |
| Some("lsx") => "video/x-la-asf", |
| Some("lzh") => "application/octet-stream", |
| Some("m13") => "application/x-msmediaview", |
| Some("m14") => "application/x-msmediaview", |
| Some("m1v") => "video/mpeg", |
| Some("m2t") => "video/vnd.dlna.mpeg-tts", |
| Some("m2ts") => "video/vnd.dlna.mpeg-tts", |
| Some("m2v") => "video/mpeg", |
| Some("m3u") => "audio/x-mpegurl", |
| Some("m3u8") => "audio/x-mpegurl", |
| Some("m4a") => "audio/m4a", |
| Some("m4b") => "audio/m4b", |
| Some("m4p") => "audio/m4p", |
| Some("m4r") => "audio/x-m4r", |
| Some("m4v") => "video/x-m4v", |
| Some("mac") => "image/x-macpaint", |
| Some("mak") => "text/plain; charset=utf8", |
| Some("man") => "application/x-troff-man", |
| Some("manifest") => "application/x-ms-manifest", |
| Some("map") => "text/plain; charset=utf8", |
| Some("master") => "application/xml", |
| Some("mda") => "application/msaccess", |
| Some("mdb") => "application/x-msaccess", |
| Some("mde") => "application/msaccess", |
| Some("mdp") => "application/octet-stream", |
| Some("me") => "application/x-troff-me", |
| Some("mfp") => "application/x-shockwave-flash", |
| Some("mht") => "message/rfc822", |
| Some("mhtml") => "message/rfc822", |
| Some("mid") => "audio/mid", |
| Some("midi") => "audio/mid", |
| Some("mix") => "application/octet-stream", |
| Some("mk") => "text/plain; charset=utf8", |
| Some("mmf") => "application/x-smaf", |
| Some("mno") => "application/xml", |
| Some("mny") => "application/x-msmoney", |
| Some("mod") => "video/mpeg", |
| Some("mov") => "video/quicktime", |
| Some("movie") => "video/x-sgi-movie", |
| Some("mp2") => "video/mpeg", |
| Some("mp2v") => "video/mpeg", |
| Some("mp3") => "audio/mpeg", |
| Some("mp4") => "video/mp4", |
| Some("mp4v") => "video/mp4", |
| Some("mpa") => "video/mpeg", |
| Some("mpe") => "video/mpeg", |
| Some("mpeg") => "video/mpeg", |
| Some("mpf") => "application/vnd.ms-mediapackage", |
| Some("mpg") => "video/mpeg", |
| Some("mpp") => "application/vnd.ms-project", |
| Some("mpv2") => "video/mpeg", |
| Some("mqv") => "video/quicktime", |
| Some("ms") => "application/x-troff-ms", |
| Some("msi") => "application/octet-stream", |
| Some("mso") => "application/octet-stream", |
| Some("mts") => "video/vnd.dlna.mpeg-tts", |
| Some("mtx") => "application/xml", |
| Some("mvb") => "application/x-msmediaview", |
| Some("mvc") => "application/x-miva-compiled", |
| Some("mxp") => "application/x-mmxp", |
| Some("nc") => "application/x-netcdf", |
| Some("nsc") => "video/x-ms-asf", |
| Some("nws") => "message/rfc822", |
| Some("ocx") => "application/octet-stream", |
| Some("oda") => "application/oda", |
| Some("odc") => "text/x-ms-odc; charset=utf8", |
| Some("odh") => "text/plain; charset=utf8", |
| Some("odl") => "text/plain; charset=utf8", |
| Some("odp") => "application/vnd.oasis.opendocument.presentation", |
| Some("ods") => "application/oleobject", |
| Some("odt") => "application/vnd.oasis.opendocument.text", |
| Some("ogg") => "application/ogg", |
| Some("one") => "application/onenote", |
| Some("onea") => "application/onenote", |
| Some("onepkg") => "application/onenote", |
| Some("onetmp") => "application/onenote", |
| Some("onetoc") => "application/onenote", |
| Some("onetoc2") => "application/onenote", |
| Some("orderedtest") => "application/xml", |
| Some("osdx") => "application/opensearchdescription+xml", |
| Some("otf") => "application/x-font-opentype", |
| Some("p10") => "application/pkcs10", |
| Some("p12") => "application/x-pkcs12", |
| Some("p7b") => "application/x-pkcs7-certificates", |
| Some("p7c") => "application/pkcs7-mime", |
| Some("p7m") => "application/pkcs7-mime", |
| Some("p7r") => "application/x-pkcs7-certreqresp", |
| Some("p7s") => "application/pkcs7-signature", |
| Some("pbm") => "image/x-portable-bitmap", |
| Some("pcast") => "application/x-podcast", |
| Some("pct") => "image/pict", |
| Some("pcx") => "application/octet-stream", |
| Some("pcz") => "application/octet-stream", |
| Some("pdf") => "application/pdf", |
| Some("pfb") => "application/octet-stream", |
| Some("pfm") => "application/octet-stream", |
| Some("pfx") => "application/x-pkcs12", |
| Some("pgm") => "image/x-portable-graymap", |
| Some("pic") => "image/pict", |
| Some("pict") => "image/pict", |
| Some("pkgdef") => "text/plain; charset=utf8", |
| Some("pkgundef") => "text/plain; charset=utf8", |
| Some("pko") => "application/vnd.ms-pki.pko", |
| Some("pls") => "audio/scpls", |
| Some("pma") => "application/x-perfmon", |
| Some("pmc") => "application/x-perfmon", |
| Some("pml") => "application/x-perfmon", |
| Some("pmr") => "application/x-perfmon", |
| Some("pmw") => "application/x-perfmon", |
| Some("png") => "image/png", |
| Some("pnm") => "image/x-portable-anymap", |
| Some("pnt") => "image/x-macpaint", |
| Some("pntg") => "image/x-macpaint", |
| Some("pnz") => "image/png", |
| Some("pot") => "application/vnd.ms-powerpoint", |
| Some("potm") => "application/vnd.ms-powerpoint.template.macroEnabled.12", |
| Some("potx") => "application/vnd.openxmlformats-officedocument.presentationml.template", |
| Some("ppa") => "application/vnd.ms-powerpoint", |
| Some("ppam") => "application/vnd.ms-powerpoint.addin.macroEnabled.12", |
| Some("ppm") => "image/x-portable-pixmap", |
| Some("pps") => "application/vnd.ms-powerpoint", |
| Some("ppsm") => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", |
| Some("ppsx") => "application/vnd.openxmlformats-officedocument.presentationml.slideshow", |
| Some("ppt") => "application/vnd.ms-powerpoint", |
| Some("pptm") => "application/vnd.ms-powerpoint.presentation.macroEnabled.12", |
| Some("pptx") => "application/vnd.openxmlformats-officedocument.presentationml.presentation", |
| Some("prf") => "application/pics-rules", |
| Some("prm") => "application/octet-stream", |
| Some("prx") => "application/octet-stream", |
| Some("ps") => "application/postscript", |
| Some("psc1") => "application/PowerShell", |
| Some("psd") => "application/octet-stream", |
| Some("psess") => "application/xml", |
| Some("psm") => "application/octet-stream", |
| Some("psp") => "application/octet-stream", |
| Some("pub") => "application/x-mspublisher", |
| Some("pwz") => "application/vnd.ms-powerpoint", |
| Some("qht") => "text/x-html-insertion; charset=utf8", |
| Some("qhtm") => "text/x-html-insertion; charset=utf8", |
| Some("qt") => "video/quicktime", |
| Some("qti") => "image/x-quicktime", |
| Some("qtif") => "image/x-quicktime", |
| Some("qtl") => "application/x-quicktimeplayer", |
| Some("qxd") => "application/octet-stream", |
| Some("ra") => "audio/x-pn-realaudio", |
| Some("ram") => "audio/x-pn-realaudio", |
| Some("rar") => "application/octet-stream", |
| Some("ras") => "image/x-cmu-raster", |
| Some("rat") => "application/rat-file", |
| Some("rc") => "text/plain; charset=utf8", |
| Some("rc2") => "text/plain; charset=utf8", |
| Some("rct") => "text/plain; charset=utf8", |
| Some("rdlc") => "application/xml", |
| Some("resx") => "application/xml", |
| Some("rf") => "image/vnd.rn-realflash", |
| Some("rgb") => "image/x-rgb", |
| Some("rgs") => "text/plain; charset=utf8", |
| Some("rm") => "application/vnd.rn-realmedia", |
| Some("rmi") => "audio/mid", |
| Some("rmp") => "application/vnd.rn-rn_music_package", |
| Some("roff") => "application/x-troff", |
| Some("rpm") => "audio/x-pn-realaudio-plugin", |
| Some("rqy") => "text/x-ms-rqy; charset=utf8", |
| Some("rtf") => "application/rtf", |
| Some("rtx") => "text/richtext; charset=utf8", |
| Some("ruleset") => "application/xml", |
| Some("s") => "text/plain; charset=utf8", |
| Some("safariextz") => "application/x-safari-safariextz", |
| Some("scd") => "application/x-msschedule", |
| Some("sct") => "text/scriptlet; charset=utf8", |
| Some("sd2") => "audio/x-sd2", |
| Some("sdp") => "application/sdp", |
| Some("sea") => "application/octet-stream", |
| Some("searchConnector-ms") => "application/windows-search-connector+xml", |
| Some("setpay") => "application/set-payment-initiation", |
| Some("setreg") => "application/set-registration-initiation", |
| Some("settings") => "application/xml", |
| Some("sfnt") => "application/font-sfnt", |
| Some("sgimb") => "application/x-sgimb", |
| Some("sgml") => "text/sgml; charset=utf8", |
| Some("sh") => "application/x-sh", |
| Some("shar") => "application/x-shar", |
| Some("shtml") => "text/html; charset=utf8", |
| Some("sit") => "application/x-stuffit", |
| Some("sitemap") => "application/xml", |
| Some("skin") => "application/xml", |
| Some("sldm") => "application/vnd.ms-powerpoint.slide.macroEnabled.12", |
| Some("sldx") => "application/vnd.openxmlformats-officedocument.presentationml.slide", |
| Some("slk") => "application/vnd.ms-excel", |
| Some("sln") => "text/plain; charset=utf8", |
| Some("slupkg-ms") => "application/x-ms-license", |
| Some("smd") => "audio/x-smd", |
| Some("smi") => "application/octet-stream", |
| Some("smx") => "audio/x-smd", |
| Some("smz") => "audio/x-smd", |
| Some("snd") => "audio/basic", |
| Some("snippet") => "application/xml", |
| Some("snp") => "application/octet-stream", |
| Some("sol") => "text/plain; charset=utf8", |
| Some("sor") => "text/plain; charset=utf8", |
| Some("spc") => "application/x-pkcs7-certificates", |
| Some("spl") => "application/futuresplash", |
| Some("src") => "application/x-wais-source", |
| Some("srf") => "text/plain; charset=utf8", |
| Some("ssisdeploymentmanifest") => "application/xml", |
| Some("ssm") => "application/streamingmedia", |
| Some("sst") => "application/vnd.ms-pki.certstore", |
| Some("stl") => "application/vnd.ms-pki.stl", |
| Some("sv4cpio") => "application/x-sv4cpio", |
| Some("sv4crc") => "application/x-sv4crc", |
| Some("svc") => "application/xml", |
| Some("svg") => "image/svg+xml", |
| Some("swf") => "application/x-shockwave-flash", |
| Some("t") => "application/x-troff", |
| Some("tar") => "application/x-tar", |
| Some("tcl") => "application/x-tcl", |
| Some("testrunconfig") => "application/xml", |
| Some("testsettings") => "application/xml", |
| Some("tex") => "application/x-tex", |
| Some("texi") => "application/x-texinfo", |
| Some("texinfo") => "application/x-texinfo", |
| Some("tgz") => "application/x-compressed", |
| Some("thmx") => "application/vnd.ms-officetheme", |
| Some("thn") => "application/octet-stream", |
| Some("tif") => "image/tiff", |
| Some("tiff") => "image/tiff", |
| Some("tlh") => "text/plain; charset=utf8", |
| Some("tli") => "text/plain; charset=utf8", |
| Some("toc") => "application/octet-stream", |
| Some("tr") => "application/x-troff", |
| Some("trm") => "application/x-msterminal", |
| Some("trx") => "application/xml", |
| Some("ts") => "video/vnd.dlna.mpeg-tts", |
| Some("tsv") => "text/tab-separated-values; charset=utf8", |
| Some("ttf") => "application/x-font-ttf", |
| Some("tts") => "video/vnd.dlna.mpeg-tts", |
| Some("txt") => "text/plain; charset=utf8", |
| Some("u32") => "application/octet-stream", |
| Some("uls") => "text/iuls; charset=utf8", |
| Some("user") => "text/plain; charset=utf8", |
| Some("ustar") => "application/x-ustar", |
| Some("vb") => "text/plain; charset=utf8", |
| Some("vbdproj") => "text/plain; charset=utf8", |
| Some("vbk") => "video/mpeg", |
| Some("vbproj") => "text/plain; charset=utf8", |
| Some("vbs") => "text/vbscript; charset=utf8", |
| Some("vcf") => "text/x-vcard; charset=utf8", |
| Some("vcproj") => "Application/xml", |
| Some("vcs") => "text/plain; charset=utf8", |
| Some("vcxproj") => "Application/xml", |
| Some("vddproj") => "text/plain; charset=utf8", |
| Some("vdp") => "text/plain; charset=utf8", |
| Some("vdproj") => "text/plain; charset=utf8", |
| Some("vdx") => "application/vnd.ms-visio.viewer", |
| Some("vml") => "application/xml", |
| Some("vscontent") => "application/xml", |
| Some("vsct") => "application/xml", |
| Some("vsd") => "application/vnd.visio", |
| Some("vsi") => "application/ms-vsi", |
| Some("vsix") => "application/vsix", |
| Some("vsixlangpack") => "application/xml", |
| Some("vsixmanifest") => "application/xml", |
| Some("vsmdi") => "application/xml", |
| Some("vspscc") => "text/plain; charset=utf8", |
| Some("vss") => "application/vnd.visio", |
| Some("vsscc") => "text/plain; charset=utf8", |
| Some("vssettings") => "application/xml", |
| Some("vssscc") => "text/plain; charset=utf8", |
| Some("vst") => "application/vnd.visio", |
| Some("vstemplate") => "application/xml", |
| Some("vsto") => "application/x-ms-vsto", |
| Some("vsw") => "application/vnd.visio", |
| Some("vsx") => "application/vnd.visio", |
| Some("vtx") => "application/vnd.visio", |
| Some("wasm") => "application/wasm", |
| Some("wav") => "audio/wav", |
| Some("wave") => "audio/wav", |
| Some("wax") => "audio/x-ms-wax", |
| Some("wbk") => "application/msword", |
| Some("wbmp") => "image/vnd.wap.wbmp", |
| Some("wcm") => "application/vnd.ms-works", |
| Some("wdb") => "application/vnd.ms-works", |
| Some("wdp") => "image/vnd.ms-photo", |
| Some("webarchive") => "application/x-safari-webarchive", |
| Some("webtest") => "application/xml", |
| Some("wiq") => "application/xml", |
| Some("wiz") => "application/msword", |
| Some("wks") => "application/vnd.ms-works", |
| Some("wlmp") => "application/wlmoviemaker", |
| Some("wlpginstall") => "application/x-wlpg-detect", |
| Some("wlpginstall3") => "application/x-wlpg3-detect", |
| Some("wm") => "video/x-ms-wm", |
| Some("wma") => "audio/x-ms-wma", |
| Some("wmd") => "application/x-ms-wmd", |
| Some("wmf") => "application/x-msmetafile", |
| Some("wml") => "text/vnd.wap.wml; charset=utf8", |
| Some("wmlc") => "application/vnd.wap.wmlc", |
| Some("wmls") => "text/vnd.wap.wmlscript; charset=utf8", |
| Some("wmlsc") => "application/vnd.wap.wmlscriptc", |
| Some("wmp") => "video/x-ms-wmp", |
| Some("wmv") => "video/x-ms-wmv", |
| Some("wmx") => "video/x-ms-wmx", |
| Some("wmz") => "application/x-ms-wmz", |
| Some("woff") => "application/font-woff", |
| Some("woff2") => "application/font-woff2", |
| Some("wpl") => "application/vnd.ms-wpl", |
| Some("wps") => "application/vnd.ms-works", |
| Some("wri") => "application/x-mswrite", |
| Some("wrl") => "x-world/x-vrml", |
| Some("wrz") => "x-world/x-vrml", |
| Some("wsc") => "text/scriptlet; charset=utf8", |
| Some("wsdl") => "application/xml", |
| Some("wvx") => "video/x-ms-wvx", |
| Some("x") => "application/directx", |
| Some("xaf") => "x-world/x-vrml", |
| Some("xaml") => "application/xaml+xml", |
| Some("xap") => "application/x-silverlight-app", |
| Some("xbap") => "application/x-ms-xbap", |
| Some("xbm") => "image/x-xbitmap", |
| Some("xdr") => "text/plain; charset=utf8", |
| Some("xht") => "application/xhtml+xml", |
| Some("xhtml") => "application/xhtml+xml", |
| Some("xla") => "application/vnd.ms-excel", |
| Some("xlam") => "application/vnd.ms-excel.addin.macroEnabled.12", |
| Some("xlc") => "application/vnd.ms-excel", |
| Some("xld") => "application/vnd.ms-excel", |
| Some("xlk") => "application/vnd.ms-excel", |
| Some("xll") => "application/vnd.ms-excel", |
| Some("xlm") => "application/vnd.ms-excel", |
| Some("xls") => "application/vnd.ms-excel", |
| Some("xlsb") => "application/vnd.ms-excel.sheet.binary.macroEnabled.12", |
| Some("xlsm") => "application/vnd.ms-excel.sheet.macroEnabled.12", |
| Some("xlsx") => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| Some("xlt") => "application/vnd.ms-excel", |
| Some("xltm") => "application/vnd.ms-excel.template.macroEnabled.12", |
| Some("xltx") => "application/vnd.openxmlformats-officedocument.spreadsheetml.template", |
| Some("xlw") => "application/vnd.ms-excel", |
| Some("xml") => "application/xml", |
| Some("xmta") => "application/xml", |
| Some("xof") => "x-world/x-vrml", |
| Some("xoml") => "text/plain; charset=utf8", |
| Some("xpm") => "image/x-xpixmap", |
| Some("xps") => "application/vnd.ms-xpsdocument", |
| Some("xrm-ms") => "application/xml", |
| Some("xsc") => "application/xml", |
| Some("xsd") => "application/xml", |
| Some("xsf") => "application/xml", |
| Some("xsl") => "application/xml", |
| Some("xslt") => "application/xslt+xml", |
| Some("xsn") => "application/octet-stream", |
| Some("xss") => "application/xml", |
| Some("xtp") => "application/octet-stream", |
| Some("xwd") => "image/x-xwindowdump", |
| Some("z") => "application/x-compress", |
| Some("zip") => "application/zip", |
| _ => "application/octet-stream" |
| } |
| } |