mime_sniffer/lib.rs
1//! ## mime-sniffer: Detecting mime types base on content sniffer.
2//!
3//! ***The detection workflow was copied from
4//! [Chromium](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/base/mime_sniffer.cc)***
5//!
6//! Detecting mime types is a tricky business because we need to balance
7//! compatibility concerns with security issues. Here is a survey of how other
8//! browsers behave and then a description of how we intend to behave.
9//!
10//! ### HTML payload, no Content-Type header:
11//! * IE 7: Render as HTML
12//! * Firefox 2: Render as HTML
13//! * Safari 3: Render as HTML
14//! * Opera 9: Render as HTML
15//!
16//! Here the choice seems clear:
17//! => Chrome: Render as HTML
18//!
19//! ### HTML payload, Content-Type: "text/plain":
20//! * IE 7: Render as HTML
21//! * Firefox 2: Render as text
22//! * Safari 3: Render as text (Note: Safari will Render as HTML if the URL
23//! has an HTML extension)
24//! * Opera 9: Render as text
25//!
26//! Here we choose to follow the majority (and break some compatibility with IE).
27//! Many folks dislike IE's behavior here.
28//! => Chrome: Render as text
29//! We generalize this as follows. If the Content-Type header is text/plain
30//! we won't detect dangerous mime types (those that can execute script).
31//!
32//! ### HTML payload, Content-Type: "application/octet-stream":
33//! * IE 7: Render as HTML
34//! * Firefox 2: Download as application/octet-stream
35//! * Safari 3: Render as HTML
36//! * Opera 9: Render as HTML
37//!
38//! We follow Firefox.
39//! => Chrome: Download as application/octet-stream
40//! One factor in this decision is that IIS 4 and 5 will send
41//! application/octet-stream for .xhtml files (because they don't recognize
42//! the extension). We did some experiments and it looks like this doesn't occur
43//! very often on the web. We choose the more secure option.
44//!
45//! ### GIF payload, no Content-Type header:
46//! * IE 7: Render as GIF
47//! * Firefox 2: Render as GIF
48//! * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the
49//! URL has an GIF extension)
50//! * Opera 9: Render as GIF
51//!
52//! The choice is clear.
53//! => Chrome: Render as GIF
54//! Once we decide to render HTML without a Content-Type header, there isn't much
55//! reason not to render GIFs.
56//!
57//! ### GIF payload, Content-Type: "text/plain":
58//! * IE 7: Render as GIF
59//! * Firefox 2: Download as application/octet-stream (Note: Firefox will
60//! Download as GIF if the URL has an GIF extension)
61//! * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the
62//! URL has an GIF extension)
63//! * Opera 9: Render as GIF
64//!
65//! Displaying as text/plain makes little sense as the content will look like
66//! gibberish. Here, we could change our minds and download.
67//! => Chrome: Render as GIF
68//!
69//! ### GIF payload, Content-Type: "application/octet-stream":
70//! * IE 7: Render as GIF
71//! * Firefox 2: Download as application/octet-stream (Note: Firefox will
72//! Download as GIF if the URL has an GIF extension)
73//! * Safari 3: Download as Unknown (Note: Safari will Render as GIF if the
74//! URL has an GIF extension)
75//! * Opera 9: Render as GIF
76//!
77//! We used to render as GIF here, but the problem is that some sites want to
78//! trigger downloads by sending application/octet-stream (even though they
79//! should be sending Content-Disposition: attachment). Although it is safe
80//! to render as GIF from a security perspective, we actually get better
81//! compatibility if we don't sniff from application/octet stream at all.
82//! => Chrome: Download as application/octet-stream
83//!
84//! Note that our definition of HTML payload is much stricter than IE's
85//! definition and roughly the same as Firefox's definition.
86//!
87//! # Examples
88//!
89//! ```rust
90//! use mime_sniffer::MimeTypeSniffer;
91//!
92//! assert_eq!(Some("application/pdf"), b"%PDF-1.5".sniff_mime_type());
93//! ```
94//!
95//! ```rust
96//! #[macro_use]
97//! extern crate mime;
98//! extern crate mime_sniffer;
99//!
100//! use mime_sniffer::{HttpRequest, MimeTypeSniffer, MimeTypeSnifferExt};
101//!
102//! fn main() {
103//! let req = HttpRequest {
104//! content: b"\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1",
105//! url: &"http://localhost/notes.ppt",
106//! type_hint: "text/plain",
107//! };
108//!
109//! assert_eq!(req.sniff_mime_type(), Some("application/vnd.ms-powerpoint"));
110//! assert_eq!(req.sniff_mime_type_ext().unwrap().type_(), mime::APPLICATION);
111//! }
112//! ```
113extern crate mime;
114extern crate url;
115
116mod api;
117mod magic;
118
119pub use api::{HttpRequest, MimeTypeSniffable, MimeTypeSniffer, MimeTypeSnifferExt};