Merge net and net_tests
44
components/net/tests/chrome_loader.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::test::resolve_chrome_url;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
fn c(s: &str) -> Result<ServoUrl, ()> {
|
||||
resolve_chrome_url(&ServoUrl::parse(s).unwrap())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_chrome_url() {
|
||||
assert_eq!(c("chrome://resources/nonexistent.jpg"), Err(()));
|
||||
assert_eq!(c("chrome://not-resources/badcert.jpg"), Err(()));
|
||||
assert_eq!(c("chrome://resources/badcert.jpg").unwrap().scheme(), "file");
|
||||
assert_eq!(c("chrome://resources/subdir/../badcert.jpg").unwrap().scheme(), "file");
|
||||
assert_eq!(c("chrome://resources/subdir/../../badcert.jpg").unwrap().scheme(), "file");
|
||||
assert_eq!(c("chrome://resources/../badcert.jpg").unwrap().scheme(), "file");
|
||||
assert_eq!(c("chrome://resources/../README.md"), Err(()));
|
||||
assert_eq!(c("chrome://resources/%2e%2e/README.md"), Err(()));
|
||||
|
||||
assert_eq!(c("chrome://resources/etc/passwd"), Err(()));
|
||||
assert_eq!(c("chrome://resources//etc/passwd"), Err(()));
|
||||
assert_eq!(c("chrome://resources/%2Fetc%2Fpasswd"), Err(()));
|
||||
|
||||
assert_eq!(c("chrome://resources/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources/C:\\Windows\\notepad.exe"), Err(()));
|
||||
|
||||
assert_eq!(c("chrome://resources/localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources//localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources///localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources/\\\\localhost\\C:\\Windows\\notepad.exe"), Err(()));
|
||||
|
||||
assert_eq!(c("chrome://resources/%3F/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources//%3F/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources///%3F/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources/\\\\%3F\\C:\\Windows\\notepad.exe"), Err(()));
|
||||
|
||||
assert_eq!(c("chrome://resources/%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources//%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources///%3F/UNC/localhost/C:/Windows/notepad.exe"), Err(()));
|
||||
assert_eq!(c("chrome://resources/\\\\%3F\\UNC\\localhost\\C:\\Windows\\notepad.exe"), Err(()));
|
||||
}
|
413
components/net/tests/cookie.rs
Normal file
|
@ -0,0 +1,413 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cookie_rs;
|
||||
use hyper::header::{Header, SetCookie};
|
||||
use net::cookie::Cookie;
|
||||
use net::cookie_storage::CookieStorage;
|
||||
use net_traits::CookieSource;
|
||||
use servo_url::ServoUrl;
|
||||
|
||||
#[test]
|
||||
fn test_domain_match() {
|
||||
assert!(Cookie::domain_match("foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("bar.foo.com", "foo.com"));
|
||||
assert!(Cookie::domain_match("baz.bar.foo.com", "foo.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.foo.com", "bar.com"));
|
||||
assert!(!Cookie::domain_match("bar.com", "baz.bar.com"));
|
||||
assert!(!Cookie::domain_match("foo.com", "bar.com"));
|
||||
|
||||
assert!(!Cookie::domain_match("bar.com", "bbar.com"));
|
||||
assert!(Cookie::domain_match("235.132.2.3", "235.132.2.3"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", "1.1.1.1"));
|
||||
assert!(!Cookie::domain_match("235.132.2.3", ".2.3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_match() {
|
||||
assert!(Cookie::path_match("/", "/"));
|
||||
assert!(Cookie::path_match("/index.html", "/"));
|
||||
assert!(Cookie::path_match("/w/index.html", "/"));
|
||||
assert!(Cookie::path_match("/w/index.html", "/w/index.html"));
|
||||
assert!(Cookie::path_match("/w/index.html", "/w/"));
|
||||
assert!(Cookie::path_match("/w/index.html", "/w"));
|
||||
|
||||
assert!(!Cookie::path_match("/", "/w/"));
|
||||
assert!(!Cookie::path_match("/a", "/w/"));
|
||||
assert!(!Cookie::path_match("/", "/w"));
|
||||
assert!(!Cookie::path_match("/w/index.html", "/w/index"));
|
||||
assert!(!Cookie::path_match("/windex.html", "/w/"));
|
||||
assert!(!Cookie::path_match("/windex.html", "/w"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_path() {
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz/") == "/foo/bar/baz");
|
||||
assert!(&*Cookie::default_path("/foo/bar/baz") == "/foo/bar");
|
||||
assert!(&*Cookie::default_path("/foo/") == "/foo");
|
||||
assert!(&*Cookie::default_path("/foo") == "/");
|
||||
assert!(&*Cookie::default_path("/") == "/");
|
||||
assert!(&*Cookie::default_path("") == "/");
|
||||
assert!(&*Cookie::default_path("foo") == "/");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_cookie_constructor() {
|
||||
use net_traits::CookieSource;
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com/foo").unwrap();
|
||||
|
||||
let gov_url = &ServoUrl::parse("http://gov.ac/foo").unwrap();
|
||||
// cookie name/value test
|
||||
assert!(cookie_rs::Cookie::parse(" baz ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" = bar ").is_err());
|
||||
assert!(cookie_rs::Cookie::parse(" baz = ").is_ok());
|
||||
|
||||
// cookie domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = ").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_some());
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(&**cookie.cookie.domain().as_ref().unwrap() == "example.com");
|
||||
|
||||
// cookie public domains test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar; Domain = gov.ac").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie.clone(), url, CookieSource::HTTP).is_none());
|
||||
assert!(Cookie::new_wrapped(cookie, gov_url, CookieSource::HTTP).is_some());
|
||||
|
||||
// cookie domain matching test
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Domain = bazample.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; HttpOnly").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::NonHTTP).is_none());
|
||||
|
||||
let cookie = cookie_rs::Cookie::parse(" baz = bar ; Secure; Path = /foo/bar/").unwrap();
|
||||
let cookie = Cookie::new_wrapped(cookie, url, CookieSource::HTTP).unwrap();
|
||||
assert!(cookie.cookie.value() == "bar");
|
||||
assert!(cookie.cookie.name() == "baz");
|
||||
assert!(cookie.cookie.secure());
|
||||
assert!(&cookie.cookie.path().as_ref().unwrap()[..] == "/foo/bar/");
|
||||
assert!(&cookie.cookie.domain().as_ref().unwrap()[..] == "example.com");
|
||||
assert!(cookie.host_only);
|
||||
|
||||
let u = &ServoUrl::parse("http://example.com/foobar").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("foobar=value;path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, u, CookieSource::HTTP).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cookie_secure_prefix() {
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345; Secure").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345; Secure").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345; Secure; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Secure-SID=12345; Secure; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cookie_host_prefix() {
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Domain=example.com; Path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure; Domain=example.com").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure; Domain=example.com; Path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_none());
|
||||
|
||||
let url = &ServoUrl::parse("https://example.com").unwrap();
|
||||
let cookie = cookie_rs::Cookie::parse("__Host-SID=12345; Secure; Path=/").unwrap();
|
||||
assert!(Cookie::new_wrapped(cookie, url, CookieSource::HTTP).is_some());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn delay_to_ensure_different_timestamp() {
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
// time::now()'s resolution on some platforms isn't granular enought to ensure
|
||||
// that two back-to-back calls to Cookie::new_wrapped generate different timestamps .
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn delay_to_ensure_different_timestamp() {}
|
||||
|
||||
#[test]
|
||||
fn test_sort_order() {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let url = &ServoUrl::parse("http://example.com/foo").unwrap();
|
||||
let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap();
|
||||
let a = Cookie::new_wrapped(a_wrapped.clone(), url, CookieSource::HTTP).unwrap();
|
||||
delay_to_ensure_different_timestamp();
|
||||
let a_prime = Cookie::new_wrapped(a_wrapped, url, CookieSource::HTTP).unwrap();
|
||||
let b = cookie_rs::Cookie::parse("baz=bar;Path=/foo/bar/baz/").unwrap();
|
||||
let b = Cookie::new_wrapped(b, url, CookieSource::HTTP).unwrap();
|
||||
|
||||
assert!(b.cookie.path().as_ref().unwrap().len() > a.cookie.path().as_ref().unwrap().len());
|
||||
assert!(CookieStorage::cookie_comparator(&a, &b) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&b, &a) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a_prime) == Ordering::Less);
|
||||
assert!(CookieStorage::cookie_comparator(&a_prime, &a) == Ordering::Greater);
|
||||
assert!(CookieStorage::cookie_comparator(&a, &a) == Ordering::Equal);
|
||||
}
|
||||
|
||||
fn add_cookie_to_storage(storage: &mut CookieStorage, url: &ServoUrl, cookie_str: &str)
|
||||
{
|
||||
let source = CookieSource::HTTP;
|
||||
let cookie = cookie_rs::Cookie::parse(cookie_str.to_owned()).unwrap();
|
||||
let cookie = Cookie::new_wrapped(cookie, url, source).unwrap();
|
||||
storage.push(cookie, url, source);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_insecure_cookies_cannot_evict_secure_cookie() {
|
||||
let mut storage = CookieStorage::new(5);
|
||||
let secure_url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
let mut cookies = Vec::new();
|
||||
|
||||
cookies.push(cookie_rs::Cookie::parse("foo=bar; Secure; Domain=home.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo2=bar; Secure; Domain=.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo3=bar; Secure; Path=/foo").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo4=bar; Secure; Path=/foo/bar").unwrap());
|
||||
|
||||
for bare_cookie in cookies {
|
||||
let cookie = Cookie::new_wrapped(bare_cookie, &secure_url, source).unwrap();
|
||||
storage.push(cookie, &secure_url, source);
|
||||
}
|
||||
|
||||
let insecure_url = ServoUrl::parse("http://home.example.org:8888/cookie-parser?0001").unwrap();
|
||||
|
||||
add_cookie_to_storage(&mut storage, &insecure_url, "foo=value; Domain=home.example.org");
|
||||
add_cookie_to_storage(&mut storage, &insecure_url, "foo2=value; Domain=.example.org");
|
||||
add_cookie_to_storage(&mut storage, &insecure_url, "foo3=value; Path=/foo/bar");
|
||||
add_cookie_to_storage(&mut storage, &insecure_url, "foo4=value; Path=/foo");
|
||||
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&secure_url, source).unwrap(), "foo=bar; foo2=bar");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo3=bar; foo4=value; foo=bar; foo2=bar");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/bar/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo4=bar; foo3=bar; foo4=value; foo=bar; foo2=bar");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_secure_cookies_eviction() {
|
||||
let mut storage = CookieStorage::new(5);
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
let mut cookies = Vec::new();
|
||||
|
||||
cookies.push(cookie_rs::Cookie::parse("foo=bar; Secure; Domain=home.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo2=bar; Secure; Domain=.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo3=bar; Secure; Path=/foo").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo4=bar; Secure; Path=/foo/bar").unwrap());
|
||||
|
||||
for bare_cookie in cookies {
|
||||
let cookie = Cookie::new_wrapped(bare_cookie, &url, source).unwrap();
|
||||
storage.push(cookie, &url, source);
|
||||
}
|
||||
|
||||
add_cookie_to_storage(&mut storage, &url, "foo=value; Domain=home.example.org");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo2=value; Domain=.example.org");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo3=value; Path=/foo/bar");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo4=value; Path=/foo");
|
||||
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo2=value");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo3=bar; foo4=value; foo2=value");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/bar/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(),
|
||||
"foo4=bar; foo3=value; foo3=bar; foo4=value; foo2=value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_secure_cookies_eviction_non_http_source() {
|
||||
let mut storage = CookieStorage::new(5);
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap();
|
||||
let source = CookieSource::NonHTTP;
|
||||
let mut cookies = Vec::new();
|
||||
|
||||
cookies.push(cookie_rs::Cookie::parse("foo=bar; Secure; Domain=home.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo2=bar; Secure; Domain=.example.org").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo3=bar; Secure; Path=/foo").unwrap());
|
||||
cookies.push(cookie_rs::Cookie::parse("foo4=bar; Secure; Path=/foo/bar").unwrap());
|
||||
|
||||
for bare_cookie in cookies {
|
||||
let cookie = Cookie::new_wrapped(bare_cookie, &url, source).unwrap();
|
||||
storage.push(cookie, &url, source);
|
||||
}
|
||||
|
||||
add_cookie_to_storage(&mut storage, &url, "foo=value; Domain=home.example.org");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo2=value; Domain=.example.org");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo3=value; Path=/foo/bar");
|
||||
add_cookie_to_storage(&mut storage, &url, "foo4=value; Path=/foo");
|
||||
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo2=value");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(), "foo3=bar; foo4=value; foo2=value");
|
||||
|
||||
let url = ServoUrl::parse("https://home.example.org:8888/foo/bar/cookie-parser-result?0001").unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
assert_eq!(storage.cookies_for_url(&url, source).unwrap(),
|
||||
"foo4=bar; foo3=value; foo3=bar; foo4=value; foo2=value");
|
||||
}
|
||||
|
||||
|
||||
fn add_retrieve_cookies(set_location: &str,
|
||||
set_cookies: &[String],
|
||||
final_location: &str)
|
||||
-> String {
|
||||
let mut storage = CookieStorage::new(5);
|
||||
let url = ServoUrl::parse(set_location).unwrap();
|
||||
let source = CookieSource::HTTP;
|
||||
|
||||
// Add all cookies to the store
|
||||
for str_cookie in set_cookies {
|
||||
let bytes = str_cookie.to_string().into_bytes();
|
||||
let header = Header::parse_header(&[bytes]).unwrap();
|
||||
let SetCookie(cookies) = header;
|
||||
for bare_cookie in cookies {
|
||||
let cookie = Cookie::from_cookie_string(bare_cookie, &url, source).unwrap();
|
||||
storage.push(cookie, &url, source);
|
||||
}
|
||||
}
|
||||
|
||||
// Get cookies for the test location
|
||||
let url = ServoUrl::parse(final_location).unwrap();
|
||||
storage.cookies_for_url(&url, source).unwrap_or("".to_string())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cookie_eviction_expired() {
|
||||
let mut vec = Vec::new();
|
||||
for i in 1..6 {
|
||||
let st = format!("extra{}=bar; Secure; expires=Sun, 18-Apr-2000 21:06:29 GMT",
|
||||
i);
|
||||
vec.push(st);
|
||||
}
|
||||
vec.push("foo=bar; Secure; expires=Sun, 18-Apr-2027 21:06:29 GMT".to_owned());
|
||||
let r = add_retrieve_cookies("https://home.example.org:8888/cookie-parser?0001",
|
||||
&vec, "https://home.example.org:8888/cookie-parser-result?0001");
|
||||
assert_eq!(&r, "foo=bar");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cookie_eviction_all_secure_one_nonsecure() {
|
||||
let mut vec = Vec::new();
|
||||
for i in 1..5 {
|
||||
let st = format!("extra{}=bar; Secure; expires=Sun, 18-Apr-2026 21:06:29 GMT",
|
||||
i);
|
||||
vec.push(st);
|
||||
}
|
||||
vec.push("foo=bar; expires=Sun, 18-Apr-2026 21:06:29 GMT".to_owned());
|
||||
vec.push("foo2=bar; Secure; expires=Sun, 18-Apr-2028 21:06:29 GMT".to_owned());
|
||||
let r = add_retrieve_cookies("https://home.example.org:8888/cookie-parser?0001",
|
||||
&vec, "https://home.example.org:8888/cookie-parser-result?0001");
|
||||
assert_eq!(&r, "extra1=bar; extra2=bar; extra3=bar; extra4=bar; foo2=bar");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cookie_eviction_all_secure_new_nonsecure() {
|
||||
let mut vec = Vec::new();
|
||||
for i in 1..6 {
|
||||
let st = format!("extra{}=bar; Secure; expires=Sun, 18-Apr-2026 21:06:29 GMT",
|
||||
i);
|
||||
vec.push(st);
|
||||
}
|
||||
vec.push("foo=bar; expires=Sun, 18-Apr-2077 21:06:29 GMT".to_owned());
|
||||
let r = add_retrieve_cookies("https://home.example.org:8888/cookie-parser?0001",
|
||||
&vec, "https://home.example.org:8888/cookie-parser-result?0001");
|
||||
assert_eq!(&r, "extra1=bar; extra2=bar; extra3=bar; extra4=bar; extra5=bar");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cookie_eviction_all_nonsecure_new_secure() {
|
||||
let mut vec = Vec::new();
|
||||
for i in 1..6 {
|
||||
let st = format!("extra{}=bar; expires=Sun, 18-Apr-2026 21:06:29 GMT", i);
|
||||
vec.push(st);
|
||||
}
|
||||
vec.push("foo=bar; Secure; expires=Sun, 18-Apr-2077 21:06:29 GMT".to_owned());
|
||||
let r = add_retrieve_cookies("https://home.example.org:8888/cookie-parser?0001",
|
||||
&vec, "https://home.example.org:8888/cookie-parser-result?0001");
|
||||
assert_eq!(&r, "extra2=bar; extra3=bar; extra4=bar; extra5=bar; foo=bar");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cookie_eviction_all_nonsecure_new_nonsecure() {
|
||||
let mut vec = Vec::new();
|
||||
for i in 1..6 {
|
||||
let st = format!("extra{}=bar; expires=Sun, 18-Apr-2026 21:06:29 GMT", i);
|
||||
vec.push(st);
|
||||
}
|
||||
vec.push("foo=bar; expires=Sun, 18-Apr-2077 21:06:29 GMT".to_owned());
|
||||
let r = add_retrieve_cookies("https://home.example.org:8888/cookie-parser?0001",
|
||||
&vec, "https://home.example.org:8888/cookie-parser-result?0001");
|
||||
assert_eq!(&r, "extra2=bar; extra3=bar; extra4=bar; extra5=bar; foo=bar");
|
||||
}
|
1927
components/net/tests/cookie_http_state.rs
Normal file
174
components/net/tests/cookie_http_state_utils.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
REPO = "https://github.com/abarth/http-state.git"
|
||||
TEST_FILE = "cookie_http_state.rs"
|
||||
DOMAIN = "http://home.example.org:8888"
|
||||
RUST_FN = """
|
||||
#[test]{should_panic}
|
||||
fn test_{name}() {{
|
||||
let r = run("{set_location}",
|
||||
{set_cookies},
|
||||
"{location}");
|
||||
assert_eq!(&r, "{expect}");
|
||||
}}
|
||||
"""
|
||||
SET_COOKIES_INDENT = 18
|
||||
SHOULD_PANIC = "\n#[should_panic] // Look at cookie_http_state_utils.py if this test fails"
|
||||
|
||||
# Those tests should PASS. But until fixes land in servo, keep them failing
|
||||
FAILING_TESTS = [
|
||||
"0003", # Waiting for a way to clean expired cookies
|
||||
"0006", # Waiting for a way to clean expired cookies
|
||||
"mozilla0001", # Waiting for a way to clean expired cookies
|
||||
"mozilla0002", # Waiting for a way to clean expired cookies
|
||||
"mozilla0003", # Waiting for a way to clean expired cookies
|
||||
"mozilla0005", # Waiting for a way to clean expired cookies
|
||||
"mozilla0007", # Waiting for a way to clean expired cookies
|
||||
"mozilla0009", # Waiting for a way to clean expired cookies
|
||||
"mozilla0010", # Waiting for a way to clean expired cookies
|
||||
"mozilla0013", # Waiting for a way to clean expired cookies
|
||||
]
|
||||
|
||||
|
||||
def list_tests(dir):
|
||||
suffix = "-test"
|
||||
|
||||
def keep(name):
|
||||
return name.endswith(suffix) and not name.startswith("disabled")
|
||||
|
||||
tests = [name[:-len(suffix)] for name in os.listdir(dir) if keep(name)]
|
||||
tests.sort()
|
||||
return tests
|
||||
|
||||
|
||||
def escape(s):
|
||||
""" Escape the string `s` so that it can be parsed by rust as a valid
|
||||
UTF-8 string.
|
||||
We can't use only `encode("unicode_escape")` as it produces things that
|
||||
rust does not accept ("\\xbf", "\\u6265" for example). So we manually
|
||||
convert all character whose code point is greater than 128 to
|
||||
\\u{code_point}.
|
||||
All other characters are encoded with "unicode_escape" to get escape
|
||||
sequences ("\\r" for example) except for `"` that we specifically escape
|
||||
because our string will be quoted by double-quotes.
|
||||
Lines are also limited in size, so split the string every 70 characters
|
||||
(gives room for indentation).
|
||||
"""
|
||||
res = ""
|
||||
last_split = 0
|
||||
for c in s:
|
||||
if len(res) - last_split > 70:
|
||||
res += "\\\n"
|
||||
last_split = len(res)
|
||||
o = ord(c)
|
||||
if o == 34:
|
||||
res += "\\\""
|
||||
continue
|
||||
if o >= 128:
|
||||
res += "\\u{" + hex(o)[2:] + "}"
|
||||
else:
|
||||
res += c.encode("unicode_escape")
|
||||
return res
|
||||
|
||||
|
||||
def format_slice_cookies(cookies):
|
||||
esc_cookies = ['"%s"' % escape(c) for c in cookies]
|
||||
if sum(len(s) for s in esc_cookies) < 80:
|
||||
sep = ", "
|
||||
else:
|
||||
sep = ",\n" + " " * SET_COOKIES_INDENT
|
||||
return "&[" + sep.join(esc_cookies) + "]"
|
||||
|
||||
|
||||
def generate_code_for_test(test_dir, name):
|
||||
if name in FAILING_TESTS:
|
||||
should_panic = SHOULD_PANIC
|
||||
else:
|
||||
should_panic = ""
|
||||
|
||||
test_file = os.path.join(test_dir, name + "-test")
|
||||
expect_file = os.path.join(test_dir, name + "-expected")
|
||||
|
||||
set_cookies = []
|
||||
set_location = DOMAIN + "/cookie-parser?" + name
|
||||
expect = ""
|
||||
location = DOMAIN + "/cookie-parser-result?" + name
|
||||
|
||||
with open(test_file) as fo:
|
||||
for line in fo:
|
||||
line = line.decode("utf-8").rstrip()
|
||||
prefix = "Set-Cookie: "
|
||||
if line.startswith(prefix):
|
||||
set_cookies.append(line[len(prefix):])
|
||||
prefix = "Location: "
|
||||
if line.startswith(prefix):
|
||||
location = line[len(prefix):]
|
||||
if location.startswith("/"):
|
||||
location = DOMAIN + location
|
||||
|
||||
with open(expect_file) as fo:
|
||||
for line in fo:
|
||||
line = line.decode("utf-8").rstrip()
|
||||
prefix = "Cookie: "
|
||||
if line.startswith(prefix):
|
||||
expect = line[len(prefix):]
|
||||
|
||||
return RUST_FN.format(name=name.replace('-', '_'),
|
||||
set_location=escape(set_location),
|
||||
set_cookies=format_slice_cookies(set_cookies),
|
||||
should_panic=should_panic,
|
||||
location=escape(location),
|
||||
expect=escape(expect))
|
||||
|
||||
|
||||
def update_test_file(cachedir):
|
||||
workdir = os.path.dirname(os.path.realpath(__file__))
|
||||
test_file = os.path.join(workdir, TEST_FILE)
|
||||
|
||||
# Create the cache dir
|
||||
if not os.path.isdir(cachedir):
|
||||
os.makedirs(cachedir)
|
||||
|
||||
# Clone or update the repo
|
||||
repo_dir = os.path.join(cachedir, "http-state")
|
||||
if os.path.isdir(repo_dir):
|
||||
args = ["git", "pull", "-f"]
|
||||
process = subprocess.Popen(args, cwd=repo_dir)
|
||||
if process.wait() != 0:
|
||||
print("failed to update the http-state git repo")
|
||||
return 1
|
||||
else:
|
||||
args = ["git", "clone", REPO, repo_dir]
|
||||
process = subprocess.Popen(args)
|
||||
if process.wait() != 0:
|
||||
print("failed to clone the http-state git repo")
|
||||
return 1
|
||||
|
||||
# Truncate the unit test file to remove all existing tests
|
||||
with open(test_file, "r+") as fo:
|
||||
while True:
|
||||
line = fo.readline()
|
||||
if line.strip() == "// Test listing":
|
||||
fo.truncate()
|
||||
fo.flush()
|
||||
break
|
||||
if line == "":
|
||||
print("Failed to find listing delimiter on unit test file")
|
||||
return 1
|
||||
|
||||
# Append all tests to unit test file
|
||||
tests_dir = os.path.join(repo_dir, "tests", "data", "parser")
|
||||
with open(test_file, "a") as fo:
|
||||
for test in list_tests(tests_dir):
|
||||
fo.write(generate_code_for_test(tests_dir, test).encode("utf-8"))
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_test_file(tempfile.gettempdir())
|
139
components/net/tests/data_loader.rs
Normal file
|
@ -0,0 +1,139 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use fetch;
|
||||
use hyper::header::ContentType;
|
||||
use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value};
|
||||
use hyper_serde::Serde;
|
||||
use net_traits::{FetchMetadata, FilteredMetadata, NetworkError};
|
||||
use net_traits::request::{Origin, Request};
|
||||
use net_traits::response::ResponseBody;
|
||||
use servo_url::ServoUrl;
|
||||
use std::ops::Deref;
|
||||
|
||||
#[cfg(test)]
|
||||
fn assert_parse(url: &'static str,
|
||||
content_type: Option<ContentType>,
|
||||
charset: Option<&str>,
|
||||
data: Option<&[u8]>) {
|
||||
let url = ServoUrl::parse(url).unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
|
||||
let response = fetch(&mut request, None);
|
||||
|
||||
match data {
|
||||
Some(data) => {
|
||||
assert!(!response.is_network_error());
|
||||
assert_eq!(response.headers.len(), 1);
|
||||
|
||||
let header_content_type = response.headers.get::<ContentType>();
|
||||
assert_eq!(header_content_type, content_type.as_ref());
|
||||
|
||||
let metadata = match response.metadata() {
|
||||
Ok(FetchMetadata::Filtered { filtered: FilteredMetadata::Basic(m), .. }) => m,
|
||||
result => panic!(result),
|
||||
};
|
||||
assert_eq!(metadata.content_type.map(Serde::into_inner), content_type);
|
||||
assert_eq!(metadata.charset.as_ref().map(String::deref), charset);
|
||||
|
||||
let resp_body = response.body.lock().unwrap();
|
||||
match *resp_body {
|
||||
ResponseBody::Done(ref val) => {
|
||||
assert_eq!(val, &data);
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
},
|
||||
None => {
|
||||
assert!(response.is_network_error());
|
||||
assert_eq!(response.metadata().err(), Some(NetworkError::Internal("Decoding data URL failed".to_owned())));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_invalid() {
|
||||
assert_parse("data:", None, None, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain() {
|
||||
assert_parse(
|
||||
"data:,hello%20world",
|
||||
Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
|
||||
vec!((Attr::Charset, Value::Ext("US-ASCII".to_owned())))))),
|
||||
Some("US-ASCII"),
|
||||
Some(b"hello world"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_ct() {
|
||||
assert_parse(
|
||||
"data:text/plain,hello",
|
||||
Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec!()))),
|
||||
None,
|
||||
Some(b"hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_html() {
|
||||
assert_parse(
|
||||
"data:text/html,<p>Servo</p>",
|
||||
Some(ContentType(Mime(TopLevel::Text, SubLevel::Html, vec!()))),
|
||||
None,
|
||||
Some(b"<p>Servo</p>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_charset() {
|
||||
assert_parse(
|
||||
"data:text/plain;charset=latin1,hello",
|
||||
Some(ContentType(Mime(TopLevel::Text,
|
||||
SubLevel::Plain,
|
||||
vec!((Attr::Charset, Value::Ext("latin1".to_owned())))))),
|
||||
Some("latin1"),
|
||||
Some(b"hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plain_only_charset() {
|
||||
assert_parse(
|
||||
"data:;charset=utf-8,hello",
|
||||
Some(ContentType(Mime(TopLevel::Text,
|
||||
SubLevel::Plain,
|
||||
vec!((Attr::Charset, Value::Utf8))))),
|
||||
Some("utf-8"),
|
||||
Some(b"hello"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64() {
|
||||
assert_parse(
|
||||
"data:;base64,C62+7w==",
|
||||
Some(ContentType(Mime(TopLevel::Text,
|
||||
SubLevel::Plain,
|
||||
vec!((Attr::Charset, Value::Ext("US-ASCII".to_owned())))))),
|
||||
Some("US-ASCII"),
|
||||
Some(&[0x0B, 0xAD, 0xBE, 0xEF]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_ct() {
|
||||
assert_parse(
|
||||
"data:application/octet-stream;base64,C62+7w==",
|
||||
Some(ContentType(Mime(TopLevel::Application, SubLevel::Ext("octet-stream".to_owned()), vec!()))),
|
||||
None,
|
||||
Some(&[0x0B, 0xAD, 0xBE, 0xEF]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base64_charset() {
|
||||
assert_parse(
|
||||
"data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
|
||||
Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain,
|
||||
vec!((Attr::Charset, Value::Ext("koi8-r".to_owned())))))),
|
||||
Some("koi8-r"),
|
||||
Some(&[0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4]));
|
||||
}
|
982
components/net/tests/fetch.rs
Normal file
|
@ -0,0 +1,982 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use {DEFAULT_USER_AGENT, new_fetch_context, fetch, make_server};
|
||||
use devtools_traits::DevtoolsControlMsg;
|
||||
use devtools_traits::HttpRequest as DevtoolsHttpRequest;
|
||||
use devtools_traits::HttpResponse as DevtoolsHttpResponse;
|
||||
use fetch_with_context;
|
||||
use fetch_with_cors_cache;
|
||||
use http_loader::{expect_devtools_http_request, expect_devtools_http_response};
|
||||
use hyper::LanguageTag;
|
||||
use hyper::header::{Accept, AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowOrigin};
|
||||
use hyper::header::{AcceptEncoding, AcceptLanguage, AccessControlAllowMethods, AccessControlMaxAge};
|
||||
use hyper::header::{AccessControlRequestHeaders, AccessControlRequestMethod, Date, UserAgent};
|
||||
use hyper::header::{CacheControl, ContentLanguage, ContentLength, ContentType, Expires, LastModified};
|
||||
use hyper::header::{Encoding, Location, Pragma, Quality, QualityItem, SetCookie, qitem};
|
||||
use hyper::header::{Headers, Host, HttpDate, Referer as HyperReferer};
|
||||
use hyper::method::Method;
|
||||
use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||
use hyper::server::{Request as HyperRequest, Response as HyperResponse, Server};
|
||||
use hyper::status::StatusCode;
|
||||
use hyper::uri::RequestUri;
|
||||
use hyper_openssl;
|
||||
use msg::constellation_msg::TEST_PIPELINE_ID;
|
||||
use net::connector::create_ssl_client;
|
||||
use net::fetch::cors_cache::CorsCache;
|
||||
use net::fetch::methods::{CancellationListener, FetchContext};
|
||||
use net::filemanager_thread::FileManager;
|
||||
use net::hsts::HstsEntry;
|
||||
use net::test::HttpState;
|
||||
use net_traits::IncludeSubdomains;
|
||||
use net_traits::NetworkError;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use net_traits::request::{Destination, Origin, RedirectMode, Referrer, Request, RequestMode};
|
||||
use net_traits::response::{CacheState, Response, ResponseBody, ResponseType};
|
||||
use servo_config::resource_files::resources_dir_path;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use time::{self, Duration};
|
||||
use unicase::UniCase;
|
||||
|
||||
// TODO write a struct that impls Handler for storing test values
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_is_not_network_error() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
if fetch_response.is_network_error() {
|
||||
panic!("fetch response shouldn't be a network error");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_on_bad_port_is_network_error() {
|
||||
let url = ServoUrl::parse("http://www.example.org:6667").unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
assert!(fetch_response.is_network_error());
|
||||
let fetch_error = fetch_response.get_network_error().unwrap();
|
||||
assert!(fetch_error == &NetworkError::Internal("Request attempted on bad port".into()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_body_matches_const_message() {
|
||||
static MESSAGE: &'static [u8] = b"Hello World!";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Basic);
|
||||
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Done(ref body) => {
|
||||
assert_eq!(&**body, MESSAGE);
|
||||
},
|
||||
_ => panic!()
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_aboutblank() {
|
||||
let url = ServoUrl::parse("about:blank").unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert!(*fetch_response.body.lock().unwrap() == ResponseBody::Done(vec![]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_blob() {
|
||||
use ipc_channel::ipc;
|
||||
use net_traits::blob_url_store::BlobBuf;
|
||||
|
||||
let context = new_fetch_context(None);
|
||||
|
||||
let bytes = b"content";
|
||||
let blob_buf = BlobBuf {
|
||||
filename: Some("test.txt".into()),
|
||||
type_string: "text/plain".into(),
|
||||
size: bytes.len() as u64,
|
||||
bytes: bytes.to_vec(),
|
||||
};
|
||||
|
||||
let origin = ServoUrl::parse("http://www.example.org/").unwrap();
|
||||
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
context.filemanager.promote_memory(blob_buf, true, sender, "http://www.example.org".into());
|
||||
let id = receiver.recv().unwrap().unwrap();
|
||||
let url = ServoUrl::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap();
|
||||
|
||||
|
||||
let mut request = Request::new(url, Some(Origin::Origin(origin.origin())), None);
|
||||
let fetch_response = fetch_with_context(&mut request, &context);
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
|
||||
assert_eq!(fetch_response.headers.len(), 2);
|
||||
|
||||
let content_type: &ContentType = fetch_response.headers.get().unwrap();
|
||||
assert_eq!(**content_type, Mime(TopLevel::Text, SubLevel::Plain, vec![]));
|
||||
|
||||
let content_length: &ContentLength = fetch_response.headers.get().unwrap();
|
||||
assert_eq!(**content_length, bytes.len() as u64);
|
||||
|
||||
assert_eq!(*fetch_response.body.lock().unwrap(),
|
||||
ResponseBody::Done(bytes.to_vec()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_file() {
|
||||
let mut path = resources_dir_path().expect("Cannot find resource dir");
|
||||
path.push("servo.css");
|
||||
|
||||
let url = ServoUrl::from_file_path(path.clone()).unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.headers.len(), 1);
|
||||
let content_type: &ContentType = fetch_response.headers.get().unwrap();
|
||||
assert!(**content_type == Mime(TopLevel::Text, SubLevel::Css, vec![]));
|
||||
|
||||
let resp_body = fetch_response.body.lock().unwrap();
|
||||
let mut file = File::open(path).unwrap();
|
||||
let mut bytes = vec![];
|
||||
let _ = file.read_to_end(&mut bytes);
|
||||
|
||||
match *resp_body {
|
||||
ResponseBody::Done(ref val) => {
|
||||
assert_eq!(val, &bytes);
|
||||
},
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_ftp() {
|
||||
let url = ServoUrl::parse("ftp://not-supported").unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
assert!(fetch_response.is_network_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_bogus_scheme() {
|
||||
let url = ServoUrl::parse("bogus://whatever").unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
assert!(fetch_response.is_network_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cors_preflight_fetch() {
|
||||
static ACK: &'static [u8] = b"ACK";
|
||||
let state = Arc::new(AtomicUsize::new(0));
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
if request.method == Method::Options && state.clone().fetch_add(1, Ordering::SeqCst) == 0 {
|
||||
assert!(request.headers.has::<AccessControlRequestMethod>());
|
||||
assert!(!request.headers.has::<AccessControlRequestHeaders>());
|
||||
assert!(!request.headers.get::<HyperReferer>().unwrap().contains("a.html"));
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.headers_mut().set(AccessControlAllowCredentials);
|
||||
response.headers_mut().set(AccessControlAllowMethods(vec![Method::Get]));
|
||||
} else {
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.send(ACK).unwrap();
|
||||
}
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let target_url = url.clone().join("a.html").unwrap();
|
||||
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url.clone(), Some(origin), None);
|
||||
request.referrer = Referrer::ReferrerUrl(target_url);
|
||||
request.referrer_policy = Some(ReferrerPolicy::Origin);
|
||||
request.use_cors_preflight = true;
|
||||
request.mode = RequestMode::CorsMode;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Done(ref body) => assert_eq!(&**body, ACK),
|
||||
_ => panic!()
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cors_preflight_cache_fetch() {
|
||||
static ACK: &'static [u8] = b"ACK";
|
||||
let state = Arc::new(AtomicUsize::new(0));
|
||||
let counter = state.clone();
|
||||
let mut cache = CorsCache::new();
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
if request.method == Method::Options && state.clone().fetch_add(1, Ordering::SeqCst) == 0 {
|
||||
assert!(request.headers.has::<AccessControlRequestMethod>());
|
||||
assert!(!request.headers.has::<AccessControlRequestHeaders>());
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.headers_mut().set(AccessControlAllowCredentials);
|
||||
response.headers_mut().set(AccessControlAllowMethods(vec![Method::Get]));
|
||||
response.headers_mut().set(AccessControlMaxAge(6000));
|
||||
} else {
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.send(ACK).unwrap();
|
||||
}
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url.clone(), Some(origin.clone()), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.use_cors_preflight = true;
|
||||
request.mode = RequestMode::CorsMode;
|
||||
let mut wrapped_request0 = request.clone();
|
||||
let mut wrapped_request1 = request;
|
||||
|
||||
let fetch_response0 = fetch_with_cors_cache(&mut wrapped_request0, &mut cache);
|
||||
let fetch_response1 = fetch_with_cors_cache(&mut wrapped_request1, &mut cache);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response0.is_network_error() && !fetch_response1.is_network_error());
|
||||
|
||||
// The response from the CORS-preflight cache was used
|
||||
assert_eq!(1, counter.load(Ordering::SeqCst));
|
||||
|
||||
// The entry exists in the CORS-preflight cache
|
||||
assert_eq!(true, cache.match_method(&wrapped_request0, Method::Get));
|
||||
assert_eq!(true, cache.match_method(&wrapped_request1, Method::Get));
|
||||
|
||||
match *fetch_response0.body.lock().unwrap() {
|
||||
ResponseBody::Done(ref body) => assert_eq!(&**body, ACK),
|
||||
_ => panic!()
|
||||
};
|
||||
match *fetch_response1.body.lock().unwrap() {
|
||||
ResponseBody::Done(ref body) => assert_eq!(&**body, ACK),
|
||||
_ => panic!()
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cors_preflight_fetch_network_error() {
|
||||
static ACK: &'static [u8] = b"ACK";
|
||||
let state = Arc::new(AtomicUsize::new(0));
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
if request.method == Method::Options && state.clone().fetch_add(1, Ordering::SeqCst) == 0 {
|
||||
assert!(request.headers.has::<AccessControlRequestMethod>());
|
||||
assert!(!request.headers.has::<AccessControlRequestHeaders>());
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.headers_mut().set(AccessControlAllowCredentials);
|
||||
response.headers_mut().set(AccessControlAllowMethods(vec![Method::Get]));
|
||||
} else {
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
response.send(ACK).unwrap();
|
||||
}
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.method = Method::Extension("CHICKEN".to_owned());
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.use_cors_preflight = true;
|
||||
request.mode = RequestMode::CorsMode;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(fetch_response.is_network_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_is_basic_filtered() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, mut response: HyperResponse| {
|
||||
response.headers_mut().set(SetCookie(vec![]));
|
||||
// this header is obsoleted, so hyper doesn't implement it, but it's still covered by the spec
|
||||
response.headers_mut().set_raw("Set-Cookie2", vec![]);
|
||||
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Basic);
|
||||
|
||||
let headers = fetch_response.headers;
|
||||
assert!(!headers.has::<SetCookie>());
|
||||
assert!(headers.get_raw("Set-Cookie2").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_is_cors_filtered() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, mut response: HyperResponse| {
|
||||
// this is mandatory for the Cors Check to pass
|
||||
// TODO test using different url encodings with this value ie. punycode
|
||||
response.headers_mut().set(AccessControlAllowOrigin::Any);
|
||||
|
||||
// these are the headers that should be kept after filtering
|
||||
response.headers_mut().set(CacheControl(vec![]));
|
||||
response.headers_mut().set(ContentLanguage(vec![]));
|
||||
response.headers_mut().set(ContentType::html());
|
||||
response.headers_mut().set(Expires(HttpDate(time::now() + Duration::days(1))));
|
||||
response.headers_mut().set(LastModified(HttpDate(time::now())));
|
||||
response.headers_mut().set(Pragma::NoCache);
|
||||
|
||||
// these headers should not be kept after filtering, even though they are given a pass
|
||||
response.headers_mut().set(SetCookie(vec![]));
|
||||
response.headers_mut().set_raw("Set-Cookie2", vec![]);
|
||||
response.headers_mut().set(
|
||||
AccessControlAllowHeaders(vec![
|
||||
UniCase("set-cookie".to_owned()),
|
||||
UniCase("set-cookie2".to_owned())
|
||||
])
|
||||
);
|
||||
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
// an origin mis-match will stop it from defaulting to a basic filtered response
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.mode = RequestMode::CorsMode;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Cors);
|
||||
|
||||
let headers = fetch_response.headers;
|
||||
assert!(headers.has::<CacheControl>());
|
||||
assert!(headers.has::<ContentLanguage>());
|
||||
assert!(headers.has::<ContentType>());
|
||||
assert!(headers.has::<Expires>());
|
||||
assert!(headers.has::<LastModified>());
|
||||
assert!(headers.has::<Pragma>());
|
||||
|
||||
assert!(!headers.has::<AccessControlAllowOrigin>());
|
||||
assert!(!headers.has::<SetCookie>());
|
||||
assert!(headers.get_raw("Set-Cookie2").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_is_opaque_filtered() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
// an origin mis-match will fall through to an Opaque filtered response
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Opaque);
|
||||
|
||||
assert!(fetch_response.url().is_none());
|
||||
assert!(fetch_response.url_list.is_empty());
|
||||
// this also asserts that status message is "the empty byte sequence"
|
||||
assert!(fetch_response.status.is_none());
|
||||
assert_eq!(fetch_response.headers, Headers::new());
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Empty => { },
|
||||
_ => panic!()
|
||||
}
|
||||
match fetch_response.cache_state {
|
||||
CacheState::None => { },
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_response_is_opaque_redirect_filtered() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
let redirects = match request.uri {
|
||||
RequestUri::AbsolutePath(url) =>
|
||||
url.split("/").collect::<String>().parse::<u32>().unwrap_or(0),
|
||||
RequestUri::AbsoluteUri(url) =>
|
||||
url.path_segments().unwrap().next_back().unwrap().parse::<u32>().unwrap_or(0),
|
||||
_ => panic!()
|
||||
};
|
||||
|
||||
if redirects == 1 {
|
||||
response.send(MESSAGE).unwrap();
|
||||
} else {
|
||||
*response.status_mut() = StatusCode::Found;
|
||||
let url = format!("{}", 1);
|
||||
response.headers_mut().set(Location(url.to_owned()));
|
||||
}
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.redirect_mode = RedirectMode::Manual;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::OpaqueRedirect);
|
||||
|
||||
// this also asserts that status message is "the empty byte sequence"
|
||||
assert!(fetch_response.status.is_none());
|
||||
assert_eq!(fetch_response.headers, Headers::new());
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Empty => { },
|
||||
_ => panic!()
|
||||
}
|
||||
match fetch_response.cache_state {
|
||||
CacheState::None => { },
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_with_local_urls_only() {
|
||||
// If flag `local_urls_only` is set, fetching a non-local URL must result in network error.
|
||||
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, server_url) = make_server(handler);
|
||||
|
||||
let do_fetch = |url: ServoUrl| {
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
|
||||
// Set the flag.
|
||||
request.local_urls_only = true;
|
||||
|
||||
fetch(&mut request, None)
|
||||
};
|
||||
|
||||
let local_url = ServoUrl::parse("about:blank").unwrap();
|
||||
let local_response = do_fetch(local_url);
|
||||
let server_response = do_fetch(server_url);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
assert!(!local_response.is_network_error());
|
||||
assert!(server_response.is_network_error());
|
||||
}
|
||||
|
||||
// NOTE(emilio): If this test starts failing:
|
||||
//
|
||||
// openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||
// -keyout resources/privatekey_for_testing.key \
|
||||
// -out resources/self_signed_certificate_for_testing.crt
|
||||
//
|
||||
// And make sure to specify `localhost` as the server name.
|
||||
#[test]
|
||||
fn test_fetch_with_hsts() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
|
||||
let path = resources_dir_path().expect("Cannot find resource dir");
|
||||
let mut cert_path = path.clone();
|
||||
cert_path.push("self_signed_certificate_for_testing.crt");
|
||||
|
||||
let mut key_path = path.clone();
|
||||
key_path.push("privatekey_for_testing.key");
|
||||
|
||||
let ssl = hyper_openssl::OpensslServer::from_files(key_path, cert_path)
|
||||
.unwrap();
|
||||
|
||||
//takes an address and something that implements hyper::net::Ssl
|
||||
let mut server = Server::https("0.0.0.0:0", ssl).unwrap().handle_threads(handler, 1).unwrap();
|
||||
|
||||
let ca_file = resources_dir_path().unwrap().join("self_signed_certificate_for_testing.crt");
|
||||
let ssl_client = create_ssl_client(&ca_file);
|
||||
|
||||
let context = FetchContext {
|
||||
state: Arc::new(HttpState::new(ssl_client)),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: None,
|
||||
filemanager: FileManager::new(),
|
||||
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))),
|
||||
};
|
||||
|
||||
{
|
||||
let mut list = context.state.hsts_list.write().unwrap();
|
||||
list.push(HstsEntry::new("localhost".to_owned(), IncludeSubdomains::NotIncluded, None)
|
||||
.unwrap());
|
||||
}
|
||||
let url_string = format!("http://localhost:{}", server.socket.port());
|
||||
let url = ServoUrl::parse(&url_string).unwrap();
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
// Set the flag.
|
||||
request.local_urls_only = false;
|
||||
let response = fetch_with_context(&mut request, &context);
|
||||
let _ = server.close();
|
||||
assert_eq!(response.internal_response.unwrap().url().unwrap().scheme(),
|
||||
"https");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_with_sri_network_error() {
|
||||
static MESSAGE: &'static [u8] = b"alert('Hello, Network Error');";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
// To calulate hash use :
|
||||
// echo -n "alert('Hello, Network Error');" | openssl dgst -sha384 -binary | openssl base64 -A
|
||||
request.integrity_metadata =
|
||||
"sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO".to_owned();
|
||||
// Set the flag.
|
||||
request.local_urls_only = false;
|
||||
|
||||
let response = fetch(&mut request, None);
|
||||
|
||||
let _ = server.close();
|
||||
assert!(response.is_network_error());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_with_sri_sucess() {
|
||||
static MESSAGE: &'static [u8] = b"alert('Hello, world.');";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
// To calulate hash use :
|
||||
// echo -n "alert('Hello, Network Error');" | openssl dgst -sha384 -binary | openssl base64 -A
|
||||
request.integrity_metadata =
|
||||
"sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO".to_owned();
|
||||
// Set the flag.
|
||||
request.local_urls_only = false;
|
||||
|
||||
let response = fetch(&mut request, None);
|
||||
|
||||
let _ = server.close();
|
||||
assert_eq!(response_is_done(&response), true);
|
||||
}
|
||||
|
||||
/// `fetch` should return a network error if there is a header `X-Content-Type-Options: nosniff`
|
||||
#[test]
|
||||
fn test_fetch_blocked_nosniff() {
|
||||
#[inline]
|
||||
fn test_nosniff_request(destination: Destination,
|
||||
mime: Mime,
|
||||
should_error: bool) {
|
||||
const MESSAGE: &'static [u8] = b"";
|
||||
const HEADER: &'static str = "X-Content-Type-Options";
|
||||
const VALUE: &'static [u8] = b"nosniff";
|
||||
|
||||
let handler = move |_: HyperRequest, mut response: HyperResponse| {
|
||||
let mime_header = ContentType(mime.clone());
|
||||
response.headers_mut().set(mime_header);
|
||||
assert!(response.headers().has::<ContentType>());
|
||||
// Add the nosniff header
|
||||
response.headers_mut().set_raw(HEADER, vec![VALUE.to_vec()]);
|
||||
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.destination = destination;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
|
||||
assert_eq!(fetch_response.is_network_error(), should_error);
|
||||
}
|
||||
|
||||
let tests = vec![
|
||||
(Destination::Script, Mime(TopLevel::Text, SubLevel::Javascript, vec![]), false),
|
||||
(Destination::Script, Mime(TopLevel::Text, SubLevel::Css, vec![]), true),
|
||||
(Destination::Style, Mime(TopLevel::Text, SubLevel::Css, vec![]), false),
|
||||
];
|
||||
|
||||
for test in tests {
|
||||
let (destination, mime, should_error) = test;
|
||||
test_nosniff_request(destination, mime, should_error);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response {
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
let redirects = match request.uri {
|
||||
RequestUri::AbsolutePath(url) =>
|
||||
url.split("/").collect::<String>().parse::<u32>().unwrap_or(0),
|
||||
RequestUri::AbsoluteUri(url) =>
|
||||
url.path_segments().unwrap().next_back().unwrap().parse::<u32>().unwrap_or(0),
|
||||
_ => panic!()
|
||||
};
|
||||
|
||||
if redirects >= redirect_cap {
|
||||
response.send(message).unwrap();
|
||||
} else {
|
||||
*response.status_mut() = StatusCode::Found;
|
||||
let url = format!("{redirects}", redirects = redirects + 1);
|
||||
response.headers_mut().set(Location(url.to_owned()));
|
||||
}
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
fetch_response
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_redirect_count_ceiling() {
|
||||
static MESSAGE: &'static [u8] = b"no more redirects";
|
||||
// how many redirects to cause
|
||||
let redirect_cap = 20;
|
||||
|
||||
let fetch_response = setup_server_and_fetch(MESSAGE, redirect_cap);
|
||||
|
||||
assert!(!fetch_response.is_network_error());
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Basic);
|
||||
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Done(ref body) => {
|
||||
assert_eq!(&**body, MESSAGE);
|
||||
},
|
||||
_ => panic!()
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_redirect_count_failure() {
|
||||
static MESSAGE: &'static [u8] = b"this message shouldn't be reachable";
|
||||
// how many redirects to cause
|
||||
let redirect_cap = 21;
|
||||
|
||||
let fetch_response = setup_server_and_fetch(MESSAGE, redirect_cap);
|
||||
|
||||
assert!(fetch_response.is_network_error());
|
||||
|
||||
match *fetch_response.body.lock().unwrap() {
|
||||
ResponseBody::Done(_) | ResponseBody::Receiving(_) => panic!(),
|
||||
_ => { }
|
||||
};
|
||||
}
|
||||
|
||||
fn test_fetch_redirect_updates_method_runner(tx: Sender<bool>, status_code: StatusCode, method: Method) {
|
||||
let handler_method = method.clone();
|
||||
let handler_tx = Arc::new(Mutex::new(tx));
|
||||
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
let redirects = match request.uri {
|
||||
RequestUri::AbsolutePath(url) =>
|
||||
url.split("/").collect::<String>().parse::<u32>().unwrap_or(0),
|
||||
RequestUri::AbsoluteUri(url) =>
|
||||
url.path_segments().unwrap().next_back().unwrap().parse::<u32>().unwrap_or(0),
|
||||
_ => panic!()
|
||||
};
|
||||
|
||||
let mut test_pass = true;
|
||||
|
||||
if redirects == 0 {
|
||||
*response.status_mut() = StatusCode::TemporaryRedirect;
|
||||
response.headers_mut().set(Location("1".to_owned()));
|
||||
|
||||
} else if redirects == 1 {
|
||||
// this makes sure that the request method does't change from the wrong status code
|
||||
if handler_method != Method::Get && request.method == Method::Get {
|
||||
test_pass = false;
|
||||
}
|
||||
*response.status_mut() = status_code;
|
||||
response.headers_mut().set(Location("2".to_owned()));
|
||||
|
||||
} else if request.method != Method::Get {
|
||||
test_pass = false;
|
||||
}
|
||||
|
||||
// the first time this handler is reached, nothing is being tested, so don't send anything
|
||||
if redirects > 0 {
|
||||
handler_tx.lock().unwrap().send(test_pass).unwrap();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.method = method;
|
||||
|
||||
let _ = fetch(&mut request, None);
|
||||
let _ = server.close();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_redirect_updates_method() {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::MovedPermanently, Method::Post);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
// make sure the test doesn't send more data than expected
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::Found, Method::Post);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::SeeOther, Method::Get);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
|
||||
let extension = Method::Extension("FOO".to_owned());
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::MovedPermanently, extension.clone());
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
// for MovedPermanently and Found, Method should only be changed if it was Post
|
||||
assert_eq!(rx.recv().unwrap(), false);
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::Found, extension.clone());
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.recv().unwrap(), false);
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
|
||||
test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::SeeOther, extension.clone());
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
// for SeeOther, Method should always be changed, so this should be true
|
||||
assert_eq!(rx.recv().unwrap(), true);
|
||||
assert_eq!(rx.try_recv().is_err(), true);
|
||||
}
|
||||
|
||||
fn response_is_done(response: &Response) -> bool {
|
||||
let response_complete = match response.response_type {
|
||||
ResponseType::Default | ResponseType::Basic | ResponseType::Cors => {
|
||||
(*response.body.lock().unwrap()).is_done()
|
||||
}
|
||||
// if the internal response cannot have a body, it shouldn't block the "done" state
|
||||
ResponseType::Opaque | ResponseType::OpaqueRedirect | ResponseType::Error(..) => true
|
||||
};
|
||||
|
||||
let internal_complete = if let Some(ref res) = response.internal_response {
|
||||
res.body.lock().unwrap().is_done()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
response_complete && internal_complete
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_async_returns_complete_response() {
|
||||
static MESSAGE: &'static [u8] = b"this message should be retrieved in full";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
|
||||
let _ = server.close();
|
||||
assert_eq!(response_is_done(&fetch_response), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_opaque_filtered_fetch_async_returns_complete_response() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
// an origin mis-match will fall through to an Opaque filtered response
|
||||
let origin = Origin::Origin(ImmutableOrigin::new_opaque());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
assert_eq!(fetch_response.response_type, ResponseType::Opaque);
|
||||
assert_eq!(response_is_done(&fetch_response), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() {
|
||||
static MESSAGE: &'static [u8] = b"";
|
||||
let handler = move |request: HyperRequest, mut response: HyperResponse| {
|
||||
let redirects = match request.uri {
|
||||
RequestUri::AbsolutePath(url) =>
|
||||
url.split("/").collect::<String>().parse::<u32>().unwrap_or(0),
|
||||
RequestUri::AbsoluteUri(url) =>
|
||||
url.path_segments().unwrap().last().unwrap().parse::<u32>().unwrap_or(0),
|
||||
_ => panic!()
|
||||
};
|
||||
|
||||
if redirects == 1 {
|
||||
response.send(MESSAGE).unwrap();
|
||||
} else {
|
||||
*response.status_mut() = StatusCode::Found;
|
||||
let url = format!("{}", 1);
|
||||
response.headers_mut().set(Location(url.to_owned()));
|
||||
}
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url, Some(origin), None);
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
request.redirect_mode = RedirectMode::Manual;
|
||||
|
||||
let fetch_response = fetch(&mut request, None);
|
||||
|
||||
let _ = server.close();
|
||||
|
||||
assert_eq!(fetch_response.response_type, ResponseType::OpaqueRedirect);
|
||||
assert_eq!(response_is_done(&fetch_response), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fetch_with_devtools() {
|
||||
static MESSAGE: &'static [u8] = b"Yay!";
|
||||
let handler = move |_: HyperRequest, response: HyperResponse| {
|
||||
response.send(MESSAGE).unwrap();
|
||||
};
|
||||
|
||||
let (mut server, url) = make_server(handler);
|
||||
|
||||
let origin = Origin::Origin(url.origin());
|
||||
let mut request = Request::new(url.clone(), Some(origin), Some(TEST_PIPELINE_ID));
|
||||
request.referrer = Referrer::NoReferrer;
|
||||
|
||||
let (devtools_chan, devtools_port) = channel::<DevtoolsControlMsg>();
|
||||
|
||||
let _ = fetch(&mut request, Some(devtools_chan));
|
||||
let _ = server.close();
|
||||
|
||||
// notification received from devtools
|
||||
let devhttprequest = expect_devtools_http_request(&devtools_port);
|
||||
let mut devhttpresponse = expect_devtools_http_response(&devtools_port);
|
||||
|
||||
//Creating default headers for request
|
||||
let mut headers = Headers::new();
|
||||
|
||||
headers.set(AcceptEncoding(vec![
|
||||
qitem(Encoding::Gzip),
|
||||
qitem(Encoding::Deflate),
|
||||
qitem(Encoding::EncodingExt("br".to_owned()))
|
||||
]));
|
||||
|
||||
headers.set(Host { hostname: url.host_str().unwrap().to_owned() , port: url.port().to_owned() });
|
||||
|
||||
let accept = Accept(vec![qitem(Mime(TopLevel::Star, SubLevel::Star, vec![]))]);
|
||||
headers.set(accept);
|
||||
|
||||
let mut en_us: LanguageTag = Default::default();
|
||||
en_us.language = Some("en".to_owned());
|
||||
en_us.region = Some("US".to_owned());
|
||||
let mut en: LanguageTag = Default::default();
|
||||
en.language = Some("en".to_owned());
|
||||
headers.set(AcceptLanguage(vec![
|
||||
qitem(en_us),
|
||||
QualityItem::new(en, Quality(500)),
|
||||
]));
|
||||
|
||||
headers.set(UserAgent(DEFAULT_USER_AGENT.to_owned()));
|
||||
|
||||
let httprequest = DevtoolsHttpRequest {
|
||||
url: url,
|
||||
method: Method::Get,
|
||||
headers: headers,
|
||||
body: None,
|
||||
pipeline_id: TEST_PIPELINE_ID,
|
||||
startedDateTime: devhttprequest.startedDateTime,
|
||||
timeStamp: devhttprequest.timeStamp,
|
||||
connect_time: devhttprequest.connect_time,
|
||||
send_time: devhttprequest.send_time,
|
||||
is_xhr: true,
|
||||
};
|
||||
|
||||
let content = "Yay!";
|
||||
let mut response_headers = Headers::new();
|
||||
response_headers.set(ContentLength(content.len() as u64));
|
||||
devhttpresponse.headers.as_mut().unwrap().remove::<Date>();
|
||||
|
||||
let httpresponse = DevtoolsHttpResponse {
|
||||
headers: Some(response_headers),
|
||||
status: Some((200, b"OK".to_vec())),
|
||||
body: None,
|
||||
pipeline_id: TEST_PIPELINE_ID,
|
||||
};
|
||||
|
||||
assert_eq!(devhttprequest, httprequest);
|
||||
assert_eq!(devhttpresponse, httpresponse);
|
||||
}
|
17
components/net/tests/file_loader.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::env;
|
||||
use url::Url;
|
||||
|
||||
#[test]
|
||||
fn load_htm() {
|
||||
let mut path = env::current_dir().expect("didn't get working dir");
|
||||
path.push("tests/test.jpeg");
|
||||
|
||||
let canon_path = path.canonicalize().expect("file path doesn't exist");
|
||||
let url = Url::from_file_path(canon_path);
|
||||
|
||||
assert!(url.is_ok());
|
||||
}
|
110
components/net/tests/filemanager_thread.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use ipc_channel::ipc;
|
||||
use net::filemanager_thread::{FileManager, UIProvider};
|
||||
use net_traits::blob_url_store::BlobURLStoreError;
|
||||
use net_traits::filemanager_thread::{FilterPattern, FileManagerThreadMsg, FileManagerThreadError, ReadFileProgress};
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const TEST_PROVIDER: &'static TestProvider = &TestProvider;
|
||||
|
||||
pub struct TestProvider;
|
||||
|
||||
impl UIProvider for TestProvider {
|
||||
fn open_file_dialog(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<String> {
|
||||
Some("tests/test.jpeg".to_string())
|
||||
}
|
||||
|
||||
fn open_file_dialog_multi(&self, _path: &str, _patterns: Vec<FilterPattern>) -> Option<Vec<String>> {
|
||||
Some(vec!["tests/test.jpeg".to_string()])
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filemanager() {
|
||||
let filemanager = FileManager::new();
|
||||
|
||||
// Try to open a dummy file "components/net/tests/test.jpeg" in tree
|
||||
let mut handler = File::open("tests/test.jpeg").expect("test.jpeg is stolen");
|
||||
let mut test_file_content = vec![];
|
||||
|
||||
handler.read_to_end(&mut test_file_content)
|
||||
.expect("Read components/net/tests/test.jpeg error");
|
||||
|
||||
let patterns = vec![FilterPattern(".txt".to_string())];
|
||||
let origin = "test.com".to_string();
|
||||
|
||||
{
|
||||
// Try to select a dummy file "components/net/tests/test.jpeg"
|
||||
let (tx, rx) = ipc::channel().unwrap();
|
||||
filemanager.handle(FileManagerThreadMsg::SelectFile(patterns.clone(), tx, origin.clone(), None),
|
||||
TEST_PROVIDER);
|
||||
let selected = rx.recv().expect("Broken channel")
|
||||
.expect("The file manager failed to find test.jpeg");
|
||||
|
||||
// Expecting attributes conforming the spec
|
||||
assert_eq!(selected.filename, PathBuf::from("test.jpeg"));
|
||||
assert_eq!(selected.type_string, "image/jpeg".to_string());
|
||||
|
||||
// Test by reading, expecting same content
|
||||
{
|
||||
let (tx2, rx2) = ipc::channel().unwrap();
|
||||
filemanager.handle(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone()),
|
||||
TEST_PROVIDER);
|
||||
|
||||
let msg = rx2.recv().expect("Broken channel");
|
||||
|
||||
if let ReadFileProgress::Meta(blob_buf) = msg.expect("File manager reading failure is unexpected") {
|
||||
let mut bytes = blob_buf.bytes;
|
||||
|
||||
loop {
|
||||
match rx2.recv().expect("Broken channel").expect("File manager reading failure is unexpected") {
|
||||
ReadFileProgress::Meta(_) => {
|
||||
panic!("Invalid FileManager reply");
|
||||
}
|
||||
ReadFileProgress::Partial(mut bytes_in) => {
|
||||
bytes.append(&mut bytes_in);
|
||||
}
|
||||
ReadFileProgress::EOF => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(test_file_content, bytes, "Read content differs");
|
||||
} else {
|
||||
panic!("Invalid FileManager reply");
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the id
|
||||
{
|
||||
let (tx2, rx2) = ipc::channel().unwrap();
|
||||
filemanager.handle(FileManagerThreadMsg::DecRef(selected.id.clone(), origin.clone(), tx2),
|
||||
TEST_PROVIDER);
|
||||
|
||||
let ret = rx2.recv().expect("Broken channel");
|
||||
assert!(ret.is_ok(), "DecRef is not okay");
|
||||
}
|
||||
|
||||
// Test by reading again, expecting read error because we invalidated the id
|
||||
{
|
||||
let (tx2, rx2) = ipc::channel().unwrap();
|
||||
filemanager.handle(FileManagerThreadMsg::ReadFile(tx2, selected.id.clone(), false, origin.clone()),
|
||||
TEST_PROVIDER);
|
||||
|
||||
let msg = rx2.recv().expect("Broken channel");
|
||||
|
||||
match msg {
|
||||
Err(FileManagerThreadError::BlobURLStoreError(BlobURLStoreError::InvalidFileID)) => {},
|
||||
other => {
|
||||
assert!(false, "Get unexpected response after deleting the id: {:?}", other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
294
components/net/tests/hsts.rs
Normal file
|
@ -0,0 +1,294 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::hsts::{HstsEntry, HstsList};
|
||||
use net_traits::IncludeSubdomains;
|
||||
use std::collections::HashMap;
|
||||
use time;
|
||||
|
||||
#[test]
|
||||
fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() {
|
||||
let entry = HstsEntry {
|
||||
host: "mozilla.org".to_owned(),
|
||||
include_subdomains: false,
|
||||
max_age: Some(20),
|
||||
timestamp: None
|
||||
};
|
||||
|
||||
assert!(!entry.is_expired());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_entry_is_not_expired_when_it_has_no_max_age() {
|
||||
let entry = HstsEntry {
|
||||
host: "mozilla.org".to_owned(),
|
||||
include_subdomains: false,
|
||||
max_age: None,
|
||||
timestamp: Some(time::get_time().sec as u64)
|
||||
};
|
||||
|
||||
assert!(!entry.is_expired());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() {
|
||||
let entry = HstsEntry {
|
||||
host: "mozilla.org".to_owned(),
|
||||
include_subdomains: false,
|
||||
max_age: Some(10),
|
||||
timestamp: Some(time::get_time().sec as u64 - 20u64)
|
||||
};
|
||||
|
||||
assert!(entry.is_expired());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_entry_cant_be_created_with_ipv6_address_as_host() {
|
||||
let entry = HstsEntry::new(
|
||||
"2001:0db8:0000:0000:0000:ff00:0042:8329".to_owned(), IncludeSubdomains::NotIncluded, None
|
||||
);
|
||||
|
||||
assert!(entry.is_none(), "able to create HstsEntry with IPv6 host");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_entry_cant_be_created_with_ipv4_address_as_host() {
|
||||
let entry = HstsEntry::new(
|
||||
"4.4.4.4".to_owned(), IncludeSubdomains::NotIncluded, None
|
||||
);
|
||||
|
||||
assert!(entry.is_none(), "able to create HstsEntry with IPv4 host");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_base_domain_in_entries_map() {
|
||||
let entries_map = HashMap::new();
|
||||
|
||||
let mut list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
list.push(HstsEntry::new("servo.mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
list.push(HstsEntry::new("firefox.mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
list.push(HstsEntry::new("bugzilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
|
||||
assert_eq!(list.entries_map.len(), 2);
|
||||
assert_eq!(list.entries_map.get("mozilla.org").unwrap().len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_entry_with_0_max_age_evicts_entry_from_list() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec!(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, Some(500000u64)).unwrap()));
|
||||
let mut list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
list.push(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, Some(0)).unwrap());
|
||||
|
||||
assert!(list.is_host_secure("mozilla.org") == false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_entry_to_hsts_list_should_not_add_subdomains_whose_superdomain_is_already_matched() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec!(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap()));
|
||||
let mut list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
list.push(HstsEntry::new("servo.mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
|
||||
assert!(list.entries_map.get("mozilla.org").unwrap().len() == 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_entry_to_hsts_list_should_update_existing_domain_entrys_include_subdomains() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec!(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap()));
|
||||
let mut list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(list.is_host_secure("servo.mozilla.org"));
|
||||
|
||||
list.push(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
|
||||
assert!(!list.is_host_secure("servo.mozilla.org"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_entry_to_hsts_list_should_not_create_duplicate_entry() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec!(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap()));
|
||||
let mut list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
list.push(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap());
|
||||
|
||||
assert!(list.entries_map.get("mozilla.org").unwrap().len() == 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_multiple_entrie_to_hsts_list_should_add_them_all() {
|
||||
let mut list = HstsList {
|
||||
entries_map: HashMap::new()
|
||||
};
|
||||
|
||||
assert!(!list.is_host_secure("mozilla.org"));
|
||||
assert!(!list.is_host_secure("bugzilla.org"));
|
||||
|
||||
list.push(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap());
|
||||
list.push(HstsEntry::new("bugzilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap());
|
||||
|
||||
assert!(list.is_host_secure("mozilla.org"));
|
||||
assert!(list.is_host_secure("bugzilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push_entry_to_hsts_list_should_add_an_entry() {
|
||||
let mut list = HstsList {
|
||||
entries_map: HashMap::new()
|
||||
};
|
||||
|
||||
assert!(!list.is_host_secure("mozilla.org"));
|
||||
|
||||
list.push(HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap());
|
||||
|
||||
assert!(list.is_host_secure("mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hsts_preload_should_return_none_when_json_invalid() {
|
||||
let mock_preload_content = b"derp";
|
||||
assert!(HstsList::from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hsts_preload_should_return_none_when_json_contains_no_entries_map_key() {
|
||||
let mock_preload_content = b"{\"nothing\": \"to see here\"}";
|
||||
assert!(HstsList::from_preload(mock_preload_content).is_none(), "invalid preload list should not have parsed")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_hsts_preload_should_decode_host_and_includes_subdomains() {
|
||||
let mock_preload_content = b"{\
|
||||
\"entries\": [\
|
||||
{\"host\": \"mozilla.org\",\
|
||||
\"include_subdomains\": false}\
|
||||
]\
|
||||
}";
|
||||
let hsts_list = HstsList::from_preload(mock_preload_content);
|
||||
let entries_map = hsts_list.unwrap().entries_map;
|
||||
|
||||
assert_eq!(entries_map.get("mozilla.org").unwrap()[0].host, "mozilla.org");
|
||||
assert!(!entries_map.get("mozilla.org").unwrap()[0].include_subdomains);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_no_entries_map_does_not_is_host_secure() {
|
||||
let hsts_list = HstsList {
|
||||
entries_map: HashMap::new()
|
||||
};
|
||||
|
||||
assert!(!hsts_list.is_host_secure("mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_exact_domain_entry_is_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap()]);
|
||||
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(hsts_list.is_host_secure("mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_subdomain_when_include_subdomains_is_true_is_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap()]);
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(hsts_list.is_host_secure("servo.mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_subdomain_when_include_subdomains_is_false_is_not_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::NotIncluded, None).unwrap()]);
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(!hsts_list.is_host_secure("servo.mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_subdomain_when_host_is_not_a_subdomain_is_not_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap()]);
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(!hsts_list.is_host_secure("servo-mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_subdomain_when_host_is_exact_match_is_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry::new("mozilla.org".to_owned(),
|
||||
IncludeSubdomains::Included, None).unwrap()]);
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(hsts_list.is_host_secure("mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hsts_list_with_expired_entry_is_not_is_host_secure() {
|
||||
let mut entries_map = HashMap::new();
|
||||
entries_map.insert("mozilla.org".to_owned(), vec![HstsEntry {
|
||||
host: "mozilla.org".to_owned(),
|
||||
include_subdomains: false,
|
||||
max_age: Some(20),
|
||||
timestamp: Some(time::get_time().sec as u64 - 100u64)
|
||||
}]);
|
||||
let hsts_list = HstsList {
|
||||
entries_map: entries_map
|
||||
};
|
||||
|
||||
assert!(!hsts_list.is_host_secure("mozilla.org"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_preload_hsts_domains_well_formed() {
|
||||
let hsts_list = HstsList::from_servo_preload();
|
||||
assert!(!hsts_list.entries_map.is_empty());
|
||||
}
|
1186
components/net/tests/http_loader.rs
Normal file
112
components/net/tests/main.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
extern crate cookie as cookie_rs;
|
||||
extern crate devtools_traits;
|
||||
extern crate flate2;
|
||||
extern crate hyper;
|
||||
extern crate hyper_openssl;
|
||||
extern crate hyper_serde;
|
||||
extern crate ipc_channel;
|
||||
extern crate msg;
|
||||
extern crate net;
|
||||
extern crate net_traits;
|
||||
extern crate profile_traits;
|
||||
extern crate servo_config;
|
||||
extern crate servo_url;
|
||||
extern crate time;
|
||||
extern crate unicase;
|
||||
extern crate url;
|
||||
|
||||
mod chrome_loader;
|
||||
mod cookie;
|
||||
mod cookie_http_state;
|
||||
mod data_loader;
|
||||
mod fetch;
|
||||
mod file_loader;
|
||||
mod filemanager_thread;
|
||||
mod hsts;
|
||||
mod http_loader;
|
||||
mod mime_classifier;
|
||||
mod resource_thread;
|
||||
mod subresource_integrity;
|
||||
|
||||
use devtools_traits::DevtoolsControlMsg;
|
||||
use hyper::server::{Handler, Listening, Server};
|
||||
use net::connector::create_ssl_client;
|
||||
use net::fetch::cors_cache::CorsCache;
|
||||
use net::fetch::methods::{self, CancellationListener, FetchContext};
|
||||
use net::filemanager_thread::FileManager;
|
||||
use net::test::HttpState;
|
||||
use net_traits::FetchTaskTarget;
|
||||
use net_traits::request::Request;
|
||||
use net_traits::response::Response;
|
||||
use servo_config::resource_files::resources_dir_path;
|
||||
use servo_url::ServoUrl;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
|
||||
const DEFAULT_USER_AGENT: &'static str = "Such Browser. Very Layout. Wow.";
|
||||
|
||||
struct FetchResponseCollector {
|
||||
sender: Sender<Response>,
|
||||
}
|
||||
|
||||
fn new_fetch_context(dc: Option<Sender<DevtoolsControlMsg>>) -> FetchContext {
|
||||
let ca_file = resources_dir_path().unwrap().join("certs");
|
||||
let ssl_client = create_ssl_client(&ca_file);
|
||||
FetchContext {
|
||||
state: Arc::new(HttpState::new(ssl_client)),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: dc,
|
||||
filemanager: FileManager::new(),
|
||||
cancellation_listener: Arc::new(Mutex::new(CancellationListener::new(None))),
|
||||
}
|
||||
}
|
||||
impl FetchTaskTarget for FetchResponseCollector {
|
||||
fn process_request_body(&mut self, _: &Request) {}
|
||||
fn process_request_eof(&mut self, _: &Request) {}
|
||||
fn process_response(&mut self, _: &Response) {}
|
||||
fn process_response_chunk(&mut self, _: Vec<u8>) {}
|
||||
/// Fired when the response is fully fetched
|
||||
fn process_response_eof(&mut self, response: &Response) {
|
||||
let _ = self.sender.send(response.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch(request: &mut Request, dc: Option<Sender<DevtoolsControlMsg>>) -> Response {
|
||||
fetch_with_context(request, &new_fetch_context(dc))
|
||||
}
|
||||
|
||||
fn fetch_with_context(request: &mut Request, context: &FetchContext) -> Response {
|
||||
let (sender, receiver) = channel();
|
||||
let mut target = FetchResponseCollector {
|
||||
sender: sender,
|
||||
};
|
||||
|
||||
methods::fetch(request, &mut target, context);
|
||||
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
||||
fn fetch_with_cors_cache(request: &mut Request, cache: &mut CorsCache) -> Response {
|
||||
let (sender, receiver) = channel();
|
||||
let mut target = FetchResponseCollector {
|
||||
sender: sender,
|
||||
};
|
||||
|
||||
methods::fetch_with_cors_cache(request, cache, &mut target, &new_fetch_context(None));
|
||||
|
||||
receiver.recv().unwrap()
|
||||
}
|
||||
|
||||
fn make_server<H: Handler + 'static>(handler: H) -> (Listening, ServoUrl) {
|
||||
// this is a Listening server because of handle_threads()
|
||||
let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 2).unwrap();
|
||||
let url_string = format!("http://localhost:{}", server.socket.port());
|
||||
let url = ServoUrl::parse(&url_string).unwrap();
|
||||
(server, url)
|
||||
}
|
560
components/net/tests/mime_classifier.rs
Normal file
|
@ -0,0 +1,560 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use net::mime_classifier::{ApacheBugFlag, MimeClassifier, Mp4Matcher, NoSniffFlag};
|
||||
use net::mime_classifier::as_string_option;
|
||||
use net_traits::LoadContext;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
use std::path::{self, PathBuf};
|
||||
|
||||
fn read_file(path: &path::Path) -> io::Result<Vec<u8>> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
file.read_to_end(&mut buffer)?;
|
||||
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_mp4_matcher() {
|
||||
let matcher = Mp4Matcher;
|
||||
|
||||
let p = PathBuf::from("tests/parsable_mime/video/mp4/test.mp4");
|
||||
let read_result = read_file(&p);
|
||||
|
||||
match read_result {
|
||||
Ok(data) => {
|
||||
println!("Data Length {:?}", data.len());
|
||||
if !matcher.matches(&data) {
|
||||
panic!("Didn't read mime type")
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("Couldn't read from file with error {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_mp4_matcher_long() {
|
||||
// Check that a multi-byte length is calculated correctly
|
||||
let matcher = Mp4Matcher;
|
||||
|
||||
let mut data: [u8; 260] = [0; 260];
|
||||
&data[.. 11].clone_from_slice(
|
||||
&[0x00, 0x00, 0x01, 0x04, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x70, 0x34]
|
||||
);
|
||||
|
||||
assert!(matcher.matches(&data));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_classifier() {
|
||||
let classifier = MimeClassifier::new();
|
||||
classifier.validate().expect("Validation error")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_sniff_with_flags(filename_orig: &path::Path,
|
||||
type_string: &str,
|
||||
subtype_string: &str,
|
||||
supplied_type: Option<(&'static str, &'static str)>,
|
||||
no_sniff_flag: NoSniffFlag,
|
||||
apache_bug_flag: ApacheBugFlag) {
|
||||
let current_working_directory = env::current_dir().unwrap();
|
||||
println!("The current directory is {}", current_working_directory.display());
|
||||
|
||||
let mut filename = PathBuf::from("tests/parsable_mime/");
|
||||
filename.push(filename_orig);
|
||||
|
||||
let classifier = MimeClassifier::new();
|
||||
|
||||
let read_result = read_file(&filename);
|
||||
|
||||
match read_result {
|
||||
Ok(data) => {
|
||||
let supplied_type = supplied_type.map(|(x, y)| (x.parse().unwrap(), y));
|
||||
let (parsed_type, parsed_subtp) = classifier.classify(LoadContext::Browsing,
|
||||
no_sniff_flag,
|
||||
apache_bug_flag,
|
||||
&as_string_option(supplied_type),
|
||||
&data);
|
||||
if (&parsed_type[..] != type_string) ||
|
||||
(&parsed_subtp[..] != subtype_string) {
|
||||
panic!("File {:?} parsed incorrectly should be {}/{}, parsed as {}/{}",
|
||||
filename, type_string, subtype_string,
|
||||
parsed_type, parsed_subtp);
|
||||
}
|
||||
}
|
||||
Err(e) => panic!("Couldn't read from file {:?} with error {}",
|
||||
filename, e),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_sniff_full(filename_orig: &path::Path, type_string: &str, subtype_string: &str,
|
||||
supplied_type: Option<(&'static str, &'static str)>) {
|
||||
test_sniff_with_flags(filename_orig,
|
||||
type_string,
|
||||
subtype_string,
|
||||
supplied_type,
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::Off)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn test_sniff_classification(file: &str, type_string: &str, subtype_string: &str,
|
||||
supplied_type: Option<(&'static str, &'static str)>) {
|
||||
let mut x = PathBuf::from("./");
|
||||
x.push(type_string);
|
||||
x.push(subtype_string);
|
||||
x.push(file);
|
||||
test_sniff_full(&x, type_string, subtype_string, supplied_type);
|
||||
}
|
||||
#[cfg(test)]
|
||||
fn test_sniff_classification_sup(file: &str, type_string: &'static str, subtype_string: &str) {
|
||||
test_sniff_classification(file, type_string, subtype_string, None);
|
||||
let class_type = Some((type_string, ""));
|
||||
test_sniff_classification(file, type_string, subtype_string, class_type);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_x_icon() {
|
||||
test_sniff_classification_sup("test.ico", "image", "x-icon");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_x_icon_cursor() {
|
||||
test_sniff_classification_sup("test_cursor.ico", "image", "x-icon");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_bmp() {
|
||||
test_sniff_classification_sup("test.bmp", "image", "bmp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_gif87a() {
|
||||
test_sniff_classification_sup("test87a", "image", "gif");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_gif89a() {
|
||||
test_sniff_classification_sup("test89a.gif", "image", "gif");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_webp() {
|
||||
test_sniff_classification_sup("test.webp", "image", "webp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_png() {
|
||||
test_sniff_classification_sup("test.png", "image", "png");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_jpg() {
|
||||
test_sniff_classification_sup("test.jpg", "image", "jpeg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_webm() {
|
||||
test_sniff_classification_sup("test.webm", "video", "webm");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_mp4() {
|
||||
test_sniff_classification_sup("test.mp4", "video", "mp4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_avi() {
|
||||
test_sniff_classification_sup("test.avi", "video", "avi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_basic() {
|
||||
test_sniff_classification_sup("test.au", "audio", "basic");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_aiff() {
|
||||
test_sniff_classification_sup("test.aif", "audio", "aiff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_mpeg() {
|
||||
test_sniff_classification_sup("test.mp3", "audio", "mpeg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_midi() {
|
||||
test_sniff_classification_sup("test.mid", "audio", "midi");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_wave() {
|
||||
test_sniff_classification_sup("test.wav", "audio", "wave");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_ogg() {
|
||||
test_sniff_classification("small.ogg", "application", "ogg", None);
|
||||
test_sniff_classification("small.ogg", "application", "ogg", Some(("audio", "")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_sniff_vsn_ms_fontobject() {
|
||||
test_sniff_classification_sup("vnd.ms-fontobject", "application", "vnd.ms-fontobject");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_sniff_true_type() {
|
||||
test_sniff_full(&PathBuf::from("unknown/true_type.ttf"), "(TrueType)", "", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_sniff_open_type() {
|
||||
test_sniff_full(&PathBuf::from("unknown/open_type"), "(OpenType)", "", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_sniff_true_type_collection() {
|
||||
test_sniff_full(&PathBuf::from("unknown/true_type_collection.ttc"), "(TrueType Collection)", "", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_sniff_woff() {
|
||||
test_sniff_classification_sup("test.wof", "application", "font-woff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_gzip() {
|
||||
test_sniff_classification("test.gz", "application", "x-gzip", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_zip() {
|
||||
test_sniff_classification("test.zip", "application", "zip", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_rar() {
|
||||
test_sniff_classification("test.rar", "application", "x-rar-compressed", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_doctype_20() {
|
||||
test_sniff_classification("text_html_doctype_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_doctype_20_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_doctype_3e() {
|
||||
test_sniff_classification("text_html_doctype_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_doctype_3e_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_page_20() {
|
||||
test_sniff_classification("text_html_page_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_page_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_page_3e() {
|
||||
test_sniff_classification("text_html_page_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_page_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_head_20() {
|
||||
test_sniff_classification("text_html_head_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_head_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_head_3e() {
|
||||
test_sniff_classification("text_html_head_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_head_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_script_20() {
|
||||
test_sniff_classification("text_html_script_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_script_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_script_3e() {
|
||||
test_sniff_classification("text_html_script_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_script_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_iframe_20() {
|
||||
test_sniff_classification("text_html_iframe_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_iframe_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_iframe_3e() {
|
||||
test_sniff_classification("text_html_iframe_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_iframe_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_h1_20() {
|
||||
test_sniff_classification("text_html_h1_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_h1_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_h1_3e() {
|
||||
test_sniff_classification("text_html_h1_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_h1_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_div_20() {
|
||||
test_sniff_classification("text_html_div_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_div_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_div_3e() {
|
||||
test_sniff_classification("text_html_div_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_div_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_font_20() {
|
||||
test_sniff_classification("text_html_font_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_font_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_font_3e() {
|
||||
test_sniff_classification("text_html_font_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_font_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_table_20() {
|
||||
test_sniff_classification("text_html_table_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_table_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_table_3e() {
|
||||
test_sniff_classification("text_html_table_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_table_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_a_20() {
|
||||
test_sniff_classification("text_html_a_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_a_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_a_3e() {
|
||||
test_sniff_classification("text_html_a_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_a_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_style_20() {
|
||||
test_sniff_classification("text_html_style_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_style_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_style_3e() {
|
||||
test_sniff_classification("text_html_style_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_style_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_title_20() {
|
||||
test_sniff_classification("text_html_title_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_title_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_title_3e() {
|
||||
test_sniff_classification("text_html_title_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_title_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_b_20() {
|
||||
test_sniff_classification("text_html_b_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_b_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_b_3e() {
|
||||
test_sniff_classification("text_html_b_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_b_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_body_20() {
|
||||
test_sniff_classification("text_html_body_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_body_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_body_3e() {
|
||||
test_sniff_classification("text_html_body_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_body_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_br_20() {
|
||||
test_sniff_classification("text_html_br_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_br_20_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_br_3e() {
|
||||
test_sniff_classification("text_html_br_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_br_3e_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_p_20() {
|
||||
test_sniff_classification("text_html_p_20.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_p_20_u.html", "text", "html", None);
|
||||
}
|
||||
#[test]
|
||||
fn test_sniff_text_html_p_3e() {
|
||||
test_sniff_classification("text_html_p_3e.html", "text", "html", None);
|
||||
test_sniff_classification("text_html_p_3e_u.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_comment_20() {
|
||||
test_sniff_classification("text_html_comment_20.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_text_html_comment_3e() {
|
||||
test_sniff_classification("text_html_comment_3e.html", "text", "html", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_xml() {
|
||||
test_sniff_classification("test.xml", "text", "xml", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_pdf() {
|
||||
test_sniff_classification("test.pdf", "application", "pdf", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_postscript() {
|
||||
test_sniff_classification("test.ps", "application", "postscript", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_16be_bom() {
|
||||
test_sniff_classification("utf16bebom.txt", "text", "plain", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_16le_bom() {
|
||||
test_sniff_classification("utf16lebom.txt", "text", "plain", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_8_bom() {
|
||||
test_sniff_classification("utf8bom.txt", "text", "plain", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_rss_feed() {
|
||||
// RSS feeds
|
||||
test_sniff_full(&PathBuf::from("text/xml/feed.rss"), "application", "rss+xml", Some(("text", "html")));
|
||||
test_sniff_full(&PathBuf::from("text/xml/rdf_rss.xml"), "application", "rss+xml", Some(("text", "html")));
|
||||
// Not RSS feeds
|
||||
test_sniff_full(&PathBuf::from("text/xml/rdf_rss_ko_1.xml"), "text", "html", Some(("text", "html")));
|
||||
test_sniff_full(&PathBuf::from("text/xml/rdf_rss_ko_2.xml"), "text", "html", Some(("text", "html")));
|
||||
test_sniff_full(&PathBuf::from("text/xml/rdf_rss_ko_3.xml"), "text", "html", Some(("text", "html")));
|
||||
test_sniff_full(&PathBuf::from("text/xml/rdf_rss_ko_4.xml"), "text", "html", Some(("text", "html")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_atom_feed() {
|
||||
test_sniff_full(&PathBuf::from("text/xml/feed.atom"), "application", "atom+xml", Some(("text", "html")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_binary_file() {
|
||||
test_sniff_full(&PathBuf::from("unknown/binary_file"), "application", "octet-stream", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_atom_feed_with_no_sniff_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("text/xml/feed.atom"),
|
||||
"text",
|
||||
"html",
|
||||
Some(("text", "html")),
|
||||
NoSniffFlag::On,
|
||||
ApacheBugFlag::Off);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_with_no_sniff_flag_on_and_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("text/xml/feed.atom"),
|
||||
"text",
|
||||
"html",
|
||||
Some(("text", "html")),
|
||||
NoSniffFlag::On,
|
||||
ApacheBugFlag::On);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_8_bom_with_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("text/plain/utf8bom.txt"),
|
||||
"text",
|
||||
"plain",
|
||||
Some(("dummy", "text")),
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::On);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_16be_bom_with_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("text/plain/utf16bebom.txt"),
|
||||
"text",
|
||||
"plain",
|
||||
Some(("dummy", "text")),
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::On);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_utf_16le_bom_with_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("text/plain/utf16lebom.txt"),
|
||||
"text",
|
||||
"plain",
|
||||
Some(("dummy", "text")),
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::On);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_octet_stream_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("unknown/binary_file"),
|
||||
"application",
|
||||
"octet-stream",
|
||||
Some(("dummy", "binary")),
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::On);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniff_mp4_video_apache_flag_on() {
|
||||
test_sniff_with_flags(&PathBuf::from("video/mp4/test.mp4"),
|
||||
"application",
|
||||
"octet-stream",
|
||||
Some(("video", "mp4")),
|
||||
NoSniffFlag::Off,
|
||||
ApacheBugFlag::On);
|
||||
}
|
1
components/net/tests/parsable_mime/application/font-woff/test.wof
Executable file
|
@ -0,0 +1 @@
|
|||
wOFF
|
BIN
components/net/tests/parsable_mime/application/ogg/small.ogg
Normal file
157
components/net/tests/parsable_mime/application/pdf/test.pdf
Normal file
|
@ -0,0 +1,157 @@
|
|||
%PDF-1.2
|
||||
%âãÏÓ
|
||||
|
||||
9 0 obj
|
||||
<<
|
||||
/Length 10 0 R
|
||||
/Filter /FlateDecode
|
||||
>>
|
||||
stream
|
||||
H‰Í<EFBFBD>ÑJÃ0†Ÿ ïð{§²fç$M“ínÒ-<14>‚<EFBFBD>[&jeŠâÛÛ¤ñ~‚$ÉÉÿ}ÉÉ…¬Ij«¬ÌsÀ—‚Ç~€XÖ-],÷‚$Y—÷Ó)ü'N«u1!œ„ÀVÙ?ŸÁ?
|
||||
žb1RbbœÒ‰ÉH²[¹™TD:#ž&ØÙÌX®¦øiç»$qnf¬ƒ¿†¶]»ÀõËîãaÿ¶{ÿÂØ£‰›×q|JªLs]™QÒI¸¬jî„%¯Œ9Øé`ß঺¼ÅU»ite<74>zÛ$›’Ú¿OeBÆÄ’Ò¯á¸Råþ@zÜ—úóÿgª¼ø<õ¡ª
|
||||
endstream
|
||||
endobj
|
||||
10 0 obj
|
||||
246
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Type /Page
|
||||
/Parent 5 0 R
|
||||
/Resources <<
|
||||
/Font <<
|
||||
/F0 6 0 R
|
||||
/F1 7 0 R
|
||||
>>
|
||||
/ProcSet 2 0 R
|
||||
>>
|
||||
/Contents 9 0 R
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Type /Font
|
||||
/Subtype /TrueType
|
||||
/Name /F0
|
||||
/BaseFont /Arial
|
||||
/Encoding /WinAnsiEncoding
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Type /Font
|
||||
/Subtype /TrueType
|
||||
/Name /F1
|
||||
/BaseFont /BookAntiqua,Bold
|
||||
/FirstChar 31
|
||||
/LastChar 255
|
||||
/Widths [ 750 250 278 402 606 500 889 833 227 333 333 444 606 250 333 250
|
||||
296 500 500 500 500 500 500 500 500 500 500 250 250 606 606 606
|
||||
444 747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833
|
||||
833 611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606
|
||||
500 333 500 611 444 611 500 389 556 611 333 333 611 333 889 611
|
||||
556 611 611 389 444 333 611 556 833 500 556 500 310 606 310 606
|
||||
750 500 750 333 500 500 1000 500 500 333 1000 611 389 1000 750 750
|
||||
750 750 278 278 500 500 606 500 1000 333 998 444 389 833 750 750
|
||||
667 250 278 500 500 606 500 606 500 333 747 438 500 606 333 747
|
||||
500 400 549 361 361 333 576 641 250 333 361 488 500 889 890 889
|
||||
444 778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389
|
||||
389 833 833 833 833 833 833 833 606 833 778 778 778 778 667 611
|
||||
611 500 500 500 500 500 500 778 444 500 500 500 500 333 333 333
|
||||
333 556 611 556 556 556 556 556 549 556 611 611 611 611 556 611
|
||||
556 ]
|
||||
/Encoding /WinAnsiEncoding
|
||||
/FontDescriptor 8 0 R
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Type /FontDescriptor
|
||||
/FontName /BookAntiqua,Bold
|
||||
/Flags 16418
|
||||
/FontBBox [ -250 -260 1236 930 ]
|
||||
/MissingWidth 750
|
||||
/StemV 146
|
||||
/StemH 146
|
||||
/ItalicAngle 0
|
||||
/CapHeight 930
|
||||
/XHeight 651
|
||||
/Ascent 930
|
||||
/Descent 260
|
||||
/Leading 210
|
||||
/MaxWidth 1030
|
||||
/AvgWidth 460
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
[ /PDF /Text ]
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/Kids [4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
/MediaBox [ 0 0 612 792 ]
|
||||
>>
|
||||
endobj
|
||||
1 0 obj
|
||||
<<
|
||||
/Creator (1725.fm)
|
||||
/CreationDate (1-Jan-3 18:15PM)
|
||||
/Title (1725.PDF)
|
||||
/Author (Unknown)
|
||||
/Producer (Acrobat PDFWriter 3.02 for Windows)
|
||||
/Keywords ()
|
||||
/Subject ()
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/Pages 5 0 R
|
||||
/Type /Catalog
|
||||
/DefaultGray 11 0 R
|
||||
/DefaultRGB 12 0 R
|
||||
>>
|
||||
endobj
|
||||
11 0 obj
|
||||
[/CalGray
|
||||
<<
|
||||
/WhitePoint [0.9505 1 1.0891 ]
|
||||
/Gamma 0.2468
|
||||
>>
|
||||
]
|
||||
endobj
|
||||
12 0 obj
|
||||
[/CalRGB
|
||||
<<
|
||||
/WhitePoint [0.9505 1 1.0891 ]
|
||||
/Gamma [0.2468 0.2468 0.2468 ]
|
||||
/Matrix [0.4361 0.2225 0.0139 0.3851 0.7169 0.0971 0.1431 0.0606 0.7141 ]
|
||||
>>
|
||||
]
|
||||
endobj
|
||||
xref
|
||||
0 13
|
||||
0000000000 65535 f
|
||||
0000002172 00000 n
|
||||
0000002046 00000 n
|
||||
0000002363 00000 n
|
||||
0000000375 00000 n
|
||||
0000002080 00000 n
|
||||
0000000518 00000 n
|
||||
0000000633 00000 n
|
||||
0000001760 00000 n
|
||||
0000000021 00000 n
|
||||
0000000352 00000 n
|
||||
0000002460 00000 n
|
||||
0000002548 00000 n
|
||||
trailer
|
||||
<<
|
||||
/Size 13
|
||||
/Root 3 0 R
|
||||
/Info 1 0 R
|
||||
/ID [<47149510433dd4882f05f8c124223734><47149510433dd4882f05f8c124223734>]
|
||||
>>
|
||||
startxref
|
||||
2726
|
||||
%%EOF
|
1
components/net/tests/parsable_mime/application/postscript/test.ps
Executable file
|
@ -0,0 +1 @@
|
|||
%!PS-Adobe-
|
BIN
components/net/tests/parsable_mime/application/x-gzip/test.gz
Normal file
BIN
components/net/tests/parsable_mime/application/x-rar-compressed/test.rar
Executable file
1
components/net/tests/parsable_mime/application/zip/test.zip
Executable file
|
@ -0,0 +1 @@
|
|||
PK
|
BIN
components/net/tests/parsable_mime/audio/aiff/test.aif
Normal file
BIN
components/net/tests/parsable_mime/audio/basic/test.au
Normal file
BIN
components/net/tests/parsable_mime/audio/midi/test.mid
Normal file
BIN
components/net/tests/parsable_mime/audio/mpeg/test.mp3
Normal file
BIN
components/net/tests/parsable_mime/audio/wave/test.wav
Normal file
BIN
components/net/tests/parsable_mime/image/bmp/test.bmp
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
components/net/tests/parsable_mime/image/gif/test87a
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
components/net/tests/parsable_mime/image/gif/test89a.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
components/net/tests/parsable_mime/image/jpeg/test.jpg
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
components/net/tests/parsable_mime/image/png/test.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
components/net/tests/parsable_mime/image/webp/test.webp
Executable file
After Width: | Height: | Size: 14 B |
BIN
components/net/tests/parsable_mime/image/x-icon/test.ico
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
components/net/tests/parsable_mime/image/x-icon/test_cursor.ico
Normal file
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<A
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<a
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<A>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<a>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<B
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<b
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<B>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<b>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<BODY
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<body
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<BODY>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<body>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<BR
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<br
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<BR>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<br>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!--
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!--
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!-->
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!-->
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<DIV
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<div
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<DIV>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<div>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!DOCTYPE HTML
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<!doctype html
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
<!doctype html>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<FONT
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<font
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<FONT>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<font>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<H1
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<h1
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<H1>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<h1>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<HEAD
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<head
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<HEAD>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<head>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<IFRAME
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<iframe
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<IFRAME>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<iframe>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<P
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<p
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<P>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<p>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<HTML
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<html
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<HTML>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<html>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<SCRIPT
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<script
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<SCRIPT>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<script>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<STYLE
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<style
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<STYLE>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<style>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<TABLE
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<table
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<TABLE>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<table>
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<TITLE
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<title
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
|
||||
<TITLE>
|