summaryrefslogtreecommitdiffstats
path: root/third_party/rust/mime
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/mime/.cargo-checksum.json1
-rw-r--r--third_party/rust/mime/CONTRIBUTING.md12
-rw-r--r--third_party/rust/mime/Cargo.toml23
-rw-r--r--third_party/rust/mime/LICENSE-APACHE201
-rw-r--r--third_party/rust/mime/LICENSE-MIT20
-rw-r--r--third_party/rust/mime/README.md31
-rw-r--r--third_party/rust/mime/benches/cmp.rs46
-rw-r--r--third_party/rust/mime/benches/fmt.rs19
-rw-r--r--third_party/rust/mime/benches/parse.rs29
-rw-r--r--third_party/rust/mime/src/lib.rs937
-rw-r--r--third_party/rust/mime/src/parse.rs363
-rw-r--r--third_party/rust/mime_guess/.cargo-checksum.json1
-rw-r--r--third_party/rust/mime_guess/Cargo.lock686
-rw-r--r--third_party/rust/mime_guess/Cargo.toml43
-rw-r--r--third_party/rust/mime_guess/LICENSE22
-rw-r--r--third_party/rust/mime_guess/README.md81
-rw-r--r--third_party/rust/mime_guess/benches/benchmark.rs31
-rw-r--r--third_party/rust/mime_guess/build.rs191
-rw-r--r--third_party/rust/mime_guess/examples/rev_map.rs14
-rw-r--r--third_party/rust/mime_guess/src/impl_bin_search.rs41
-rw-r--r--third_party/rust/mime_guess/src/impl_phf.rs40
-rw-r--r--third_party/rust/mime_guess/src/lib.rs526
-rw-r--r--third_party/rust/mime_guess/src/mime_types.rs1489
23 files changed, 4847 insertions, 0 deletions
diff --git a/third_party/rust/mime/.cargo-checksum.json b/third_party/rust/mime/.cargo-checksum.json
new file mode 100644
index 0000000000..220a471312
--- /dev/null
+++ b/third_party/rust/mime/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CONTRIBUTING.md":"7a8f1d12eb98bd09c290d31f25b03c71ff78027d9fc468e8782efa7dd3e69f1c","Cargo.toml":"75e36b40187c8edad0baae326a0903b6b462f1acd0d68102a8e4f006b8802041","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"df9cfd06d8a44d9a671eadd39ffd97f166481da015a30f45dfd27886209c5922","README.md":"4ac32f1d6d7e1ac9f89f0a6d7d0cbc26f20ef9defdc7b206ef3a77616f493bbf","benches/cmp.rs":"9deb7c222eb69e7c5160aa82d361d4883792be3b557fbf8f7c807b398ba951a1","benches/fmt.rs":"46ec1e7c7970a3eed84b303309a2395ac16d16534ea691db7f361d0016ef0673","benches/parse.rs":"af2b35fc314e39c7fb3fbe6a77b65e54d0f4bd8956950330700028a98513b7d8","src/lib.rs":"c848e55a49ae4ed6451e94c8c120451b5031ba2ab87170ed389eeb4731679446","src/parse.rs":"cfe11f611901a581245b091942bb28ef2eec57645b981e1699d247f11c9e6fe3"},"package":"2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"} \ No newline at end of file
diff --git a/third_party/rust/mime/CONTRIBUTING.md b/third_party/rust/mime/CONTRIBUTING.md
new file mode 100644
index 0000000000..3fbc3a3123
--- /dev/null
+++ b/third_party/rust/mime/CONTRIBUTING.md
@@ -0,0 +1,12 @@
+# Contributing to mime
+
+## License
+
+Licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://apache.org/licenses/LICENSE-2.0)
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
diff --git a/third_party/rust/mime/Cargo.toml b/third_party/rust/mime/Cargo.toml
new file mode 100644
index 0000000000..1f34190e7e
--- /dev/null
+++ b/third_party/rust/mime/Cargo.toml
@@ -0,0 +1,23 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "mime"
+version = "0.3.16"
+authors = ["Sean McArthur <sean@seanmonstar.com>"]
+description = "Strongly Typed Mimes"
+documentation = "https://docs.rs/mime"
+keywords = ["mime", "media-extensions", "media-types"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/hyperium/mime"
+
+[dependencies]
diff --git a/third_party/rust/mime/LICENSE-APACHE b/third_party/rust/mime/LICENSE-APACHE
new file mode 100644
index 0000000000..16fe87b06e
--- /dev/null
+++ b/third_party/rust/mime/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/third_party/rust/mime/LICENSE-MIT b/third_party/rust/mime/LICENSE-MIT
new file mode 100644
index 0000000000..557b7e5fc9
--- /dev/null
+++ b/third_party/rust/mime/LICENSE-MIT
@@ -0,0 +1,20 @@
+Copyright (c) 2014 Sean McArthur
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/third_party/rust/mime/README.md b/third_party/rust/mime/README.md
new file mode 100644
index 0000000000..dba6314078
--- /dev/null
+++ b/third_party/rust/mime/README.md
@@ -0,0 +1,31 @@
+# mime
+
+[![Build Status](https://travis-ci.org/hyperium/mime.svg?branch=master)](https://travis-ci.org/hyperium/mime)
+[![crates.io](https://img.shields.io/crates/v/mime.svg)](https://crates.io/crates/mime)
+[![docs.rs](https://docs.rs/mime/badge.svg)](https://docs.rs/mime)
+
+Support MIME (Media Types) as strong types in Rust.
+
+[Documentation](https://docs.rs/mime)
+
+## Usage
+
+```rust
+extern crate mime;
+
+// common types are constants
+let text = mime::TEXT_PLAIN;
+
+// deconstruct Mimes to match on them
+match (text.type_(), text.subtype()) {
+ (mime::TEXT, mime::PLAIN) => {
+ // plain text!
+ },
+ (mime::TEXT, _) => {
+ // structured text!
+ },
+ _ => {
+ // not text!
+ }
+}
+```
diff --git a/third_party/rust/mime/benches/cmp.rs b/third_party/rust/mime/benches/cmp.rs
new file mode 100644
index 0000000000..b7c64f64f6
--- /dev/null
+++ b/third_party/rust/mime/benches/cmp.rs
@@ -0,0 +1,46 @@
+#![feature(test)]
+
+extern crate mime;
+extern crate test;
+
+use mime::*;
+use test::Bencher;
+
+#[bench]
+fn bench_eq_parsed(b: &mut Bencher) {
+ let mime = "text/plain; charset=utf-8".parse::<Mime>().unwrap();
+ b.bytes = mime.as_ref().len() as u64;
+ b.iter(|| {
+ assert_eq!(mime, TEXT_PLAIN_UTF_8);
+ })
+}
+
+#[bench]
+fn bench_eq_consts(b: &mut Bencher) {
+ let mime = TEXT_PLAIN_UTF_8;
+ b.bytes = mime.as_ref().len() as u64;
+ b.iter(|| {
+ assert_eq!(mime, TEXT_PLAIN_UTF_8);
+ });
+}
+
+
+#[bench]
+fn bench_ne_consts(b: &mut Bencher) {
+ let one = TEXT_XML;
+ let two = TEXT_CSS;
+ b.bytes = one.as_ref().len() as u64;
+ b.iter(|| {
+ assert_ne!(one, two);
+ });
+}
+
+#[bench]
+fn bench_eq_type_(b: &mut Bencher) {
+ let mime = TEXT_PLAIN_UTF_8;
+ let name = TEXT;
+ b.bytes = name.as_ref().len() as u64;
+ b.iter(|| {
+ assert_eq!(mime.type_(), name);
+ });
+}
diff --git a/third_party/rust/mime/benches/fmt.rs b/third_party/rust/mime/benches/fmt.rs
new file mode 100644
index 0000000000..106de1a1e6
--- /dev/null
+++ b/third_party/rust/mime/benches/fmt.rs
@@ -0,0 +1,19 @@
+#![feature(test)]
+
+extern crate mime;
+extern crate test;
+
+use test::Bencher;
+
+#[bench]
+fn bench_fmt(b: &mut Bencher) {
+ use std::fmt::Write;
+ let mime = ::mime::TEXT_PLAIN_UTF_8;
+ b.bytes = mime.to_string().as_bytes().len() as u64;
+ let mut s = String::with_capacity(64);
+ b.iter(|| {
+ let _ = write!(s, "{}", mime);
+ ::test::black_box(&s);
+ unsafe { s.as_mut_vec().set_len(0); }
+ })
+}
diff --git a/third_party/rust/mime/benches/parse.rs b/third_party/rust/mime/benches/parse.rs
new file mode 100644
index 0000000000..7d47781a0d
--- /dev/null
+++ b/third_party/rust/mime/benches/parse.rs
@@ -0,0 +1,29 @@
+#![feature(test)]
+
+extern crate mime;
+extern crate test;
+
+use mime::Mime;
+use test::Bencher;
+
+
+#[bench]
+fn bench_from_str(b: &mut Bencher) {
+ let s = "text/plain";
+ b.bytes = s.as_bytes().len() as u64;
+ b.iter(|| s.parse::<Mime>())
+}
+
+#[bench]
+fn bench_from_str_charset_utf8(b: &mut Bencher) {
+ let s = "text/plain; charset=utf-8";
+ b.bytes = s.as_bytes().len() as u64;
+ b.iter(|| s.parse::<Mime>())
+}
+
+#[bench]
+fn bench_from_str_extended(b: &mut Bencher) {
+ let s = "text/plain; charset=utf-8; foo=bar";
+ b.bytes = s.as_bytes().len() as u64;
+ b.iter(|| s.parse::<Mime>())
+}
diff --git a/third_party/rust/mime/src/lib.rs b/third_party/rust/mime/src/lib.rs
new file mode 100644
index 0000000000..1f24fb1cf0
--- /dev/null
+++ b/third_party/rust/mime/src/lib.rs
@@ -0,0 +1,937 @@
+//! # Mime
+//!
+//! Mime is now Media Type, technically, but `Mime` is more immediately
+//! understandable, so the main type here is `Mime`.
+//!
+//! ## What is Mime?
+//!
+//! Example mime string: `text/plain`
+//!
+//! ```
+//! let plain_text: mime::Mime = "text/plain".parse().unwrap();
+//! assert_eq!(plain_text, mime::TEXT_PLAIN);
+//! ```
+//!
+//! ## Inspecting Mimes
+//!
+//! ```
+//! let mime = mime::TEXT_PLAIN;
+//! match (mime.type_(), mime.subtype()) {
+//! (mime::TEXT, mime::PLAIN) => println!("plain text!"),
+//! (mime::TEXT, _) => println!("structured text"),
+//! _ => println!("not text"),
+//! }
+//! ```
+
+#![doc(html_root_url = "https://docs.rs/mime/0.3.16")]
+#![deny(warnings)]
+#![deny(missing_docs)]
+#![deny(missing_debug_implementations)]
+
+
+use std::cmp::Ordering;
+use std::error::Error;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::str::FromStr;
+use std::slice;
+
+mod parse;
+
+/// A parsed mime or media type.
+#[derive(Clone)]
+pub struct Mime {
+ source: Source,
+ slash: usize,
+ plus: Option<usize>,
+ params: ParamSource,
+}
+
+/// A section of a `Mime`.
+///
+/// For instance, for the Mime `image/svg+xml`, it contains 3 `Name`s,
+/// `image`, `svg`, and `xml`.
+///
+/// In most cases, `Name`s are compared ignoring case.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Name<'a> {
+ // TODO: optimize with an Atom-like thing
+ // There a `const` Names, and so it is possible for the statis strings
+ // to havea different memory address. Additionally, when used in match
+ // statements, the strings are compared with a memcmp, possibly even
+ // if the address and length are the same.
+ //
+ // Being an enum with an Atom variant that is a usize (and without a
+ // string pointer and boolean) would allow for faster comparisons.
+ source: &'a str,
+ insensitive: bool,
+}
+
+/// An error when parsing a `Mime` from a string.
+#[derive(Debug)]
+pub struct FromStrError {
+ inner: parse::ParseError,
+}
+
+impl FromStrError {
+ fn s(&self) -> &str {
+ "mime parse error"
+ }
+}
+
+impl fmt::Display for FromStrError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}: {}", self.s(), self.inner)
+ }
+}
+
+impl Error for FromStrError {
+ // Minimum Rust is 1.15, Error::description was still required then
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.s()
+ }
+}
+
+#[derive(Clone)]
+enum Source {
+ Atom(u8, &'static str),
+ Dynamic(String),
+}
+
+impl Source {
+ fn as_ref(&self) -> &str {
+ match *self {
+ Source::Atom(_, s) => s,
+ Source::Dynamic(ref s) => s,
+ }
+ }
+}
+
+#[derive(Clone)]
+enum ParamSource {
+ Utf8(usize),
+ Custom(usize, Vec<(Indexed, Indexed)>),
+ None,
+}
+
+#[derive(Clone, Copy)]
+struct Indexed(usize, usize);
+
+impl Mime {
+ /// Get the top level media type for this `Mime`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let mime = mime::TEXT_PLAIN;
+ /// assert_eq!(mime.type_(), "text");
+ /// assert_eq!(mime.type_(), mime::TEXT);
+ /// ```
+ #[inline]
+ pub fn type_(&self) -> Name {
+ Name {
+ source: &self.source.as_ref()[..self.slash],
+ insensitive: true,
+ }
+ }
+
+ /// Get the subtype of this `Mime`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let mime = mime::TEXT_PLAIN;
+ /// assert_eq!(mime.subtype(), "plain");
+ /// assert_eq!(mime.subtype(), mime::PLAIN);
+ /// ```
+ #[inline]
+ pub fn subtype(&self) -> Name {
+ let end = self.plus.unwrap_or_else(|| {
+ return self.semicolon().unwrap_or(self.source.as_ref().len())
+ });
+ Name {
+ source: &self.source.as_ref()[self.slash + 1..end],
+ insensitive: true,
+ }
+ }
+
+ /// Get an optional +suffix for this `Mime`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let svg = "image/svg+xml".parse::<mime::Mime>().unwrap();
+ /// assert_eq!(svg.suffix(), Some(mime::XML));
+ /// assert_eq!(svg.suffix().unwrap(), "xml");
+ ///
+ ///
+ /// assert!(mime::TEXT_PLAIN.suffix().is_none());
+ /// ```
+ #[inline]
+ pub fn suffix(&self) -> Option<Name> {
+ let end = self.semicolon().unwrap_or(self.source.as_ref().len());
+ self.plus.map(|idx| Name {
+ source: &self.source.as_ref()[idx + 1..end],
+ insensitive: true,
+ })
+ }
+
+ /// Look up a parameter by name.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// let mime = mime::TEXT_PLAIN_UTF_8;
+ /// assert_eq!(mime.get_param(mime::CHARSET), Some(mime::UTF_8));
+ /// assert_eq!(mime.get_param("charset").unwrap(), "utf-8");
+ /// assert!(mime.get_param("boundary").is_none());
+ ///
+ /// let mime = "multipart/form-data; boundary=ABCDEFG".parse::<mime::Mime>().unwrap();
+ /// assert_eq!(mime.get_param(mime::BOUNDARY).unwrap(), "ABCDEFG");
+ /// ```
+ pub fn get_param<'a, N>(&'a self, attr: N) -> Option<Name<'a>>
+ where N: PartialEq<Name<'a>> {
+ self.params().find(|e| attr == e.0).map(|e| e.1)
+ }
+
+ /// Returns an iterator over the parameters.
+ #[inline]
+ pub fn params<'a>(&'a self) -> Params<'a> {
+ let inner = match self.params {
+ ParamSource::Utf8(_) => ParamsInner::Utf8,
+ ParamSource::Custom(_, ref params) => {
+ ParamsInner::Custom {
+ source: &self.source,
+ params: params.iter(),
+ }
+ }
+ ParamSource::None => ParamsInner::None,
+ };
+
+ Params(inner)
+ }
+
+ /// Return a `&str` of the Mime's ["essence"][essence].
+ ///
+ /// [essence]: https://mimesniff.spec.whatwg.org/#mime-type-essence
+ pub fn essence_str(&self) -> &str {
+ let end = self.semicolon().unwrap_or(self.source.as_ref().len());
+
+ &self.source.as_ref()[..end]
+ }
+
+ #[cfg(test)]
+ fn has_params(&self) -> bool {
+ match self.params {
+ ParamSource::None => false,
+ _ => true,
+ }
+ }
+
+ #[inline]
+ fn semicolon(&self) -> Option<usize> {
+ match self.params {
+ ParamSource::Utf8(i) |
+ ParamSource::Custom(i, _) => Some(i),
+ ParamSource::None => None,
+ }
+ }
+
+ fn atom(&self) -> u8 {
+ match self.source {
+ Source::Atom(a, _) => a,
+ _ => 0,
+ }
+ }
+}
+
+// Mime ============
+
+fn eq_ascii(a: &str, b: &str) -> bool {
+ // str::eq_ignore_ascii_case didn't stabilize until Rust 1.23.
+ // So while our MSRV is 1.15, gotta import this trait.
+ #[allow(deprecated, unused)]
+ use std::ascii::AsciiExt;
+
+ a.eq_ignore_ascii_case(b)
+}
+
+fn mime_eq_str(mime: &Mime, s: &str) -> bool {
+ if let ParamSource::Utf8(semicolon) = mime.params {
+ if mime.source.as_ref().len() == s.len() {
+ eq_ascii(mime.source.as_ref(), s)
+ } else {
+ params_eq(semicolon, mime.source.as_ref(), s)
+ }
+ } else if let Some(semicolon) = mime.semicolon() {
+ params_eq(semicolon, mime.source.as_ref(), s)
+ } else {
+ eq_ascii(mime.source.as_ref(), s)
+ }
+}
+
+fn params_eq(semicolon: usize, a: &str, b: &str) -> bool {
+ if b.len() < semicolon + 1 {
+ false
+ } else if !eq_ascii(&a[..semicolon], &b[..semicolon]) {
+ false
+ } else {
+ // gotta check for quotes, LWS, and for case senstive names
+ let mut a = &a[semicolon + 1..];
+ let mut b = &b[semicolon + 1..];
+ let mut sensitive;
+
+ loop {
+ a = a.trim();
+ b = b.trim();
+
+ match (a.is_empty(), b.is_empty()) {
+ (true, true) => return true,
+ (true, false) |
+ (false, true) => return false,
+ (false, false) => (),
+ }
+
+ //name
+ if let Some(a_idx) = a.find('=') {
+ let a_name = {
+ #[allow(deprecated)]
+ { a[..a_idx].trim_left() }
+ };
+ if let Some(b_idx) = b.find('=') {
+ let b_name = {
+ #[allow(deprecated)]
+ { b[..b_idx].trim_left() }
+ };
+ if !eq_ascii(a_name, b_name) {
+ return false;
+ }
+ sensitive = a_name != CHARSET;
+ a = &a[..a_idx];
+ b = &b[..b_idx];
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ //value
+ let a_quoted = if a.as_bytes()[0] == b'"' {
+ a = &a[1..];
+ true
+ } else {
+ false
+ };
+ let b_quoted = if b.as_bytes()[0] == b'"' {
+ b = &b[1..];
+ true
+ } else {
+ false
+ };
+
+ let a_end = if a_quoted {
+ if let Some(quote) = a.find('"') {
+ quote
+ } else {
+ return false;
+ }
+ } else {
+ a.find(';').unwrap_or(a.len())
+ };
+
+ let b_end = if b_quoted {
+ if let Some(quote) = b.find('"') {
+ quote
+ } else {
+ return false;
+ }
+ } else {
+ b.find(';').unwrap_or(b.len())
+ };
+
+ if sensitive {
+ if !eq_ascii(&a[..a_end], &b[..b_end]) {
+ return false;
+ }
+ } else {
+ if &a[..a_end] != &b[..b_end] {
+ return false;
+ }
+ }
+ a = &a[a_end..];
+ b = &b[b_end..];
+ }
+ }
+}
+
+impl PartialEq for Mime {
+ #[inline]
+ fn eq(&self, other: &Mime) -> bool {
+ match (self.atom(), other.atom()) {
+ // TODO:
+ // This could optimize for when there are no customs parameters.
+ // Any parsed mime has already been lowercased, so if there aren't
+ // any parameters that are case sensistive, this can skip the
+ // eq_ascii, and just use a memcmp instead.
+ (0, _) |
+ (_, 0) => mime_eq_str(self, other.source.as_ref()),
+ (a, b) => a == b,
+ }
+ }
+}
+
+impl Eq for Mime {}
+
+impl PartialOrd for Mime {
+ fn partial_cmp(&self, other: &Mime) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Mime {
+ fn cmp(&self, other: &Mime) -> Ordering {
+ self.source.as_ref().cmp(other.source.as_ref())
+ }
+}
+
+impl Hash for Mime {
+ fn hash<T: Hasher>(&self, hasher: &mut T) {
+ hasher.write(self.source.as_ref().as_bytes());
+ }
+}
+
+impl<'a> PartialEq<&'a str> for Mime {
+ #[inline]
+ fn eq(&self, s: & &'a str) -> bool {
+ mime_eq_str(self, *s)
+ }
+}
+
+impl<'a> PartialEq<Mime> for &'a str {
+ #[inline]
+ fn eq(&self, mime: &Mime) -> bool {
+ mime_eq_str(mime, *self)
+ }
+}
+
+impl FromStr for Mime {
+ type Err = FromStrError;
+
+ fn from_str(s: &str) -> Result<Mime, Self::Err> {
+ parse::parse(s).map_err(|e| FromStrError { inner: e })
+ }
+}
+
+impl AsRef<str> for Mime {
+ #[inline]
+ fn as_ref(&self) -> &str {
+ self.source.as_ref()
+ }
+}
+
+impl fmt::Debug for Mime {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.source.as_ref(), f)
+ }
+}
+
+impl fmt::Display for Mime {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.source.as_ref(), f)
+ }
+}
+
+// Name ============
+
+fn name_eq_str(name: &Name, s: &str) -> bool {
+ if name.insensitive {
+ eq_ascii(name.source, s)
+ } else {
+ name.source == s
+ }
+}
+
+impl<'a> Name<'a> {
+ /// Get the value of this `Name` as a string.
+ ///
+ /// Note that the borrow is not tied to `&self` but the `'a` lifetime, allowing the
+ /// string to outlive `Name`. Alternately, there is an `impl<'a> From<Name<'a>> for &'a str`
+ /// which isn't rendered by Rustdoc, that can be accessed using `str::from(name)` or `name.into()`.
+ pub fn as_str(&self) -> &'a str {
+ self.source
+ }
+}
+
+impl<'a, 'b> PartialEq<&'b str> for Name<'a> {
+ #[inline]
+ fn eq(&self, other: & &'b str) -> bool {
+ name_eq_str(self, *other)
+ }
+}
+
+impl<'a, 'b> PartialEq<Name<'a>> for &'b str {
+ #[inline]
+ fn eq(&self, other: &Name<'a>) -> bool {
+ name_eq_str(other, *self)
+ }
+}
+
+impl<'a> AsRef<str> for Name<'a> {
+ #[inline]
+ fn as_ref(&self) -> &str {
+ self.source
+ }
+}
+
+impl<'a> From<Name<'a>> for &'a str {
+ #[inline]
+ fn from(name: Name<'a>) -> &'a str {
+ name.source
+ }
+}
+
+impl<'a> fmt::Debug for Name<'a> {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.source, f)
+ }
+}
+
+impl<'a> fmt::Display for Name<'a> {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.source, f)
+ }
+}
+
+// Params ===================
+
+enum ParamsInner<'a> {
+ Utf8,
+ Custom {
+ source: &'a Source,
+ params: slice::Iter<'a, (Indexed, Indexed)>,
+ },
+ None,
+}
+
+/// An iterator over the parameters of a MIME.
+pub struct Params<'a>(ParamsInner<'a>);
+
+impl<'a> fmt::Debug for Params<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("Params").finish()
+ }
+}
+
+impl<'a> Iterator for Params<'a> {
+ type Item = (Name<'a>, Name<'a>);
+
+ #[inline]
+ fn next(&mut self) -> Option<(Name<'a>, Name<'a>)> {
+ match self.0 {
+ ParamsInner::Utf8 => {
+ let value = (CHARSET, UTF_8);
+ self.0 = ParamsInner::None;
+ Some(value)
+ }
+ ParamsInner::Custom { source, ref mut params } => {
+ params.next().map(|&(name, value)| {
+ let name = Name {
+ source: &source.as_ref()[name.0..name.1],
+ insensitive: true,
+ };
+ let value = Name {
+ source: &source.as_ref()[value.0..value.1],
+ insensitive: name == CHARSET,
+ };
+ (name, value)
+ })
+ }
+ ParamsInner::None => None
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self.0 {
+ ParamsInner::Utf8 => (1, Some(1)),
+ ParamsInner::Custom { ref params, .. } => params.size_hint(),
+ ParamsInner::None => (0, Some(0)),
+ }
+ }
+}
+
+macro_rules! names {
+ ($($id:ident, $e:expr;)*) => (
+ $(
+ #[doc = $e]
+ pub const $id: Name<'static> = Name {
+ source: $e,
+ insensitive: true,
+ };
+ )*
+
+ #[test]
+ fn test_names_macro_consts() {
+ #[allow(unused, deprecated)]
+ use std::ascii::AsciiExt;
+ $(
+ assert_eq!($id.source.to_ascii_lowercase(), $id.source);
+ )*
+ }
+ )
+}
+
+names! {
+ STAR, "*";
+
+ TEXT, "text";
+ IMAGE, "image";
+ AUDIO, "audio";
+ VIDEO, "video";
+ APPLICATION, "application";
+ MULTIPART, "multipart";
+ MESSAGE, "message";
+ MODEL, "model";
+ FONT, "font";
+
+ // common text/ *
+ PLAIN, "plain";
+ HTML, "html";
+ XML, "xml";
+ JAVASCRIPT, "javascript";
+ CSS, "css";
+ CSV, "csv";
+ EVENT_STREAM, "event-stream";
+ VCARD, "vcard";
+
+ // common application/*
+ JSON, "json";
+ WWW_FORM_URLENCODED, "x-www-form-urlencoded";
+ MSGPACK, "msgpack";
+ OCTET_STREAM, "octet-stream";
+ PDF, "pdf";
+
+ // common font/*
+ WOFF, "woff";
+ WOFF2, "woff2";
+
+ // multipart/*
+ FORM_DATA, "form-data";
+
+ // common image/*
+ BMP, "bmp";
+ GIF, "gif";
+ JPEG, "jpeg";
+ PNG, "png";
+ SVG, "svg";
+
+ // audio/*
+ BASIC, "basic";
+ MPEG, "mpeg";
+ MP4, "mp4";
+ OGG, "ogg";
+
+ // parameters
+ CHARSET, "charset";
+ BOUNDARY, "boundary";
+ UTF_8, "utf-8";
+}
+
+macro_rules! mimes {
+ ($($id:ident, $($piece:expr),*;)*) => (
+ #[allow(non_camel_case_types)]
+ enum __Atoms {
+ __Dynamic,
+ $(
+ $id,
+ )*
+ }
+
+ $(
+ mime_constant! {
+ $id, $($piece),*
+ }
+ )*
+
+ #[test]
+ fn test_mimes_macro_consts() {
+ let _ = [
+ $(
+ mime_constant_test! {
+ $id, $($piece),*
+ }
+ ),*
+ ].iter().enumerate().map(|(pos, &atom)| {
+ assert_eq!(pos + 1, atom as usize, "atom {} in position {}", atom, pos + 1);
+ }).collect::<Vec<()>>();
+ }
+ )
+}
+
+macro_rules! mime_constant {
+ ($id:ident, $src:expr, $slash:expr) => (
+ mime_constant!($id, $src, $slash, None);
+ );
+ ($id:ident, $src:expr, $slash:expr, $plus:expr) => (
+ mime_constant!(FULL $id, $src, $slash, $plus, ParamSource::None);
+ );
+
+ ($id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
+ mime_constant!(FULL $id, $src, $slash, $plus, ParamSource::Utf8($params));
+ );
+
+
+ (FULL $id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
+ #[doc = "`"]
+ #[doc = $src]
+ #[doc = "`"]
+ pub const $id: Mime = Mime {
+ source: Source::Atom(__Atoms::$id as u8, $src),
+ slash: $slash,
+ plus: $plus,
+ params: $params,
+ };
+ )
+}
+
+
+#[cfg(test)]
+macro_rules! mime_constant_test {
+ ($id:ident, $src:expr, $slash:expr) => (
+ mime_constant_test!($id, $src, $slash, None);
+ );
+ ($id:ident, $src:expr, $slash:expr, $plus:expr) => (
+ mime_constant_test!(FULL $id, $src, $slash, $plus, ParamSource::None);
+ );
+
+ ($id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
+ mime_constant_test!(FULL $id, $src, $slash, $plus, ParamSource::Utf8($params));
+ );
+
+ (FULL $id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => ({
+ let __mime = $id;
+ let __slash = __mime.as_ref().as_bytes()[$slash];
+ assert_eq!(__slash, b'/', "{:?} has {:?} at slash position {:?}", __mime, __slash as char, $slash);
+ if let Some(plus) = __mime.plus {
+ let __c = __mime.as_ref().as_bytes()[plus];
+ assert_eq!(__c, b'+', "{:?} has {:?} at plus position {:?}", __mime, __c as char, plus);
+ } else {
+ assert!(!__mime.as_ref().as_bytes().contains(&b'+'), "{:?} forgot plus", __mime);
+ }
+ if let ParamSource::Utf8(semicolon) = __mime.params {
+ assert_eq!(__mime.as_ref().as_bytes()[semicolon], b';');
+ assert_eq!(&__mime.as_ref()[semicolon..], "; charset=utf-8");
+ } else if let ParamSource::None = __mime.params {
+ assert!(!__mime.as_ref().as_bytes().contains(&b';'));
+ } else {
+ unreachable!();
+ }
+ __mime.atom()
+ })
+}
+
+
+mimes! {
+ STAR_STAR, "*/*", 1;
+
+ TEXT_STAR, "text/*", 4;
+ TEXT_PLAIN, "text/plain", 4;
+ TEXT_PLAIN_UTF_8, "text/plain; charset=utf-8", 4, None, 10;
+ TEXT_HTML, "text/html", 4;
+ TEXT_HTML_UTF_8, "text/html; charset=utf-8", 4, None, 9;
+ TEXT_CSS, "text/css", 4;
+ TEXT_CSS_UTF_8, "text/css; charset=utf-8", 4, None, 8;
+ TEXT_JAVASCRIPT, "text/javascript", 4;
+ TEXT_XML, "text/xml", 4;
+ TEXT_EVENT_STREAM, "text/event-stream", 4;
+ TEXT_CSV, "text/csv", 4;
+ TEXT_CSV_UTF_8, "text/csv; charset=utf-8", 4, None, 8;
+ TEXT_TAB_SEPARATED_VALUES, "text/tab-separated-values", 4;
+ TEXT_TAB_SEPARATED_VALUES_UTF_8, "text/tab-separated-values; charset=utf-8", 4, None, 25;
+ TEXT_VCARD, "text/vcard", 4;
+
+ IMAGE_STAR, "image/*", 5;
+ IMAGE_JPEG, "image/jpeg", 5;
+ IMAGE_GIF, "image/gif", 5;
+ IMAGE_PNG, "image/png", 5;
+ IMAGE_BMP, "image/bmp", 5;
+ IMAGE_SVG, "image/svg+xml", 5, Some(9);
+
+ FONT_WOFF, "font/woff", 4;
+ FONT_WOFF2, "font/woff2", 4;
+
+ APPLICATION_JSON, "application/json", 11;
+ APPLICATION_JAVASCRIPT, "application/javascript", 11;
+ APPLICATION_JAVASCRIPT_UTF_8, "application/javascript; charset=utf-8", 11, None, 22;
+ APPLICATION_WWW_FORM_URLENCODED, "application/x-www-form-urlencoded", 11;
+ APPLICATION_OCTET_STREAM, "application/octet-stream", 11;
+ APPLICATION_MSGPACK, "application/msgpack", 11;
+ APPLICATION_PDF, "application/pdf", 11;
+
+ MULTIPART_FORM_DATA, "multipart/form-data", 9;
+}
+
+#[deprecated(since="0.3.1", note="please use `TEXT_JAVASCRIPT` instead")]
+#[doc(hidden)]
+pub const TEXT_JAVSCRIPT: Mime = TEXT_JAVASCRIPT;
+
+
+#[cfg(test)]
+mod tests {
+ use std::str::FromStr;
+ use super::*;
+
+ #[test]
+ fn test_type_() {
+ assert_eq!(TEXT_PLAIN.type_(), TEXT);
+ }
+
+
+ #[test]
+ fn test_subtype() {
+ assert_eq!(TEXT_PLAIN.subtype(), PLAIN);
+ assert_eq!(TEXT_PLAIN_UTF_8.subtype(), PLAIN);
+ let mime = Mime::from_str("text/html+xml").unwrap();
+ assert_eq!(mime.subtype(), HTML);
+ }
+
+ #[test]
+ fn test_matching() {
+ match (TEXT_PLAIN.type_(), TEXT_PLAIN.subtype()) {
+ (TEXT, PLAIN) => (),
+ _ => unreachable!(),
+ }
+ }
+
+ #[test]
+ fn test_suffix() {
+ assert_eq!(TEXT_PLAIN.suffix(), None);
+ let mime = Mime::from_str("text/html+xml").unwrap();
+ assert_eq!(mime.suffix(), Some(XML));
+ }
+
+ #[test]
+ fn test_mime_fmt() {
+ let mime = TEXT_PLAIN;
+ assert_eq!(mime.to_string(), "text/plain");
+ let mime = TEXT_PLAIN_UTF_8;
+ assert_eq!(mime.to_string(), "text/plain; charset=utf-8");
+ }
+
+ #[test]
+ fn test_mime_from_str() {
+ assert_eq!(Mime::from_str("text/plain").unwrap(), TEXT_PLAIN);
+ assert_eq!(Mime::from_str("TEXT/PLAIN").unwrap(), TEXT_PLAIN);
+ assert_eq!(Mime::from_str("text/plain;charset=utf-8").unwrap(), TEXT_PLAIN_UTF_8);
+ assert_eq!(Mime::from_str("text/plain;charset=\"utf-8\"").unwrap(), TEXT_PLAIN_UTF_8);
+
+ // spaces
+ assert_eq!(Mime::from_str("text/plain; charset=utf-8").unwrap(), TEXT_PLAIN_UTF_8);
+
+ // quotes + semi colon
+ Mime::from_str("text/plain;charset=\"utf-8\"; foo=bar").unwrap();
+ Mime::from_str("text/plain;charset=\"utf-8\" ; foo=bar").unwrap();
+
+ let upper = Mime::from_str("TEXT/PLAIN").unwrap();
+ assert_eq!(upper, TEXT_PLAIN);
+ assert_eq!(upper.type_(), TEXT);
+ assert_eq!(upper.subtype(), PLAIN);
+
+
+ let extended = Mime::from_str("TEXT/PLAIN; CHARSET=UTF-8; FOO=BAR").unwrap();
+ assert_eq!(extended, "text/plain; charset=utf-8; foo=BAR");
+ assert_eq!(extended.get_param("charset").unwrap(), "utf-8");
+ assert_eq!(extended.get_param("foo").unwrap(), "BAR");
+
+ Mime::from_str("multipart/form-data; boundary=--------foobar").unwrap();
+
+ // stars
+ assert_eq!("*/*".parse::<Mime>().unwrap(), STAR_STAR);
+ assert_eq!("image/*".parse::<Mime>().unwrap(), "image/*");
+ assert_eq!("text/*; charset=utf-8".parse::<Mime>().unwrap(), "text/*; charset=utf-8");
+
+ // parse errors
+ Mime::from_str("f o o / bar").unwrap_err();
+ Mime::from_str("text\n/plain").unwrap_err();
+ Mime::from_str("text\r/plain").unwrap_err();
+ Mime::from_str("text/\r\nplain").unwrap_err();
+ Mime::from_str("text/plain;\r\ncharset=utf-8").unwrap_err();
+ Mime::from_str("text/plain; charset=\r\nutf-8").unwrap_err();
+ Mime::from_str("text/plain; charset=\"\r\nutf-8\"").unwrap_err();
+ }
+
+ #[test]
+ fn test_mime_from_str_empty_parameter_list() {
+ static CASES: &'static [&'static str] = &[
+ "text/event-stream;",
+ "text/event-stream; ",
+ "text/event-stream; ",
+ ];
+
+ for case in CASES {
+ let mime = Mime::from_str(case).expect(case);
+ assert_eq!(mime, TEXT_EVENT_STREAM, "case = {:?}", case);
+ assert_eq!(mime.type_(), TEXT, "case = {:?}", case);
+ assert_eq!(mime.subtype(), EVENT_STREAM, "case = {:?}", case);
+ assert!(!mime.has_params(), "case = {:?}", case);
+ }
+
+ }
+
+ #[test]
+ fn test_case_sensitive_values() {
+ let mime = Mime::from_str("multipart/form-data; charset=BASE64; boundary=ABCDEFG").unwrap();
+ assert_eq!(mime.get_param(CHARSET).unwrap(), "bAsE64");
+ assert_eq!(mime.get_param(BOUNDARY).unwrap(), "ABCDEFG");
+ assert_ne!(mime.get_param(BOUNDARY).unwrap(), "abcdefg");
+ }
+
+ #[test]
+ fn test_get_param() {
+ assert_eq!(TEXT_PLAIN.get_param("charset"), None);
+ assert_eq!(TEXT_PLAIN.get_param("baz"), None);
+
+ assert_eq!(TEXT_PLAIN_UTF_8.get_param("charset"), Some(UTF_8));
+ assert_eq!(TEXT_PLAIN_UTF_8.get_param("baz"), None);
+
+ let mime = Mime::from_str("text/plain; charset=utf-8; foo=bar").unwrap();
+ assert_eq!(mime.get_param(CHARSET).unwrap(), "utf-8");
+ assert_eq!(mime.get_param("foo").unwrap(), "bar");
+ assert_eq!(mime.get_param("baz"), None);
+
+
+ let mime = Mime::from_str("text/plain;charset=\"utf-8\"").unwrap();
+ assert_eq!(mime.get_param(CHARSET), Some(UTF_8));
+ }
+
+ #[test]
+ fn test_name_eq() {
+ assert_eq!(TEXT, TEXT);
+ assert_eq!(TEXT, "text");
+ assert_eq!("text", TEXT);
+ assert_eq!(TEXT, "TEXT");
+
+ let param = Name {
+ source: "ABC",
+ insensitive: false,
+ };
+
+ assert_eq!(param, param);
+ assert_eq!(param, "ABC");
+ assert_eq!("ABC", param);
+ assert_ne!(param, "abc");
+ assert_ne!("abc", param);
+ }
+
+ #[test]
+ fn test_essence_str() {
+ assert_eq!(TEXT_PLAIN.essence_str(), "text/plain");
+ assert_eq!(TEXT_PLAIN_UTF_8.essence_str(), "text/plain");
+ assert_eq!(IMAGE_SVG.essence_str(), "image/svg+xml");
+ }
+}
diff --git a/third_party/rust/mime/src/parse.rs b/third_party/rust/mime/src/parse.rs
new file mode 100644
index 0000000000..d55e5494cb
--- /dev/null
+++ b/third_party/rust/mime/src/parse.rs
@@ -0,0 +1,363 @@
+#[allow(unused, deprecated)]
+use std::ascii::AsciiExt;
+use std::error::Error;
+use std::fmt;
+use std::iter::Enumerate;
+use std::str::Bytes;
+
+use super::{Mime, Source, ParamSource, Indexed, CHARSET, UTF_8};
+
+#[derive(Debug)]
+pub enum ParseError {
+ MissingSlash,
+ MissingEqual,
+ MissingQuote,
+ InvalidToken {
+ pos: usize,
+ byte: u8,
+ },
+}
+
+impl ParseError {
+ fn s(&self) -> &str {
+ use self::ParseError::*;
+
+ match *self {
+ MissingSlash => "a slash (/) was missing between the type and subtype",
+ MissingEqual => "an equals sign (=) was missing between a parameter and its value",
+ MissingQuote => "a quote (\") was missing from a parameter value",
+ InvalidToken { .. } => "an invalid token was encountered",
+ }
+ }
+}
+
+impl fmt::Display for ParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let ParseError::InvalidToken { pos, byte } = *self {
+ write!(f, "{}, {:X} at position {}", self.s(), byte, pos)
+ } else {
+ f.write_str(self.s())
+ }
+ }
+}
+
+impl Error for ParseError {
+ // Minimum Rust is 1.15, Error::description was still required then
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ self.s()
+ }
+}
+
+pub fn parse(s: &str) -> Result<Mime, ParseError> {
+ if s == "*/*" {
+ return Ok(::STAR_STAR);
+ }
+
+ let mut iter = s.bytes().enumerate();
+ // toplevel
+ let mut start;
+ let slash;
+ loop {
+ match iter.next() {
+ Some((_, c)) if is_token(c) => (),
+ Some((i, b'/')) if i > 0 => {
+ slash = i;
+ start = i + 1;
+ break;
+ },
+ None => return Err(ParseError::MissingSlash), // EOF and no toplevel is no Mime
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ })
+ };
+
+ }
+
+ // sublevel
+ let mut plus = None;
+ loop {
+ match iter.next() {
+ Some((i, b'+')) if i > start => {
+ plus = Some(i);
+ },
+ Some((i, b';')) if i > start => {
+ start = i;
+ break;
+ },
+ Some((_, c)) if is_token(c) => (),
+ None => {
+ return Ok(Mime {
+ source: Source::Dynamic(s.to_ascii_lowercase()),
+ slash: slash,
+ plus: plus,
+ params: ParamSource::None,
+ });
+ },
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ })
+ };
+ }
+
+ // params
+ let params = params_from_str(s, &mut iter, start)?;
+
+ let src = match params {
+ ParamSource::Utf8(_) => s.to_ascii_lowercase(),
+ ParamSource::Custom(semicolon, ref indices) => lower_ascii_with_params(s, semicolon, indices),
+ ParamSource::None => {
+ // Chop off the empty list
+ s[..start].to_ascii_lowercase()
+ }
+ };
+
+ Ok(Mime {
+ source: Source::Dynamic(src),
+ slash: slash,
+ plus: plus,
+ params: params,
+ })
+}
+
+
+fn params_from_str(s: &str, iter: &mut Enumerate<Bytes>, mut start: usize) -> Result<ParamSource, ParseError> {
+ let semicolon = start;
+ start += 1;
+ let mut params = ParamSource::None;
+ 'params: while start < s.len() {
+ let name;
+ // name
+ 'name: loop {
+ match iter.next() {
+ Some((i, b' ')) if i == start => {
+ start = i + 1;
+ continue 'params;
+ },
+ Some((_, c)) if is_token(c) => (),
+ Some((i, b'=')) if i > start => {
+ name = Indexed(start, i);
+ start = i + 1;
+ break 'name;
+ },
+ None => return Err(ParseError::MissingEqual),
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ }),
+ }
+ }
+
+ let value;
+ // values must be restrict-name-char or "anything goes"
+ let mut is_quoted = false;
+
+ 'value: loop {
+ if is_quoted {
+ match iter.next() {
+ Some((i, b'"')) if i > start => {
+ value = Indexed(start, i);
+ break 'value;
+ },
+ Some((_, c)) if is_restricted_quoted_char(c) => (),
+ None => return Err(ParseError::MissingQuote),
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ }),
+ }
+ } else {
+ match iter.next() {
+ Some((i, b'"')) if i == start => {
+ is_quoted = true;
+ start = i + 1;
+ },
+ Some((_, c)) if is_token(c) => (),
+ Some((i, b';')) if i > start => {
+ value = Indexed(start, i);
+ start = i + 1;
+ break 'value;
+ }
+ None => {
+ value = Indexed(start, s.len());
+ start = s.len();
+ break 'value;
+ },
+
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ }),
+ }
+ }
+ }
+
+ if is_quoted {
+ 'ws: loop {
+ match iter.next() {
+ Some((i, b';')) => {
+ // next param
+ start = i + 1;
+ break 'ws;
+ },
+ Some((_, b' ')) => {
+ // skip whitespace
+ },
+ None => {
+ // eof
+ start = s.len();
+ break 'ws;
+ },
+ Some((pos, byte)) => return Err(ParseError::InvalidToken {
+ pos: pos,
+ byte: byte,
+ }),
+ }
+ }
+ }
+
+ match params {
+ ParamSource::Utf8(i) => {
+ let i = i + 2;
+ let charset = Indexed(i, "charset".len() + i);
+ let utf8 = Indexed(charset.1 + 1, charset.1 + "utf-8".len() + 1);
+ params = ParamSource::Custom(semicolon, vec![
+ (charset, utf8),
+ (name, value),
+ ]);
+ },
+ ParamSource::Custom(_, ref mut vec) => {
+ vec.push((name, value));
+ },
+ ParamSource::None => {
+ if semicolon + 2 == name.0 && CHARSET == &s[name.0..name.1] {
+ if UTF_8 == &s[value.0..value.1] {
+ params = ParamSource::Utf8(semicolon);
+ continue 'params;
+ }
+ }
+ params = ParamSource::Custom(semicolon, vec![(name, value)]);
+ },
+ }
+ }
+ Ok(params)
+}
+
+fn lower_ascii_with_params(s: &str, semi: usize, params: &[(Indexed, Indexed)]) -> String {
+ let mut owned = s.to_owned();
+ owned[..semi].make_ascii_lowercase();
+
+ for &(ref name, ref value) in params {
+ owned[name.0..name.1].make_ascii_lowercase();
+ // Since we just converted this part of the string to lowercase,
+ // we can skip the `Name == &str` unicase check and do a faster
+ // memcmp instead.
+ if &owned[name.0..name.1] == CHARSET.source {
+ owned[value.0..value.1].make_ascii_lowercase();
+ }
+ }
+
+ owned
+}
+
+// From [RFC6838](http://tools.ietf.org/html/rfc6838#section-4.2):
+//
+// > All registered media types MUST be assigned top-level type and
+// > subtype names. The combination of these names serves to uniquely
+// > identify the media type, and the subtype name facet (or the absence
+// > of one) identifies the registration tree. Both top-level type and
+// > subtype names are case-insensitive.
+// >
+// > Type and subtype names MUST conform to the following ABNF:
+// >
+// > type-name = restricted-name
+// > subtype-name = restricted-name
+// >
+// > restricted-name = restricted-name-first *126restricted-name-chars
+// > restricted-name-first = ALPHA / DIGIT
+// > restricted-name-chars = ALPHA / DIGIT / "!" / "#" /
+// > "$" / "&" / "-" / "^" / "_"
+// > restricted-name-chars =/ "." ; Characters before first dot always
+// > ; specify a facet name
+// > restricted-name-chars =/ "+" ; Characters after last plus always
+// > ; specify a structured syntax suffix
+
+// However, [HTTP](https://tools.ietf.org/html/rfc7231#section-3.1.1.1):
+//
+// > media-type = type "/" subtype *( OWS ";" OWS parameter )
+// > type = token
+// > subtype = token
+// > parameter = token "=" ( token / quoted-string )
+//
+// Where token is defined as:
+//
+// > token = 1*tchar
+// > tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+// > "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+//
+// So, clearly, ¯\_(Ä_/¯
+
+macro_rules! byte_map {
+ ($($flag:expr,)*) => ([
+ $($flag != 0,)*
+ ])
+}
+
+static TOKEN_MAP: [bool; 256] = byte_map![
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+];
+
+fn is_token(c: u8) -> bool {
+ TOKEN_MAP[c as usize]
+}
+
+fn is_restricted_quoted_char(c: u8) -> bool {
+ c > 31 && c != 127
+}
+
+#[test]
+#[allow(warnings)] // ... ranges deprecated
+fn test_lookup_tables() {
+ for (i, &valid) in TOKEN_MAP.iter().enumerate() {
+ let i = i as u8;
+ let should = match i {
+ b'a'...b'z' |
+ b'A'...b'Z' |
+ b'0'...b'9' |
+ b'!' |
+ b'#' |
+ b'$' |
+ b'%' |
+ b'&' |
+ b'\'' |
+ b'*' |
+ b'+' |
+ b'-' |
+ b'.' |
+ b'^' |
+ b'_' |
+ b'`' |
+ b'|' |
+ b'~' => true,
+ _ => false
+ };
+ assert_eq!(valid, should, "{:?} ({}) should be {}", i as char, i, should);
+ }
+}
diff --git a/third_party/rust/mime_guess/.cargo-checksum.json b/third_party/rust/mime_guess/.cargo-checksum.json
new file mode 100644
index 0000000000..5652db3fcf
--- /dev/null
+++ b/third_party/rust/mime_guess/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.lock":"68df26849ead62e10cc255ca2009ddba651d393be3499aefa24d25538922768f","Cargo.toml":"b7877455bb621228f87ed556f04c007d2704ad3193d1aabeb7526d4006008699","LICENSE":"6919f1acec82afc721be2d9907b993267f433a44d25d8aedf1003b5f59ebfd46","README.md":"8e1db7c6f134caf08edd05732f61de07a322446c58f081cfc0220e7447ab051c","benches/benchmark.rs":"2287c7233cf78a9af98b2b53cd20e221e4a785209bd70a87030f1ade34a02507","build.rs":"8e47254c0a927eeb243058cfc0da413f34a958226707c941e8634e4514562f04","examples/rev_map.rs":"0bab6cc20b9eace741c6cc4a8c67ebfa124df1bf213038c5e34976081ffd2ebc","src/impl_bin_search.rs":"32a89409690d57f074f11eb93a9d6e422f73788af63fc29f980e13d1c2d2fa6f","src/impl_phf.rs":"321028cc657364c6f7c5b5f538b0033bcfd6f3b5ef711304d806c0644466a964","src/lib.rs":"8c8db560605b46a13062a168283e8b0f459242718682642b1f167bec686e5606","src/mime_types.rs":"06223533119bc845dece004db99b2cdc6d43ba5bad19f65628438bc36adb9b2d"},"package":"2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"} \ No newline at end of file
diff --git a/third_party/rust/mime_guess/Cargo.lock b/third_party/rust/mime_guess/Cargo.lock
new file mode 100644
index 0000000000..cc4a1eae48
--- /dev/null
+++ b/third_party/rust/mime_guess/Cargo.lock
@@ -0,0 +1,686 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "anyhow"
+version = "1.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bstr"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cast"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "criterion"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "criterion-plot 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "oorandom 11.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "plotters 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "csv"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "csv-core"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "either"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itertools"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "js-sys"
+version = "0.3.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "log"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "maybe-uninit"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memchr"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "memoffset"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+dependencies = [
+ "criterion 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "nom"
+version = "4.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "oorandom"
+version = "11.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "plotters"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde"
+version = "1.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "sourcefile"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tinytemplate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "version_check"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "version_check"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "walkdir"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "wasm-bindgen-webidl"
+version = "0.2.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "weedle"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c"
+"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
+"checksum bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "502ae1441a0a5adb8fbd38a5955a6416b9493e92b465de5e4a9bde6a539c2c48"
+"checksum bumpalo 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742"
+"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0"
+"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
+"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+"checksum criterion 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc755679c12bda8e5523a71e4d654b6bf2e14bd838dfc48cde6559a05caf7d1"
+"checksum criterion-plot 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a01e15e0ea58e8234f96146b1f91fa9d0e4dd7a38da93ff7a75d42c0b9d3a545"
+"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
+"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
+"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
+"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279"
+"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
+"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
+"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
+"checksum js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7889c7c36282151f6bf465be4700359318aef36baa951462382eae49e9577cf9"
+"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
+"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
+"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
+"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
+"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
+"checksum oorandom 11.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebcec7c9c2a95cacc7cd0ecb89d8a8454eca13906f6deb55258ffff0adeb9405"
+"checksum plotters 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "4e3bb8da247d27ae212529352020f3e5ee16e83c0c258061d27b08ab92675eeb"
+"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
+"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
+"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
+"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
+"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
+"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
+"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
+"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
+"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
+"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
+"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+"checksum tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57a3c6667d3e65eb1bc3aed6fd14011c6cbc3a0665218ab7f5daf040b9ec371a"
+"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
+"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
+"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
+"checksum wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c"
+"checksum wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "11cdb95816290b525b32587d76419facd99662a07e59d3cdb560488a819d9a45"
+"checksum wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3"
+"checksum wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668"
+"checksum wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601"
+"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d"
+"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b"
+"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
+"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/third_party/rust/mime_guess/Cargo.toml b/third_party/rust/mime_guess/Cargo.toml
new file mode 100644
index 0000000000..2718d6dda0
--- /dev/null
+++ b/third_party/rust/mime_guess/Cargo.toml
@@ -0,0 +1,43 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "mime_guess"
+version = "2.0.3"
+authors = ["Austin Bonander <austin.bonander@gmail.com>"]
+description = "A simple crate for detection of a file's MIME type by its extension."
+documentation = "https://docs.rs/mime_guess/"
+readme = "README.md"
+keywords = ["mime", "filesystem", "extension"]
+license = "MIT"
+repository = "https://github.com/abonander/mime_guess"
+
+[[example]]
+name = "rev_map"
+required-features = ["rev-mappings"]
+
+[[bench]]
+name = "benchmark"
+harness = false
+[dependencies.mime]
+version = "0.3"
+
+[dependencies.unicase]
+version = "2.4.0"
+[dev-dependencies.criterion]
+version = "0.3"
+[build-dependencies.unicase]
+version = "2.4.0"
+
+[features]
+default = ["rev-mappings"]
+rev-mappings = []
diff --git a/third_party/rust/mime_guess/LICENSE b/third_party/rust/mime_guess/LICENSE
new file mode 100644
index 0000000000..e3a1862857
--- /dev/null
+++ b/third_party/rust/mime_guess/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Austin Bonander
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/third_party/rust/mime_guess/README.md b/third_party/rust/mime_guess/README.md
new file mode 100644
index 0000000000..e2d1d7eb96
--- /dev/null
+++ b/third_party/rust/mime_guess/README.md
@@ -0,0 +1,81 @@
+# mime_guess [![Build Status](https://travis-ci.org/abonander/mime_guess.svg?branch=master)](https://travis-ci.org/abonander/mime_guess) [![Crates.io](https://img.shields.io/crates/v/mime_guess.svg)](https://crates.io/crates/mime_guess)
+
+MIME/MediaType guessing by file extension.
+Uses a static map of known file extension -> MIME type mappings.
+
+**Returning Contributors: New Requirements for Submissions Below**
+
+##### Required Rust Version: 1.33
+
+#### [Documentation](https://docs.rs/mime_guess/)
+
+### Versioning
+
+Due to a mistaken premature release, `mime_guess` currently publicly depends on a pre-1.0 `mime`,
+which means `mime` upgrades are breaking changes and necessitate a major version bump.
+Refer to the following table to find a version of `mime_guess` which matches your version of `mime`:
+
+| `mime` version | `mime_guess` version |
+|----------------|----------------------|
+| `0.1.x, 0.2.x` | `1.x.y` |
+| `0.3.x` | `2.x.y` |
+
+#### Note: MIME Types Returned Are Not Stable/Guaranteed
+The media types returned for a given extension are not considered to be part of the crate's
+ stable API and are often updated in patch (`x.y.z + 1`) releases to be as correct as possible. MIME
+ changes are backported to previous major releases on a best-effort basis.
+
+Note that only the extensions of paths/filenames are inspected in order to guess the MIME type. The
+file that may or may not reside at that path may or may not be a valid file of the returned MIME type.
+Be wary of unsafe or un-validated assumptions about file structure or length.
+
+An extension may also have multiple applicable MIME types. When more than one is returned, the first
+is considered to be the most "correct"--see below for elaboration.
+
+Contributing
+-----------
+
+#### Adding or correcting MIME types for extensions
+
+Is the MIME type for a file extension wrong or missing? Great!
+Well, not great for us, but great for you if you'd like to open a pull request!
+
+The file extension -> MIME type mappings are listed in `src/mime_types.rs`.
+**The list is sorted lexicographically by file extension, and all extensions are lowercase (where applicable).**
+The former is necessary to support fallback to binary search when the
+`phf-map` feature is turned off, and for the maintainers' sanity.
+The latter is only for consistency's sake; the search is case-insensitive.
+
+Simply add or update the appropriate string pair(s) to make the correction(s) needed.
+Run `cargo test` to make sure the library continues to work correctly.
+
+#### Important! Citing the corrected MIME type
+
+When opening a pull request, please include a link to an official document or RFC noting
+the correct MIME type for the file type in question **in the commit message** so
+that the commit history can be used as an audit trail.
+
+Though we're only guessing here, we like to be as correct as we can.
+It makes it much easier to vet your contribution if we don't have to search for corroborating material.
+
+#### Multiple MIME types per extension
+As of `2.0.0`, multiple MIME types per extension are supported. The first MIME type in the list for
+a given extension should be the most "correct" so users who only care about getting a single MIME
+type can use the `first*()` methods.
+
+The definition of "correct" is open to debate, however. In the author's opinion this should be
+whatever is defined by the latest IETF RFC for the given file format, or otherwise explicitly
+supercedes all others.
+
+If an official IANA registration replaces an older "experimental" style media type, please
+place the new type before the old type in the list, but keep the old type for reference.
+
+#### Changes to the API or operation of the crate
+
+We're open to changes to the crate's API or its inner workings, breaking or not, if it improves the overall operation, efficiency, or ergonomics of the crate. However, it would be a good idea to open an issue on the repository so we can discuss your proposed changes and decide how best to approach them.
+
+
+License
+-------
+
+MIT (See the `LICENSE` file in this repository for more information.)
diff --git a/third_party/rust/mime_guess/benches/benchmark.rs b/third_party/rust/mime_guess/benches/benchmark.rs
new file mode 100644
index 0000000000..4a7af2e584
--- /dev/null
+++ b/third_party/rust/mime_guess/benches/benchmark.rs
@@ -0,0 +1,31 @@
+#[macro_use]
+extern crate criterion;
+extern crate mime_guess;
+
+use self::criterion::Criterion;
+
+use mime_guess::from_ext;
+
+include!("../src/mime_types.rs");
+
+/// WARNING: this may take a while!
+fn bench_mime_str(c: &mut Criterion) {
+ c.bench_function("from_ext", |b| {
+ for (mime_ext, _) in MIME_TYPES {
+ b.iter(|| from_ext(mime_ext).first_raw());
+ }
+ });
+}
+
+fn bench_mime_str_uppercase(c: &mut Criterion) {
+ c.bench_function("from_ext uppercased", |b| {
+ let uppercased = MIME_TYPES.into_iter().map(|(s, _)| s.to_uppercase());
+
+ for mime_ext in uppercased {
+ b.iter(|| from_ext(&mime_ext).first_raw());
+ }
+ });
+}
+
+criterion_group!(benches, bench_mime_str, bench_mime_str_uppercase);
+criterion_main!(benches);
diff --git a/third_party/rust/mime_guess/build.rs b/third_party/rust/mime_guess/build.rs
new file mode 100644
index 0000000000..ff4ea764ef
--- /dev/null
+++ b/third_party/rust/mime_guess/build.rs
@@ -0,0 +1,191 @@
+#[cfg(feature = "phf")]
+extern crate phf_codegen;
+extern crate unicase;
+
+use unicase::UniCase;
+
+use std::env;
+use std::fs::File;
+use std::io::prelude::*;
+use std::io::BufWriter;
+use std::path::Path;
+
+use std::collections::BTreeMap;
+
+use mime_types::MIME_TYPES;
+
+#[path = "src/mime_types.rs"]
+mod mime_types;
+
+#[cfg(feature = "phf")]
+const PHF_PATH: &str = "::impl_::phf";
+
+fn main() {
+ let out_dir = env::var("OUT_DIR").unwrap();
+ let dest_path = Path::new(&out_dir).join("mime_types_generated.rs");
+ let mut outfile = BufWriter::new(File::create(dest_path).unwrap());
+
+ #[cfg(feature = "phf")]
+ build_forward_map(&mut outfile);
+
+ #[cfg(feature = "rev-mappings")]
+ build_rev_map(&mut outfile);
+}
+
+// Build forward mappings (ext -> mime type)
+#[cfg(feature = "phf")]
+fn build_forward_map<W: Write>(out: &mut W) {
+ use phf_codegen::Map as PhfMap;
+
+ let mut forward_map = PhfMap::new();
+ forward_map.phf_path(PHF_PATH);
+
+ let mut map_entries: Vec<(&str, Vec<&str>)> = Vec::new();
+
+ for &(key, types) in MIME_TYPES {
+ if let Some(&mut (key_, ref mut values)) = map_entries.last_mut() {
+ // deduplicate extensions
+ if key == key_ {
+ values.extend_from_slice(types);
+ continue;
+ }
+ }
+
+ map_entries.push((key, types.into()));
+ }
+
+ for (key, values) in map_entries {
+ forward_map.entry(
+ UniCase::new(key),
+ &format!("&{:?}", values),
+ );
+ }
+
+ writeln!(
+ out,
+ "static MIME_TYPES: phf::Map<UniCase<&'static str>, &'static [&'static str]> = \n{};",
+ forward_map.build()
+ )
+ .unwrap();
+}
+
+// Build reverse mappings (mime type -> ext)
+#[cfg(all(feature = "phf", feature = "rev-mappings"))]
+fn build_rev_map<W: Write>(out: &mut W) {
+ use phf_codegen::Map as PhfMap;
+
+ let dyn_map = get_rev_mappings();
+
+ let mut rev_map = PhfMap::new();
+ rev_map.phf_path(PHF_PATH);
+
+ let mut exts = Vec::new();
+
+ for (top, subs) in dyn_map {
+ let top_start = exts.len();
+
+ let mut sub_map = PhfMap::new();
+ sub_map.phf_path(PHF_PATH);
+
+ for (sub, sub_exts) in subs {
+ let sub_start = exts.len();
+ exts.extend(sub_exts);
+ let sub_end = exts.len();
+
+ sub_map.entry(sub, &format!("({}, {})", sub_start, sub_end));
+ }
+
+ let top_end = exts.len();
+
+ rev_map.entry(
+ top,
+ &format!(
+ "TopLevelExts {{ start: {}, end: {}, subs: {} }}",
+ top_start, top_end, sub_map.build()
+ ),
+ );
+ }
+
+ writeln!(
+ out,
+ "static REV_MAPPINGS: phf::Map<UniCase<&'static str>, TopLevelExts> = \n{};",
+ rev_map.build()
+ ).unwrap();
+
+ writeln!(out, "const EXTS: &'static [&'static str] = &{:?};", exts).unwrap();
+}
+
+#[cfg(all(not(feature = "phf"), feature = "rev-mappings"))]
+fn build_rev_map<W: Write>(out: &mut W) {
+ use std::fmt::Write as _;
+
+ macro_rules! unicase_const {
+ ($s:expr) => ({
+ format_args!("{}({:?})", (if $s.is_ascii() {
+ "UniCase::ascii"
+ } else {
+ "UniCase::unicode"
+ }), $s)
+ })
+ }
+
+ let dyn_map = get_rev_mappings();
+
+ write!(out, "static REV_MAPPINGS: &'static [(UniCase<&'static str>, TopLevelExts)] = &[").unwrap();
+
+ let mut exts = Vec::new();
+
+ for (top, subs) in dyn_map {
+ let top_start = exts.len();
+
+ let mut sub_map = String::new();
+
+ for (sub, sub_exts) in subs {
+ let sub_start = exts.len();
+ exts.extend(sub_exts);
+ let sub_end = exts.len();
+
+ write!(
+ sub_map,
+ "({}, ({}, {})),",
+ unicase_const!(sub), sub_start, sub_end
+ ).unwrap();
+ }
+
+ let top_end = exts.len();
+
+ write!(
+ out,
+ "({}, TopLevelExts {{ start: {}, end: {}, subs: &[{}] }}),",
+ unicase_const!(top), top_start, top_end, sub_map
+ ).unwrap();
+ }
+
+ writeln!(out, "];").unwrap();
+
+ writeln!(out, "const EXTS: &'static [&'static str] = &{:?};", exts).unwrap();
+}
+
+#[cfg(feature = "rev-mappings")]
+fn get_rev_mappings(
+) -> BTreeMap<UniCase<&'static str>, BTreeMap<UniCase<&'static str>, Vec<&'static str>>> {
+ // First, collect all the mime type -> ext mappings)
+ let mut dyn_map = BTreeMap::new();
+ for &(key, types) in MIME_TYPES {
+ for val in types {
+ let (top, sub) = split_mime(val);
+ dyn_map
+ .entry(UniCase::new(top))
+ .or_insert_with(BTreeMap::new)
+ .entry(UniCase::new(sub))
+ .or_insert_with(Vec::new)
+ .push(key);
+ }
+ }
+ dyn_map
+}
+
+fn split_mime(mime: &str) -> (&str, &str) {
+ let split_idx = mime.find('/').unwrap();
+ (&mime[..split_idx], &mime[split_idx + 1..])
+}
diff --git a/third_party/rust/mime_guess/examples/rev_map.rs b/third_party/rust/mime_guess/examples/rev_map.rs
new file mode 100644
index 0000000000..f6f2fdeaf9
--- /dev/null
+++ b/third_party/rust/mime_guess/examples/rev_map.rs
@@ -0,0 +1,14 @@
+extern crate mime_guess;
+
+fn main() {
+ print_exts("video/*");
+ print_exts("video/x-matroska");
+}
+
+fn print_exts(mime_type: &str) {
+ println!(
+ "Exts for {:?}: {:?}",
+ mime_type,
+ mime_guess::get_mime_extensions_str(mime_type)
+ );
+}
diff --git a/third_party/rust/mime_guess/src/impl_bin_search.rs b/third_party/rust/mime_guess/src/impl_bin_search.rs
new file mode 100644
index 0000000000..2653714505
--- /dev/null
+++ b/third_party/rust/mime_guess/src/impl_bin_search.rs
@@ -0,0 +1,41 @@
+use unicase::UniCase;
+
+include!("mime_types.rs");
+include!(concat!(env!("OUT_DIR"), "/mime_types_generated.rs"));
+
+#[cfg(feature = "rev-mappings")]
+#[derive(Copy, Clone)]
+struct TopLevelExts {
+ start: usize,
+ end: usize,
+ subs: &'static [(UniCase<&'static str>, (usize, usize))],
+}
+
+pub fn get_mime_types(ext: &str) -> Option<&'static [&'static str]> {
+ let ext = UniCase::new(ext);
+
+ map_lookup(MIME_TYPES, &ext)
+}
+
+#[cfg(feature = "rev-mappings")]
+pub fn get_extensions(toplevel: &str, sublevel: &str) -> Option<&'static [&'static str]> {
+ if toplevel == "*" {
+ return Some(EXTS);
+ }
+
+ let top = map_lookup(REV_MAPPINGS, toplevel)?;
+
+ if sublevel == "*" {
+ return Some(&EXTS[top.start..top.end]);
+ }
+
+ let sub = map_lookup(&top.subs, sublevel)?;
+ Some(&EXTS[sub.0..sub.1])
+}
+
+fn map_lookup<K, V>(map: &'static [(K, V)], key: &str) -> Option<V>
+ where K: Copy + Into<UniCase<&'static str>>, V: Copy {
+ map.binary_search_by_key(&UniCase::new(key), |(k, _)| (*k).into())
+ .ok()
+ .map(|i| map[i].1)
+}
diff --git a/third_party/rust/mime_guess/src/impl_phf.rs b/third_party/rust/mime_guess/src/impl_phf.rs
new file mode 100644
index 0000000000..980c31f369
--- /dev/null
+++ b/third_party/rust/mime_guess/src/impl_phf.rs
@@ -0,0 +1,40 @@
+extern crate phf;
+
+use unicase::UniCase;
+
+include!(concat!(env!("OUT_DIR"), "/mime_types_generated.rs"));
+
+#[cfg(feature = "rev-mappings")]
+struct TopLevelExts {
+ start: usize,
+ end: usize,
+ subs: phf::Map<UniCase<&'static str>, (usize, usize)>,
+}
+
+pub fn get_mime_types(ext: &str) -> Option<&'static [&'static str]> {
+ map_lookup(&MIME_TYPES, ext).cloned()
+}
+
+pub fn get_extensions(toplevel: &str, sublevel: &str) -> Option<&'static [&'static str]> {
+ if toplevel == "*" {
+ return Some(EXTS);
+ }
+
+ let top = map_lookup(&REV_MAPPINGS, toplevel)?;
+
+ if sublevel == "*" {
+ return Some(&EXTS[top.start..top.end]);
+ }
+
+ let sub = map_lookup(&top.subs, sublevel)?;
+ Some(&EXTS[sub.0..sub.1])
+}
+
+fn map_lookup<'key, 'map: 'key, V>(
+ map: &'map phf::Map<UniCase<&'static str>, V>,
+ key: &'key str,
+) -> Option<&'map V> {
+ // FIXME: this doesn't compile unless we transmute `key` to `UniCase<&'static str>`
+ // https://github.com/sfackler/rust-phf/issues/169
+ map.get(&UniCase::new(key))
+}
diff --git a/third_party/rust/mime_guess/src/lib.rs b/third_party/rust/mime_guess/src/lib.rs
new file mode 100644
index 0000000000..a40c4ecfc0
--- /dev/null
+++ b/third_party/rust/mime_guess/src/lib.rs
@@ -0,0 +1,526 @@
+//! Guessing of MIME types by file extension.
+//!
+//! Uses a static list of file-extension : MIME type mappings.
+//!
+//! ```
+//! # extern crate mime;
+//! // the file doesn't have to exist, it just looks at the path
+//! let guess = mime_guess::from_path("some_file.gif");
+//! assert_eq!(guess.first(), Some(mime::IMAGE_GIF));
+//!
+//! ```
+//!
+//! #### Note: MIME Types Returned Are Not Stable/Guaranteed
+//! The media types returned for a given extension are not considered to be part of the crate's
+//! stable API and are often updated in patch <br /> (`x.y.[z + 1]`) releases to be as correct as
+//! possible.
+//!
+//! Additionally, only the extensions of paths/filenames are inspected in order to guess the MIME
+//! type. The file that may or may not reside at that path may or may not be a valid file of the
+//! returned MIME type. Be wary of unsafe or un-validated assumptions about file structure or
+//! length.
+pub extern crate mime;
+extern crate unicase;
+
+pub use mime::Mime;
+
+use std::ffi::OsStr;
+use std::iter::FusedIterator;
+use std::path::Path;
+use std::{iter, slice};
+
+#[cfg(feature = "phf")]
+#[path = "impl_phf.rs"]
+mod impl_;
+
+#[cfg(not(feature = "phf"))]
+#[path = "impl_bin_search.rs"]
+mod impl_;
+
+/// A "guess" of the MIME/Media Type(s) of an extension or path as one or more
+/// [`Mime`](struct.Mime.html) instances.
+///
+/// ### Note: Ordering
+/// A given file format may have one or more applicable Media Types; in this case
+/// the first Media Type returned is whatever is declared in the latest IETF RFC for the
+/// presumed file format or the one that explicitly supercedes all others.
+/// Ordering of additional Media Types is arbitrary.
+///
+/// ### Note: Values Not Stable
+/// The exact Media Types returned in any given guess are not considered to be stable and are often
+/// updated in patch releases in order to reflect the most up-to-date information possible.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+// FIXME: change repr when `mime` gains macro/const fn constructor
+pub struct MimeGuess(&'static [&'static str]);
+
+impl MimeGuess {
+ /// Guess the MIME type of a file (real or otherwise) with the given extension.
+ ///
+ /// The search is case-insensitive.
+ ///
+ /// If `ext` is empty or has no (currently) known MIME type mapping, then an empty guess is
+ /// returned.
+ pub fn from_ext(ext: &str) -> MimeGuess {
+ if ext.is_empty() {
+ return MimeGuess(&[]);
+ }
+
+ impl_::get_mime_types(ext).map_or(MimeGuess(&[]), |v| MimeGuess(v))
+ }
+
+ /// Guess the MIME type of `path` by its extension (as defined by
+ /// [`Path::extension()`]). **No disk access is performed.**
+ ///
+ /// If `path` has no extension, the extension cannot be converted to `str`, or has
+ /// no known MIME type mapping, then an empty guess is returned.
+ ///
+ /// The search is case-insensitive.
+ ///
+ /// ## Note
+ /// **Guess** is the operative word here, as there are no guarantees that the contents of the
+ /// file that `path` points to match the MIME type associated with the path's extension.
+ ///
+ /// Take care when processing files with assumptions based on the return value of this function.
+ ///
+ /// [`Path::extension()`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.extension
+ pub fn from_path<P: AsRef<Path>>(path: P) -> MimeGuess {
+ path.as_ref()
+ .extension()
+ .and_then(OsStr::to_str)
+ .map_or(MimeGuess(&[]), Self::from_ext)
+ }
+
+ /// `true` if the guess did not return any known mappings for the given path or extension.
+ pub fn is_empty(&self) -> bool {
+ self.0.is_empty()
+ }
+
+ /// Get the number of MIME types in the current guess.
+ pub fn count(&self) -> usize {
+ self.0.len()
+ }
+
+ /// Get the first guessed `Mime`, if applicable.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn first(&self) -> Option<Mime> {
+ self.first_raw().map(expect_mime)
+ }
+
+ /// Get the first guessed Media Type as a string, if applicable.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn first_raw(&self) -> Option<&'static str> {
+ self.0.get(0).cloned()
+ }
+
+ /// Get the first guessed `Mime`, or if the guess is empty, return
+ /// [`application/octet-stream`] instead.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ ///
+ /// ### Note: HTTP Applications
+ /// For HTTP request and response bodies if a value for the `Content-Type` header
+ /// cannot be determined it might be preferable to not send one at all instead of defaulting to
+ /// `application/content-stream` as the recipient will expect to infer the format directly from
+ /// the content instead. ([RFC 7231, Section 3.1.1.5][rfc7231])
+ ///
+ /// On the contrary, for `multipart/form-data` bodies, the `Content-Type` of a form-data part is
+ /// assumed to be `text/plain` unless specified so a default of `application/content-stream`
+ /// for non-text parts is safer. ([RFC 7578, Section 4.4][rfc7578])
+ ///
+ /// [`application/octet-stream`]: https://docs.rs/mime/0.3/mime/constant.APPLICATION_OCTET_STREAM.html
+ /// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
+ /// [rfc7578]: https://tools.ietf.org/html/rfc7578#section-4.4
+ pub fn first_or_octet_stream(&self) -> Mime {
+ self.first_or(mime::APPLICATION_OCTET_STREAM)
+ }
+
+ /// Get the first guessed `Mime`, or if the guess is empty, return
+ /// [`text/plain`](::mime::TEXT_PLAIN) instead.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn first_or_text_plain(&self) -> Mime {
+ self.first_or(mime::TEXT_PLAIN)
+ }
+
+ /// Get the first guessed `Mime`, or if the guess is empty, return the given `Mime` instead.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn first_or(&self, default: Mime) -> Mime {
+ self.first().unwrap_or(default)
+ }
+
+ /// Get the first guessed `Mime`, or if the guess is empty, execute the closure and return its
+ /// result.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn first_or_else<F>(&self, default_fn: F) -> Mime
+ where
+ F: FnOnce() -> Mime,
+ {
+ self.first().unwrap_or_else(default_fn)
+ }
+
+ /// Get an iterator over the `Mime` values contained in this guess.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn iter(&self) -> Iter {
+ Iter(self.iter_raw().map(expect_mime))
+ }
+
+ /// Get an iterator over the raw media-type strings in this guess.
+ ///
+ /// See [Note: Ordering](#note-ordering) above.
+ pub fn iter_raw(&self) -> IterRaw {
+ IterRaw(self.0.iter().cloned())
+ }
+}
+
+impl IntoIterator for MimeGuess {
+ type Item = Mime;
+ type IntoIter = Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl<'a> IntoIterator for &'a MimeGuess {
+ type Item = Mime;
+ type IntoIter = Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+/// An iterator over the `Mime` types of a `MimeGuess`.
+///
+/// See [Note: Ordering on `MimeGuess`](struct.MimeGuess.html#note-ordering).
+#[derive(Clone, Debug)]
+pub struct Iter(iter::Map<IterRaw, fn(&'static str) -> Mime>);
+
+impl Iterator for Iter {
+ type Item = Mime;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+}
+
+impl DoubleEndedIterator for Iter {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.0.next_back()
+ }
+}
+
+impl FusedIterator for Iter {}
+
+impl ExactSizeIterator for Iter {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+/// An iterator over the raw media type strings of a `MimeGuess`.
+///
+/// See [Note: Ordering on `MimeGuess`](struct.MimeGuess.html#note-ordering).
+#[derive(Clone, Debug)]
+pub struct IterRaw(iter::Cloned<slice::Iter<'static, &'static str>>);
+
+impl Iterator for IterRaw {
+ type Item = &'static str;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+}
+
+impl DoubleEndedIterator for IterRaw {
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.0.next_back()
+ }
+}
+
+impl FusedIterator for IterRaw {}
+
+impl ExactSizeIterator for IterRaw {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+fn expect_mime(s: &str) -> Mime {
+ // `.parse()` should be checked at compile time to never fail
+ s.parse()
+ .unwrap_or_else(|e| panic!("failed to parse media-type {:?}: {}", s, e))
+}
+
+/// Wrapper of [`MimeGuess::from_ext()`](struct.MimeGuess.html#method.from_ext).
+pub fn from_ext(ext: &str) -> MimeGuess {
+ MimeGuess::from_ext(ext)
+}
+
+/// Wrapper of [`MimeGuess::from_path()`](struct.MimeGuess.html#method.from_path).
+pub fn from_path<P: AsRef<Path>>(path: P) -> MimeGuess {
+ MimeGuess::from_path(path)
+}
+
+/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
+///
+/// If `path` has no extension, or its extension has no known MIME type mapping,
+/// then the MIME type is assumed to be `application/octet-stream`.
+///
+/// ## Note
+/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
+/// that `path` points to match the MIME type associated with the path's extension.
+///
+/// Take care when processing files with assumptions based on the return value of this function.
+///
+/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
+/// header at all instead of defaulting to `application/content-stream`.
+///
+/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
+#[deprecated(
+ since = "2.0.0",
+ note = "Use `from_path(path).first_or_octet_stream()` instead"
+)]
+pub fn guess_mime_type<P: AsRef<Path>>(path: P) -> Mime {
+ from_path(path).first_or_octet_stream()
+}
+
+/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
+///
+/// If `path` has no extension, or its extension has no known MIME type mapping,
+/// then `None` is returned.
+///
+#[deprecated(since = "2.0.0", note = "Use `from_path(path).first()` instead")]
+pub fn guess_mime_type_opt<P: AsRef<Path>>(path: P) -> Option<Mime> {
+ from_path(path).first()
+}
+
+/// Guess the MIME type string of `path` by its extension (as defined by `Path::extension()`).
+///
+/// If `path` has no extension, or its extension has no known MIME type mapping,
+/// then `None` is returned.
+///
+/// ## Note
+/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
+/// that `path` points to match the MIME type associated with the path's extension.
+///
+/// Take care when processing files with assumptions based on the return value of this function.
+#[deprecated(since = "2.0.0", note = "Use `from_path(path).first_raw()` instead")]
+pub fn mime_str_for_path_ext<P: AsRef<Path>>(path: P) -> Option<&'static str> {
+ from_path(path).first_raw()
+}
+
+/// Get the MIME type associated with a file extension.
+///
+/// If there is no association for the extension, or `ext` is empty,
+/// `application/octet-stream` is returned.
+///
+/// ## Note
+/// In HTTP applications, it might be [preferable][rfc7231] to not send a `Content-Type`
+/// header at all instead of defaulting to `application/content-stream`.
+///
+/// [rfc7231]: https://tools.ietf.org/html/rfc7231#section-3.1.1.5
+#[deprecated(
+ since = "2.0.0",
+ note = "use `from_ext(search_ext).first_or_octet_stream()` instead"
+)]
+pub fn get_mime_type(search_ext: &str) -> Mime {
+ from_ext(search_ext).first_or_octet_stream()
+}
+
+/// Get the MIME type associated with a file extension.
+///
+/// If there is no association for the extension, or `ext` is empty,
+/// `None` is returned.
+#[deprecated(since = "2.0.0", note = "use `from_ext(search_ext).first()` instead")]
+pub fn get_mime_type_opt(search_ext: &str) -> Option<Mime> {
+ from_ext(search_ext).first()
+}
+
+/// Get the MIME type string associated with a file extension. Case-insensitive.
+///
+/// If `search_ext` is not already lowercase,
+/// it will be converted to lowercase to facilitate the search.
+///
+/// Returns `None` if `search_ext` is empty or an associated extension was not found.
+#[deprecated(
+ since = "2.0.0",
+ note = "use `from_ext(search_ext).first_raw()` instead"
+)]
+pub fn get_mime_type_str(search_ext: &str) -> Option<&'static str> {
+ from_ext(search_ext).first_raw()
+}
+
+/// Get a list of known extensions for a given `Mime`.
+///
+/// Ignores parameters (only searches with `<main type>/<subtype>`). Case-insensitive (for extension types).
+///
+/// Returns `None` if the MIME type is unknown.
+///
+/// ### Wildcards
+/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
+///
+/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
+#[cfg(feature = "rev-mappings")]
+pub fn get_mime_extensions(mime: &Mime) -> Option<&'static [&'static str]> {
+ get_extensions(mime.type_().as_ref(), mime.subtype().as_ref())
+}
+
+/// Get a list of known extensions for a MIME type string.
+///
+/// Ignores parameters (only searches `<main type>/<subtype>`). Case-insensitive.
+///
+/// Returns `None` if the MIME type is unknown.
+///
+/// ### Wildcards
+/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
+///
+/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
+///
+/// ### Panics
+/// If `mime_str` is not a valid MIME type specifier (naive).
+#[cfg(feature = "rev-mappings")]
+pub fn get_mime_extensions_str(mut mime_str: &str) -> Option<&'static [&'static str]> {
+ mime_str = mime_str.trim();
+
+ if let Some(sep_idx) = mime_str.find(';') {
+ mime_str = &mime_str[..sep_idx];
+ }
+
+ let (top, sub) = {
+ let split_idx = mime_str.find('/').unwrap();
+ (&mime_str[..split_idx], &mime_str[split_idx + 1..])
+ };
+
+ get_extensions(top, sub)
+}
+
+/// Get the extensions for a given top-level and sub-level of a MIME type
+/// (`{toplevel}/{sublevel}`).
+///
+/// Returns `None` if `toplevel` or `sublevel` are unknown.
+///
+/// ### Wildcards
+/// If the top-level of the MIME type is a wildcard (`*`), returns all extensions.
+///
+/// If the sub-level of the MIME type is a wildcard, returns all extensions for the top-level.
+#[cfg(feature = "rev-mappings")]
+pub fn get_extensions(toplevel: &str, sublevel: &str) -> Option<&'static [&'static str]> {
+ impl_::get_extensions(toplevel, sublevel)
+}
+
+/// Get the MIME type for `application/octet-stream` (generic binary stream)
+#[deprecated(since = "2.0.0", note = "use `mime::APPLICATION_OCTET_STREAM` instead")]
+pub fn octet_stream() -> Mime {
+ "application/octet-stream".parse().unwrap()
+}
+
+#[cfg(test)]
+mod tests {
+ include!("mime_types.rs");
+
+ use super::{from_ext, from_path, expect_mime};
+ #[allow(deprecated, unused_imports)]
+ use std::ascii::AsciiExt;
+
+ use std::fmt::Debug;
+ use std::path::Path;
+
+
+ #[test]
+ fn check_type_bounds() {
+ fn assert_type_bounds<T: Clone + Debug + Send + Sync + 'static>() {}
+
+ assert_type_bounds::<super::MimeGuess>();
+ assert_type_bounds::<super::Iter>();
+ assert_type_bounds::<super::IterRaw>();
+ }
+
+ #[test]
+ fn test_mime_type_guessing() {
+ assert_eq!(
+ from_ext("gif").first_or_octet_stream().to_string(),
+ "image/gif".to_string()
+ );
+ assert_eq!(
+ from_ext("TXT").first_or_octet_stream().to_string(),
+ "text/plain".to_string()
+ );
+ assert_eq!(
+ from_ext("blahblah").first_or_octet_stream().to_string(),
+ "application/octet-stream".to_string()
+ );
+
+ assert_eq!(
+ from_path(Path::new("/path/to/file.gif"))
+ .first_or_octet_stream()
+ .to_string(),
+ "image/gif".to_string()
+ );
+ assert_eq!(
+ from_path("/path/to/file.gif").first_or_octet_stream().to_string(),
+ "image/gif".to_string()
+ );
+ }
+
+ #[test]
+ fn test_mime_type_guessing_opt() {
+ assert_eq!(
+ from_ext("gif").first().unwrap().to_string(),
+ "image/gif".to_string()
+ );
+ assert_eq!(
+ from_ext("TXT").first().unwrap().to_string(),
+ "text/plain".to_string()
+ );
+ assert_eq!(from_ext("blahblah").first(), None);
+
+ assert_eq!(
+ from_path("/path/to/file.gif").first().unwrap().to_string(),
+ "image/gif".to_string()
+ );
+ assert_eq!(from_path("/path/to/file").first(), None);
+ }
+
+ #[test]
+ fn test_are_mime_types_parseable() {
+ for (_, mimes) in MIME_TYPES {
+ mimes.iter().for_each(|s| { expect_mime(s); });
+ }
+ }
+
+ // RFC: Is this test necessary anymore? --@cybergeek94, 2/1/2016
+ #[test]
+ fn test_are_extensions_ascii() {
+ for (ext, _) in MIME_TYPES {
+ assert!(ext.is_ascii(), "Extension not ASCII: {:?}", ext);
+ }
+ }
+
+ #[test]
+ fn test_are_extensions_sorted() {
+ // simultaneously checks the requirement that duplicate extension entries are adjacent
+ for (&(ext, _), &(n_ext, _)) in MIME_TYPES.iter().zip(MIME_TYPES.iter().skip(1)) {
+ assert!(
+ ext <= n_ext,
+ "Extensions in src/mime_types should be sorted lexicographically
+ in ascending order. Failed assert: {:?} <= {:?}",
+ ext,
+ n_ext
+ );
+ }
+ }
+}
diff --git a/third_party/rust/mime_guess/src/mime_types.rs b/third_party/rust/mime_guess/src/mime_types.rs
new file mode 100644
index 0000000000..244b4c819c
--- /dev/null
+++ b/third_party/rust/mime_guess/src/mime_types.rs
@@ -0,0 +1,1489 @@
+/// A mapping of known file extensions and their MIME types.
+///
+/// Required to be sorted lexicographically by extension for ease of maintenance.
+///
+/// Multiple MIME types per extension are supported; the order is arbitrary but the first should be
+/// the most prevalent by most recent RFC declaration or explicit succession of other media types.
+///
+/// NOTE: when adding or modifying entries, please include a citation in the commit message.
+/// If a media type for an extension changed, please keep the old entry but add the new one before
+/// it in the slice literal, e.g.:
+///
+///
+///
+/// Sourced from:
+/// https://github.com/samuelneff/MimeTypeMap/blob/master/src/MimeTypes/MimeTypeMap.cs
+/// https://github.com/jshttp/mime-db extracted with https://gist.github.com/soyuka/b7e29d359b2c14c21bdead923c01cc81
+pub static MIME_TYPES: &[(&str, &[&str])] = &[
+ ("123", &["application/vnd.lotus-1-2-3"]),
+ ("323", &["text/h323"]),
+ ("3dml", &["text/vnd.in3d.3dml"]),
+ ("3ds", &["image/x-3ds"]),
+ ("3g2", &["video/3gpp2"]),
+ ("3gp", &["video/3gpp"]),
+ ("3gp2", &["video/3gpp2"]),
+ ("3gpp", &["video/3gpp"]),
+ ("7z", &["application/x-7z-compressed"]),
+ ("aa", &["audio/audible"]),
+ ("aab", &["application/x-authorware-bin"]),
+ ("aac", &["audio/aac"]),
+ ("aaf", &["application/octet-stream"]),
+ ("aam", &["application/x-authorware-map"]),
+ ("aas", &["application/x-authorware-seg"]),
+ ("aax", &["audio/vnd.audible.aax"]),
+ ("abw", &["application/x-abiword"]),
+ ("ac", &["application/pkix-attr-cert"]),
+ ("ac3", &["audio/ac3"]),
+ ("aca", &["application/octet-stream"]),
+ ("acc", &["application/vnd.americandynamics.acc"]),
+ ("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"]),
+ ("ace", &["application/x-ace-compressed"]),
+ ("acu", &["application/vnd.acucobol"]),
+ ("acutc", &["application/vnd.acucorp"]),
+ ("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"]),
+ ("aep", &["application/vnd.audiograph"]),
+ ("afm", &["application/octet-stream"]),
+ ("afp", &["application/vnd.ibm.modcap"]),
+ ("ahead", &["application/vnd.ahead.space"]),
+ ("ai", &["application/postscript"]),
+ ("aif", &["audio/aiff"]),
+ ("aifc", &["audio/aiff"]),
+ ("aiff", &["audio/aiff"]),
+ (
+ "air",
+ &["application/vnd.adobe.air-application-installer-package+zip"],
+ ),
+ ("ait", &["application/vnd.dvb.ait"]),
+ ("amc", &["application/mpeg"]),
+ ("ami", &["application/vnd.amiga.ami"]),
+ ("anx", &["application/annodex"]),
+ ("apk", &["application/vnd.android.package-archive"]),
+ ("apng", &["image/apng"]),
+ ("appcache", &["text/cache-manifest"]),
+ ("application", &["application/x-ms-application"]),
+ ("apr", &["application/vnd.lotus-approach"]),
+ ("arc", &["application/x-freearc"]),
+ ("arj", &["application/x-arj"]),
+ ("art", &["image/x-jg"]),
+ ("asa", &["application/xml"]),
+ ("asax", &["application/xml"]),
+ ("asc", &["application/pgp-signature"]),
+ ("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"]),
+ ("aso", &["application/vnd.accpac.simply.aso"]),
+ ("aspx", &["application/xml"]),
+ ("asr", &["video/x-ms-asf"]),
+ ("asx", &["video/x-ms-asf"]),
+ ("atc", &["application/vnd.acucorp"]),
+ ("atom", &["application/atom+xml"]),
+ ("atomcat", &["application/atomcat+xml"]),
+ ("atomsvc", &["application/atomsvc+xml"]),
+ ("atx", &["application/vnd.antix.game-component"]),
+ ("au", &["audio/basic"]),
+ ("avi", &["video/x-msvideo"]),
+ ("aw", &["application/applixware"]),
+ ("axa", &["audio/annodex"]),
+ ("axs", &["application/olescript"]),
+ ("axv", &["video/annodex"]),
+ ("azf", &["application/vnd.airzip.filesecure.azf"]),
+ ("azs", &["application/vnd.airzip.filesecure.azs"]),
+ ("azw", &["application/vnd.amazon.ebook"]),
+ ("bas", &["text/plain"]),
+ ("bat", &["application/x-msdownload"]),
+ ("bcpio", &["application/x-bcpio"]),
+ ("bdf", &["application/x-font-bdf"]),
+ ("bdm", &["application/vnd.syncml.dm+wbxml"]),
+ ("bdoc", &["application/bdoc"]),
+ ("bed", &["application/vnd.realvnc.bed"]),
+ ("bh2", &["application/vnd.fujitsu.oasysprs"]),
+ ("bin", &["application/octet-stream"]),
+ ("blb", &["application/x-blorb"]),
+ ("blorb", &["application/x-blorb"]),
+ ("bmi", &["application/vnd.bmi"]),
+ ("bmp", &["image/bmp"]),
+ ("book", &["application/vnd.framemaker"]),
+ ("box", &["application/vnd.previewsystems.box"]),
+ ("boz", &["application/x-bzip2"]),
+ ("bpk", &["application/octet-stream"]),
+ ("btif", &["image/prs.btif"]),
+ ("buffer", &["application/octet-stream"]),
+ ("bz", &["application/x-bzip"]),
+ ("bz2", &["application/x-bzip2"]),
+ ("c", &["text/plain"]),
+ ("c11amc", &["application/vnd.cluetrust.cartomobile-config"]),
+ (
+ "c11amz",
+ &["application/vnd.cluetrust.cartomobile-config-pkg"],
+ ),
+ ("c4d", &["application/vnd.clonk.c4group"]),
+ ("c4f", &["application/vnd.clonk.c4group"]),
+ ("c4g", &["application/vnd.clonk.c4group"]),
+ ("c4p", &["application/vnd.clonk.c4group"]),
+ ("c4u", &["application/vnd.clonk.c4group"]),
+ ("cab", &["application/octet-stream"]),
+ ("caf", &["audio/x-caf"]),
+ ("calx", &["application/vnd.ms-office.calx"]),
+ ("cap", &["application/vnd.tcpdump.pcap"]),
+ ("car", &["application/vnd.curl.car"]),
+ ("cat", &["application/vnd.ms-pki.seccat"]),
+ ("cb7", &["application/x-cbr"]),
+ ("cba", &["application/x-cbr"]),
+ ("cbr", &["application/x-cbr"]),
+ ("cbt", &["application/x-cbr"]),
+ ("cbz", &["application/x-cbr"]),
+ ("cc", &["text/plain"]),
+ ("cco", &["application/x-cocoa"]),
+ ("cct", &["application/x-director"]),
+ ("ccxml", &["application/ccxml+xml"]),
+ ("cd", &["text/plain"]),
+ ("cdbcmsg", &["application/vnd.contact.cmsg"]),
+ ("cdda", &["audio/aiff"]),
+ ("cdf", &["application/x-cdf"]),
+ ("cdkey", &["application/vnd.mediastation.cdkey"]),
+ ("cdmia", &["application/cdmi-capability"]),
+ ("cdmic", &["application/cdmi-container"]),
+ ("cdmid", &["application/cdmi-domain"]),
+ ("cdmio", &["application/cdmi-object"]),
+ ("cdmiq", &["application/cdmi-queue"]),
+ ("cdx", &["chemical/x-cdx"]),
+ ("cdxml", &["application/vnd.chemdraw+xml"]),
+ ("cdy", &["application/vnd.cinderella"]),
+ ("cer", &["application/x-x509-ca-cert"]),
+ ("cfg", &["text/plain"]),
+ ("cfs", &["application/x-cfs-compressed"]),
+ ("cgm", &["image/cgm"]),
+ ("chat", &["application/x-chat"]),
+ ("chm", &["application/octet-stream"]),
+ ("chrt", &["application/vnd.kde.kchart"]),
+ ("cif", &["chemical/x-cif"]),
+ (
+ "cii",
+ &["application/vnd.anser-web-certificate-issue-initiation"],
+ ),
+ ("cil", &["application/vnd.ms-artgalry"]),
+ ("cla", &["application/vnd.claymore"]),
+ ("class", &["application/x-java-applet"]),
+ ("clkk", &["application/vnd.crick.clicker.keyboard"]),
+ ("clkp", &["application/vnd.crick.clicker.palette"]),
+ ("clkt", &["application/vnd.crick.clicker.template"]),
+ ("clkw", &["application/vnd.crick.clicker.wordbank"]),
+ ("clkx", &["application/vnd.crick.clicker"]),
+ ("clp", &["application/x-msclip"]),
+ ("cmc", &["application/vnd.cosmocaller"]),
+ ("cmd", &["text/plain"]),
+ ("cmdf", &["chemical/x-cmdf"]),
+ ("cml", &["chemical/x-cml"]),
+ ("cmp", &["application/vnd.yellowriver-custom-menu"]),
+ ("cmx", &["image/x-cmx"]),
+ ("cnf", &["text/plain"]),
+ ("cod", &["image/cis-cod"]),
+ ("coffee", &["text/coffeescript"]),
+ ("com", &["application/x-msdownload"]),
+ ("conf", &["text/plain"]),
+ ("config", &["application/xml"]),
+ ("contact", &["text/x-ms-contact"]),
+ ("coverage", &["application/xml"]),
+ ("cpio", &["application/x-cpio"]),
+ ("cpp", &["text/plain"]),
+ ("cpt", &["application/mac-compactpro"]),
+ ("crd", &["application/x-mscardfile"]),
+ ("crl", &["application/pkix-crl"]),
+ ("crt", &["application/x-x509-ca-cert"]),
+ ("crx", &["application/x-chrome-extension"]),
+ ("cryptonote", &["application/vnd.rig.cryptonote"]),
+ ("cs", &["text/plain"]),
+ ("csdproj", &["text/plain"]),
+ ("csh", &["application/x-csh"]),
+ ("csl", &["application/vnd.citationstyles.style+xml"]),
+ ("csml", &["chemical/x-csml"]),
+ ("csp", &["application/vnd.commonspace"]),
+ ("csproj", &["text/plain"]),
+ ("css", &["text/css"]),
+ ("cst", &["application/x-director"]),
+ ("csv", &["text/csv"]),
+ ("cu", &["application/cu-seeme"]),
+ ("cur", &["application/octet-stream"]),
+ ("curl", &["text/vnd.curl"]),
+ ("cww", &["application/prs.cww"]),
+ ("cxt", &["application/x-director"]),
+ ("cxx", &["text/plain"]),
+ ("dae", &["model/vnd.collada+xml"]),
+ ("daf", &["application/vnd.mobius.daf"]),
+ ("dart", &["application/vnd.dart"]),
+ ("dat", &["application/octet-stream"]),
+ ("dataless", &["application/vnd.fdsn.seed"]),
+ ("datasource", &["application/xml"]),
+ ("davmount", &["application/davmount+xml"]),
+ ("dbk", &["application/docbook+xml"]),
+ ("dbproj", &["text/plain"]),
+ ("dcr", &["application/x-director"]),
+ ("dcurl", &["text/vnd.curl.dcurl"]),
+ ("dd2", &["application/vnd.oma.dd2+xml"]),
+ ("ddd", &["application/vnd.fujixerox.ddd"]),
+ ("deb", &["application/octet-stream"]),
+ ("def", &["text/plain"]),
+ ("deploy", &["application/octet-stream"]),
+ ("der", &["application/x-x509-ca-cert"]),
+ ("dfac", &["application/vnd.dreamfactory"]),
+ ("dgc", &["application/x-dgc-compressed"]),
+ ("dgml", &["application/xml"]),
+ ("dib", &["image/bmp"]),
+ ("dic", &["text/x-c"]),
+ ("dif", &["video/x-dv"]),
+ ("dir", &["application/x-director"]),
+ ("dis", &["application/vnd.mobius.dis"]),
+ ("disco", &["text/xml"]),
+ (
+ "disposition-notification",
+ &["message/disposition-notification"],
+ ),
+ ("dist", &["application/octet-stream"]),
+ ("distz", &["application/octet-stream"]),
+ ("divx", &["video/divx"]),
+ ("djv", &["image/vnd.djvu"]),
+ ("djvu", &["image/vnd.djvu"]),
+ ("dll", &["application/x-msdownload"]),
+ ("dll.config", &["text/xml"]),
+ ("dlm", &["text/dlm"]),
+ ("dmg", &["application/octet-stream"]),
+ ("dmp", &["application/vnd.tcpdump.pcap"]),
+ ("dms", &["application/octet-stream"]),
+ ("dna", &["application/vnd.dna"]),
+ ("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"],
+ ),
+ ("dp", &["application/vnd.osgi.dp"]),
+ ("dpg", &["application/vnd.dpgraph"]),
+ ("dra", &["audio/vnd.dra"]),
+ ("dsc", &["text/prs.lines.tag"]),
+ ("dsp", &["application/octet-stream"]),
+ ("dssc", &["application/dssc+der"]),
+ ("dsw", &["text/plain"]),
+ ("dtb", &["application/x-dtbook+xml"]),
+ ("dtd", &["text/xml"]),
+ ("dts", &["audio/vnd.dts"]),
+ ("dtsconfig", &["text/xml"]),
+ ("dtshd", &["audio/vnd.dts.hd"]),
+ ("dump", &["application/octet-stream"]),
+ ("dv", &["video/x-dv"]),
+ ("dvb", &["video/vnd.dvb.file"]),
+ ("dvi", &["application/x-dvi"]),
+ ("dwf", &["drawing/x-dwf"]),
+ ("dwg", &["application/acad"]),
+ ("dwp", &["application/octet-stream"]),
+ ("dxf", &["application/x-dxf"]),
+ ("dxp", &["application/vnd.spotfire.dxp"]),
+ ("dxr", &["application/x-director"]),
+ ("ear", &["application/java-archive"]),
+ ("ecelp4800", &["audio/vnd.nuera.ecelp4800"]),
+ ("ecelp7470", &["audio/vnd.nuera.ecelp7470"]),
+ ("ecelp9600", &["audio/vnd.nuera.ecelp9600"]),
+ ("ecma", &["application/ecmascript"]),
+ ("edm", &["application/vnd.novadigm.edm"]),
+ ("edx", &["application/vnd.novadigm.edx"]),
+ ("efif", &["application/vnd.picsel"]),
+ ("ei6", &["application/vnd.pg.osasli"]),
+ ("elc", &["application/octet-stream"]),
+ ("emf", &["application/x-msmetafile"]),
+ ("eml", &["message/rfc822"]),
+ ("emma", &["application/emma+xml"]),
+ ("emz", &["application/octet-stream"]),
+ ("eol", &["audio/vnd.digital-winds"]),
+ ("eot", &["application/vnd.ms-fontobject"]),
+ ("eps", &["application/postscript"]),
+ ("epub", &["application/epub+zip"]),
+ ("es", &["application/ecmascript"]),
+ ("es3", &["application/vnd.eszigno3+xml"]),
+ ("esa", &["application/vnd.osgi.subsystem"]),
+ ("esf", &["application/vnd.epson.esf"]),
+ ("et3", &["application/vnd.eszigno3+xml"]),
+ ("etl", &["application/etl"]),
+ ("etx", &["text/x-setext"]),
+ ("eva", &["application/x-eva"]),
+ ("evy", &["application/envoy"]),
+ ("exe", &["application/octet-stream"]),
+ ("exe.config", &["text/xml"]),
+ ("exi", &["application/exi"]),
+ ("ext", &["application/vnd.novadigm.ext"]),
+ ("ez", &["application/andrew-inset"]),
+ ("ez2", &["application/vnd.ezpix-album"]),
+ ("ez3", &["application/vnd.ezpix-package"]),
+ ("f", &["text/x-fortran"]),
+ ("f4v", &["video/x-f4v"]),
+ ("f77", &["text/x-fortran"]),
+ ("f90", &["text/x-fortran"]),
+ ("fbs", &["image/vnd.fastbidsheet"]),
+ ("fcdt", &["application/vnd.adobe.formscentral.fcdt"]),
+ ("fcs", &["application/vnd.isac.fcs"]),
+ ("fdf", &["application/vnd.fdf"]),
+ ("fe_launch", &["application/vnd.denovo.fcselayout-link"]),
+ ("fg5", &["application/vnd.fujitsu.oasysgp"]),
+ ("fgd", &["application/x-director"]),
+ ("fh", &["image/x-freehand"]),
+ ("fh4", &["image/x-freehand"]),
+ ("fh5", &["image/x-freehand"]),
+ ("fh7", &["image/x-freehand"]),
+ ("fhc", &["image/x-freehand"]),
+ ("fif", &["application/fractals"]),
+ ("fig", &["application/x-xfig"]),
+ ("filters", &["application/xml"]),
+ ("fla", &["application/octet-stream"]),
+ ("flac", &["audio/flac"]),
+ ("fli", &["video/x-fli"]),
+ ("flo", &["application/vnd.micrografx.flo"]),
+ ("flr", &["x-world/x-vrml"]),
+ ("flv", &["video/x-flv"]),
+ ("flw", &["application/vnd.kde.kivio"]),
+ ("flx", &["text/vnd.fmi.flexstor"]),
+ ("fly", &["text/vnd.fly"]),
+ ("fm", &["application/vnd.framemaker"]),
+ ("fnc", &["application/vnd.frogans.fnc"]),
+ ("for", &["text/x-fortran"]),
+ ("fpx", &["image/vnd.fpx"]),
+ ("frame", &["application/vnd.framemaker"]),
+ ("fsc", &["application/vnd.fsc.weblaunch"]),
+ ("fsscript", &["application/fsharp-script"]),
+ ("fst", &["image/vnd.fst"]),
+ ("fsx", &["application/fsharp-script"]),
+ ("ftc", &["application/vnd.fluxtime.clip"]),
+ (
+ "fti",
+ &["application/vnd.anser-web-funds-transfer-initiation"],
+ ),
+ ("fvt", &["video/vnd.fvt"]),
+ ("fxp", &["application/vnd.adobe.fxp"]),
+ ("fxpl", &["application/vnd.adobe.fxp"]),
+ ("fzs", &["application/vnd.fuzzysheet"]),
+ ("g2w", &["application/vnd.geoplan"]),
+ ("g3", &["image/g3fax"]),
+ ("g3w", &["application/vnd.geospace"]),
+ ("gac", &["application/vnd.groove-account"]),
+ ("gam", &["application/x-tads"]),
+ ("gbr", &["application/rpki-ghostbusters"]),
+ ("gca", &["application/x-gca-compressed"]),
+ ("gdl", &["model/vnd.gdl"]),
+ ("gdoc", &["application/vnd.google-apps.document"]),
+ ("generictest", &["application/xml"]),
+ ("geo", &["application/vnd.dynageo"]),
+ ("geojson", &["application/geo+json"]),
+ ("gex", &["application/vnd.geometry-explorer"]),
+ ("ggb", &["application/vnd.geogebra.file"]),
+ ("ggt", &["application/vnd.geogebra.tool"]),
+ ("ghf", &["application/vnd.groove-help"]),
+ ("gif", &["image/gif"]),
+ ("gim", &["application/vnd.groove-identity-message"]),
+ ("glb", &["model/gltf-binary"]),
+ ("gltf", &["model/gltf+json"]),
+ ("gml", &["application/gml+xml"]),
+ ("gmx", &["application/vnd.gmx"]),
+ ("gnumeric", &["application/x-gnumeric"]),
+ ("gph", &["application/vnd.flographit"]),
+ ("gpx", &["application/gpx+xml"]),
+ ("gqf", &["application/vnd.grafeq"]),
+ ("gqs", &["application/vnd.grafeq"]),
+ ("gram", &["application/srgs"]),
+ ("gramps", &["application/x-gramps-xml"]),
+ ("gre", &["application/vnd.geometry-explorer"]),
+ ("group", &["text/x-ms-group"]),
+ ("grv", &["application/vnd.groove-injector"]),
+ ("grxml", &["application/srgs+xml"]),
+ ("gsf", &["application/x-font-ghostscript"]),
+ ("gsheet", &["application/vnd.google-apps.spreadsheet"]),
+ ("gslides", &["application/vnd.google-apps.presentation"]),
+ ("gsm", &["audio/x-gsm"]),
+ ("gtar", &["application/x-gtar"]),
+ ("gtm", &["application/vnd.groove-tool-message"]),
+ ("gtw", &["model/vnd.gtw"]),
+ ("gv", &["text/vnd.graphviz"]),
+ ("gxf", &["application/gxf"]),
+ ("gxt", &["application/vnd.geonext"]),
+ ("gz", &["application/x-gzip"]),
+ ("h", &["text/plain"]),
+ ("h261", &["video/h261"]),
+ ("h263", &["video/h263"]),
+ ("h264", &["video/h264"]),
+ ("hal", &["application/vnd.hal+xml"]),
+ ("hbci", &["application/vnd.hbci"]),
+ ("hbs", &["text/x-handlebars-template"]),
+ ("hdd", &["application/x-virtualbox-hdd"]),
+ ("hdf", &["application/x-hdf"]),
+ ("hdml", &["text/x-hdml"]),
+ ("hdr", &["image/vnd.radiance"]),
+ ("hh", &["text/plain"]),
+ ("hhc", &["application/x-oleobject"]),
+ ("hhk", &["application/octet-stream"]),
+ ("hhp", &["application/octet-stream"]),
+ ("hjson", &["application/hjson"]),
+ ("hlp", &["application/winhlp"]),
+ ("hpgl", &["application/vnd.hp-hpgl"]),
+ ("hpid", &["application/vnd.hp-hpid"]),
+ ("hpp", &["text/plain"]),
+ ("hps", &["application/vnd.hp-hps"]),
+ ("hqx", &["application/mac-binhex40"]),
+ ("hta", &["application/hta"]),
+ ("htc", &["text/x-component"]),
+ ("htke", &["application/vnd.kenameaapp"]),
+ ("htm", &["text/html"]),
+ ("html", &["text/html"]),
+ ("htt", &["text/webviewhtml"]),
+ ("hvd", &["application/vnd.yamaha.hv-dic"]),
+ ("hvp", &["application/vnd.yamaha.hv-voice"]),
+ ("hvs", &["application/vnd.yamaha.hv-script"]),
+ ("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"]),
+ ("i2g", &["application/vnd.intergeo"]),
+ ("icc", &["application/vnd.iccprofile"]),
+ ("ice", &["x-conference/x-cooltalk"]),
+ ("icm", &["application/vnd.iccprofile"]),
+ ("ico", &["image/x-icon"]),
+ ("ics", &["application/octet-stream"]),
+ ("idl", &["text/plain"]),
+ ("ief", &["image/ief"]),
+ ("ifb", &["text/calendar"]),
+ ("ifm", &["application/vnd.shana.informed.formdata"]),
+ ("iges", &["model/iges"]),
+ ("igl", &["application/vnd.igloader"]),
+ ("igm", &["application/vnd.insors.igm"]),
+ ("igs", &["model/iges"]),
+ ("igx", &["application/vnd.micrografx.igx"]),
+ ("iif", &["application/vnd.shana.informed.interchange"]),
+ ("iii", &["application/x-iphone"]),
+ ("img", &["application/octet-stream"]),
+ ("imp", &["application/vnd.accpac.simply.imp"]),
+ ("ims", &["application/vnd.ms-ims"]),
+ ("in", &["text/plain"]),
+ ("inc", &["text/plain"]),
+ ("inf", &["application/octet-stream"]),
+ ("ini", &["text/plain"]),
+ ("ink", &["application/inkml+xml"]),
+ ("inkml", &["application/inkml+xml"]),
+ ("inl", &["text/plain"]),
+ ("ins", &["application/x-internet-signup"]),
+ ("install", &["application/x-install-instructions"]),
+ ("iota", &["application/vnd.astraea-software.iota"]),
+ ("ipa", &["application/x-itunes-ipa"]),
+ ("ipfix", &["application/ipfix"]),
+ ("ipg", &["application/x-itunes-ipg"]),
+ ("ipk", &["application/vnd.shana.informed.package"]),
+ ("ipproj", &["text/plain"]),
+ ("ipsw", &["application/x-itunes-ipsw"]),
+ ("iqy", &["text/x-ms-iqy"]),
+ ("irm", &["application/vnd.ibm.rights-management"]),
+ ("irp", &["application/vnd.irepository.package+xml"]),
+ ("iso", &["application/octet-stream"]),
+ ("isp", &["application/x-internet-signup"]),
+ ("ite", &["application/x-itunes-ite"]),
+ ("itlp", &["application/x-itunes-itlp"]),
+ ("itms", &["application/x-itunes-itms"]),
+ ("itp", &["application/vnd.shana.informed.formtemplate"]),
+ ("itpc", &["application/x-itunes-itpc"]),
+ ("ivf", &["video/x-ivf"]),
+ ("ivp", &["application/vnd.immervision-ivp"]),
+ ("ivu", &["application/vnd.immervision-ivu"]),
+ ("jad", &["text/vnd.sun.j2me.app-descriptor"]),
+ ("jade", &["text/jade"]),
+ ("jam", &["application/vnd.jam"]),
+ ("jar", &["application/java-archive"]),
+ ("jardiff", &["application/x-java-archive-diff"]),
+ ("java", &["application/octet-stream"]),
+ ("jck", &["application/liquidmotion"]),
+ ("jcz", &["application/liquidmotion"]),
+ ("jfif", &["image/pjpeg"]),
+ ("jisp", &["application/vnd.jisp"]),
+ ("jlt", &["application/vnd.hp-jlyt"]),
+ ("jng", &["image/x-jng"]),
+ ("jnlp", &["application/x-java-jnlp-file"]),
+ ("joda", &["application/vnd.joost.joda-archive"]),
+ ("jp2", &["image/jp2"]),
+ ("jpb", &["application/octet-stream"]),
+ ("jpe", &["image/jpeg"]),
+ ("jpeg", &["image/jpeg"]),
+ ("jpf", &["image/jpx"]),
+ ("jpg", &["image/jpeg"]),
+ ("jpg2", &["image/jp2"]),
+ ("jpgm", &["video/jpm"]),
+ ("jpgv", &["video/jpeg"]),
+ ("jpm", &["image/jpm"]),
+ ("jpx", &["image/jpx"]),
+ ("js", &["application/javascript"]),
+ ("jsm", &["application/javascript"]),
+ ("json", &["application/json"]),
+ ("json5", &["application/json5"]),
+ ("jsonld", &["application/ld+json"]),
+ ("jsonml", &["application/jsonml+json"]),
+ ("jsx", &["text/jscript"]),
+ ("jsxbin", &["text/plain"]),
+ ("kar", &["audio/midi"]),
+ ("karbon", &["application/vnd.kde.karbon"]),
+ ("kfo", &["application/vnd.kde.kformula"]),
+ ("kia", &["application/vnd.kidspiration"]),
+ ("kml", &["application/vnd.google-earth.kml+xml"]),
+ ("kmz", &["application/vnd.google-earth.kmz"]),
+ ("kne", &["application/vnd.kinar"]),
+ ("knp", &["application/vnd.kinar"]),
+ ("kon", &["application/vnd.kde.kontour"]),
+ ("kpr", &["application/vnd.kde.kpresenter"]),
+ ("kpt", &["application/vnd.kde.kpresenter"]),
+ ("kpxx", &["application/vnd.ds-keypoint"]),
+ ("ksp", &["application/vnd.kde.kspread"]),
+ ("ktr", &["application/vnd.kahootz"]),
+ ("ktx", &["image/ktx"]),
+ ("ktz", &["application/vnd.kahootz"]),
+ ("kwd", &["application/vnd.kde.kword"]),
+ ("kwt", &["application/vnd.kde.kword"]),
+ ("lasxml", &["application/vnd.las.las+xml"]),
+ ("latex", &["application/x-latex"]),
+ (
+ "lbd",
+ &["application/vnd.llamagraphics.life-balance.desktop"],
+ ),
+ (
+ "lbe",
+ &["application/vnd.llamagraphics.life-balance.exchange+xml"],
+ ),
+ ("les", &["application/vnd.hhe.lesson-player"]),
+ ("less", &["text/less"]),
+ ("lha", &["application/x-lzh-compressed"]),
+ ("library-ms", &["application/windows-library+xml"]),
+ ("link66", &["application/vnd.route66.link66+xml"]),
+ ("list", &["text/plain"]),
+ ("list3820", &["application/vnd.ibm.modcap"]),
+ ("listafp", &["application/vnd.ibm.modcap"]),
+ ("lit", &["application/x-ms-reader"]),
+ ("litcoffee", &["text/coffeescript"]),
+ ("lnk", &["application/x-ms-shortcut"]),
+ ("loadtest", &["application/xml"]),
+ ("log", &["text/plain"]),
+ ("lostxml", &["application/lost+xml"]),
+ ("lpk", &["application/octet-stream"]),
+ ("lrf", &["application/octet-stream"]),
+ ("lrm", &["application/vnd.ms-lrm"]),
+ ("lsf", &["video/x-la-asf"]),
+ ("lst", &["text/plain"]),
+ ("lsx", &["video/x-la-asf"]),
+ ("ltf", &["application/vnd.frogans.ltf"]),
+ ("lua", &["text/x-lua"]),
+ ("luac", &["application/x-lua-bytecode"]),
+ ("lvp", &["audio/vnd.lucent.voice"]),
+ ("lwp", &["application/vnd.lotus-wordpro"]),
+ ("lzh", &["application/octet-stream"]),
+ ("m13", &["application/x-msmediaview"]),
+ ("m14", &["application/x-msmediaview"]),
+ ("m1v", &["video/mpeg"]),
+ ("m21", &["application/mp21"]),
+ ("m2a", &["audio/mpeg"]),
+ ("m2t", &["video/vnd.dlna.mpeg-tts"]),
+ ("m2ts", &["video/vnd.dlna.mpeg-tts"]),
+ ("m2v", &["video/mpeg"]),
+ ("m3a", &["audio/mpeg"]),
+ ("m3u", &["audio/x-mpegurl"]),
+ ("m3u8", &["audio/x-mpegurl"]),
+ ("m4a", &["audio/m4a"]),
+ ("m4b", &["audio/m4b"]),
+ ("m4p", &["audio/m4p"]),
+ ("m4r", &["audio/x-m4r"]),
+ ("m4u", &["video/vnd.mpegurl"]),
+ ("m4v", &["video/x-m4v"]),
+ ("ma", &["application/mathematica"]),
+ ("mac", &["image/x-macpaint"]),
+ ("mads", &["application/mads+xml"]),
+ ("mag", &["application/vnd.ecowin.chart"]),
+ ("mak", &["text/plain"]),
+ ("maker", &["application/vnd.framemaker"]),
+ ("man", &["application/x-troff-man"]),
+ ("manifest", &["application/x-ms-manifest"]),
+ ("map", &["text/plain"]),
+ ("mar", &["application/octet-stream"]),
+ ("markdown", &["text/markdown"]),
+ ("master", &["application/xml"]),
+ ("mathml", &["application/mathml+xml"]),
+ ("mb", &["application/mathematica"]),
+ ("mbk", &["application/vnd.mobius.mbk"]),
+ ("mbox", &["application/mbox"]),
+ ("mc1", &["application/vnd.medcalcdata"]),
+ ("mcd", &["application/vnd.mcd"]),
+ ("mcurl", &["text/vnd.curl.mcurl"]),
+ ("md", &["text/markdown", "text/x-markdown"]),
+ ("mda", &["application/msaccess"]),
+ ("mdb", &["application/x-msaccess"]),
+ ("mde", &["application/msaccess"]),
+ ("mdi", &["image/vnd.ms-modi"]),
+ ("mdp", &["application/octet-stream"]),
+ ("me", &["application/x-troff-me"]),
+ ("mesh", &["model/mesh"]),
+ ("meta4", &["application/metalink4+xml"]),
+ ("metalink", &["application/metalink+xml"]),
+ ("mets", &["application/mets+xml"]),
+ ("mfm", &["application/vnd.mfmp"]),
+ ("mfp", &["application/x-shockwave-flash"]),
+ ("mft", &["application/rpki-manifest"]),
+ ("mgp", &["application/vnd.osgeo.mapguide.package"]),
+ ("mgz", &["application/vnd.proteus.magazine"]),
+ ("mht", &["message/rfc822"]),
+ ("mhtml", &["message/rfc822"]),
+ ("mid", &["audio/mid"]),
+ ("midi", &["audio/mid"]),
+ ("mie", &["application/x-mie"]),
+ ("mif", &["application/vnd.mif"]),
+ ("mime", &["message/rfc822"]),
+ ("mix", &["application/octet-stream"]),
+ ("mj2", &["video/mj2"]),
+ ("mjp2", &["video/mj2"]),
+ ("mjs", &["application/javascript"]),
+ ("mk", &["text/plain"]),
+ ("mk3d", &["video/x-matroska"]),
+ ("mka", &["audio/x-matroska"]),
+ ("mkd", &["text/x-markdown"]),
+ ("mks", &["video/x-matroska"]),
+ ("mkv", &["video/x-matroska"]),
+ ("mlp", &["application/vnd.dolby.mlp"]),
+ ("mmd", &["application/vnd.chipnuts.karaoke-mmd"]),
+ ("mmf", &["application/x-smaf"]),
+ ("mml", &["text/mathml"]),
+ ("mmr", &["image/vnd.fujixerox.edmics-mmr"]),
+ ("mng", &["video/x-mng"]),
+ ("mno", &["text/xml"]),
+ ("mny", &["application/x-msmoney"]),
+ ("mobi", &["application/x-mobipocket-ebook"]),
+ ("mod", &["video/mpeg"]),
+ ("mods", &["application/mods+xml"]),
+ ("mov", &["video/quicktime"]),
+ ("movie", &["video/x-sgi-movie"]),
+ ("mp2", &["video/mpeg"]),
+ ("mp21", &["application/mp21"]),
+ ("mp2a", &["audio/mpeg"]),
+ ("mp2v", &["video/mpeg"]),
+ ("mp3", &["audio/mpeg"]),
+ ("mp4", &["video/mp4"]),
+ ("mp4a", &["audio/mp4"]),
+ ("mp4s", &["application/mp4"]),
+ ("mp4v", &["video/mp4"]),
+ ("mpa", &["video/mpeg"]),
+ ("mpc", &["application/vnd.mophun.certificate"]),
+ ("mpd", &["application/dash+xml"]),
+ ("mpe", &["video/mpeg"]),
+ ("mpeg", &["video/mpeg"]),
+ ("mpf", &["application/vnd.ms-mediapackage"]),
+ ("mpg", &["video/mpeg"]),
+ ("mpg4", &["video/mp4"]),
+ ("mpga", &["audio/mpeg"]),
+ ("mpkg", &["application/vnd.apple.installer+xml"]),
+ ("mpm", &["application/vnd.blueice.multipass"]),
+ ("mpn", &["application/vnd.mophun.application"]),
+ ("mpp", &["application/vnd.ms-project"]),
+ ("mpt", &["application/vnd.ms-project"]),
+ ("mpv2", &["video/mpeg"]),
+ ("mpy", &["application/vnd.ibm.minipay"]),
+ ("mqv", &["video/quicktime"]),
+ ("mqy", &["application/vnd.mobius.mqy"]),
+ ("mrc", &["application/marc"]),
+ ("mrcx", &["application/marcxml+xml"]),
+ ("ms", &["application/x-troff-ms"]),
+ ("mscml", &["application/mediaservercontrol+xml"]),
+ ("mseed", &["application/vnd.fdsn.mseed"]),
+ ("mseq", &["application/vnd.mseq"]),
+ ("msf", &["application/vnd.epson.msf"]),
+ ("msg", &["application/vnd.ms-outlook"]),
+ ("msh", &["model/mesh"]),
+ ("msi", &["application/octet-stream"]),
+ ("msl", &["application/vnd.mobius.msl"]),
+ ("msm", &["application/octet-stream"]),
+ ("mso", &["application/octet-stream"]),
+ ("msp", &["application/octet-stream"]),
+ ("msty", &["application/vnd.muvee.style"]),
+ ("mts", &["video/vnd.dlna.mpeg-tts"]),
+ ("mtx", &["application/xml"]),
+ ("mus", &["application/vnd.musician"]),
+ ("musicxml", &["application/vnd.recordare.musicxml+xml"]),
+ ("mvb", &["application/x-msmediaview"]),
+ ("mvc", &["application/x-miva-compiled"]),
+ ("mwf", &["application/vnd.mfer"]),
+ ("mxf", &["application/mxf"]),
+ ("mxl", &["application/vnd.recordare.musicxml"]),
+ ("mxml", &["application/xv+xml"]),
+ ("mxp", &["application/x-mmxp"]),
+ ("mxs", &["application/vnd.triscape.mxs"]),
+ ("mxu", &["video/vnd.mpegurl"]),
+ ("n-gage", &["application/vnd.nokia.n-gage.symbian.install"]),
+ ("n3", &["text/n3"]),
+ ("nb", &["application/mathematica"]),
+ ("nbp", &["application/vnd.wolfram.player"]),
+ ("nc", &["application/x-netcdf"]),
+ ("ncx", &["application/x-dtbncx+xml"]),
+ ("nfo", &["text/x-nfo"]),
+ ("ngdat", &["application/vnd.nokia.n-gage.data"]),
+ ("nitf", &["application/vnd.nitf"]),
+ ("nlu", &["application/vnd.neurolanguage.nlu"]),
+ ("nml", &["application/vnd.enliven"]),
+ ("nnd", &["application/vnd.noblenet-directory"]),
+ ("nns", &["application/vnd.noblenet-sealer"]),
+ ("nnw", &["application/vnd.noblenet-web"]),
+ ("npx", &["image/vnd.net-fpx"]),
+ ("nsc", &["video/x-ms-asf"]),
+ ("nsf", &["application/vnd.lotus-notes"]),
+ ("ntf", &["application/vnd.nitf"]),
+ ("nws", &["message/rfc822"]),
+ ("nzb", &["application/x-nzb"]),
+ ("oa2", &["application/vnd.fujitsu.oasys2"]),
+ ("oa3", &["application/vnd.fujitsu.oasys3"]),
+ ("oas", &["application/vnd.fujitsu.oasys"]),
+ ("obd", &["application/x-msbinder"]),
+ ("obj", &["application/x-tgif"]),
+ ("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"]),
+ (
+ "odft",
+ &["application/vnd.oasis.opendocument.formula-template"],
+ ),
+ ("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"]),
+ ("omdoc", &["application/omdoc+xml"]),
+ ("one", &["application/onenote"]),
+ ("onea", &["application/onenote"]),
+ ("onepkg", &["application/onenote"]),
+ ("onetmp", &["application/onenote"]),
+ ("onetoc", &["application/onenote"]),
+ ("onetoc2", &["application/onenote"]),
+ ("opf", &["application/oebps-package+xml"]),
+ ("opml", &["text/x-opml"]),
+ ("oprc", &["application/vnd.palm"]),
+ ("opus", &["audio/ogg"]),
+ ("orderedtest", &["application/xml"]),
+ ("org", &["application/vnd.lotus-organizer"]),
+ ("osdx", &["application/opensearchdescription+xml"]),
+ ("osf", &["application/vnd.yamaha.openscoreformat"]),
+ (
+ "osfpvg",
+ &["application/vnd.yamaha.openscoreformat.osfpvg+xml"],
+ ),
+ (
+ "otc",
+ &["application/vnd.oasis.opendocument.chart-template"],
+ ),
+ ("otf", &["application/font-sfnt"]),
+ (
+ "otg",
+ &["application/vnd.oasis.opendocument.graphics-template"],
+ ),
+ ("oth", &["application/vnd.oasis.opendocument.text-web"]),
+ (
+ "oti",
+ &["application/vnd.oasis.opendocument.image-template"],
+ ),
+ (
+ "otp",
+ &["application/vnd.oasis.opendocument.presentation-template"],
+ ),
+ (
+ "ots",
+ &["application/vnd.oasis.opendocument.spreadsheet-template"],
+ ),
+ ("ott", &["application/vnd.oasis.opendocument.text-template"]),
+ ("ova", &["application/x-virtualbox-ova"]),
+ ("ovf", &["application/x-virtualbox-ovf"]),
+ ("oxps", &["application/oxps"]),
+ ("oxt", &["application/vnd.openofficeorg.extension"]),
+ ("p", &["text/x-pascal"]),
+ ("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"]),
+ ("p8", &["application/pkcs8"]),
+ ("pac", &["application/x-ns-proxy-autoconfig"]),
+ ("pas", &["text/x-pascal"]),
+ ("paw", &["application/vnd.pawaafile"]),
+ ("pbd", &["application/vnd.powerbuilder6"]),
+ ("pbm", &["image/x-portable-bitmap"]),
+ ("pcap", &["application/vnd.tcpdump.pcap"]),
+ ("pcast", &["application/x-podcast"]),
+ ("pcf", &["application/x-font-pcf"]),
+ ("pcl", &["application/vnd.hp-pcl"]),
+ ("pclxl", &["application/vnd.hp-pclxl"]),
+ ("pct", &["image/pict"]),
+ ("pcurl", &["application/vnd.curl.pcurl"]),
+ ("pcx", &["application/octet-stream"]),
+ ("pcz", &["application/octet-stream"]),
+ ("pdb", &["application/vnd.palm"]),
+ ("pde", &["text/x-processing"]),
+ ("pdf", &["application/pdf"]),
+ ("pem", &["application/x-x509-ca-cert"]),
+ ("pfa", &["application/x-font-type1"]),
+ ("pfb", &["application/octet-stream"]),
+ ("pfm", &["application/octet-stream"]),
+ ("pfr", &["application/font-tdpfr"]),
+ ("pfx", &["application/x-pkcs12"]),
+ ("pgm", &["image/x-portable-graymap"]),
+ ("pgn", &["application/x-chess-pgn"]),
+ ("pgp", &["application/pgp-encrypted"]),
+ ("php", &["application/x-httpd-php"]),
+ ("pic", &["image/pict"]),
+ ("pict", &["image/pict"]),
+ ("pkg", &["application/octet-stream"]),
+ ("pkgdef", &["text/plain"]),
+ ("pkgundef", &["text/plain"]),
+ ("pki", &["application/pkixcmp"]),
+ ("pkipath", &["application/pkix-pkipath"]),
+ ("pko", &["application/vnd.ms-pki.pko"]),
+ ("pkpass", &["application/vnd.apple.pkpass"]),
+ ("pl", &["application/x-perl"]),
+ ("plb", &["application/vnd.3gpp.pic-bw-large"]),
+ ("plc", &["application/vnd.mobius.plc"]),
+ ("plf", &["application/vnd.pocketlearn"]),
+ ("pls", &["audio/scpls"]),
+ ("pm", &["application/x-perl"]),
+ ("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"]),
+ ("portpkg", &["application/vnd.macports.portpkg"]),
+ ("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"],
+ ),
+ ("ppd", &["application/vnd.cups-ppd"]),
+ ("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"],
+ ),
+ ("pqa", &["application/vnd.palm"]),
+ ("prc", &["application/x-mobipocket-ebook"]),
+ ("pre", &["application/vnd.lotus-freelance"]),
+ ("prf", &["application/pics-rules"]),
+ ("prm", &["application/octet-stream"]),
+ ("prx", &["application/octet-stream"]),
+ ("ps", &["application/postscript"]),
+ ("psb", &["application/vnd.3gpp.pic-bw-small"]),
+ ("psc1", &["application/PowerShell"]),
+ ("psd", &["application/octet-stream"]),
+ ("psess", &["application/xml"]),
+ ("psf", &["application/x-font-linux-psf"]),
+ ("pskcxml", &["application/pskc+xml"]),
+ ("psm", &["application/octet-stream"]),
+ ("psp", &["application/octet-stream"]),
+ ("pst", &["application/vnd.ms-outlook"]),
+ ("ptid", &["application/vnd.pvi.ptid1"]),
+ ("pub", &["application/x-mspublisher"]),
+ ("pvb", &["application/vnd.3gpp.pic-bw-var"]),
+ ("pwn", &["application/vnd.3m.post-it-notes"]),
+ ("pwz", &["application/vnd.ms-powerpoint"]),
+ ("py", &["text/plain"]),
+ ("pya", &["audio/vnd.ms-playready.media.pya"]),
+ ("pyv", &["video/vnd.ms-playready.media.pyv"]),
+ ("qam", &["application/vnd.epson.quickanime"]),
+ ("qbo", &["application/vnd.intu.qbo"]),
+ ("qfx", &["application/vnd.intu.qfx"]),
+ ("qht", &["text/x-html-insertion"]),
+ ("qhtm", &["text/x-html-insertion"]),
+ ("qps", &["application/vnd.publishare-delta-tree"]),
+ ("qt", &["video/quicktime"]),
+ ("qti", &["image/x-quicktime"]),
+ ("qtif", &["image/x-quicktime"]),
+ ("qtl", &["application/x-quicktimeplayer"]),
+ ("qwd", &["application/vnd.quark.quarkxpress"]),
+ ("qwt", &["application/vnd.quark.quarkxpress"]),
+ ("qxb", &["application/vnd.quark.quarkxpress"]),
+ ("qxd", &["application/octet-stream"]),
+ ("qxl", &["application/vnd.quark.quarkxpress"]),
+ ("qxt", &["application/vnd.quark.quarkxpress"]),
+ ("ra", &["audio/x-pn-realaudio"]),
+ ("ram", &["audio/x-pn-realaudio"]),
+ ("raml", &["application/raml+yaml"]),
+ ("rar", &["application/x-rar-compressed"]),
+ ("ras", &["image/x-cmu-raster"]),
+ ("rat", &["application/rat-file"]),
+ ("rc", &["text/plain"]),
+ ("rc2", &["text/plain"]),
+ ("rcprofile", &["application/vnd.ipunplugged.rcprofile"]),
+ ("rct", &["text/plain"]),
+ ("rdf", &["application/rdf+xml"]),
+ ("rdlc", &["application/xml"]),
+ ("rdz", &["application/vnd.data-vision.rdz"]),
+ ("reg", &["text/plain"]),
+ ("rep", &["application/vnd.businessobjects"]),
+ ("res", &["application/x-dtbresource+xml"]),
+ ("resx", &["application/xml"]),
+ ("rf", &["image/vnd.rn-realflash"]),
+ ("rgb", &["image/x-rgb"]),
+ ("rgs", &["text/plain"]),
+ ("rif", &["application/reginfo+xml"]),
+ ("rip", &["audio/vnd.rip"]),
+ ("ris", &["application/x-research-info-systems"]),
+ ("rl", &["application/resource-lists+xml"]),
+ ("rlc", &["image/vnd.fujixerox.edmics-rlc"]),
+ ("rld", &["application/resource-lists-diff+xml"]),
+ ("rm", &["application/vnd.rn-realmedia"]),
+ ("rmi", &["audio/mid"]),
+ ("rmp", &["application/vnd.rn-rn_music_package"]),
+ ("rms", &["application/vnd.jcp.javame.midlet-rms"]),
+ ("rmvb", &["application/vnd.rn-realmedia-vbr"]),
+ ("rnc", &["application/relax-ng-compact-syntax"]),
+ ("rng", &["application/xml"]),
+ ("roa", &["application/rpki-roa"]),
+ ("roff", &["application/x-troff"]),
+ ("rp9", &["application/vnd.cloanto.rp9"]),
+ ("rpm", &["audio/x-pn-realaudio-plugin"]),
+ ("rpss", &["application/vnd.nokia.radio-presets"]),
+ ("rpst", &["application/vnd.nokia.radio-preset"]),
+ ("rq", &["application/sparql-query"]),
+ ("rqy", &["text/x-ms-rqy"]),
+ ("rs", &["text/x-rust"]),
+ ("rsd", &["application/rsd+xml"]),
+ ("rss", &["application/rss+xml"]),
+ ("rtf", &["application/rtf"]),
+ ("rtx", &["text/richtext"]),
+ ("ruleset", &["application/xml"]),
+ ("run", &["application/x-makeself"]),
+ ("rvt", &["application/octet-stream"]),
+ ("s", &["text/plain"]),
+ ("s3m", &["audio/s3m"]),
+ ("saf", &["application/vnd.yamaha.smaf-audio"]),
+ ("safariextz", &["application/x-safari-safariextz"]),
+ ("sass", &["text/x-sass"]),
+ ("sbml", &["application/sbml+xml"]),
+ ("sc", &["application/vnd.ibm.secure-container"]),
+ ("scd", &["application/x-msschedule"]),
+ ("scm", &["application/vnd.lotus-screencam"]),
+ ("scq", &["application/scvp-cv-request"]),
+ ("scr", &["text/plain"]),
+ ("scs", &["application/scvp-cv-response"]),
+ ("scss", &["text/x-scss"]),
+ ("sct", &["text/scriptlet"]),
+ ("scurl", &["text/vnd.curl.scurl"]),
+ ("sd2", &["audio/x-sd2"]),
+ ("sda", &["application/vnd.stardivision.draw"]),
+ ("sdc", &["application/vnd.stardivision.calc"]),
+ ("sdd", &["application/vnd.stardivision.impress"]),
+ ("sdkd", &["application/vnd.solent.sdkm+xml"]),
+ ("sdkm", &["application/vnd.solent.sdkm+xml"]),
+ ("sdp", &["application/sdp"]),
+ ("sdw", &["application/vnd.stardivision.writer"]),
+ ("sea", &["application/octet-stream"]),
+ (
+ "searchconnector-ms",
+ &["application/windows-search-connector+xml"],
+ ),
+ ("see", &["application/vnd.seemail"]),
+ ("seed", &["application/vnd.fdsn.seed"]),
+ ("sema", &["application/vnd.sema"]),
+ ("semd", &["application/vnd.semd"]),
+ ("semf", &["application/vnd.semf"]),
+ ("ser", &["application/java-serialized-object"]),
+ ("setpay", &["application/set-payment-initiation"]),
+ ("setreg", &["application/set-registration-initiation"]),
+ ("settings", &["application/xml"]),
+ ("sfd-hdstx", &["application/vnd.hydrostatix.sof-data"]),
+ ("sfs", &["application/vnd.spotfire.sfs"]),
+ ("sfv", &["text/x-sfv"]),
+ ("sgi", &["image/sgi"]),
+ ("sgimb", &["application/x-sgimb"]),
+ ("sgl", &["application/vnd.stardivision.writer-global"]),
+ ("sgm", &["text/sgml"]),
+ ("sgml", &["text/sgml"]),
+ ("sh", &["application/x-sh"]),
+ ("shar", &["application/x-shar"]),
+ ("shex", &["text/shex"]),
+ ("shf", &["application/shf+xml"]),
+ ("shtml", &["text/html"]),
+ ("sid", &["image/x-mrsid-image"]),
+ ("sig", &["application/pgp-signature"]),
+ ("sil", &["audio/silk"]),
+ ("silo", &["model/mesh"]),
+ ("sis", &["application/vnd.symbian.install"]),
+ ("sisx", &["application/vnd.symbian.install"]),
+ ("sit", &["application/x-stuffit"]),
+ ("sitemap", &["application/xml"]),
+ ("sitx", &["application/x-stuffitx"]),
+ ("skd", &["application/vnd.koan"]),
+ ("skin", &["application/xml"]),
+ ("skm", &["application/vnd.koan"]),
+ ("skp", &["application/x-koan"]),
+ ("skt", &["application/vnd.koan"]),
+ (
+ "sldm",
+ &["application/vnd.ms-powerpoint.slide.macroEnabled.12"],
+ ),
+ (
+ "sldx",
+ &["application/vnd.openxmlformats-officedocument.presentationml.slide"],
+ ),
+ ("slim", &["text/slim"]),
+ ("slk", &["application/vnd.ms-excel"]),
+ ("slm", &["text/slim"]),
+ ("sln", &["text/plain"]),
+ ("slt", &["application/vnd.epson.salt"]),
+ ("slupkg-ms", &["application/x-ms-license"]),
+ ("sm", &["application/vnd.stepmania.stepchart"]),
+ ("smd", &["audio/x-smd"]),
+ ("smf", &["application/vnd.stardivision.math"]),
+ ("smi", &["application/octet-stream"]),
+ ("smil", &["application/smil+xml"]),
+ ("smv", &["video/x-smv"]),
+ ("smx", &["audio/x-smd"]),
+ ("smz", &["audio/x-smd"]),
+ ("smzip", &["application/vnd.stepmania.package"]),
+ ("snd", &["audio/basic"]),
+ ("snf", &["application/x-font-snf"]),
+ ("snippet", &["application/xml"]),
+ ("snp", &["application/octet-stream"]),
+ ("so", &["application/octet-stream"]),
+ ("sol", &["text/plain"]),
+ ("sor", &["text/plain"]),
+ ("spc", &["application/x-pkcs7-certificates"]),
+ ("spf", &["application/vnd.yamaha.smaf-phrase"]),
+ ("spl", &["application/futuresplash"]),
+ ("spot", &["text/vnd.in3d.spot"]),
+ ("spp", &["application/scvp-vp-response"]),
+ ("spq", &["application/scvp-vp-request"]),
+ ("spx", &["audio/ogg"]),
+ ("sql", &["application/x-sql"]),
+ ("src", &["application/x-wais-source"]),
+ ("srf", &["text/plain"]),
+ ("srt", &["application/x-subrip"]),
+ ("sru", &["application/sru+xml"]),
+ ("srx", &["application/sparql-results+xml"]),
+ ("ssdl", &["application/ssdl+xml"]),
+ ("sse", &["application/vnd.kodak-descriptor"]),
+ ("ssf", &["application/vnd.epson.ssf"]),
+ ("ssisdeploymentmanifest", &["text/xml"]),
+ ("ssm", &["application/streamingmedia"]),
+ ("ssml", &["application/ssml+xml"]),
+ ("sst", &["application/vnd.ms-pki.certstore"]),
+ ("st", &["application/vnd.sailingtracker.track"]),
+ ("stc", &["application/vnd.sun.xml.calc.template"]),
+ ("std", &["application/vnd.sun.xml.draw.template"]),
+ ("step", &["application/step"]),
+ ("stf", &["application/vnd.wt.stf"]),
+ ("sti", &["application/vnd.sun.xml.impress.template"]),
+ ("stk", &["application/hyperstudio"]),
+ ("stl", &["application/vnd.ms-pki.stl"]),
+ ("stp", &["application/step"]),
+ ("str", &["application/vnd.pg.format"]),
+ ("stw", &["application/vnd.sun.xml.writer.template"]),
+ ("styl", &["text/stylus"]),
+ ("stylus", &["text/stylus"]),
+ ("sub", &["text/vnd.dvb.subtitle"]),
+ ("sus", &["application/vnd.sus-calendar"]),
+ ("susp", &["application/vnd.sus-calendar"]),
+ ("sv4cpio", &["application/x-sv4cpio"]),
+ ("sv4crc", &["application/x-sv4crc"]),
+ ("svc", &["application/xml"]),
+ ("svd", &["application/vnd.svd"]),
+ ("svg", &["image/svg+xml"]),
+ ("svgz", &["image/svg+xml"]),
+ ("swa", &["application/x-director"]),
+ ("swf", &["application/x-shockwave-flash"]),
+ ("swi", &["application/vnd.aristanetworks.swi"]),
+ ("sxc", &["application/vnd.sun.xml.calc"]),
+ ("sxd", &["application/vnd.sun.xml.draw"]),
+ ("sxg", &["application/vnd.sun.xml.writer.global"]),
+ ("sxi", &["application/vnd.sun.xml.impress"]),
+ ("sxm", &["application/vnd.sun.xml.math"]),
+ ("sxw", &["application/vnd.sun.xml.writer"]),
+ ("t", &["application/x-troff"]),
+ ("t3", &["application/x-t3vm-image"]),
+ ("taglet", &["application/vnd.mynfc"]),
+ ("tao", &["application/vnd.tao.intent-module-archive"]),
+ ("tar", &["application/x-tar"]),
+ ("tcap", &["application/vnd.3gpp2.tcap"]),
+ ("tcl", &["application/x-tcl"]),
+ ("teacher", &["application/vnd.smart.teacher"]),
+ ("tei", &["application/tei+xml"]),
+ ("teicorpus", &["application/tei+xml"]),
+ ("testrunconfig", &["application/xml"]),
+ ("testsettings", &["application/xml"]),
+ ("tex", &["application/x-tex"]),
+ ("texi", &["application/x-texinfo"]),
+ ("texinfo", &["application/x-texinfo"]),
+ ("text", &["text/plain"]),
+ ("tfi", &["application/thraud+xml"]),
+ ("tfm", &["application/x-tex-tfm"]),
+ ("tga", &["image/x-tga"]),
+ ("tgz", &["application/x-compressed"]),
+ ("thmx", &["application/vnd.ms-officetheme"]),
+ ("thn", &["application/octet-stream"]),
+ ("tif", &["image/tiff"]),
+ ("tiff", &["image/tiff"]),
+ ("tk", &["application/x-tcl"]),
+ ("tlh", &["text/plain"]),
+ ("tli", &["text/plain"]),
+ ("tmo", &["application/vnd.tmobile-livetv"]),
+ ("toc", &["application/octet-stream"]),
+ ("toml", &["text/x-toml"]),
+ ("torrent", &["application/x-bittorrent"]),
+ ("tpl", &["application/vnd.groove-tool-template"]),
+ ("tpt", &["application/vnd.trid.tpt"]),
+ ("tr", &["application/x-troff"]),
+ ("tra", &["application/vnd.trueapp"]),
+ ("trm", &["application/x-msterminal"]),
+ ("trx", &["application/xml"]),
+ ("ts", &["video/vnd.dlna.mpeg-tts"]),
+ ("tsd", &["application/timestamped-data"]),
+ ("tsv", &["text/tab-separated-values"]),
+ ("ttc", &["font/collection"]),
+ ("ttf", &["application/font-sfnt"]),
+ ("ttl", &["text/turtle"]),
+ ("tts", &["video/vnd.dlna.mpeg-tts"]),
+ ("twd", &["application/vnd.simtech-mindmapper"]),
+ ("twds", &["application/vnd.simtech-mindmapper"]),
+ ("txd", &["application/vnd.genomatix.tuxedo"]),
+ ("txf", &["application/vnd.mobius.txf"]),
+ ("txt", &["text/plain"]),
+ ("u32", &["application/octet-stream"]),
+ ("u8dsn", &["message/global-delivery-status"]),
+ ("u8hdr", &["message/global-headers"]),
+ ("u8mdn", &["message/global-disposition-notification"]),
+ ("u8msg", &["message/global"]),
+ ("udeb", &["application/x-debian-package"]),
+ ("ufd", &["application/vnd.ufdl"]),
+ ("ufdl", &["application/vnd.ufdl"]),
+ ("uls", &["text/iuls"]),
+ ("ulx", &["application/x-glulx"]),
+ ("umj", &["application/vnd.umajin"]),
+ ("unityweb", &["application/vnd.unity"]),
+ ("uoml", &["application/vnd.uoml+xml"]),
+ ("uri", &["text/uri-list"]),
+ ("uris", &["text/uri-list"]),
+ ("urls", &["text/uri-list"]),
+ ("user", &["text/plain"]),
+ ("ustar", &["application/x-ustar"]),
+ ("utz", &["application/vnd.uiq.theme"]),
+ ("uu", &["text/x-uuencode"]),
+ ("uva", &["audio/vnd.dece.audio"]),
+ ("uvd", &["application/vnd.dece.data"]),
+ ("uvf", &["application/vnd.dece.data"]),
+ ("uvg", &["image/vnd.dece.graphic"]),
+ ("uvh", &["video/vnd.dece.hd"]),
+ ("uvi", &["image/vnd.dece.graphic"]),
+ ("uvm", &["video/vnd.dece.mobile"]),
+ ("uvp", &["video/vnd.dece.pd"]),
+ ("uvs", &["video/vnd.dece.sd"]),
+ ("uvt", &["application/vnd.dece.ttml+xml"]),
+ ("uvu", &["video/vnd.uvvu.mp4"]),
+ ("uvv", &["video/vnd.dece.video"]),
+ ("uvva", &["audio/vnd.dece.audio"]),
+ ("uvvd", &["application/vnd.dece.data"]),
+ ("uvvf", &["application/vnd.dece.data"]),
+ ("uvvg", &["image/vnd.dece.graphic"]),
+ ("uvvh", &["video/vnd.dece.hd"]),
+ ("uvvi", &["image/vnd.dece.graphic"]),
+ ("uvvm", &["video/vnd.dece.mobile"]),
+ ("uvvp", &["video/vnd.dece.pd"]),
+ ("uvvs", &["video/vnd.dece.sd"]),
+ ("uvvt", &["application/vnd.dece.ttml+xml"]),
+ ("uvvu", &["video/vnd.uvvu.mp4"]),
+ ("uvvv", &["video/vnd.dece.video"]),
+ ("uvvx", &["application/vnd.dece.unspecified"]),
+ ("uvvz", &["application/vnd.dece.zip"]),
+ ("uvx", &["application/vnd.dece.unspecified"]),
+ ("uvz", &["application/vnd.dece.zip"]),
+ ("vb", &["text/plain"]),
+ ("vbdproj", &["text/plain"]),
+ ("vbk", &["video/mpeg"]),
+ ("vbox", &["application/x-virtualbox-vbox"]),
+ ("vbox-extpack", &["application/x-virtualbox-vbox-extpack"]),
+ ("vbproj", &["text/plain"]),
+ ("vbs", &["text/vbscript"]),
+ ("vcard", &["text/vcard"]),
+ ("vcd", &["application/x-cdlink"]),
+ ("vcf", &["text/x-vcard"]),
+ ("vcg", &["application/vnd.groove-vcard"]),
+ ("vcproj", &["application/xml"]),
+ ("vcs", &["text/plain"]),
+ ("vcx", &["application/vnd.vcx"]),
+ ("vcxproj", &["application/xml"]),
+ ("vddproj", &["text/plain"]),
+ ("vdi", &["application/x-virtualbox-vdi"]),
+ ("vdp", &["text/plain"]),
+ ("vdproj", &["text/plain"]),
+ ("vdx", &["application/vnd.ms-visio.viewer"]),
+ ("vhd", &["application/x-virtualbox-vhd"]),
+ ("vis", &["application/vnd.visionary"]),
+ ("viv", &["video/vnd.vivo"]),
+ ("vmdk", &["application/x-virtualbox-vmdk"]),
+ ("vml", &["text/xml"]),
+ ("vob", &["video/x-ms-vob"]),
+ ("vor", &["application/vnd.stardivision.writer"]),
+ ("vox", &["application/x-authorware-bin"]),
+ ("vrml", &["model/vrml"]),
+ ("vscontent", &["application/xml"]),
+ ("vsct", &["text/xml"]),
+ ("vsd", &["application/vnd.visio"]),
+ ("vsf", &["application/vnd.vsf"]),
+ ("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"]),
+ ("vtt", &["text/vtt"]),
+ ("vtu", &["model/vnd.vtu"]),
+ ("vtx", &["application/vnd.visio"]),
+ ("vxml", &["application/voicexml+xml"]),
+ ("w3d", &["application/x-director"]),
+ ("wad", &["application/x-doom"]),
+ ("wadl", &["application/vnd.sun.wadl+xml"]),
+ ("war", &["application/java-archive"]),
+ ("wasm", &["application/wasm"]),
+ ("wav", &["audio/wav"]),
+ ("wave", &["audio/wav"]),
+ ("wax", &["audio/x-ms-wax"]),
+ ("wbk", &["application/msword"]),
+ ("wbmp", &["image/vnd.wap.wbmp"]),
+ ("wbs", &["application/vnd.criticaltools.wbs+xml"]),
+ ("wbxml", &["application/vnd.wap.wbxml"]),
+ ("wcm", &["application/vnd.ms-works"]),
+ ("wdb", &["application/vnd.ms-works"]),
+ ("wdp", &["image/vnd.ms-photo"]),
+ ("weba", &["audio/webm"]),
+ ("webapp", &["application/x-web-app-manifest+json"]),
+ ("webarchive", &["application/x-safari-webarchive"]),
+ ("webm", &["video/webm"]),
+ ("webmanifest", &["application/manifest+json"]),
+ ("webp", &["image/webp"]),
+ ("webtest", &["application/xml"]),
+ ("wg", &["application/vnd.pmi.widget"]),
+ ("wgt", &["application/widget"]),
+ ("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"]),
+ ("woff2", &["font/woff2"]),
+ ("wpd", &["application/vnd.wordperfect"]),
+ ("wpl", &["application/vnd.ms-wpl"]),
+ ("wps", &["application/vnd.ms-works"]),
+ ("wqd", &["application/vnd.wqd"]),
+ ("wri", &["application/x-mswrite"]),
+ ("wrl", &["x-world/x-vrml"]),
+ ("wrz", &["x-world/x-vrml"]),
+ ("wsc", &["text/scriptlet"]),
+ ("wsdl", &["text/xml"]),
+ ("wspolicy", &["application/wspolicy+xml"]),
+ ("wtb", &["application/vnd.webturbo"]),
+ ("wvx", &["video/x-ms-wvx"]),
+ ("x", &["application/directx"]),
+ ("x32", &["application/x-authorware-bin"]),
+ ("x3d", &["model/x3d+xml"]),
+ ("x3db", &["model/x3d+binary"]),
+ ("x3dbz", &["model/x3d+binary"]),
+ ("x3dv", &["model/x3d+vrml"]),
+ ("x3dvz", &["model/x3d+vrml"]),
+ ("x3dz", &["model/x3d+xml"]),
+ ("xaf", &["x-world/x-vrml"]),
+ ("xaml", &["application/xaml+xml"]),
+ ("xap", &["application/x-silverlight-app"]),
+ ("xar", &["application/vnd.xara"]),
+ ("xbap", &["application/x-ms-xbap"]),
+ ("xbd", &["application/vnd.fujixerox.docuworks.binder"]),
+ ("xbm", &["image/x-xbitmap"]),
+ ("xdf", &["application/xcap-diff+xml"]),
+ ("xdm", &["application/vnd.syncml.dm+xml"]),
+ ("xdp", &["application/vnd.adobe.xdp+xml"]),
+ ("xdr", &["text/plain"]),
+ ("xdssc", &["application/dssc+xml"]),
+ ("xdw", &["application/vnd.fujixerox.docuworks"]),
+ ("xenc", &["application/xenc+xml"]),
+ ("xer", &["application/patch-ops-error+xml"]),
+ ("xfdf", &["application/vnd.adobe.xfdf"]),
+ ("xfdl", &["application/vnd.xfdl"]),
+ ("xht", &["application/xhtml+xml"]),
+ ("xhtml", &["application/xhtml+xml"]),
+ ("xhvml", &["application/xv+xml"]),
+ ("xif", &["image/vnd.xiff"]),
+ ("xla", &["application/vnd.ms-excel"]),
+ ("xlam", &["application/vnd.ms-excel.addin.macroEnabled.12"]),
+ ("xlc", &["application/vnd.ms-excel"]),
+ ("xld", &["application/vnd.ms-excel"]),
+ ("xlf", &["application/x-xliff+xml"]),
+ ("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"]),
+ ("xm", &["audio/xm"]),
+ ("xml", &["text/xml"]),
+ ("xmp", &["application/octet-stream"]),
+ ("xmta", &["application/xml"]),
+ ("xo", &["application/vnd.olpc-sugar"]),
+ ("xof", &["x-world/x-vrml"]),
+ ("xoml", &["text/plain"]),
+ ("xop", &["application/xop+xml"]),
+ ("xpi", &["application/x-xpinstall"]),
+ ("xpl", &["application/xproc+xml"]),
+ ("xpm", &["image/x-xpixmap"]),
+ ("xpr", &["application/vnd.is-xpr"]),
+ ("xps", &["application/vnd.ms-xpsdocument"]),
+ ("xpw", &["application/vnd.intercon.formnet"]),
+ ("xpx", &["application/vnd.intercon.formnet"]),
+ ("xrm-ms", &["text/xml"]),
+ ("xsc", &["application/xml"]),
+ ("xsd", &["text/xml"]),
+ ("xsf", &["text/xml"]),
+ ("xsl", &["text/xml"]),
+ ("xslt", &["text/xml"]),
+ ("xsm", &["application/vnd.syncml+xml"]),
+ ("xsn", &["application/octet-stream"]),
+ ("xspf", &["application/xspf+xml"]),
+ ("xss", &["application/xml"]),
+ ("xtp", &["application/octet-stream"]),
+ ("xul", &["application/vnd.mozilla.xul+xml"]),
+ ("xvm", &["application/xv+xml"]),
+ ("xvml", &["application/xv+xml"]),
+ ("xwd", &["image/x-xwindowdump"]),
+ ("xyz", &["chemical/x-xyz"]),
+ ("xz", &["application/x-xz"]),
+ ("yaml", &["text/x-yaml"]),
+ ("yang", &["application/yang"]),
+ ("yin", &["application/yin+xml"]),
+ ("yml", &["text/x-yaml"]),
+ ("ymp", &["text/x-suse-ymp"]),
+ ("z", &["application/x-compress"]),
+ ("z1", &["application/x-zmachine"]),
+ ("z2", &["application/x-zmachine"]),
+ ("z3", &["application/x-zmachine"]),
+ ("z4", &["application/x-zmachine"]),
+ ("z5", &["application/x-zmachine"]),
+ ("z6", &["application/x-zmachine"]),
+ ("z7", &["application/x-zmachine"]),
+ ("z8", &["application/x-zmachine"]),
+ ("zaz", &["application/vnd.zzazz.deck+xml"]),
+ ("zip", &["application/zip"]),
+ ("zir", &["application/vnd.zul"]),
+ ("zirz", &["application/vnd.zul"]),
+ ("zmm", &["application/vnd.handheld-entertainment+xml"]),
+];