diff --git a/Cargo.lock b/Cargo.lock index d24134b383d..c6002808308 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,10 +193,10 @@ dependencies = [ name = "bluetooth_traits" version = "0.0.1" dependencies = [ + "embedder_traits 0.0.1", "ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "servo_config 0.0.1", ] [[package]] @@ -452,6 +452,7 @@ dependencies = [ "compositing 0.0.1", "debugger 0.0.1", "devtools_traits 0.0.1", + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gaol 0.0.1 (git+https://github.com/servo/gaol)", "gfx 0.0.1", @@ -782,6 +783,13 @@ name = "either" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "embedder_traits" +version = "0.0.1" +dependencies = [ + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "encoding_rs" version = "0.7.1" @@ -1453,6 +1461,7 @@ version = "0.0.1" dependencies = [ "app_units 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "gfx 0.0.1", @@ -1563,6 +1572,7 @@ dependencies = [ "debugger 0.0.1", "devtools 0.0.1", "devtools_traits 0.0.1", + "embedder_traits 0.0.1", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "gaol 0.0.1 (git+https://github.com/servo/gaol)", @@ -1882,6 +1892,7 @@ dependencies = [ "brotli 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "devtools_traits 0.0.1", + "embedder_traits 0.0.1", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-openssl 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1932,6 +1943,7 @@ name = "net_traits" version = "0.0.1" dependencies = [ "cookie 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "embedder_traits 0.0.1", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper_serde 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2510,6 +2522,7 @@ dependencies = [ "devtools_traits 0.0.1", "dom_struct 0.0.1", "domobject_derive 0.0.1", + "embedder_traits 0.0.1", "encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2736,6 +2749,7 @@ dependencies = [ "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.34 (registry+https://github.com/rust-lang/crates.io-index)", "glutin 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libservo 0.0.1", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "osmesa-src 17.3.1-devel (git+https://github.com/servo/osmesa-src)", @@ -2852,6 +2866,7 @@ name = "servo_config" version = "0.0.1" dependencies = [ "android_injected_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "embedder_traits 0.0.1", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3078,6 +3093,7 @@ dependencies = [ "app_units 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", + "embedder_traits 0.0.1", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/bluetooth_traits/Cargo.toml b/components/bluetooth_traits/Cargo.toml index 52b01c33c67..c1d84570765 100644 --- a/components/bluetooth_traits/Cargo.toml +++ b/components/bluetooth_traits/Cargo.toml @@ -13,4 +13,4 @@ path = "lib.rs" ipc-channel = "0.10" regex = "0.2" serde = "1.0" -servo_config = {path = "../config"} +embedder_traits = { path = "../embedder_traits" } diff --git a/components/bluetooth_traits/blocklist.rs b/components/bluetooth_traits/blocklist.rs index 26df3413c10..f141baf81f4 100644 --- a/components/bluetooth_traits/blocklist.rs +++ b/components/bluetooth_traits/blocklist.rs @@ -2,15 +2,12 @@ * 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 embedder_traits::resources::{self, Resource}; use regex::Regex; -use servo_config::resource_files::read_resource_file; use std::cell::RefCell; use std::collections::HashMap; -use std::io::BufRead; use std::string::String; -const BLOCKLIST_FILE: &'static str = "gatt_blocklist.txt"; -const BLOCKLIST_FILE_NOT_FOUND: &'static str = "Could not find gatt_blocklist.txt file"; const EXCLUDE_READS: &'static str = "exclude-reads"; const EXCLUDE_WRITES: &'static str = "exclude-writes"; const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; @@ -75,15 +72,11 @@ impl BluetoothBlocklist { fn parse_blocklist() -> Option> { // Step 1 missing, currently we parse ./resources/gatt_blocklist.txt. let valid_uuid_regex = Regex::new(VALID_UUID_REGEX).unwrap(); - let content = read_resource_file(BLOCKLIST_FILE).expect(BLOCKLIST_FILE_NOT_FOUND); + let content = resources::read_string(Resource::BluetoothBlocklist); // Step 3 let mut result = HashMap::new(); // Step 2 and 4 for line in content.lines() { - let line = match line { - Ok(l) => l, - Err(_) => return None, - }; // Step 4.1 if line.is_empty() || line.starts_with('#') { continue; diff --git a/components/bluetooth_traits/lib.rs b/components/bluetooth_traits/lib.rs index 31e644bd863..b1cc68728a7 100644 --- a/components/bluetooth_traits/lib.rs +++ b/components/bluetooth_traits/lib.rs @@ -2,10 +2,10 @@ * 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/. */ +extern crate embedder_traits; extern crate ipc_channel; extern crate regex; #[macro_use] extern crate serde; -extern crate servo_config; pub mod blocklist; pub mod scanfilter; diff --git a/components/config/Cargo.toml b/components/config/Cargo.toml index adcefa67156..fdab7afc61a 100644 --- a/components/config/Cargo.toml +++ b/components/config/Cargo.toml @@ -13,6 +13,7 @@ doctest = false [dependencies] euclid = "0.17" +embedder_traits = { path = "../embedder_traits" } getopts = "0.2.11" lazy_static = "1" log = "0.4" diff --git a/components/config/lib.rs b/components/config/lib.rs index 55c33e25b02..89604c5883b 100644 --- a/components/config/lib.rs +++ b/components/config/lib.rs @@ -6,6 +6,7 @@ #[cfg(target_os = "android")] extern crate android_injected_glue; +extern crate embedder_traits; extern crate euclid; extern crate getopts; #[macro_use] extern crate lazy_static; @@ -22,7 +23,6 @@ extern crate xdg; pub mod basedir; #[allow(unsafe_code)] pub mod opts; pub mod prefs; -pub mod resource_files; pub fn servo_version() -> String { let cargo_version = env!("CARGO_PKG_VERSION"); diff --git a/components/config/opts.rs b/components/config/opts.rs index 2c1de227728..a93d39bdf73 100644 --- a/components/config/opts.rs +++ b/components/config/opts.rs @@ -9,7 +9,6 @@ use euclid::TypedSize2D; use getopts::Options; use num_cpus; use prefs::{self, PrefValue, PREFS}; -use resource_files::set_resources_path; use servo_geometry::DeviceIndependentPixel; use servo_url::ServoUrl; use std::borrow::Cow; @@ -196,6 +195,9 @@ pub struct Opts { /// True if webrender is allowed to batch draw calls as instances. pub webrender_batch: bool, + /// Load shaders from disk. + pub shaders_dir: Option, + /// True to compile all webrender shaders at init time. This is mostly /// useful when modifying the shaders, to ensure they all compile /// after each change is made. @@ -544,6 +546,7 @@ pub fn default_opts() -> Opts { is_printing_version: false, webrender_record: false, webrender_batch: true, + shaders_dir: None, precache_shaders: false, signpost: false, certificate_path: None, @@ -575,6 +578,8 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { "Uses userscripts in resources/user-agent-js, or a specified full path", ""); opts.optmulti("", "user-stylesheet", "A user stylesheet to be added to every document", "file.css"); + opts.optopt("", "shaders", + "Shaders will be loaded from the specified directory instead of using the builtin ones.", ""); opts.optflag("z", "headless", "Headless mode"); opts.optflag("f", "hard-fail", "Exit on thread failure instead of displaying about:failure"); opts.optflag("F", "soft-fail", "Display about:failure on thread failure instead of exiting"); @@ -619,8 +624,6 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { Err(f) => args_fail(&f.to_string()), }; - set_resources_path(opt_match.opt_str("resources-path")); - if opt_match.opt_present("h") || opt_match.opt_present("help") { print_usage(app_name, &opts); process::exit(0); @@ -844,6 +847,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { is_printing_version: is_printing_version, webrender_record: debug_options.webrender_record, webrender_batch: !debug_options.webrender_disable_batch, + shaders_dir: opt_match.opt_str("shaders").map(Into::into), precache_shaders: debug_options.precache_shaders, signpost: debug_options.signpost, certificate_path: opt_match.opt_str("certificate-path"), diff --git a/components/config/prefs.rs b/components/config/prefs.rs index fff7880e569..69c8277ce8f 100644 --- a/components/config/prefs.rs +++ b/components/config/prefs.rs @@ -3,9 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use basedir::default_config_dir; +use embedder_traits::resources::{self, Resource}; use num_cpus; use opts; -use resource_files::resources_dir_path; use rustc_serialize::json::{Json, ToJson}; use std::borrow::ToOwned; use std::cmp::max; @@ -18,7 +18,7 @@ use std::sync::{Arc, RwLock}; lazy_static! { pub static ref PREFS: Preferences = { let defaults = default_prefs(); - if let Ok(prefs) = read_prefs() { + if let Ok(prefs) = read_prefs(&resources::read_string(Resource::Preferences)) { defaults.extend(prefs); } defaults @@ -156,9 +156,8 @@ pub fn default_prefs() -> Preferences { prefs } -pub fn read_prefs_from_file(mut file: T) - -> Result, ()> where T: Read { - let json = Json::from_reader(&mut file).or_else(|e| { +pub fn read_prefs(txt: &str) -> Result, ()> { + let json = Json::from_str(txt).or_else(|e| { println!("Ignoring invalid JSON in preferences: {:?}.", e); Err(()) })?; @@ -194,8 +193,10 @@ pub fn add_user_prefs() { fn init_user_prefs(path: &mut PathBuf) { path.push("prefs.json"); - if let Ok(file) = File::open(path) { - if let Ok(prefs) = read_prefs_from_file(file) { + if let Ok(mut file) = File::open(path) { + let mut txt = String::new(); + file.read_to_string(&mut txt).expect("Can't read use prefs"); + if let Ok(prefs) = read_prefs(&txt) { PREFS.extend(prefs); } } else { @@ -204,19 +205,6 @@ fn init_user_prefs(path: &mut PathBuf) { } } -fn read_prefs() -> Result, ()> { - let mut path = resources_dir_path().map_err(|_| ())?; - path.push("prefs.json"); - - let file = File::open(path).or_else(|e| { - writeln!(&mut stderr(), "Error opening preferences: {:?}.", e) - .expect("failed printing to stderr"); - Err(()) - })?; - - read_prefs_from_file(file) -} - pub struct Preferences(Arc>>); impl Preferences { diff --git a/components/config/resource_files.rs b/components/config/resource_files.rs deleted file mode 100644 index e8fc58328b0..00000000000 --- a/components/config/resource_files.rs +++ /dev/null @@ -1,83 +0,0 @@ -/* 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(target_os = "android")] -use android_injected_glue; -#[cfg(not(target_os = "android"))] -use std::env; -#[cfg(target_os = "android")] -use std::ffi::CStr; -use std::fs::File; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; - -lazy_static! { - static ref CMD_RESOURCE_DIR: Arc>> = { - Arc::new(Mutex::new(None)) - }; -} - -pub fn set_resources_path(path: Option) { - let mut dir = CMD_RESOURCE_DIR.lock().unwrap(); - *dir = path; -} - -#[cfg(target_os = "android")] -#[allow(unsafe_code)] -pub fn resources_dir_path() -> io::Result { - let mut dir = CMD_RESOURCE_DIR.lock().unwrap(); - - if let Some(ref path) = *dir { - return Ok(PathBuf::from(path)); - } - - let data_path = unsafe { - CStr::from_ptr((*android_injected_glue::get_app().activity).externalDataPath) - }; - let path = PathBuf::from(data_path.to_str().unwrap()); - *dir = Some(path.to_str().unwrap().to_owned()); - Ok(path) -} - -#[cfg(not(target_os = "android"))] -pub fn resources_dir_path() -> io::Result { - let mut dir = CMD_RESOURCE_DIR.lock().unwrap(); - - if let Some(ref path) = *dir { - return Ok(PathBuf::from(path)); - } - - // FIXME: Find a way to not rely on the executable being - // under `[/$target_triple]/target/debug` - // or `[/$target_triple]/target/release`. - let mut path = env::current_exe()?; - // Follow symlink - path = path.canonicalize()?; - - while path.pop() { - path.push("resources"); - if path.is_dir() { - break; - } - path.pop(); - // Check for Resources on mac when using a case sensitive filesystem. - path.push("Resources"); - if path.is_dir() { - break; - } - path.pop(); - } - *dir = Some(path.to_str().unwrap().to_owned()); - Ok(path) -} - -pub fn read_resource_file>(relative_path: P) -> io::Result> { - let mut path = resources_dir_path()?; - path.push(relative_path); - let mut file = File::open(&path)?; - let mut data = Vec::new(); - file.read_to_end(&mut data)?; - Ok(data) -} diff --git a/components/config/tests/opts.rs b/components/config/tests/opts.rs index 53a049e103c..23e9bae4341 100644 --- a/components/config/tests/opts.rs +++ b/components/config/tests/opts.rs @@ -2,8 +2,10 @@ * 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/. */ +extern crate embedder_traits; extern crate servo_config; +use embedder_traits::resources::register_resources_for_tests; use servo_config::opts::{parse_url_or_filename, parse_pref_from_command_line}; use servo_config::prefs::{PrefValue, PREFS}; use std::path::Path; @@ -73,6 +75,7 @@ fn test_argument_parsing_special() { #[test] fn test_parse_pref_from_command_line() { + register_resources_for_tests(); // Test with boolean values. parse_pref_from_command_line("testtrue=true"); assert_eq!(*PREFS.get("testtrue"), PrefValue::Boolean(true)); diff --git a/components/config/tests/prefs.rs b/components/config/tests/prefs.rs index 605b0f2f49b..dc11f0939a6 100644 --- a/components/config/tests/prefs.rs +++ b/components/config/tests/prefs.rs @@ -2,10 +2,12 @@ * 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/. */ +extern crate embedder_traits; extern crate servo_config; +use embedder_traits::resources::register_resources_for_tests; use servo_config::basedir; -use servo_config::prefs::{PREFS, PrefValue, read_prefs_from_file}; +use servo_config::prefs::{PREFS, PrefValue, read_prefs}; use std::fs::{self, File}; use std::io::{Read, Write}; @@ -17,7 +19,7 @@ fn test_create_pref() { \"shell.homepage\": \"https://servo.org\"\ }"; - let prefs = read_prefs_from_file(json_str.as_bytes()); + let prefs = read_prefs(json_str); assert!(prefs.is_ok()); let prefs = prefs.unwrap(); @@ -26,6 +28,7 @@ fn test_create_pref() { #[test] fn test_get_set_reset_extend() { + register_resources_for_tests(); let json_str = "{\ \"layout.writing-mode.enabled\": true,\ \"extra.stuff\": false,\ @@ -41,7 +44,7 @@ fn test_get_set_reset_extend() { PREFS.reset("shell.homepage"); assert_eq!(*PREFS.get("shell.homepage"), PrefValue::String("https://servo.org".to_owned())); - let extension = read_prefs_from_file(json_str.as_bytes()).unwrap(); + let extension = read_prefs(json_str).unwrap(); PREFS.extend(extension); assert_eq!(*PREFS.get("shell.homepage"), PrefValue::String("https://google.com".to_owned())); assert_eq!(*PREFS.get("layout.writing-mode.enabled"), PrefValue::Boolean(true)); diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index ee8067086a3..8787e67618b 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -19,6 +19,7 @@ compositing = {path = "../compositing"} debugger = {path = "../debugger"} devtools_traits = {path = "../devtools_traits"} euclid = "0.17" +embedder_traits = { path = "../embedder_traits" } gfx = {path = "../gfx"} gfx_traits = {path = "../gfx_traits"} hyper = "0.10" diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index 6ae9837e95f..5ae86080300 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -14,6 +14,8 @@ extern crate clipboard; extern crate compositing; extern crate debugger; extern crate devtools_traits; +#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] +extern crate embedder_traits; extern crate euclid; #[cfg(all(not(target_os = "windows"), not(target_os = "ios")))] extern crate gaol; diff --git a/components/constellation/sandboxing.rs b/components/constellation/sandboxing.rs index a51fd4b8ef1..29999a97ed1 100644 --- a/components/constellation/sandboxing.rs +++ b/components/constellation/sandboxing.rs @@ -2,18 +2,17 @@ * 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 embedder_traits::resources; use gaol::profile::{Operation, PathPattern, Profile}; -use servo_config::resource_files; use std::path::PathBuf; /// Our content process sandbox profile on Mac. As restrictive as possible. #[cfg(target_os = "macos")] pub fn content_process_sandbox_profile() -> Profile { use gaol::platform; - Profile::new(vec![ + + let mut operations = vec![ Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))), - Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path() - .expect("Cannot find resource dir"))), Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/Library/Fonts"))), Operation::FileReadAll(PathPattern::Subpath(PathBuf::from("/System/Library/Fonts"))), Operation::FileReadAll(PathPattern::Subpath(PathBuf::from( @@ -27,16 +26,32 @@ pub fn content_process_sandbox_profile() -> Profile { Operation::SystemInfoRead, Operation::PlatformSpecific(platform::macos::Operation::MachLookup( b"com.apple.FontServer".to_vec())), - ]).expect("Failed to create sandbox profile!") + ]; + + operations.extend(resources::sandbox_access_files().into_iter().map(|p| { + Operation::FileReadAll(PathPattern::Literal(p)) + })); + operations.extend(resources::sandbox_access_files_dirs().into_iter().map(|p| { + Operation::FileReadAll(PathPattern::Subpath(p)) + })); + + Profile::new(operations).expect("Failed to create sandbox profile!") } /// Our content process sandbox profile on Linux. As restrictive as possible. #[cfg(not(target_os = "macos"))] pub fn content_process_sandbox_profile() -> Profile { - Profile::new(vec![ + let mut operations = vec![ Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))), - Operation::FileReadAll(PathPattern::Subpath(resource_files::resources_dir_path() - .expect("Cannot find resource dir"))), - ]).expect("Failed to create sandbox profile!") + ]; + + operations.extend(resources::sandbox_access_files().into_iter().map(|p| { + Operation::FileReadAll(PathPattern::Literal(p)) + })); + operations.extend(resources::sandbox_access_files_dirs().into_iter().map(|p| { + Operation::FileReadAll(PathPattern::Subpath(p)) + })); + + Profile::new(operations).expect("Failed to create sandbox profile!") } diff --git a/components/embedder_traits/Cargo.toml b/components/embedder_traits/Cargo.toml new file mode 100644 index 00000000000..5d4db8f8063 --- /dev/null +++ b/components/embedder_traits/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "embedder_traits" +version = "0.0.1" +authors = ["The Servo Project Developers"] +license = "MPL-2.0" +publish = false + +[lib] +name = "embedder_traits" +path = "lib.rs" + +[dependencies] +lazy_static = "1" diff --git a/components/embedder_traits/lib.rs b/components/embedder_traits/lib.rs new file mode 100644 index 00000000000..aa8a3c0e111 --- /dev/null +++ b/components/embedder_traits/lib.rs @@ -0,0 +1,7 @@ +/* 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/. */ + +#[macro_use] extern crate lazy_static; + +pub mod resources; diff --git a/components/embedder_traits/resources.rs b/components/embedder_traits/resources.rs new file mode 100644 index 00000000000..2f301e21340 --- /dev/null +++ b/components/embedder_traits/resources.rs @@ -0,0 +1,97 @@ +/* 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 std::fs::File; +use std::io::Read; +use std::path::PathBuf; +use std::sync::{Once, ONCE_INIT, RwLock}; + +lazy_static! { + static ref RES: RwLock>> = RwLock::new(None); +} + +pub fn set(reader: Box) { + *RES.write().unwrap() = Some(reader); +} + +pub fn read_bytes(res: Resource) -> Vec { + RES.read().unwrap().as_ref().expect("Resource reader not set.").read(res) +} + +pub fn read_string(res: Resource) -> String { + String::from_utf8(read_bytes(res)).unwrap() +} + +pub fn sandbox_access_files() -> Vec { + RES.read().unwrap().as_ref().expect("Resource reader not set.").sandbox_access_files() +} + +pub fn sandbox_access_files_dirs() -> Vec { + RES.read().unwrap().as_ref().expect("Resource reader not set.").sandbox_access_files_dirs() +} + +pub enum Resource { + Preferences, + BluetoothBlocklist, + DomainList, + HstsPreloadList, + SSLCertificates, + BadCertHTML, + NetErrorHTML, + UserAgentCSS, + ServoCSS, + PresentationalHintsCSS, + QuirksModeCSS, + RippyPNG, +} + +pub trait ResourceReaderMethods { + fn read(&self, res: Resource) -> Vec; + fn sandbox_access_files(&self) -> Vec; + fn sandbox_access_files_dirs(&self) -> Vec; +} + +static INIT: Once = ONCE_INIT; + +pub fn register_resources_for_tests() { + INIT.call_once(|| { + struct ResourceReader; + impl ResourceReaderMethods for ResourceReader { + fn sandbox_access_files(&self) -> Vec { vec![] } + fn sandbox_access_files_dirs(&self) -> Vec { vec![] } + fn read(&self, file: Resource) -> Vec { + let file = match file { + Resource::Preferences => "prefs.json", + Resource::BluetoothBlocklist => "gatt_blocklist.txt", + Resource::DomainList => "public_domains.txt", + Resource::HstsPreloadList => "hsts_preload.json", + Resource::SSLCertificates => "certs", + Resource::BadCertHTML => "badcert.html", + Resource::NetErrorHTML => "neterror.html", + Resource::UserAgentCSS => "user-agent.css", + Resource::ServoCSS => "servo.css", + Resource::PresentationalHintsCSS => "presentational-hints.css", + Resource::QuirksModeCSS => "quirks-mode.css", + Resource::RippyPNG => "rippy.png", + }; + let mut path = env::current_exe().unwrap(); + path = path.canonicalize().unwrap(); + while path.pop() { + path.push("resources"); + if path.is_dir() { + break; + } + path.pop(); + } + path.push(file); + let mut buffer = vec![]; + File::open(path).expect(&format!("Can't find file: {}", file)) + .read_to_end(&mut buffer).expect("Can't read file"); + buffer + } + } + set(Box::new(ResourceReader)); + }); +} diff --git a/components/layout_thread/Cargo.toml b/components/layout_thread/Cargo.toml index 4bab2633a79..6aa835bd2d5 100644 --- a/components/layout_thread/Cargo.toml +++ b/components/layout_thread/Cargo.toml @@ -15,6 +15,7 @@ unstable = ["parking_lot/nightly"] [dependencies] app_units = "0.6" atomic_refcell = "0.1" +embedder_traits = {path = "../embedder_traits"} euclid = "0.17" fnv = "1.0" gfx = {path = "../gfx"} diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index cdfa0f092c2..88c00faae84 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -9,6 +9,7 @@ extern crate app_units; extern crate atomic_refcell; +extern crate embedder_traits; extern crate euclid; extern crate fnv; extern crate gfx; @@ -55,6 +56,7 @@ mod dom_wrapper; use app_units::Au; use dom_wrapper::{ServoLayoutElement, ServoLayoutDocument, ServoLayoutNode}; use dom_wrapper::drop_style_and_layout_data; +use embedder_traits::resources::{self, Resource}; use euclid::{Point2D, Rect, Size2D, TypedScale, TypedSize2D}; use fnv::FnvHashMap; use gfx::display_list::{OpaqueNode, WebRenderImageInfo}; @@ -110,7 +112,6 @@ use servo_arc::Arc as ServoArc; use servo_atoms::Atom; use servo_config::opts; use servo_config::prefs::PREFS; -use servo_config::resource_files::read_resource_file; use servo_geometry::MaxRect; use servo_url::ServoUrl; use std::borrow::ToOwned; @@ -1740,11 +1741,11 @@ fn get_root_flow_background_color(flow: &mut Flow) -> webrender_api::ColorF { fn get_ua_stylesheets() -> Result { fn parse_ua_stylesheet( shared_lock: &SharedRwLock, - filename: &'static str, + filename: &str, + content: &[u8], ) -> Result { - let res = read_resource_file(filename).map_err(|_| filename)?; Ok(DocumentStyleSheet(ServoArc::new(Stylesheet::from_bytes( - &res, + content, ServoUrl::parse(&format!("chrome://resources/{:?}", filename)).unwrap(), None, None, @@ -1758,12 +1759,17 @@ fn get_ua_stylesheets() -> Result { } let shared_lock = SharedRwLock::new(); - let mut user_or_user_agent_stylesheets = vec!(); // FIXME: presentational-hints.css should be at author origin with zero specificity. // (Does it make a difference?) - for &filename in &["user-agent.css", "servo.css", "presentational-hints.css"] { - user_or_user_agent_stylesheets.push(parse_ua_stylesheet(&shared_lock, filename)?); - } + let mut user_or_user_agent_stylesheets = vec![ + parse_ua_stylesheet(&shared_lock, "user-agent.css", + &resources::read_bytes(Resource::UserAgentCSS))?, + parse_ua_stylesheet(&shared_lock, "servo.css", + &resources::read_bytes(Resource::ServoCSS))?, + parse_ua_stylesheet(&shared_lock, "presentational-hints.css", + &resources::read_bytes(Resource::PresentationalHintsCSS))?, + ]; + for &(ref contents, ref url) in &opts::get().user_stylesheets { user_or_user_agent_stylesheets.push( DocumentStyleSheet(ServoArc::new(Stylesheet::from_bytes( @@ -1781,7 +1787,8 @@ fn get_ua_stylesheets() -> Result { ); } - let quirks_mode_stylesheet = parse_ua_stylesheet(&shared_lock, "quirks-mode.css")?; + let quirks_mode_stylesheet = parse_ua_stylesheet(&shared_lock, "quirks-mode.css", + &resources::read_bytes(Resource::QuirksModeCSS))?; Ok(UserAgentStylesheets { shared_lock: shared_lock, diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index 0d69e0f3e02..4fdee627ca9 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -16,6 +16,7 @@ base64 = "0.6" brotli = "1.0.6" cookie = "0.10" devtools_traits = {path = "../devtools_traits"} +embedder_traits = { path = "../embedder_traits" } flate2 = "1" hyper = "0.10" hyper_serde = "0.8" diff --git a/components/net/chrome_loader.rs b/components/net/chrome_loader.rs deleted file mode 100644 index 83b5b59da4a..00000000000 --- a/components/net/chrome_loader.rs +++ /dev/null @@ -1,31 +0,0 @@ -/* 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 servo_config::resource_files::resources_dir_path; -use servo_url::ServoUrl; -use std::fs::canonicalize; -use url::percent_encoding::percent_decode; - -pub fn resolve_chrome_url(url: &ServoUrl) -> Result { - assert_eq!(url.scheme(), "chrome"); - if url.host_str() != Some("resources") { - return Err(()) - } - let resources = canonicalize(resources_dir_path().expect("Error finding resource folder")) - .expect("Error canonicalizing path to the resources directory"); - let mut path = resources.clone(); - for segment in url.path_segments().unwrap() { - match percent_decode(segment.as_bytes()).decode_utf8() { - // Check ".." to prevent access to files outside of the resources directory. - Ok(segment) => path.push(&*segment), - _ => return Err(()) - } - } - match canonicalize(path) { - Ok(ref path) if path.starts_with(&resources) && path.exists() => { - Ok(ServoUrl::from_file_path(path).unwrap()) - } - _ => Err(()) - } -} diff --git a/components/net/connector.rs b/components/net/connector.rs index 58cfc8c3e81..e27884c45fc 100644 --- a/components/net/connector.rs +++ b/components/net/connector.rs @@ -9,9 +9,9 @@ use hyper::net::{NetworkConnector, HttpsStream, HttpStream, SslClient}; use hyper_openssl::OpensslClient; use openssl::ssl::{SSL_OP_NO_COMPRESSION, SSL_OP_NO_SSLV2, SSL_OP_NO_SSLV3}; use openssl::ssl::{SslConnectorBuilder, SslMethod}; +use openssl::x509; use std::io; use std::net::TcpStream; -use std::path::PathBuf; pub struct HttpsConnector { ssl: OpensslClient, @@ -50,9 +50,33 @@ impl NetworkConnector for HttpsConnector { pub type Connector = HttpsConnector; -pub fn create_ssl_client(ca_file: &PathBuf) -> OpensslClient { +pub fn create_ssl_client(certs: &str) -> OpensslClient { + // certs include multiple certificates. We could add all of them at once, + // but if any of them were already added, openssl would fail to insert all + // of them. + let mut certs = certs; let mut ssl_connector_builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); - ssl_connector_builder.set_ca_file(ca_file).expect("could not set CA file"); + loop { + let token = "-----END CERTIFICATE-----"; + if let Some(index) = certs.find(token) { + let (cert, rest) = certs.split_at(index + token.len()); + certs = rest; + let cert = x509::X509::from_pem(cert.as_bytes()).unwrap(); + ssl_connector_builder.cert_store_mut().add_cert(cert).or_else(|e| { + let v: Option> = e.errors().iter().nth(0).map(|e| e.reason()); + if v == Some(Some("cert already in hash table")) { + warn!("Cert already in hash table. Ignoring."); + // Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the + // certificate is already in the store. + Ok(()) + } else { + Err(e) + } + }).expect("could not set CA file"); + } else { + break; + } + } ssl_connector_builder.set_cipher_list(DEFAULT_CIPHERS).expect("could not set ciphers"); ssl_connector_builder.set_options(SSL_OP_NO_SSLV2 | SSL_OP_NO_SSLV3 | SSL_OP_NO_COMPRESSION); let ssl_connector = ssl_connector_builder.build(); diff --git a/components/net/hsts.rs b/components/net/hsts.rs index 85896287715..49d7168e572 100644 --- a/components/net/hsts.rs +++ b/components/net/hsts.rs @@ -2,14 +2,13 @@ * 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 embedder_traits::resources::{self, Resource}; use net_traits::IncludeSubdomains; use net_traits::pub_domains::reg_suffix; use serde_json; -use servo_config::resource_files::read_resource_file; use servo_url::ServoUrl; use std::collections::HashMap; use std::net::{Ipv4Addr, Ipv6Addr}; -use std::str::from_utf8; use time; #[derive(Clone, Deserialize, Serialize)] @@ -64,15 +63,13 @@ impl HstsList { } /// Create an `HstsList` from the bytes of a JSON preload file. - pub fn from_preload(preload_content: &[u8]) -> Option { + pub fn from_preload(preload_content: &str) -> Option { #[derive(Deserialize)] struct HstsEntries { entries: Vec, } - let hsts_entries: Option = from_utf8(&preload_content) - .ok() - .and_then(|c| serde_json::from_str(c).ok()); + let hsts_entries: Option = serde_json::from_str(preload_content).ok(); hsts_entries.map_or(None, |hsts_entries| { let mut hsts_list: HstsList = HstsList::new(); @@ -86,10 +83,8 @@ impl HstsList { } pub fn from_servo_preload() -> HstsList { - let file_bytes = read_resource_file("hsts_preload.json") - .expect("Could not find Servo HSTS preload file"); - HstsList::from_preload(&file_bytes) - .expect("Servo HSTS preload file is invalid") + let list = resources::read_string(Resource::HstsPreloadList); + HstsList::from_preload(&list).expect("Servo HSTS preload file is invalid") } pub fn is_host_secure(&self, host: &str) -> bool { diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs index b8a6e7b5b90..47eb829f962 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -2,20 +2,18 @@ * 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 embedder_traits::resources::{self, Resource}; use immeta::load_from_buf; use net_traits::{FetchMetadata, FetchResponseMsg, NetworkError}; use net_traits::image::base::{Image, ImageMetadata, PixelFormat, load_from_memory}; use net_traits::image_cache::{CanRequestImages, ImageCache, ImageResponder}; use net_traits::image_cache::{ImageOrMetadataAvailable, ImageResponse, ImageState}; use net_traits::image_cache::{PendingImageId, UsePlaceholder}; -use servo_config::resource_files::resources_dir_path; use servo_url::ServoUrl; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::fs::File; -use std::io::{self, Read}; +use std::io; use std::mem; -use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; use webrender_api; @@ -42,11 +40,8 @@ fn decode_bytes_sync(key: LoadKey, bytes: &[u8]) -> DecoderMsg { } } -fn get_placeholder_image(webrender_api: &webrender_api::RenderApi, path: &PathBuf) -> io::Result> { - let mut file = File::open(path)?; - let mut image_data = vec![]; - file.read_to_end(&mut image_data)?; - let mut image = load_from_memory(&image_data).unwrap(); +fn get_placeholder_image(webrender_api: &webrender_api::RenderApi, data: &[u8]) -> io::Result> { + let mut image = load_from_memory(&data).unwrap(); set_webrender_image_key(webrender_api, &mut image); Ok(Arc::new(image)) } @@ -403,15 +398,14 @@ impl ImageCache for ImageCacheImpl { fn new(webrender_api: webrender_api::RenderApi) -> ImageCacheImpl { debug!("New image cache"); - let mut placeholder_path = resources_dir_path().expect("Can't figure out resources path."); - placeholder_path.push("rippy.png"); + let rippy_data = resources::read_bytes(Resource::RippyPNG); ImageCacheImpl { store: Arc::new(Mutex::new(ImageCacheStore { pending_loads: AllPendingLoads::new(), completed_loads: HashMap::new(), - placeholder_image: get_placeholder_image(&webrender_api, &placeholder_path).ok(), - placeholder_url: ServoUrl::from_file_path(&placeholder_path).unwrap(), + placeholder_image: get_placeholder_image(&webrender_api, &rippy_data).ok(), + placeholder_url: ServoUrl::parse("chrome://resources/rippy.png").unwrap(), webrender_api: webrender_api, })) } diff --git a/components/net/lib.rs b/components/net/lib.rs index d5dfbf74c4f..1bc43b361f4 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -8,6 +8,7 @@ extern crate base64; extern crate brotli; extern crate cookie as cookie_rs; extern crate devtools_traits; +extern crate embedder_traits; extern crate flate2; extern crate hyper; extern crate hyper_openssl; @@ -44,7 +45,6 @@ extern crate webrender_api; extern crate websocket; mod blob_loader; -mod chrome_loader; pub mod connector; pub mod cookie; pub mod cookie_storage; @@ -68,7 +68,6 @@ pub mod fetch { /// A module for re-exports of items used in unit tests. pub mod test { - pub use chrome_loader::resolve_chrome_url; pub use http_loader::HttpState; pub use hosts::{replace_host_table, parse_hostsfile}; } diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 1192a96f949..5e708465bf7 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -8,6 +8,7 @@ use cookie; use cookie_rs; use cookie_storage::CookieStorage; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::resources::{self, Resource}; use fetch::cors_cache::CorsCache; use fetch::methods::{CancellationListener, FetchContext, fetch}; use filemanager_thread::{FileManager, TFDProvider}; @@ -31,12 +32,11 @@ use serde::{Deserialize, Serialize}; use serde_json; use servo_allocator; use servo_config::opts; -use servo_config::resource_files::resources_dir_path; use servo_url::ServoUrl; use std::borrow::{Cow, ToOwned}; use std::collections::HashMap; use std::error::Error; -use std::fs::File; +use std::fs::{self, File}; use std::io::prelude::*; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -118,14 +118,16 @@ fn create_http_states(config_dir: Option<&Path>) -> (Arc, Arc PathBuf::from(path), - None => resources_dir_path() - .expect("Need certificate file to make network requests") - .join("certs"), + let certs = match opts::get().certificate_path { + Some(ref path) => { + fs::read_to_string(path).expect("Couldn't not find certificate file") + } + None => { + resources::read_string(Resource::SSLCertificates) + }, }; - let ssl_client = create_ssl_client(&ca_file); + let ssl_client = create_ssl_client(&certs); let http_state = HttpState { cookie_jar: RwLock::new(cookie_jar), auth_cache: RwLock::new(auth_cache), @@ -136,7 +138,7 @@ fn create_http_states(config_dir: Option<&Path>) -> (Arc, Arc Result { - 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(())); -} diff --git a/components/net/tests/cookie.rs b/components/net/tests/cookie.rs index 68149736680..ed56487a0a8 100644 --- a/components/net/tests/cookie.rs +++ b/components/net/tests/cookie.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cookie_rs; +use embedder_traits::resources::register_resources_for_tests; use hyper::header::{Header, SetCookie}; use net::cookie::Cookie; use net::cookie_storage::CookieStorage; @@ -56,6 +57,7 @@ fn test_default_path() { #[test] fn fn_cookie_constructor() { use net_traits::CookieSource; + register_resources_for_tests(); let url = &ServoUrl::parse("http://example.com/foo").unwrap(); @@ -102,6 +104,7 @@ fn fn_cookie_constructor() { #[test] fn test_cookie_secure_prefix() { + register_resources_for_tests(); 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()); @@ -129,6 +132,7 @@ fn test_cookie_secure_prefix() { #[test] fn test_cookie_host_prefix() { + register_resources_for_tests(); 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()); @@ -182,6 +186,7 @@ fn delay_to_ensure_different_timestamp() {} #[test] fn test_sort_order() { use std::cmp::Ordering; + register_resources_for_tests(); let url = &ServoUrl::parse("http://example.com/foo").unwrap(); let a_wrapped = cookie_rs::Cookie::parse("baz=bar; Path=/foo/bar/").unwrap(); @@ -201,6 +206,7 @@ fn test_sort_order() { fn add_cookie_to_storage(storage: &mut CookieStorage, url: &ServoUrl, cookie_str: &str) { + register_resources_for_tests(); let source = CookieSource::HTTP; let cookie = cookie_rs::Cookie::parse(cookie_str.to_owned()).unwrap(); let cookie = Cookie::new_wrapped(cookie, url, source).unwrap(); @@ -209,6 +215,7 @@ fn add_cookie_to_storage(storage: &mut CookieStorage, url: &ServoUrl, cookie_str #[test] fn test_insecure_cookies_cannot_evict_secure_cookie() { + register_resources_for_tests(); let mut storage = CookieStorage::new(5); let secure_url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap(); let source = CookieSource::HTTP; @@ -245,6 +252,7 @@ fn test_insecure_cookies_cannot_evict_secure_cookie() { #[test] fn test_secure_cookies_eviction() { + register_resources_for_tests(); let mut storage = CookieStorage::new(5); let url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap(); let source = CookieSource::HTTP; @@ -280,6 +288,7 @@ fn test_secure_cookies_eviction() { #[test] fn test_secure_cookies_eviction_non_http_source() { + register_resources_for_tests(); let mut storage = CookieStorage::new(5); let url = ServoUrl::parse("https://home.example.org:8888/cookie-parser?0001").unwrap(); let source = CookieSource::NonHTTP; @@ -341,6 +350,7 @@ fn add_retrieve_cookies(set_location: &str, #[test] fn test_cookie_eviction_expired() { + register_resources_for_tests(); 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", @@ -356,6 +366,7 @@ fn test_cookie_eviction_expired() { #[test] fn test_cookie_eviction_all_secure_one_nonsecure() { + register_resources_for_tests(); 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", @@ -372,6 +383,7 @@ fn test_cookie_eviction_all_secure_one_nonsecure() { #[test] fn test_cookie_eviction_all_secure_new_nonsecure() { + register_resources_for_tests(); 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", @@ -387,6 +399,7 @@ fn test_cookie_eviction_all_secure_new_nonsecure() { #[test] fn test_cookie_eviction_all_nonsecure_new_secure() { + register_resources_for_tests(); 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); @@ -401,6 +414,7 @@ fn test_cookie_eviction_all_nonsecure_new_secure() { #[test] fn test_cookie_eviction_all_nonsecure_new_nonsecure() { + register_resources_for_tests(); 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); diff --git a/components/net/tests/fetch.rs b/components/net/tests/fetch.rs index e2ac5e6f313..f8552b7654e 100644 --- a/components/net/tests/fetch.rs +++ b/components/net/tests/fetch.rs @@ -6,6 +6,7 @@ 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 embedder_traits::resources::register_resources_for_tests; use fetch_with_context; use fetch_with_cors_cache; use http_loader::{expect_devtools_http_request, expect_devtools_http_response}; @@ -34,10 +35,10 @@ 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::path::Path; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::{Sender, channel}; @@ -48,6 +49,7 @@ use unicase::UniCase; #[test] fn test_fetch_response_is_not_network_error() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -67,6 +69,7 @@ fn test_fetch_response_is_not_network_error() { #[test] fn test_fetch_on_bad_port_is_network_error() { + register_resources_for_tests(); 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); @@ -79,6 +82,7 @@ fn test_fetch_on_bad_port_is_network_error() { #[test] fn test_fetch_response_body_matches_const_message() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"Hello World!"; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -104,6 +108,7 @@ fn test_fetch_response_body_matches_const_message() { #[test] fn test_fetch_aboutblank() { + register_resources_for_tests(); let url = ServoUrl::parse("about:blank").unwrap(); let origin = Origin::Origin(url.origin()); let mut request = Request::new(url, Some(origin), None); @@ -115,6 +120,7 @@ fn test_fetch_aboutblank() { #[test] fn test_fetch_blob() { + register_resources_for_tests(); use ipc_channel::ipc; use net_traits::blob_url_store::BlobBuf; @@ -155,9 +161,8 @@ fn test_fetch_blob() { #[test] fn test_fetch_file() { - let mut path = resources_dir_path().expect("Cannot find resource dir"); - path.push("servo.css"); - + register_resources_for_tests(); + let path = Path::new("../../resources/servo.css").canonicalize().unwrap(); let url = ServoUrl::from_file_path(path.clone()).unwrap(); let origin = Origin::Origin(url.origin()); let mut request = Request::new(url, Some(origin), None); @@ -183,6 +188,7 @@ fn test_fetch_file() { #[test] fn test_fetch_ftp() { + register_resources_for_tests(); let url = ServoUrl::parse("ftp://not-supported").unwrap(); let origin = Origin::Origin(url.origin()); let mut request = Request::new(url, Some(origin), None); @@ -193,6 +199,7 @@ fn test_fetch_ftp() { #[test] fn test_fetch_bogus_scheme() { + register_resources_for_tests(); let url = ServoUrl::parse("bogus://whatever").unwrap(); let origin = Origin::Origin(url.origin()); let mut request = Request::new(url, Some(origin), None); @@ -203,6 +210,7 @@ fn test_fetch_bogus_scheme() { #[test] fn test_cors_preflight_fetch() { + register_resources_for_tests(); static ACK: &'static [u8] = b"ACK"; let state = Arc::new(AtomicUsize::new(0)); let handler = move |request: HyperRequest, mut response: HyperResponse| { @@ -240,6 +248,7 @@ fn test_cors_preflight_fetch() { #[test] fn test_cors_preflight_cache_fetch() { + register_resources_for_tests(); static ACK: &'static [u8] = b"ACK"; let state = Arc::new(AtomicUsize::new(0)); let counter = state.clone(); @@ -292,6 +301,7 @@ fn test_cors_preflight_cache_fetch() { #[test] fn test_cors_preflight_fetch_network_error() { + register_resources_for_tests(); static ACK: &'static [u8] = b"ACK"; let state = Arc::new(AtomicUsize::new(0)); let handler = move |request: HyperRequest, mut response: HyperResponse| { @@ -322,6 +332,7 @@ fn test_cors_preflight_fetch_network_error() { #[test] fn test_fetch_response_is_basic_filtered() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |_: HyperRequest, mut response: HyperResponse| { response.headers_mut().set(SetCookie(vec![])); @@ -348,6 +359,7 @@ fn test_fetch_response_is_basic_filtered() { #[test] fn test_fetch_response_is_cors_filtered() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |_: HyperRequest, mut response: HyperResponse| { // this is mandatory for the Cors Check to pass @@ -402,6 +414,7 @@ fn test_fetch_response_is_cors_filtered() { #[test] fn test_fetch_response_is_opaque_filtered() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -435,6 +448,7 @@ fn test_fetch_response_is_opaque_filtered() { #[test] fn test_fetch_response_is_opaque_redirect_filtered() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |request: HyperRequest, mut response: HyperResponse| { let redirects = match request.uri { @@ -481,6 +495,7 @@ fn test_fetch_response_is_opaque_redirect_filtered() { #[test] fn test_fetch_with_local_urls_only() { + register_resources_for_tests(); // If flag `local_urls_only` is set, fetching a non-local URL must result in network error. static MESSAGE: &'static [u8] = b""; @@ -519,26 +534,24 @@ fn test_fetch_with_local_urls_only() { // And make sure to specify `localhost` as the server name. #[test] fn test_fetch_with_hsts() { + register_resources_for_tests(); 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 cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt").canonicalize().unwrap(); + let key_path = Path::new("../../resources/privatekey_for_testing.key").canonicalize().unwrap(); - let mut key_path = path.clone(); - key_path.push("privatekey_for_testing.key"); - - let ssl = hyper_openssl::OpensslServer::from_files(key_path, cert_path) + let ssl = hyper_openssl::OpensslServer::from_files(key_path, cert_path.clone()) .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 mut ca_content = String::new(); + File::open(cert_path).unwrap().read_to_string(&mut ca_content).unwrap(); + let ssl_client = create_ssl_client(&ca_content); let context = FetchContext { state: Arc::new(HttpState::new(ssl_client)), @@ -568,6 +581,7 @@ fn test_fetch_with_hsts() { #[test] fn test_fetch_with_sri_network_error() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"alert('Hello, Network Error');"; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -592,6 +606,7 @@ fn test_fetch_with_sri_network_error() { #[test] fn test_fetch_with_sri_sucess() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"alert('Hello, world.');"; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -659,6 +674,7 @@ fn test_fetch_blocked_nosniff() { } fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response { + register_resources_for_tests(); let handler = move |request: HyperRequest, mut response: HyperResponse| { let redirects = match request.uri { RequestUri::AbsolutePath(url) => @@ -689,6 +705,7 @@ fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response #[test] fn test_fetch_redirect_count_ceiling() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"no more redirects"; // how many redirects to cause let redirect_cap = 20; @@ -708,6 +725,7 @@ fn test_fetch_redirect_count_ceiling() { #[test] fn test_fetch_redirect_count_failure() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"this message shouldn't be reachable"; // how many redirects to cause let redirect_cap = 21; @@ -773,6 +791,7 @@ fn test_fetch_redirect_updates_method_runner(tx: Sender, status_code: Stat #[test] fn test_fetch_redirect_updates_method() { + register_resources_for_tests(); let (tx, rx) = channel(); test_fetch_redirect_updates_method_runner(tx.clone(), StatusCode::MovedPermanently, Method::Post); @@ -831,6 +850,7 @@ fn response_is_done(response: &Response) -> bool { #[test] fn test_fetch_async_returns_complete_response() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"this message should be retrieved in full"; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -849,6 +869,7 @@ fn test_fetch_async_returns_complete_response() { #[test] fn test_opaque_filtered_fetch_async_returns_complete_response() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); @@ -870,6 +891,7 @@ fn test_opaque_filtered_fetch_async_returns_complete_response() { #[test] fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b""; let handler = move |request: HyperRequest, mut response: HyperResponse| { let redirects = match request.uri { @@ -906,6 +928,7 @@ fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() { #[test] fn test_fetch_with_devtools() { + register_resources_for_tests(); static MESSAGE: &'static [u8] = b"Yay!"; let handler = move |_: HyperRequest, response: HyperResponse| { response.send(MESSAGE).unwrap(); diff --git a/components/net/tests/hsts.rs b/components/net/tests/hsts.rs index bd035a1616e..3c857edc5e1 100644 --- a/components/net/tests/hsts.rs +++ b/components/net/tests/hsts.rs @@ -176,24 +176,24 @@ fn test_push_entry_to_hsts_list_should_add_an_entry() { #[test] fn test_parse_hsts_preload_should_return_none_when_json_invalid() { - let mock_preload_content = b"derp"; + let mock_preload_content = "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\"}"; + let mock_preload_content = "{\"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 mock_preload_content = "{\ + \"entries\": [\ + {\"host\": \"mozilla.org\",\ + \"include_subdomains\": false}\ + ]\ + }"; let hsts_list = HstsList::from_preload(mock_preload_content); let entries_map = hsts_list.unwrap().entries_map; diff --git a/components/net/tests/http_loader.rs b/components/net/tests/http_loader.rs index 67e8f9456e9..941dda40b20 100644 --- a/components/net/tests/http_loader.rs +++ b/components/net/tests/http_loader.rs @@ -6,6 +6,7 @@ use cookie_rs::Cookie as CookiePair; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg, NetworkEvent}; use devtools_traits::HttpRequest as DevtoolsHttpRequest; use devtools_traits::HttpResponse as DevtoolsHttpResponse; +use embedder_traits::resources::register_resources_for_tests; use fetch; use fetch_with_context; use flate2::Compression; @@ -312,6 +313,7 @@ fn test_request_and_response_message_from_devtool_without_pipeline_id() { #[test] fn test_redirected_request_to_devtools() { + register_resources_for_tests(); let post_handler = move |request: HyperRequest, response: HyperResponse| { assert_eq!(request.method, Method::Get); response.send(b"Yay!").unwrap(); diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index 773b7f387f8..4e2c4c97f58 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -6,6 +6,7 @@ extern crate cookie as cookie_rs; extern crate devtools_traits; +extern crate embedder_traits; extern crate flate2; extern crate hyper; extern crate hyper_openssl; @@ -15,13 +16,11 @@ 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; @@ -35,6 +34,7 @@ mod resource_thread; mod subresource_integrity; use devtools_traits::DevtoolsControlMsg; +use embedder_traits::resources::{self, Resource}; use hyper::server::{Handler, Listening, Server}; use net::connector::create_ssl_client; use net::fetch::cors_cache::CorsCache; @@ -44,7 +44,6 @@ 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}; @@ -56,8 +55,7 @@ struct FetchResponseCollector { } fn new_fetch_context(dc: Option>) -> FetchContext { - let ca_file = resources_dir_path().unwrap().join("certs"); - let ssl_client = create_ssl_client(&ca_file); + let ssl_client = create_ssl_client(&resources::read_string(Resource::SSLCertificates)); FetchContext { state: Arc::new(HttpState::new(ssl_client)), user_agent: DEFAULT_USER_AGENT.into(), diff --git a/components/net_traits/Cargo.toml b/components/net_traits/Cargo.toml index a1315698419..f208380982e 100644 --- a/components/net_traits/Cargo.toml +++ b/components/net_traits/Cargo.toml @@ -13,6 +13,7 @@ doctest = false [dependencies] cookie = "0.10" +embedder_traits = { path = "../embedder_traits" } hyper = "0.10" hyper_serde = "0.8" image = "0.18" diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index 2a9b791a02f..87dcf034caa 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -6,6 +6,7 @@ #![deny(unsafe_code)] extern crate cookie as cookie_rs; +extern crate embedder_traits; extern crate hyper; extern crate hyper_serde; extern crate image as piston_image; @@ -18,7 +19,6 @@ extern crate msg; extern crate num_traits; #[macro_use] extern crate serde; extern crate servo_arc; -extern crate servo_config; extern crate servo_url; extern crate url; extern crate uuid; diff --git a/components/net_traits/pub_domains.rs b/components/net_traits/pub_domains.rs index 20c4de2ae8c..afe70023856 100644 --- a/components/net_traits/pub_domains.rs +++ b/components/net_traits/pub_domains.rs @@ -14,11 +14,10 @@ //! we don't need to make the code more complex for it. The `mach` update command makes sure that //! those cases are not present. -use servo_config::resource_files::read_resource_file; +use embedder_traits::resources::{self, Resource}; use servo_url::{Host, ImmutableOrigin, ServoUrl}; use std::collections::HashSet; use std::iter::FromIterator; -use std::str::from_utf8; #[derive(Clone, Debug)] pub struct PubDomainRules { @@ -121,9 +120,7 @@ impl PubDomainRules { } fn load_pub_domains() -> PubDomainRules { - let content = read_resource_file("public_domains.txt").expect("Could not find public suffix list file"); - let content = from_utf8(&content).expect("Could not read public suffix list file"); - PubDomainRules::parse(content) + PubDomainRules::parse(&resources::read_string(Resource::DomainList)) } pub fn pub_suffix(domain: &str) -> &str { diff --git a/components/net_traits/tests/pub_domains.rs b/components/net_traits/tests/pub_domains.rs index fa298633f6c..c5fa0135db2 100644 --- a/components/net_traits/tests/pub_domains.rs +++ b/components/net_traits/tests/pub_domains.rs @@ -2,14 +2,17 @@ * 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/. */ +extern crate embedder_traits; extern crate net_traits; +use embedder_traits::resources::register_resources_for_tests; use net_traits::pub_domains::{is_pub_domain, is_reg_domain, pub_suffix, reg_suffix}; // These tests may need to be updated if the PSL changes. #[test] fn test_is_pub_domain_plain() { + register_resources_for_tests(); assert!(is_pub_domain("com")); assert!(is_pub_domain(".org")); assert!(is_pub_domain("za.org")); @@ -19,6 +22,7 @@ fn test_is_pub_domain_plain() { #[test] fn test_is_pub_domain_wildcard() { + register_resources_for_tests(); assert!(is_pub_domain("hello.bd")); assert!(is_pub_domain("world.jm")); assert!(is_pub_domain("toto.kobe.jp")); @@ -26,6 +30,7 @@ fn test_is_pub_domain_wildcard() { #[test] fn test_is_pub_domain_exception() { + register_resources_for_tests(); assert_eq!(is_pub_domain("www.ck"), false); assert_eq!(is_pub_domain("city.kawasaki.jp"), false); assert_eq!(is_pub_domain("city.nagoya.jp"), false); @@ -34,6 +39,7 @@ fn test_is_pub_domain_exception() { #[test] fn test_is_pub_domain_not() { + register_resources_for_tests(); assert_eq!(is_pub_domain(""), false); assert_eq!(is_pub_domain("."), false); assert_eq!(is_pub_domain("..."), false); @@ -46,6 +52,7 @@ fn test_is_pub_domain_not() { #[test] fn test_is_pub_domain() { + register_resources_for_tests(); assert!(!is_pub_domain("city.yokohama.jp")); assert!(!is_pub_domain("foo.bar.baz.yokohama.jp")); assert!(!is_pub_domain("foo.bar.city.yokohama.jp")); @@ -64,6 +71,7 @@ fn test_is_pub_domain() { #[test] fn test_is_reg_domain() { + register_resources_for_tests(); assert!(!is_reg_domain("com")); assert!(!is_reg_domain("foo.bar.baz.yokohama.jp")); assert!(!is_reg_domain("foo.bar.com")); @@ -81,6 +89,7 @@ fn test_is_reg_domain() { #[test] fn test_pub_suffix() { + register_resources_for_tests(); assert_eq!(pub_suffix("city.yokohama.jp"), "yokohama.jp"); assert_eq!(pub_suffix("com"), "com"); assert_eq!(pub_suffix("foo.bar.baz.yokohama.jp"), "baz.yokohama.jp"); @@ -98,6 +107,7 @@ fn test_pub_suffix() { #[test] fn test_reg_suffix() { + register_resources_for_tests(); assert_eq!(reg_suffix("city.yokohama.jp"), "city.yokohama.jp"); assert_eq!(reg_suffix("com"), "com"); assert_eq!(reg_suffix("foo.bar.baz.yokohama.jp"), "bar.baz.yokohama.jp"); @@ -115,6 +125,7 @@ fn test_reg_suffix() { #[test] fn test_weirdness() { + register_resources_for_tests(); // These are weird results, but AFAICT they are spec-compliant. assert_ne!(pub_suffix("city.yokohama.jp"), pub_suffix(pub_suffix("city.yokohama.jp"))); assert!(!is_pub_domain(pub_suffix("city.yokohama.jp"))); diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index f8edccd9092..d0adbdbf6b1 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -42,6 +42,7 @@ deny_public_fields = {path = "../deny_public_fields"} devtools_traits = {path = "../devtools_traits"} dom_struct = {path = "../dom_struct"} domobject_derive = {path = "../domobject_derive"} +embedder_traits = {path = "../embedder_traits"} encoding_rs = "0.7" euclid = "0.17" fnv = "1.0" diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index eb1e12c33d4..b5bbd2e98da 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -30,6 +30,7 @@ use dom::processinginstruction::ProcessingInstruction; use dom::text::Text; use dom::virtualmethods::vtable_for; use dom_struct::dom_struct; +use embedder_traits::resources::{self, Resource}; use html5ever::{Attribute, ExpandedName, LocalName, QualName}; use html5ever::buffer_queue::BufferQueue; use html5ever::tendril::{StrTendril, ByteTendril, IncompleteUtf8}; @@ -45,7 +46,6 @@ use profile_traits::time::{TimerMetadataReflowType, ProfilerCategory, profile}; use script_thread::ScriptThread; use script_traits::DocumentActivity; use servo_config::prefs::PREFS; -use servo_config::resource_files::read_resource_file; use servo_url::ServoUrl; use std::borrow::Cow; use std::cell::Cell; @@ -671,16 +671,14 @@ impl FetchResponseListener for ParserContext { // Handle text/html if let Some(reason) = ssl_error { self.is_synthesized_document = true; - let page_bytes = read_resource_file("badcert.html").unwrap(); - let page = String::from_utf8(page_bytes).unwrap(); + let page = resources::read_string(Resource::BadCertHTML); let page = page.replace("${reason}", &reason); parser.push_string_input_chunk(page); parser.parse_sync(); } if let Some(reason) = network_error { self.is_synthesized_document = true; - let page_bytes = read_resource_file("neterror.html").unwrap(); - let page = String::from_utf8(page_bytes).unwrap(); + let page = resources::read_string(Resource::NetErrorHTML); let page = page.replace("${reason}", &reason); parser.push_string_input_chunk(page); parser.parse_sync(); diff --git a/components/script/dom/userscripts.rs b/components/script/dom/userscripts.rs index fd5ae5f023e..e2db3e4cfe0 100644 --- a/components/script/dom/userscripts.rs +++ b/components/script/dom/userscripts.rs @@ -8,7 +8,6 @@ use dom::htmlheadelement::HTMLHeadElement; use dom::node::Node; use js::jsval::UndefinedValue; use servo_config::opts; -use servo_config::resource_files::resources_dir_path; use std::fs::{File, read_dir}; use std::io::Read; use std::path::PathBuf; @@ -22,17 +21,7 @@ pub fn load_script(head: &HTMLHeadElement) { let cx = win.get_cx(); rooted!(in(cx) let mut rval = UndefinedValue()); - let path = if &**path_str == "" { - if let Ok(mut p) = resources_dir_path() { - p.push("user-agent-js"); - p - } else { - return - } - } else { - PathBuf::from(path_str) - }; - + let path = PathBuf::from(path_str); let mut files = read_dir(&path).expect("Bad path passed to --userscripts") .filter_map(|e| e.ok()) .map(|e| e.path()).collect::>(); diff --git a/components/script/lib.rs b/components/script/lib.rs index dd2bd23d1ca..bee088aa5e0 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -35,6 +35,7 @@ extern crate devtools_traits; extern crate dom_struct; #[macro_use] extern crate domobject_derive; +extern crate embedder_traits; extern crate encoding_rs; extern crate euclid; extern crate fnv; diff --git a/components/servo/Cargo.toml b/components/servo/Cargo.toml index 3929593ef00..9d616ec2885 100644 --- a/components/servo/Cargo.toml +++ b/components/servo/Cargo.toml @@ -37,6 +37,7 @@ constellation = {path = "../constellation"} debugger = {path = "../debugger"} devtools = {path = "../devtools"} devtools_traits = {path = "../devtools_traits"} +embedder_traits = {path = "../embedder_traits"} env_logger = "0.5" euclid = "0.17" gfx = {path = "../gfx"} diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 3b7973ba203..e0e8f41b1b3 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -33,6 +33,7 @@ pub extern crate constellation; pub extern crate debugger; pub extern crate devtools; pub extern crate devtools_traits; +pub extern crate embedder_traits; pub extern crate euclid; pub extern crate gfx; pub extern crate ipc_channel; @@ -95,7 +96,6 @@ use profile_traits::time; use script_traits::{ConstellationMsg, SWManagerSenders, ScriptToConstellationChan}; use servo_config::opts; use servo_config::prefs::PREFS; -use servo_config::resource_files::resources_dir_path; use std::borrow::Cow; use std::cmp::max; use std::path::PathBuf; @@ -154,9 +154,6 @@ impl Servo where Window: WindowMethods + 'static { devtools::start_server(port) }); - let mut resource_path = resources_dir_path().unwrap(); - resource_path.push("shaders"); - let coordinates = window.get_coordinates(); let (mut webrender, webrender_api_sender) = { @@ -181,7 +178,7 @@ impl Servo where Window: WindowMethods + 'static { webrender::Renderer::new(window.gl(), render_notifier, webrender::RendererOptions { device_pixel_ratio: coordinates.hidpi_factor.get(), - resource_override_path: Some(resource_path), + resource_override_path: opts.shaders_dir.clone(), enable_aa: opts.enable_text_antialiasing, debug_flags: debug_flags, recorder: recorder, diff --git a/ports/servo/Cargo.toml b/ports/servo/Cargo.toml index 7bda51c5b38..3a3cbe5481d 100644 --- a/ports/servo/Cargo.toml +++ b/ports/servo/Cargo.toml @@ -39,6 +39,7 @@ bitflags = "1.0" euclid = "0.17" gleam = "0.4.34" glutin = "0.13" +lazy_static = "1" libservo = {path = "../../components/servo"} log = "0.4" tinyfiledialogs = "3.0" diff --git a/ports/servo/main.rs b/ports/servo/main.rs index fdf1cdd6439..31d249183af 100644 --- a/ports/servo/main.rs +++ b/ports/servo/main.rs @@ -25,6 +25,8 @@ extern crate euclid; #[cfg(target_os = "windows")] extern crate gdi32; extern crate gleam; extern crate glutin; +#[cfg(not(target_os = "android"))] +#[macro_use] extern crate lazy_static; // The window backed by glutin #[macro_use] extern crate log; #[cfg(any(target_os = "linux", target_os = "macos"))] extern crate osmesa_sys; @@ -38,6 +40,7 @@ extern crate winit; #[cfg(target_os = "windows")] extern crate user32; mod glutin_app; +mod resources; use backtrace::Backtrace; use servo::Servo; @@ -99,14 +102,16 @@ fn install_crash_handler() {} fn main() { install_crash_handler(); + resources::init(); + // Parse the command line options and store them globally let opts_result = opts::from_cmdline_args(&*args()); let content_process_token = if let ArgumentParsingResult::ContentProcess(token) = opts_result { Some(token) } else { - if opts::get().is_running_problem_test && ::std::env::var("RUST_LOG").is_err() { - ::std::env::set_var("RUST_LOG", "compositing::constellation"); + if opts::get().is_running_problem_test && env::var("RUST_LOG").is_err() { + env::set_var("RUST_LOG", "compositing::constellation"); } None @@ -217,7 +222,7 @@ fn main() { #[cfg(target_os = "android")] fn setup_logging() { // Piping logs from stdout/stderr to logcat happens in android_injected_glue. - ::std::env::set_var("RUST_LOG", "error"); + env::set_var("RUST_LOG", "error"); unsafe { android_injected_glue::ffi::app_dummy() }; } @@ -263,7 +268,6 @@ fn args() -> Vec { #[cfg(not(target_os = "android"))] fn args() -> Vec { - use std::env; env::args().collect() } diff --git a/ports/servo/resources.rs b/ports/servo/resources.rs new file mode 100644 index 00000000000..2738a8a0eb4 --- /dev/null +++ b/ports/servo/resources.rs @@ -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/. */ + +use servo::embedder_traits::resources::{self, Resource}; + +struct ResourceReader; + +fn filename(file: Resource) -> &'static str { + match file { + Resource::Preferences => "prefs.json", + Resource::BluetoothBlocklist => "gatt_blocklist.txt", + Resource::DomainList => "public_domains.txt", + Resource::HstsPreloadList => "hsts_preload.json", + Resource::SSLCertificates => "certs", + Resource::BadCertHTML => "badcert.html", + Resource::NetErrorHTML => "neterror.html", + Resource::UserAgentCSS => "user-agent.css", + Resource::ServoCSS => "servo.css", + Resource::PresentationalHintsCSS => "presentational-hints.css", + Resource::QuirksModeCSS => "quirks-mode.css", + Resource::RippyPNG => "rippy.png", + } +} + +pub fn init() { + resources::set(Box::new(ResourceReader)); +} + +#[cfg(not(target_os = "android"))] +mod not_android { + use servo::embedder_traits::resources::{self, Resource}; + use std::env; + use std::fs; + use std::io; + use std::path::PathBuf; + use std::sync::Mutex; + + lazy_static! { + static ref CMD_RESOURCE_DIR: Mutex> = Mutex::new(None); + } + + impl resources::ResourceReaderMethods for super::ResourceReader { + fn read(&self, file: Resource) -> Vec { + let file = super::filename(file); + let mut path = resources_dir_path().expect("Can't find resources directory"); + path.push(file); + fs::read(path).expect("Can't read file") + } + fn sandbox_access_files_dirs(&self) -> Vec { + vec![resources_dir_path().expect("Can't find resources directory")] + } + fn sandbox_access_files(&self) -> Vec { + vec![] + } + } + + fn resources_dir_path() -> io::Result { + // This needs to be called before the process is sandboxed + // as we only give permission to read inside the resources directory, + // not the permissions the "search" for the resources directory. + let mut dir = CMD_RESOURCE_DIR.lock().unwrap(); + if let Some(ref path) = *dir { + return Ok(PathBuf::from(path)); + } + + // FIXME: Find a way to not rely on the executable being + // under `[/$target_triple]/target/debug` + // or `[/$target_triple]/target/release`. + let mut path = env::current_exe()?; + // Follow symlink + path = path.canonicalize()?; + + while path.pop() { + path.push("resources"); + if path.is_dir() { + break; + } + path.pop(); + // Check for Resources on mac when using a case sensitive filesystem. + path.push("Resources"); + if path.is_dir() { + break; + } + path.pop(); + } + *dir = Some(path.to_str().unwrap().to_owned()); + Ok(path) + } +} + +#[cfg(target_os = "android")] +mod android { + use android_injected_glue::load_asset; + use servo::embedder_traits::resources::{self, Resource}; + use std::path::PathBuf; + + impl resources::ResourceReaderMethods for super::ResourceReader { + fn read(&self, file: Resource) -> Vec { + let file = super::filename(file); + load_asset(file).unwrap_or_else(|_| { + panic!("Can't load asset"); + }) + } + fn sandbox_access_files_dirs(&self) -> Vec { + vec![] + } + fn sandbox_access_files(&self) -> Vec { + vec![] + } + } +} diff --git a/resources/badcert.html b/resources/badcert.html index fca069fac2a..5a96eee377e 100644 --- a/resources/badcert.html +++ b/resources/badcert.html @@ -3,7 +3,6 @@ Certificate error -

${reason}

diff --git a/resources/failure.html b/resources/failure.html deleted file mode 100644 index bcc90c90248..00000000000 --- a/resources/failure.html +++ /dev/null @@ -1,8 +0,0 @@ - - - about:failure - - - - - diff --git a/resources/itried.jpg b/resources/itried.jpg deleted file mode 100644 index 420ed0cf76e..00000000000 Binary files a/resources/itried.jpg and /dev/null differ diff --git a/support/android/apk/app/src/main/java/com/mozilla/servo/MainActivity.java b/support/android/apk/app/src/main/java/com/mozilla/servo/MainActivity.java index 04c57511b3e..e2ca624bc08 100644 --- a/support/android/apk/app/src/main/java/com/mozilla/servo/MainActivity.java +++ b/support/android/apk/app/src/main/java/com/mozilla/servo/MainActivity.java @@ -52,12 +52,6 @@ public class MainActivity extends android.app.NativeActivity { @Override public void onCreate(Bundle savedInstanceState) { - try { - extractAssets(); - } catch (IOException e) { - throw new RuntimeException(e); - } - final Intent intent = getIntent(); if (intent != null && intent.getAction().equals(Intent.ACTION_VIEW)) { final String url = intent.getDataString(); @@ -223,81 +217,10 @@ public class MainActivity extends android.app.NativeActivity { } } - private boolean needsToExtractAssets(String path) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - int version = BuildConfig.VERSION_CODE; - - if (!new File(path).exists()) { - // Assets folder doesn't exist, resources need to be copied - prefs.edit().putInt(PREF_KEY_RESOURCES_SYNC, version).apply(); - return true; - } - - if (version != prefs.getInt(PREF_KEY_RESOURCES_SYNC, -1)) { - // Also force a reextract when the version changes and the resources may be updated - // This can be improved by generating a hash or version number of the resources - // instead of using version code of the app - prefs.edit().putInt(PREF_KEY_RESOURCES_SYNC, version).apply(); - return true; - } - return false; - } - private File getAppDataDir() { File file = getExternalFilesDir(null); return file != null ? file : getFilesDir(); } - /** - * extracts assets/ in the APK to /sdcard/servo. - */ - private void extractAssets() throws IOException { - String path = getAppDataDir().getAbsolutePath(); - if (!needsToExtractAssets(path)) { - return; - } - - ZipFile zipFile = null; - File targetDir = new File(path); - try { - zipFile = new ZipFile(this.getApplicationInfo().sourceDir); - for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) { - ZipEntry entry = e.nextElement(); - if (entry.isDirectory() || !entry.getName().startsWith("assets/")) { - continue; - } - File targetFile = new File(targetDir, entry.getName().substring("assets/".length())); - targetFile.getParentFile().mkdirs(); - byte[] tempBuffer = new byte[(int)entry.getSize()]; - BufferedInputStream is = null; - FileOutputStream os = null; - try { - is = new BufferedInputStream(zipFile.getInputStream(entry)); - os = new FileOutputStream(targetFile); - is.read(tempBuffer); - os.write(tempBuffer); - } finally { - try { - if (is != null) { - is.close(); - } - if (os != null) { - os.close(); - } - } catch (Exception ex) { - Log.e(LOGTAG, Log.getStackTraceString(ex)); - } - } - } - } finally { - try { - if (zipFile != null) { - zipFile.close(); - } - } catch (Exception e) { - Log.e(LOGTAG, Log.getStackTraceString(e)); - } - } - } private void set_url(String url) { try { diff --git a/tests/unit/style/Cargo.toml b/tests/unit/style/Cargo.toml index 23778c73f93..73bdb7fdbff 100644 --- a/tests/unit/style/Cargo.toml +++ b/tests/unit/style/Cargo.toml @@ -13,6 +13,7 @@ doctest = false byteorder = "1.0" app_units = "0.6" cssparser = "0.23.0" +embedder_traits = {path = "../../../components/embedder_traits"} euclid = "0.17" html5ever = "0.22" parking_lot = "0.5" diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 9bcc92965e8..dea0fe9da5d 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -7,6 +7,7 @@ extern crate app_units; extern crate cssparser; +extern crate embedder_traits; extern crate euclid; #[macro_use] extern crate html5ever; extern crate parking_lot; diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index be4e2d9cbc1..c87a065be97 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cssparser::{self, SourceLocation}; +use embedder_traits::resources::register_resources_for_tests; use html5ever::{Namespace as NsAtom}; use media_queries::CSSErrorReporterTest; use parking_lot::RwLock; @@ -321,6 +322,7 @@ impl ParseErrorReporter for TestingErrorReporter { #[test] fn test_report_error_stylesheet() { + register_resources_for_tests(); PREFS.set("layout.viewport.enabled", PrefValue::Boolean(true)); let css = r" div {