diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 1816cf05373..e91d8e04d8a 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -144,10 +144,11 @@ use keyboard_types::webdriver::Event as WebDriverInputEvent; use keyboard_types::{Key, KeyState, KeyboardEvent, Modifiers}; use log::{debug, error, info, trace, warn}; use media::WindowGLContext; +use net::protocols::ProtocolRegistry; use net_traits::pub_domains::reg_host; use net_traits::request::Referrer; use net_traits::storage_thread::{StorageThreadMsg, StorageType}; -use net_traits::{self, IpcSend, ReferrerPolicy, ResourceThreads}; +use net_traits::{self, IpcSend, Protocol, Protocols, ReferrerPolicy, ResourceThreads}; use profile_traits::{mem, time}; use script_layout_interface::{LayoutFactory, ScriptThreadFactory}; use script_traits::{ @@ -474,6 +475,9 @@ pub struct Constellation { /// The process manager. process_manager: ProcessManager, + + /// Registered custom protocols + pub protocols: Arc, } /// State needed to construct a constellation. @@ -526,6 +530,9 @@ pub struct InitialConstellationState { /// User content manager pub user_content_manager: UserContentManager, + + /// Registered custom protocols + pub protocols: Arc, } /// Data needed for webdriver @@ -745,6 +752,7 @@ where rippy_data, user_content_manager: state.user_content_manager, process_manager: ProcessManager::new(state.mem_profiler_chan), + protocols: state.protocols, }; constellation.run(); @@ -984,6 +992,19 @@ where player_context: WindowGLContext::get(), rippy_data: self.rippy_data.clone(), user_content_manager: self.user_content_manager.clone(), + protocols: Protocols::new( + self.protocols + .iter() + .map(|(protocol, handler)| { + ( + protocol.to_string(), + Protocol { + is_secure: handler.is_secure(), + }, + ) + }) + .collect(), + ), }); let pipeline = match result { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 556ef9bd60f..5f697a53ba5 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -33,8 +33,8 @@ use ipc_channel::router::ROUTER; use log::{debug, error, warn}; use media::WindowGLContext; use net::image_cache::ImageCacheImpl; -use net_traits::ResourceThreads; use net_traits::image_cache::ImageCache; +use net_traits::{Protocols, ResourceThreads}; use profile::system_reporter; use profile_traits::mem::{ProfilerMsg, Reporter}; use profile_traits::{mem as profile_mem, time}; @@ -199,6 +199,9 @@ pub struct InitialPipelineState { /// User content manager pub user_content_manager: UserContentManager, + + /// Registered custom protocols + pub protocols: Protocols, } pub struct NewPipeline { @@ -296,6 +299,7 @@ impl Pipeline { rippy_data: state.rippy_data, user_content_manager: state.user_content_manager, lifeline_sender: None, + protocols: state.protocols, }; // Spawn the child process. @@ -506,6 +510,7 @@ pub struct UnprivilegedPipelineContent { player_context: WindowGLContext, rippy_data: Vec, user_content_manager: UserContentManager, + protocols: Protocols, lifeline_sender: Option>, } @@ -552,6 +557,7 @@ impl UnprivilegedPipelineContent { player_context: self.player_context.clone(), inherited_secure_context: self.load_data.inherited_secure_context, user_content_manager: self.user_content_manager, + protocols: self.protocols.clone(), }, layout_factory, Arc::new(self.system_font_service.to_proxy()), diff --git a/components/net/protocols/mod.rs b/components/net/protocols/mod.rs index 6dc58ceab64..5ce62059401 100644 --- a/components/net/protocols/mod.rs +++ b/components/net/protocols/mod.rs @@ -110,6 +110,10 @@ impl ProtocolRegistry { self.handlers.get(scheme).map(|e| e.as_ref()) } + pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, Box> { + self.handlers.iter() + } + pub fn merge(&mut self, mut other: ProtocolRegistry) { for (scheme, handler) in other.handlers.drain() { if FORBIDDEN_SCHEMES.contains(&scheme.as_str()) { diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 70c384db822..37fcfe810d4 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -68,6 +68,7 @@ impl DissimilarOriginWindow { global_to_clone_from.wgpu_id_hub(), Some(global_to_clone_from.is_secure_context()), false, + global_to_clone_from.registered_protocols().clone(), ), window_proxy: Dom::from_ref(window_proxy), location: Default::default(), diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index ec2ed70dd15..59078d9f048 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -56,7 +56,7 @@ use net_traits::policy_container::PolicyContainer; use net_traits::request::{InsecureRequestsPolicy, Referrer, RequestBuilder}; use net_traits::response::HttpsState; use net_traits::{ - CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend, ReferrerPolicy, + CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend, Protocols, ReferrerPolicy, ResourceThreads, fetch_async, }; use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time}; @@ -374,6 +374,11 @@ pub(crate) struct GlobalScope { #[ignore_malloc_size_of = "Rc is hard"] notification_permission_request_callback_map: DomRefCell>>, + + /// Registered custom protocols + #[no_trace] + #[ignore_malloc_size_of = "Arc"] + protocols: Arc, } /// A wrapper for glue-code between the ipc router and the event-loop. @@ -735,6 +740,7 @@ impl GlobalScope { #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, unminify_js: bool, + protocols: Arc, ) -> Self { Self { task_manager: Default::default(), @@ -779,6 +785,7 @@ impl GlobalScope { byte_length_queuing_strategy_size_function: OnceCell::new(), count_queuing_strategy_size_function: OnceCell::new(), notification_permission_request_callback_map: Default::default(), + protocols, } } @@ -2472,6 +2479,11 @@ impl GlobalScope { &self.creation_url } + /// Get registered custom protocols + pub(crate) fn registered_protocols(&self) -> &Arc { + &self.protocols + } + pub(crate) fn image_cache(&self) -> Arc { if let Some(window) = self.downcast::() { return window.image_cache(); @@ -3206,7 +3218,7 @@ impl GlobalScope { if creation_url.scheme() == "blob" && Some(true) == self.inherited_secure_context { return true; } - return creation_url.is_potentially_trustworthy(); + return self.protocols.is_url_potentially_trustworthy(creation_url); } false } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 24e694b4f06..551765ccd64 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -53,11 +53,11 @@ use js::rust::{ }; use malloc_size_of::MallocSizeOf; use media::WindowGLContext; -use net_traits::ResourceThreads; use net_traits::image_cache::{ ImageCache, ImageResponder, ImageResponse, PendingImageId, PendingImageResponse, }; use net_traits::storage_thread::StorageType; +use net_traits::{Protocols, ResourceThreads}; use num_traits::ToPrimitive; use profile_traits::ipc as ProfiledIpc; use profile_traits::mem::ProfilerChan as MemProfilerChan; @@ -3033,6 +3033,7 @@ impl Window { player_context: WindowGLContext, #[cfg(feature = "webgpu")] gpu_id_hub: Arc, inherited_secure_context: Option, + protocols: Arc, ) -> DomRoot { let error_reporter = CSSErrorReporter { pipelineid: pipeline_id, @@ -3060,6 +3061,7 @@ impl Window { gpu_id_hub, inherited_secure_context, unminify_js, + protocols, ), script_chan, layout: RefCell::new(layout), diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index fa94dcc1d04..39ae31ee593 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -86,6 +86,7 @@ pub(crate) fn prepare_workerscope_init( origin: global.origin().immutable().clone(), creation_url: global.creation_url().clone(), inherited_secure_context: Some(global.is_secure_context()), + protocols: global.registered_protocols().clone(), }; init @@ -158,6 +159,7 @@ impl WorkerGlobalScope { Some(..) => Some(devtools_receiver), None => None, }; + let protocols = init.protocols; Self { globalscope: GlobalScope::new_inherited( @@ -174,6 +176,7 @@ impl WorkerGlobalScope { gpu_id_hub, init.inherited_secure_context, false, + protocols, ), worker_id: init.worker_id, worker_name, diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index c478830ac0c..e7f5d0aafb2 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -12,8 +12,8 @@ use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use js::jsval::UndefinedValue; use js::rust::Runtime; -use net_traits::ResourceThreads; use net_traits::image_cache::ImageCache; +use net_traits::{Protocols, ResourceThreads}; use profile_traits::{mem, time}; use script_bindings::realms::InRealm; use script_traits::Painter; @@ -110,6 +110,7 @@ impl WorkletGlobalScope { init.gpu_id_hub.clone(), init.inherited_secure_context, false, + init.protocols.clone(), ), base_url, to_script_thread_sender: init.to_script_thread_sender.clone(), @@ -200,6 +201,8 @@ pub(crate) struct WorkletGlobalScopeInit { pub(crate) gpu_id_hub: Arc, /// Is considered secure pub(crate) inherited_secure_context: Option, + /// Registered custom protocols + pub(crate) protocols: Arc, } /// diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index e0309298f3d..a7393d77eae 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -76,7 +76,7 @@ use net_traits::request::{Referrer, RequestId}; use net_traits::response::ResponseInit; use net_traits::storage_thread::StorageType; use net_traits::{ - FetchMetadata, FetchResponseListener, FetchResponseMsg, Metadata, NetworkError, + FetchMetadata, FetchResponseListener, FetchResponseMsg, Metadata, NetworkError, Protocols, ResourceFetchTiming, ResourceThreads, ResourceTimingType, }; use percent_encoding::percent_decode; @@ -336,6 +336,10 @@ pub struct ScriptThread { /// The screen coordinates where the primary mouse button was pressed. #[no_trace] relative_mouse_down_point: Cell>, + + /// Registered custom protocols + #[no_trace] + protocols: Arc, } struct BHMExitSignal { @@ -752,6 +756,7 @@ impl ScriptThread { #[cfg(feature = "webgpu")] gpu_id_hub: script_thread.gpu_id_hub.clone(), inherited_secure_context: script_thread.inherited_secure_context, + protocols: script_thread.protocols.clone(), }; Rc::new(WorkletThreadPool::spawn(init)) }) @@ -957,6 +962,7 @@ impl ScriptThread { inherited_secure_context: state.inherited_secure_context, layout_factory, relative_mouse_down_point: Cell::new(Point2D::zero()), + protocols: Arc::new(state.protocols), } } @@ -3228,6 +3234,7 @@ impl ScriptThread { #[cfg(feature = "webgpu")] self.gpu_id_hub.clone(), incomplete.load_data.inherited_secure_context, + self.protocols.clone(), ); let _realm = enter_realm(&*window); diff --git a/components/servo/lib.rs b/components/servo/lib.rs index f2732eaddfe..2c4142decd9 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -1059,6 +1059,8 @@ fn create_constellation( let bluetooth_thread: IpcSender = BluetoothThreadFactory::new(embedder_proxy.clone()); + let protocols = Arc::new(protocols); + let (public_resource_threads, private_resource_threads) = new_resource_threads( devtools_sender.clone(), time_profiler_chan.clone(), @@ -1067,7 +1069,7 @@ fn create_constellation( config_dir, opts.certificate_path.clone(), opts.ignore_certificate_errors, - Arc::new(protocols), + protocols.clone(), ); let system_font_service = Arc::new( @@ -1106,6 +1108,7 @@ fn create_constellation( #[cfg(feature = "webgpu")] wgpu_image_map, user_content_manager, + protocols, }; let layout_factory = Arc::new(LayoutFactoryImpl()); diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs index fa391f93859..9a44928f37d 100644 --- a/components/shared/constellation/from_script_message.rs +++ b/components/shared/constellation/from_script_message.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; use std::fmt; +use std::sync::Arc; use base::Epoch; use base::id::{ @@ -26,7 +27,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use net_traits::policy_container::PolicyContainer; use net_traits::request::{Destination, InsecureRequestsPolicy, Referrer, RequestBody}; use net_traits::storage_thread::StorageType; -use net_traits::{CoreResourceMsg, ReferrerPolicy, ResourceThreads}; +use net_traits::{CoreResourceMsg, Protocols, ReferrerPolicy, ResourceThreads}; use profile_traits::mem::MemoryReportResult; use profile_traits::{mem, time as profile_time}; use serde::{Deserialize, Serialize}; @@ -444,6 +445,8 @@ pub struct WorkerGlobalScopeInit { pub creation_url: Option, /// True if secure context pub inherited_secure_context: Option, + /// Registered custom protocols + pub protocols: Arc, } /// Common entities representing a network load origin diff --git a/components/shared/net/lib.rs b/components/shared/net/lib.rs index 0126bdbcd80..73f10f6ca78 100644 --- a/components/shared/net/lib.rs +++ b/components/shared/net/lib.rs @@ -1011,3 +1011,29 @@ pub fn set_default_accept_language(headers: &mut HeaderMap) { pub static PRIVILEGED_SECRET: LazyLock = LazyLock::new(|| servo_rand::ServoRng::default().next_u32()); + +/// Registered custom protocols +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Protocols(HashMap); + +impl Protocols { + /// Construct from a HashMap of string and protocols + pub fn new(protocols: HashMap) -> Self { + Self(protocols) + } + + /// Test if the URL is potentially trustworthy or the custom protocol is registered as secure + pub fn is_url_potentially_trustworthy(&self, url: &ServoUrl) -> bool { + url.is_potentially_trustworthy() || + self.0 + .get(url.scheme()) + .is_some_and(|protocol| protocol.is_secure) + } +} + +/// A custom protocol +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Protocol { + /// If this custom protocol is considered secure context + pub is_secure: bool, +} diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index 29acc51765c..20167f62ea8 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -35,9 +35,9 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender}; use keyboard_types::Modifiers; use malloc_size_of_derive::MallocSizeOf; use media::WindowGLContext; -use net_traits::ResourceThreads; use net_traits::image_cache::ImageCache; use net_traits::storage_thread::StorageType; +use net_traits::{Protocols, ResourceThreads}; use pixels::PixelFormat; use profile_traits::mem; use serde::{Deserialize, Serialize}; @@ -335,6 +335,8 @@ pub struct InitialScriptState { pub player_context: WindowGLContext, /// User content manager pub user_content_manager: UserContentManager, + /// Registered custom protocols + pub protocols: Protocols, } /// Errors from executing a paint worklet