Merge net and net_tests

This commit is contained in:
Anthony Ramine 2018-01-19 12:52:54 +01:00
parent a311e0f569
commit 697b9e2b87
127 changed files with 18 additions and 62 deletions

View 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(()));
}

View 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");
}

File diff suppressed because it is too large Load diff

View 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())

View 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]));
}

View 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);
}

View 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());
}

View 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);
}
}
}
}
}

View 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());
}

File diff suppressed because it is too large Load diff

View 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)
}

View 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);
}

View file

@ -0,0 +1 @@
wOFF

View 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«u­1!œ„À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

View file

@ -0,0 +1 @@
%!PS-Adobe-

View file

@ -0,0 +1 @@
PK

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,3 @@
<A

View file

@ -0,0 +1,3 @@
<a

View file

@ -0,0 +1,3 @@
<A>

View file

@ -0,0 +1,3 @@
<a>

View file

@ -0,0 +1,3 @@
<B

View file

@ -0,0 +1,3 @@
<b

View file

@ -0,0 +1,3 @@
<B>

View file

@ -0,0 +1,3 @@
<b>

View file

@ -0,0 +1,3 @@
<BODY

View file

@ -0,0 +1,3 @@
<body

View file

@ -0,0 +1,3 @@
<BODY>

View file

@ -0,0 +1,3 @@
<body>

View file

@ -0,0 +1,3 @@
<BR

View file

@ -0,0 +1,3 @@
<br

View file

@ -0,0 +1,3 @@
<BR>

View file

@ -0,0 +1,3 @@
<br>

View file

@ -0,0 +1,3 @@
<!--

View file

@ -0,0 +1,3 @@
<!-->

View file

@ -0,0 +1,3 @@
<!-->

View file

@ -0,0 +1,3 @@
<DIV

View file

@ -0,0 +1,3 @@
<div

View file

@ -0,0 +1,3 @@
<DIV>

View file

@ -0,0 +1,3 @@
<div>

View file

@ -0,0 +1,3 @@
<!DOCTYPE HTML

View file

@ -0,0 +1,3 @@
<!doctype html

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML>

View file

@ -0,0 +1,4 @@
<!doctype html>

View file

@ -0,0 +1,3 @@
<FONT

View file

@ -0,0 +1,3 @@
<font

View file

@ -0,0 +1,3 @@
<FONT>

View file

@ -0,0 +1,3 @@
<font>

View file

@ -0,0 +1,3 @@
<H1

View file

@ -0,0 +1,3 @@
<h1

View file

@ -0,0 +1,3 @@
<H1>

View file

@ -0,0 +1,3 @@
<h1>

View file

@ -0,0 +1,3 @@
<HEAD

View file

@ -0,0 +1,3 @@
<head

View file

@ -0,0 +1,3 @@
<HEAD>

View file

@ -0,0 +1,3 @@
<head>

View file

@ -0,0 +1,3 @@
<IFRAME

View file

@ -0,0 +1,3 @@
<iframe

View file

@ -0,0 +1,3 @@
<IFRAME>

View file

@ -0,0 +1,3 @@
<iframe>

View file

@ -0,0 +1,3 @@
<P

View file

@ -0,0 +1,3 @@
<p

View file

@ -0,0 +1,3 @@
<P>

View file

@ -0,0 +1,3 @@
<p>

View file

@ -0,0 +1,3 @@
<HTML

View file

@ -0,0 +1,3 @@
<html

View file

@ -0,0 +1,3 @@
<HTML>

View file

@ -0,0 +1,3 @@
<html>

View file

@ -0,0 +1,3 @@
<SCRIPT

View file

@ -0,0 +1,3 @@
<script

View file

@ -0,0 +1,3 @@
<SCRIPT>

View file

@ -0,0 +1,3 @@
<script>

View file

@ -0,0 +1,3 @@
<STYLE

View file

@ -0,0 +1,3 @@
<style

View file

@ -0,0 +1,3 @@
<STYLE>

View file

@ -0,0 +1,3 @@
<style>

View file

@ -0,0 +1,3 @@
<TABLE

View file

@ -0,0 +1,3 @@
<table

View file

@ -0,0 +1,3 @@
<TABLE>

View file

@ -0,0 +1,3 @@
<table>

View file

@ -0,0 +1,3 @@
<TITLE

View file

@ -0,0 +1,3 @@
<title

View file

@ -0,0 +1,3 @@
<TITLE>

Some files were not shown because too many files have changed in this diff Show more