/* 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 https://mozilla.org/MPL/2.0/. */ use std::path::PathBuf; use std::sync::RwLock; static RES: RwLock>> = RwLock::new(None); #[cfg(feature = "baked-default-resources")] static INIT_TEST_RESOURCES: std::sync::Once = std::sync::Once::new(); #[cfg(all(feature = "baked-default-resources", servo_production))] const _: () = assert!( false, "baked-default-resources should not be used in production" ); /// The Embedder should initialize the ResourceReader early. pub fn set(reader: Box) { *RES.write().unwrap() = Some(reader); } #[cfg(not(feature = "baked-default-resources"))] pub fn read_bytes(res: Resource) -> Vec { if let Some(reader) = RES.read().unwrap().as_ref() { reader.read(res) } else { log::error!("Resource reader not set."); vec![] } } #[cfg(feature = "baked-default-resources")] pub fn read_bytes(res: Resource) -> Vec { INIT_TEST_RESOURCES.call_once(|| { let mut reader = RES.write().unwrap(); if reader.is_none() { *reader = Some(resources_for_tests()) } }); 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() .map(|reader| reader.sandbox_access_files()) .unwrap_or_default() } pub fn sandbox_access_files_dirs() -> Vec { RES.read() .unwrap() .as_ref() .map(|reader| reader.sandbox_access_files_dirs()) .unwrap_or_default() } pub enum Resource { /// A list of GATT services that are blocked from being used by web bluetooth. /// The format of the file is a list of UUIDs, one per line, with an optional second word to specify the /// type of blocklist. /// It can be empty but then all GATT services will be allowed. BluetoothBlocklist, /// A list of domain names that are considered public suffixes, typically obtained from . /// The Public Suffix List is a cross-vendor initiative to provide an accurate list of domain name suffixes /// that are under the control of a registry. This is used to prevent cookies from being set for top-level /// domains that are not controlled by the same entity as the website. /// It can be empty but all domain names will be considered not public suffixes. DomainList, /// A preloaded list of HTTP Strict Transport Security. It can be an empty list and /// `HstsList::default()` will be called. HstsPreloadList, /// A HTML page to display when `net_traits::NetworkError::SslValidation` network error is /// reported. /// The page contains placeholder `${reason}` for the error code and `${bytes}` for the certificate bytes, /// and also `${secret}` for the privileged secret. /// It can be empty but then nothing will be displayed when a certificate error occurs. BadCertHTML, /// A HTML page to display when any network error occurs that is not related to SSL validation. /// The message can contain a placeholder `${reason}` for the error code. /// It can be empty but then nothing will be displayed when an internal error occurs. NetErrorHTML, /// A placeholder image to display if we couldn't get the requested image. /// /// ## Panic /// /// If the resource is not provided, servo will fallback to a baked in default (See resources/rippy.png). /// However, if the image is provided but invalid, Servo will crash. RippyPNG, /// A placeholder HTML page to display when the code responsible for rendering a page panics and the original /// page can no longer be displayed. /// The message can contain a placeholder `${details}` for the error details. /// It can be empty but then nothing will be displayed when a crash occurs. CrashHTML, /// A HTML page to display when a directory listing is requested. /// The page contains a js function `setData` that will then be used to build the list of directory. /// It can be empty but then nothing will be displayed when a directory listing is requested. DirectoryListingHTML, /// A HTML page that is used for the about:memory url. AboutMemoryHTML, } impl Resource { pub fn filename(&self) -> &'static str { match self { Resource::BluetoothBlocklist => "gatt_blocklist.txt", Resource::DomainList => "public_domains.txt", Resource::HstsPreloadList => "hsts_preload.fstmap", Resource::BadCertHTML => "badcert.html", Resource::NetErrorHTML => "neterror.html", Resource::RippyPNG => "rippy.png", Resource::CrashHTML => "crash.html", Resource::DirectoryListingHTML => "directory-listing.html", Resource::AboutMemoryHTML => "about-memory.html", } } } pub trait ResourceReaderMethods { fn read(&self, res: Resource) -> Vec; fn sandbox_access_files(&self) -> Vec; fn sandbox_access_files_dirs(&self) -> Vec; } /// Provides baked in resources for tests. /// /// Embedder builds (e.g. servoshell) should use [`set`] and ship the resources themselves. #[cfg(feature = "baked-default-resources")] fn resources_for_tests() -> Box { 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 { match file { Resource::BluetoothBlocklist => { &include_bytes!("../../../resources/gatt_blocklist.txt")[..] }, Resource::DomainList => { &include_bytes!("../../../resources/public_domains.txt")[..] }, Resource::HstsPreloadList => { &include_bytes!("../../../resources/hsts_preload.fstmap")[..] }, Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..], Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..], Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..], Resource::CrashHTML => &include_bytes!("../../../resources/crash.html")[..], Resource::DirectoryListingHTML => { &include_bytes!("../../../resources/directory-listing.html")[..] }, Resource::AboutMemoryHTML => { &include_bytes!("../../../resources/about-memory.html")[..] }, } .to_owned() } } Box::new(ResourceReader) }