mirror of
https://github.com/servo/servo.git
synced 2025-08-01 19:50:30 +01:00
Auto merge of #26087 - gterzian:allow_service_workers_in_multiprocess, r=jdm
Fix ServiceWorker in multiprocess <!-- Please describe your changes on the following line: --> FIX #15217 FIX #26100 --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
ae49473c25
13 changed files with 415 additions and 267 deletions
|
@ -96,6 +96,7 @@ use crate::browsingcontext::{
|
||||||
use crate::event_loop::EventLoop;
|
use crate::event_loop::EventLoop;
|
||||||
use crate::network_listener::NetworkListener;
|
use crate::network_listener::NetworkListener;
|
||||||
use crate::pipeline::{InitialPipelineState, Pipeline};
|
use crate::pipeline::{InitialPipelineState, Pipeline};
|
||||||
|
use crate::serviceworker::ServiceWorkerUnprivilegedContent;
|
||||||
use crate::session_history::{
|
use crate::session_history::{
|
||||||
JointSessionHistory, NeedsToReload, SessionHistoryChange, SessionHistoryDiff,
|
JointSessionHistory, NeedsToReload, SessionHistoryChange, SessionHistoryDiff,
|
||||||
};
|
};
|
||||||
|
@ -151,10 +152,15 @@ use script_traits::{HistoryEntryReplacement, IFrameSizeMsg, WindowSizeData, Wind
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg,
|
IFrameLoadInfo, IFrameLoadInfoWithData, IFrameSandboxState, TimerSchedulerMsg,
|
||||||
};
|
};
|
||||||
use script_traits::{LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory};
|
use script_traits::{
|
||||||
|
LayoutMsg as FromLayoutMsg, ScriptMsg as FromScriptMsg, ScriptThreadFactory,
|
||||||
|
ServiceWorkerManagerFactory,
|
||||||
|
};
|
||||||
use script_traits::{MediaSessionActionType, MouseEventType};
|
use script_traits::{MediaSessionActionType, MouseEventType};
|
||||||
use script_traits::{MessagePortMsg, PortMessageTask, StructuredSerializedData};
|
use script_traits::{MessagePortMsg, PortMessageTask, StructuredSerializedData};
|
||||||
use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg};
|
use script_traits::{
|
||||||
|
SWManagerMsg, SWManagerSenders, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_config::{opts, pref};
|
use servo_config::{opts, pref};
|
||||||
use servo_rand::{random, Rng, ServoRng, SliceRandom};
|
use servo_rand::{random, Rng, ServoRng, SliceRandom};
|
||||||
|
@ -259,7 +265,7 @@ struct BrowsingContextGroup {
|
||||||
/// `LayoutThread` in the `layout` crate, and `ScriptThread` in
|
/// `LayoutThread` in the `layout` crate, and `ScriptThread` in
|
||||||
/// the `script` crate). Script and layout communicate using a `Message`
|
/// the `script` crate). Script and layout communicate using a `Message`
|
||||||
/// type.
|
/// type.
|
||||||
pub struct Constellation<Message, LTF, STF> {
|
pub struct Constellation<Message, LTF, STF, SWF> {
|
||||||
/// An ipc-sender/threaded-receiver pair
|
/// An ipc-sender/threaded-receiver pair
|
||||||
/// to facilitate installing pipeline namespaces in threads
|
/// to facilitate installing pipeline namespaces in threads
|
||||||
/// via a per-process installer.
|
/// via a per-process installer.
|
||||||
|
@ -348,9 +354,8 @@ pub struct Constellation<Message, LTF, STF> {
|
||||||
/// bluetooth thread.
|
/// bluetooth thread.
|
||||||
bluetooth_thread: IpcSender<BluetoothRequest>,
|
bluetooth_thread: IpcSender<BluetoothRequest>,
|
||||||
|
|
||||||
/// An IPC channel for the constellation to send messages to the
|
/// A map of origin to sender to a Service worker manager.
|
||||||
/// Service Worker Manager thread.
|
sw_managers: HashMap<ImmutableOrigin, IpcSender<ServiceWorkerMsg>>,
|
||||||
swmanager_chan: Option<IpcSender<ServiceWorkerMsg>>,
|
|
||||||
|
|
||||||
/// An IPC channel for Service Worker Manager threads to send
|
/// An IPC channel for Service Worker Manager threads to send
|
||||||
/// messages to the constellation. This is the SW Manager thread's
|
/// messages to the constellation. This is the SW Manager thread's
|
||||||
|
@ -453,7 +458,7 @@ pub struct Constellation<Message, LTF, STF> {
|
||||||
random_pipeline_closure: Option<(ServoRng, f32)>,
|
random_pipeline_closure: Option<(ServoRng, f32)>,
|
||||||
|
|
||||||
/// Phantom data that keeps the Rust type system happy.
|
/// Phantom data that keeps the Rust type system happy.
|
||||||
phantom: PhantomData<(Message, LTF, STF)>,
|
phantom: PhantomData<(Message, LTF, STF, SWF)>,
|
||||||
|
|
||||||
/// Entry point to create and get channels to a WebGLThread.
|
/// Entry point to create and get channels to a WebGLThread.
|
||||||
webgl_threads: Option<WebGLThreads>,
|
webgl_threads: Option<WebGLThreads>,
|
||||||
|
@ -813,10 +818,11 @@ fn handle_webrender_message(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
impl<Message, LTF, STF, SWF> Constellation<Message, LTF, STF, SWF>
|
||||||
where
|
where
|
||||||
LTF: LayoutThreadFactory<Message = Message>,
|
LTF: LayoutThreadFactory<Message = Message>,
|
||||||
STF: ScriptThreadFactory<Message = Message>,
|
STF: ScriptThreadFactory<Message = Message>,
|
||||||
|
SWF: ServiceWorkerManagerFactory,
|
||||||
{
|
{
|
||||||
/// Create a new constellation thread.
|
/// Create a new constellation thread.
|
||||||
pub fn start(
|
pub fn start(
|
||||||
|
@ -829,12 +835,11 @@ where
|
||||||
enable_canvas_antialiasing: bool,
|
enable_canvas_antialiasing: bool,
|
||||||
canvas_chan: Sender<ConstellationCanvasMsg>,
|
canvas_chan: Sender<ConstellationCanvasMsg>,
|
||||||
ipc_canvas_chan: IpcSender<CanvasMsg>,
|
ipc_canvas_chan: IpcSender<CanvasMsg>,
|
||||||
) -> (Sender<FromCompositorMsg>, IpcSender<SWManagerMsg>) {
|
) -> Sender<FromCompositorMsg> {
|
||||||
let (compositor_sender, compositor_receiver) = unbounded();
|
let (compositor_sender, compositor_receiver) = unbounded();
|
||||||
|
|
||||||
// service worker manager to communicate with constellation
|
// service worker manager to communicate with constellation
|
||||||
let (swmanager_sender, swmanager_receiver) = ipc::channel().expect("ipc channel failure");
|
let (swmanager_sender, swmanager_receiver) = ipc::channel().expect("ipc channel failure");
|
||||||
let sw_mgr_clone = swmanager_sender.clone();
|
|
||||||
|
|
||||||
thread::Builder::new()
|
thread::Builder::new()
|
||||||
.name("Constellation".to_owned())
|
.name("Constellation".to_owned())
|
||||||
|
@ -937,7 +942,7 @@ where
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut constellation: Constellation<Message, LTF, STF> = Constellation {
|
let mut constellation: Constellation<Message, LTF, STF, SWF> = Constellation {
|
||||||
namespace_receiver,
|
namespace_receiver,
|
||||||
namespace_sender,
|
namespace_sender,
|
||||||
script_sender: ipc_script_sender,
|
script_sender: ipc_script_sender,
|
||||||
|
@ -961,9 +966,9 @@ where
|
||||||
public_resource_threads: state.public_resource_threads,
|
public_resource_threads: state.public_resource_threads,
|
||||||
private_resource_threads: state.private_resource_threads,
|
private_resource_threads: state.private_resource_threads,
|
||||||
font_cache_thread: state.font_cache_thread,
|
font_cache_thread: state.font_cache_thread,
|
||||||
swmanager_chan: None,
|
sw_managers: Default::default(),
|
||||||
swmanager_receiver: swmanager_receiver,
|
swmanager_receiver: swmanager_receiver,
|
||||||
swmanager_sender: sw_mgr_clone,
|
swmanager_sender,
|
||||||
browsing_context_group_set: Default::default(),
|
browsing_context_group_set: Default::default(),
|
||||||
browsing_context_group_next_id: Default::default(),
|
browsing_context_group_next_id: Default::default(),
|
||||||
message_ports: HashMap::new(),
|
message_ports: HashMap::new(),
|
||||||
|
@ -1022,7 +1027,7 @@ where
|
||||||
})
|
})
|
||||||
.expect("Thread spawning failed");
|
.expect("Thread spawning failed");
|
||||||
|
|
||||||
(compositor_sender, swmanager_sender)
|
compositor_sender
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main event loop for the constellation.
|
/// The main event loop for the constellation.
|
||||||
|
@ -1530,9 +1535,9 @@ where
|
||||||
|
|
||||||
fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
|
fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
|
||||||
match message {
|
match message {
|
||||||
SWManagerMsg::OwnSender(sw_sender) => {
|
SWManagerMsg::PostMessageToClient => {
|
||||||
// store service worker manager for communicating with it.
|
// TODO: implement posting a message to a SW client.
|
||||||
self.swmanager_chan = Some(sw_sender);
|
// https://github.com/servo/servo/issues/24660
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1965,7 +1970,7 @@ where
|
||||||
self.handle_register_serviceworker(scope_things, scope);
|
self.handle_register_serviceworker(scope_things, scope);
|
||||||
},
|
},
|
||||||
FromScriptMsg::ForwardDOMMessage(msg_vec, scope_url) => {
|
FromScriptMsg::ForwardDOMMessage(msg_vec, scope_url) => {
|
||||||
if let Some(ref mgr) = self.swmanager_chan {
|
if let Some(mgr) = self.sw_managers.get(&scope_url.origin()) {
|
||||||
let _ = mgr.send(ServiceWorkerMsg::ForwardDOMMessage(msg_vec, scope_url));
|
let _ = mgr.send(ServiceWorkerMsg::ForwardDOMMessage(msg_vec, scope_url));
|
||||||
} else {
|
} else {
|
||||||
warn!("Unable to forward DOMMessage for postMessage call");
|
warn!("Unable to forward DOMMessage for postMessage call");
|
||||||
|
@ -2621,11 +2626,32 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_register_serviceworker(&self, scope_things: ScopeThings, scope: ServoUrl) {
|
fn handle_register_serviceworker(&mut self, scope_things: ScopeThings, scope: ServoUrl) {
|
||||||
if let Some(ref mgr) = self.swmanager_chan {
|
let origin = scope.origin();
|
||||||
|
|
||||||
|
if let Some(mgr) = self.sw_managers.get(&origin) {
|
||||||
let _ = mgr.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
|
let _ = mgr.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
|
||||||
} else {
|
} else {
|
||||||
warn!("sending scope info to service worker manager failed");
|
let (own_sender, receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
||||||
|
|
||||||
|
let sw_senders = SWManagerSenders {
|
||||||
|
swmanager_sender: self.swmanager_sender.clone(),
|
||||||
|
resource_sender: self.public_resource_threads.sender(),
|
||||||
|
own_sender: own_sender.clone(),
|
||||||
|
receiver,
|
||||||
|
};
|
||||||
|
let content = ServiceWorkerUnprivilegedContent::new(sw_senders, origin.clone());
|
||||||
|
|
||||||
|
if opts::multiprocess() {
|
||||||
|
if content.spawn_multiprocess().is_err() {
|
||||||
|
return warn!("Failed to spawn process for SW manager.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content.start::<SWF>();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = own_sender.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
|
||||||
|
self.sw_managers.insert(origin, own_sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2763,7 +2789,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("Exiting service worker manager thread.");
|
debug!("Exiting service worker manager thread.");
|
||||||
if let Some(mgr) = self.swmanager_chan.as_ref() {
|
for (_, mgr) in self.sw_managers.drain() {
|
||||||
if let Err(e) = mgr.send(ServiceWorkerMsg::Exit) {
|
if let Err(e) = mgr.send(ServiceWorkerMsg::Exit) {
|
||||||
warn!("Exit service worker manager failed ({})", e);
|
warn!("Exit service worker manager failed ({})", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,8 @@ mod constellation;
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
mod network_listener;
|
mod network_listener;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
#[cfg(all(
|
|
||||||
not(target_os = "windows"),
|
|
||||||
not(target_os = "ios"),
|
|
||||||
not(target_os = "android"),
|
|
||||||
not(target_arch = "arm"),
|
|
||||||
not(target_arch = "aarch64")
|
|
||||||
))]
|
|
||||||
mod sandboxing;
|
mod sandboxing;
|
||||||
|
mod serviceworker;
|
||||||
mod session_history;
|
mod session_history;
|
||||||
mod timer_scheduler;
|
mod timer_scheduler;
|
||||||
|
|
||||||
|
@ -31,11 +25,4 @@ pub use crate::constellation::{
|
||||||
Constellation, FromCompositorLogger, FromScriptLogger, InitialConstellationState,
|
Constellation, FromCompositorLogger, FromScriptLogger, InitialConstellationState,
|
||||||
};
|
};
|
||||||
pub use crate::pipeline::UnprivilegedPipelineContent;
|
pub use crate::pipeline::UnprivilegedPipelineContent;
|
||||||
#[cfg(all(
|
pub use crate::sandboxing::{content_process_sandbox_profile, UnprivilegedContent};
|
||||||
not(target_os = "windows"),
|
|
||||||
not(target_os = "ios"),
|
|
||||||
not(target_os = "android"),
|
|
||||||
not(target_arch = "arm"),
|
|
||||||
not(target_arch = "aarch64")
|
|
||||||
))]
|
|
||||||
pub use crate::sandboxing::content_process_sandbox_profile;
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::event_loop::EventLoop;
|
use crate::event_loop::EventLoop;
|
||||||
|
use crate::sandboxing::{spawn_multiprocess, UnprivilegedContent};
|
||||||
use background_hang_monitor::HangMonitorRegister;
|
use background_hang_monitor::HangMonitorRegister;
|
||||||
use bluetooth_traits::BluetoothRequest;
|
use bluetooth_traits::BluetoothRequest;
|
||||||
use canvas_traits::webgl::WebGLPipeline;
|
use canvas_traits::webgl::WebGLPipeline;
|
||||||
|
@ -27,7 +28,7 @@ use msg::constellation_msg::{
|
||||||
};
|
};
|
||||||
use net::image_cache::ImageCacheImpl;
|
use net::image_cache::ImageCacheImpl;
|
||||||
use net_traits::image_cache::ImageCache;
|
use net_traits::image_cache::ImageCache;
|
||||||
use net_traits::{IpcSend, ResourceThreads};
|
use net_traits::ResourceThreads;
|
||||||
use profile_traits::mem as profile_mem;
|
use profile_traits::mem as profile_mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
use script_traits::{
|
use script_traits::{
|
||||||
|
@ -35,16 +36,12 @@ use script_traits::{
|
||||||
};
|
};
|
||||||
use script_traits::{DocumentActivity, InitialScriptState};
|
use script_traits::{DocumentActivity, InitialScriptState};
|
||||||
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData};
|
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData};
|
||||||
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders};
|
use script_traits::{NewLayoutInfo, SWManagerMsg};
|
||||||
use script_traits::{ScriptThreadFactory, TimerSchedulerMsg, WindowSizeData};
|
use script_traits::{ScriptThreadFactory, TimerSchedulerMsg, WindowSizeData};
|
||||||
use servo_config::opts::{self, Opts};
|
use servo_config::opts::{self, Opts};
|
||||||
use servo_config::{prefs, prefs::PrefValue};
|
use servo_config::{prefs, prefs::PrefValue};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
#[cfg(not(windows))]
|
|
||||||
use std::env;
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::process;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -632,109 +629,8 @@ impl UnprivilegedPipelineContent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "android",
|
|
||||||
target_arch = "arm",
|
|
||||||
all(target_arch = "aarch64", not(target_os = "windows"))
|
|
||||||
))]
|
|
||||||
pub fn spawn_multiprocess(self) -> Result<(), Error> {
|
pub fn spawn_multiprocess(self) -> Result<(), Error> {
|
||||||
use ipc_channel::ipc::IpcOneShotServer;
|
spawn_multiprocess(UnprivilegedContent::Pipeline(self))
|
||||||
// Note that this function can panic, due to process creation,
|
|
||||||
// avoiding this panic would require a mechanism for dealing
|
|
||||||
// with low-resource scenarios.
|
|
||||||
let (server, token) = IpcOneShotServer::<IpcSender<UnprivilegedPipelineContent>>::new()
|
|
||||||
.expect("Failed to create IPC one-shot server.");
|
|
||||||
|
|
||||||
let path_to_self = env::current_exe().expect("Failed to get current executor.");
|
|
||||||
let mut child_process = process::Command::new(path_to_self);
|
|
||||||
self.setup_common(&mut child_process, token);
|
|
||||||
let _ = child_process
|
|
||||||
.spawn()
|
|
||||||
.expect("Failed to start unsandboxed child process!");
|
|
||||||
|
|
||||||
let (_receiver, sender) = server.accept().expect("Server failed to accept.");
|
|
||||||
sender.send(self)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(
|
|
||||||
not(target_os = "windows"),
|
|
||||||
not(target_os = "ios"),
|
|
||||||
not(target_os = "android"),
|
|
||||||
not(target_arch = "arm"),
|
|
||||||
not(target_arch = "aarch64")
|
|
||||||
))]
|
|
||||||
pub fn spawn_multiprocess(self) -> Result<(), Error> {
|
|
||||||
use crate::sandboxing::content_process_sandbox_profile;
|
|
||||||
use gaol::sandbox::{self, Sandbox, SandboxMethods};
|
|
||||||
use ipc_channel::ipc::IpcOneShotServer;
|
|
||||||
|
|
||||||
impl CommandMethods for sandbox::Command {
|
|
||||||
fn arg<T>(&mut self, arg: T)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
self.arg(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env<T, U>(&mut self, key: T, val: U)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
U: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
self.env(key, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that this function can panic, due to process creation,
|
|
||||||
// avoiding this panic would require a mechanism for dealing
|
|
||||||
// with low-resource scenarios.
|
|
||||||
let (server, token) = IpcOneShotServer::<IpcSender<UnprivilegedPipelineContent>>::new()
|
|
||||||
.expect("Failed to create IPC one-shot server.");
|
|
||||||
|
|
||||||
// If there is a sandbox, use the `gaol` API to create the child process.
|
|
||||||
if self.opts.sandbox {
|
|
||||||
let mut command = sandbox::Command::me().expect("Failed to get current sandbox.");
|
|
||||||
self.setup_common(&mut command, token);
|
|
||||||
|
|
||||||
let profile = content_process_sandbox_profile();
|
|
||||||
let _ = Sandbox::new(profile)
|
|
||||||
.start(&mut command)
|
|
||||||
.expect("Failed to start sandboxed child process!");
|
|
||||||
} else {
|
|
||||||
let path_to_self = env::current_exe().expect("Failed to get current executor.");
|
|
||||||
let mut child_process = process::Command::new(path_to_self);
|
|
||||||
self.setup_common(&mut child_process, token);
|
|
||||||
let _ = child_process
|
|
||||||
.spawn()
|
|
||||||
.expect("Failed to start unsandboxed child process!");
|
|
||||||
}
|
|
||||||
|
|
||||||
let (_receiver, sender) = server.accept().expect("Server failed to accept.");
|
|
||||||
sender.send(self)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "ios"))]
|
|
||||||
pub fn spawn_multiprocess(self) -> Result<(), Error> {
|
|
||||||
error!("Multiprocess is not supported on Windows or iOS.");
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn setup_common<C: CommandMethods>(&self, command: &mut C, token: String) {
|
|
||||||
C::arg(command, "--content-process");
|
|
||||||
C::arg(command, token);
|
|
||||||
|
|
||||||
if let Ok(value) = env::var("RUST_BACKTRACE") {
|
|
||||||
C::env(command, "RUST_BACKTRACE", value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(value) = env::var("RUST_LOG") {
|
|
||||||
C::env(command, "RUST_LOG", value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_with_background_hang_monitor(
|
pub fn register_with_background_hang_monitor(
|
||||||
|
@ -763,42 +659,4 @@ impl UnprivilegedPipelineContent {
|
||||||
pub fn prefs(&self) -> HashMap<String, PrefValue> {
|
pub fn prefs(&self) -> HashMap<String, PrefValue> {
|
||||||
self.prefs.clone()
|
self.prefs.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swmanager_senders(&self) -> SWManagerSenders {
|
|
||||||
SWManagerSenders {
|
|
||||||
swmanager_sender: self.swmanager_thread.clone(),
|
|
||||||
resource_sender: self.resource_threads.sender(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait to unify commands launched as multiprocess with or without a sandbox.
|
|
||||||
trait CommandMethods {
|
|
||||||
/// A command line argument.
|
|
||||||
fn arg<T>(&mut self, arg: T)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>;
|
|
||||||
|
|
||||||
/// An environment variable.
|
|
||||||
fn env<T, U>(&mut self, key: T, val: U)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
U: AsRef<OsStr>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandMethods for process::Command {
|
|
||||||
fn arg<T>(&mut self, arg: T)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
self.arg(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env<T, U>(&mut self, key: T, val: U)
|
|
||||||
where
|
|
||||||
T: AsRef<OsStr>,
|
|
||||||
U: AsRef<OsStr>,
|
|
||||||
{
|
|
||||||
self.env(key, val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,53 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use embedder_traits::resources;
|
use crate::pipeline::UnprivilegedPipelineContent;
|
||||||
|
use crate::serviceworker::ServiceWorkerUnprivilegedContent;
|
||||||
|
#[cfg(all(
|
||||||
|
not(target_os = "windows"),
|
||||||
|
not(target_os = "ios"),
|
||||||
|
not(target_os = "android"),
|
||||||
|
not(target_arch = "arm"),
|
||||||
|
not(target_arch = "aarch64")
|
||||||
|
))]
|
||||||
use gaol::profile::{Operation, PathPattern, Profile};
|
use gaol::profile::{Operation, PathPattern, Profile};
|
||||||
use std::path::PathBuf;
|
use ipc_channel::Error;
|
||||||
|
use servo_config::opts::Opts;
|
||||||
|
use servo_config::prefs::PrefValue;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum UnprivilegedContent {
|
||||||
|
Pipeline(UnprivilegedPipelineContent),
|
||||||
|
ServiceWorker(ServiceWorkerUnprivilegedContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnprivilegedContent {
|
||||||
|
pub fn opts(&self) -> Opts {
|
||||||
|
match self {
|
||||||
|
UnprivilegedContent::Pipeline(content) => content.opts(),
|
||||||
|
UnprivilegedContent::ServiceWorker(content) => content.opts(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prefs(&self) -> HashMap<String, PrefValue> {
|
||||||
|
match self {
|
||||||
|
UnprivilegedContent::Pipeline(content) => content.prefs(),
|
||||||
|
UnprivilegedContent::ServiceWorker(content) => content.prefs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Our content process sandbox profile on Mac. As restrictive as possible.
|
/// Our content process sandbox profile on Mac. As restrictive as possible.
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub fn content_process_sandbox_profile() -> Profile {
|
pub fn content_process_sandbox_profile() -> Profile {
|
||||||
|
use embedder_traits::resources;
|
||||||
use gaol::platform;
|
use gaol::platform;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let mut operations = vec![
|
let mut operations = vec![
|
||||||
Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
|
Operation::FileReadAll(PathPattern::Literal(PathBuf::from("/dev/urandom"))),
|
||||||
|
@ -46,8 +85,18 @@ pub fn content_process_sandbox_profile() -> Profile {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Our content process sandbox profile on Linux. As restrictive as possible.
|
/// Our content process sandbox profile on Linux. As restrictive as possible.
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(all(
|
||||||
|
not(target_os = "macos"),
|
||||||
|
not(target_os = "windows"),
|
||||||
|
not(target_os = "ios"),
|
||||||
|
not(target_os = "android"),
|
||||||
|
not(target_arch = "arm"),
|
||||||
|
not(target_arch = "aarch64")
|
||||||
|
))]
|
||||||
pub fn content_process_sandbox_profile() -> Profile {
|
pub fn content_process_sandbox_profile() -> Profile {
|
||||||
|
use embedder_traits::resources;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
let mut operations = vec![Operation::FileReadAll(PathPattern::Literal(PathBuf::from(
|
let mut operations = vec![Operation::FileReadAll(PathPattern::Literal(PathBuf::from(
|
||||||
"/dev/urandom",
|
"/dev/urandom",
|
||||||
)))];
|
)))];
|
||||||
|
@ -65,3 +114,150 @@ pub fn content_process_sandbox_profile() -> Profile {
|
||||||
|
|
||||||
Profile::new(operations).expect("Failed to create sandbox profile!")
|
Profile::new(operations).expect("Failed to create sandbox profile!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "windows",
|
||||||
|
target_os = "ios",
|
||||||
|
target_os = "android",
|
||||||
|
target_arch = "arm",
|
||||||
|
target_arch = "aarch64",
|
||||||
|
))]
|
||||||
|
pub fn content_process_sandbox_profile() {
|
||||||
|
error!("Sandboxed multiprocess is not supported on this platform.");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_arch = "arm",
|
||||||
|
all(target_arch = "aarch64", not(target_os = "windows"))
|
||||||
|
))]
|
||||||
|
pub fn spawn_multiprocess(content: UnprivilegedContent) -> Result<(), Error> {
|
||||||
|
use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
|
||||||
|
// Note that this function can panic, due to process creation,
|
||||||
|
// avoiding this panic would require a mechanism for dealing
|
||||||
|
// with low-resource scenarios.
|
||||||
|
let (server, token) = IpcOneShotServer::<IpcSender<UnprivilegedContent>>::new()
|
||||||
|
.expect("Failed to create IPC one-shot server.");
|
||||||
|
|
||||||
|
let path_to_self = env::current_exe().expect("Failed to get current executor.");
|
||||||
|
let mut child_process = process::Command::new(path_to_self);
|
||||||
|
setup_common(&mut child_process, token);
|
||||||
|
let _ = child_process
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to start unsandboxed child process!");
|
||||||
|
|
||||||
|
let (_receiver, sender) = server.accept().expect("Server failed to accept.");
|
||||||
|
sender.send(content)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
not(target_os = "windows"),
|
||||||
|
not(target_os = "ios"),
|
||||||
|
not(target_os = "android"),
|
||||||
|
not(target_arch = "arm"),
|
||||||
|
not(target_arch = "aarch64")
|
||||||
|
))]
|
||||||
|
pub fn spawn_multiprocess(content: UnprivilegedContent) -> Result<(), Error> {
|
||||||
|
use gaol::sandbox::{self, Sandbox, SandboxMethods};
|
||||||
|
use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
|
||||||
|
|
||||||
|
impl CommandMethods for sandbox::Command {
|
||||||
|
fn arg<T>(&mut self, arg: T)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
self.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env<T, U>(&mut self, key: T, val: U)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>,
|
||||||
|
U: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
self.env(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this function can panic, due to process creation,
|
||||||
|
// avoiding this panic would require a mechanism for dealing
|
||||||
|
// with low-resource scenarios.
|
||||||
|
let (server, token) = IpcOneShotServer::<IpcSender<UnprivilegedContent>>::new()
|
||||||
|
.expect("Failed to create IPC one-shot server.");
|
||||||
|
|
||||||
|
// If there is a sandbox, use the `gaol` API to create the child process.
|
||||||
|
if content.opts().sandbox {
|
||||||
|
let mut command = sandbox::Command::me().expect("Failed to get current sandbox.");
|
||||||
|
setup_common(&mut command, token);
|
||||||
|
|
||||||
|
let profile = content_process_sandbox_profile();
|
||||||
|
let _ = Sandbox::new(profile)
|
||||||
|
.start(&mut command)
|
||||||
|
.expect("Failed to start sandboxed child process!");
|
||||||
|
} else {
|
||||||
|
let path_to_self = env::current_exe().expect("Failed to get current executor.");
|
||||||
|
let mut child_process = process::Command::new(path_to_self);
|
||||||
|
setup_common(&mut child_process, token);
|
||||||
|
let _ = child_process
|
||||||
|
.spawn()
|
||||||
|
.expect("Failed to start unsandboxed child process!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_receiver, sender) = server.accept().expect("Server failed to accept.");
|
||||||
|
sender.send(content)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "windows", target_os = "ios"))]
|
||||||
|
pub fn spawn_multiprocess(_content: UnprivilegedContent) -> Result<(), Error> {
|
||||||
|
error!("Multiprocess is not supported on Windows or iOS.");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
fn setup_common<C: CommandMethods>(command: &mut C, token: String) {
|
||||||
|
C::arg(command, "--content-process");
|
||||||
|
C::arg(command, token);
|
||||||
|
|
||||||
|
if let Ok(value) = env::var("RUST_BACKTRACE") {
|
||||||
|
C::env(command, "RUST_BACKTRACE", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(value) = env::var("RUST_LOG") {
|
||||||
|
C::env(command, "RUST_LOG", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait to unify commands launched as multiprocess with or without a sandbox.
|
||||||
|
trait CommandMethods {
|
||||||
|
/// A command line argument.
|
||||||
|
fn arg<T>(&mut self, arg: T)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>;
|
||||||
|
|
||||||
|
/// An environment variable.
|
||||||
|
fn env<T, U>(&mut self, key: T, val: U)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>,
|
||||||
|
U: AsRef<OsStr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandMethods for process::Command {
|
||||||
|
fn arg<T>(&mut self, arg: T)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
self.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env<T, U>(&mut self, key: T, val: U)
|
||||||
|
where
|
||||||
|
T: AsRef<OsStr>,
|
||||||
|
U: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
self.env(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
components/constellation/serviceworker.rs
Normal file
56
components/constellation/serviceworker.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/* 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 crate::sandboxing::{spawn_multiprocess, UnprivilegedContent};
|
||||||
|
use ipc_channel::Error;
|
||||||
|
use script_traits::{SWManagerSenders, ServiceWorkerManagerFactory};
|
||||||
|
use servo_config::opts::{self, Opts};
|
||||||
|
use servo_config::prefs::{self, PrefValue};
|
||||||
|
use servo_url::ImmutableOrigin;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Conceptually, this is glue to start an agent-cluster for a service worker agent.
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#obtain-a-service-worker-agent>
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ServiceWorkerUnprivilegedContent {
|
||||||
|
opts: Opts,
|
||||||
|
prefs: HashMap<String, PrefValue>,
|
||||||
|
senders: SWManagerSenders,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServiceWorkerUnprivilegedContent {
|
||||||
|
pub fn new(
|
||||||
|
senders: SWManagerSenders,
|
||||||
|
origin: ImmutableOrigin,
|
||||||
|
) -> ServiceWorkerUnprivilegedContent {
|
||||||
|
ServiceWorkerUnprivilegedContent {
|
||||||
|
opts: (*opts::get()).clone(),
|
||||||
|
prefs: prefs::pref_map().iter().collect(),
|
||||||
|
senders,
|
||||||
|
origin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start the agent-cluster.
|
||||||
|
pub fn start<SWF>(self)
|
||||||
|
where
|
||||||
|
SWF: ServiceWorkerManagerFactory,
|
||||||
|
{
|
||||||
|
SWF::create(self.senders, self.origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start the agent-cluster in it's own process.
|
||||||
|
pub fn spawn_multiprocess(self) -> Result<(), Error> {
|
||||||
|
spawn_multiprocess(UnprivilegedContent::ServiceWorker(self))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn opts(&self) -> Opts {
|
||||||
|
self.opts.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prefs(&self) -> HashMap<String, PrefValue> {
|
||||||
|
self.prefs.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,7 +39,7 @@ use profile_traits::mem::{Report, ReportKind, ReportsChan};
|
||||||
use profile_traits::time::ProfilerChan;
|
use profile_traits::time::ProfilerChan;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use servo_arc::Arc as ServoArc;
|
use servo_arc::Arc as ServoArc;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
use std::borrow::{Cow, ToOwned};
|
use std::borrow::{Cow, ToOwned};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
@ -299,8 +299,10 @@ impl ResourceChannelManager {
|
||||||
.send(cookie_jar.cookies_for_url(&url, source))
|
.send(cookie_jar.cookies_for_url(&url, source))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
CoreResourceMsg::NetworkMediator(mediator_chan) => {
|
CoreResourceMsg::NetworkMediator(mediator_chan, origin) => {
|
||||||
self.resource_manager.swmanager_chan = Some(mediator_chan)
|
self.resource_manager
|
||||||
|
.sw_managers
|
||||||
|
.insert(origin, mediator_chan);
|
||||||
},
|
},
|
||||||
CoreResourceMsg::GetCookiesDataForUrl(url, consumer, source) => {
|
CoreResourceMsg::GetCookiesDataForUrl(url, consumer, source) => {
|
||||||
let mut cookie_jar = http_state.cookie_jar.write().unwrap();
|
let mut cookie_jar = http_state.cookie_jar.write().unwrap();
|
||||||
|
@ -431,7 +433,7 @@ pub struct AuthCache {
|
||||||
pub struct CoreResourceManager {
|
pub struct CoreResourceManager {
|
||||||
user_agent: Cow<'static, str>,
|
user_agent: Cow<'static, str>,
|
||||||
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||||
swmanager_chan: Option<IpcSender<CustomResponseMediator>>,
|
sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
|
||||||
filemanager: FileManager,
|
filemanager: FileManager,
|
||||||
thread_pool: Arc<CoreResourceThreadPool>,
|
thread_pool: Arc<CoreResourceThreadPool>,
|
||||||
certificate_path: Option<String>,
|
certificate_path: Option<String>,
|
||||||
|
@ -575,7 +577,7 @@ impl CoreResourceManager {
|
||||||
CoreResourceManager {
|
CoreResourceManager {
|
||||||
user_agent: user_agent,
|
user_agent: user_agent,
|
||||||
devtools_chan: devtools_channel,
|
devtools_chan: devtools_channel,
|
||||||
swmanager_chan: None,
|
sw_managers: Default::default(),
|
||||||
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
||||||
thread_pool: pool_handle,
|
thread_pool: pool_handle,
|
||||||
certificate_path,
|
certificate_path,
|
||||||
|
|
|
@ -30,7 +30,7 @@ use ipc_channel::router::ROUTER;
|
||||||
use ipc_channel::Error as IpcError;
|
use ipc_channel::Error as IpcError;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use msg::constellation_msg::HistoryStateId;
|
use msg::constellation_msg::HistoryStateId;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||||
use time::precise_time_ns;
|
use time::precise_time_ns;
|
||||||
use webrender_api::ImageKey;
|
use webrender_api::ImageKey;
|
||||||
|
|
||||||
|
@ -423,8 +423,8 @@ pub enum CoreResourceMsg {
|
||||||
RemoveHistoryStates(Vec<HistoryStateId>),
|
RemoveHistoryStates(Vec<HistoryStateId>),
|
||||||
/// Synchronization message solely for knowing the state of the ResourceChannelManager loop
|
/// Synchronization message solely for knowing the state of the ResourceChannelManager loop
|
||||||
Synchronize(IpcSender<()>),
|
Synchronize(IpcSender<()>),
|
||||||
/// Send the network sender in constellation to CoreResourceThread
|
/// Send the service worker network mediator for an origin to CoreResourceThread
|
||||||
NetworkMediator(IpcSender<CustomResponseMediator>),
|
NetworkMediator(IpcSender<CustomResponseMediator>, ImmutableOrigin),
|
||||||
/// Message forwarded to file manager's handler
|
/// Message forwarded to file manager's handler
|
||||||
ToFileManager(FileManagerThreadMsg),
|
ToFileManager(FileManagerThreadMsg),
|
||||||
/// Break the load handler loop, send a reply when done cleaning up local resources
|
/// Break the load handler loop, send a reply when done cleaning up local resources
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
use crate::dom::bindings::codegen::RegisterBindings;
|
use crate::dom::bindings::codegen::RegisterBindings;
|
||||||
use crate::dom::bindings::proxyhandler;
|
use crate::dom::bindings::proxyhandler;
|
||||||
use crate::script_runtime::JSEngineSetup;
|
use crate::script_runtime::JSEngineSetup;
|
||||||
use crate::serviceworker_manager::ServiceWorkerManager;
|
|
||||||
use script_traits::SWManagerSenders;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -51,11 +49,6 @@ fn perform_platform_specific_initialization() {
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
fn perform_platform_specific_initialization() {}
|
fn perform_platform_specific_initialization() {}
|
||||||
|
|
||||||
pub fn init_service_workers(sw_senders: SWManagerSenders) {
|
|
||||||
// Spawn the service worker manager passing the constellation sender
|
|
||||||
ServiceWorkerManager::spawn_manager(sw_senders);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn init() -> JSEngineSetup {
|
pub fn init() -> JSEngineSetup {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub mod script_runtime;
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub mod script_thread;
|
pub mod script_thread;
|
||||||
#[warn(deprecated)]
|
#[warn(deprecated)]
|
||||||
mod serviceworker_manager;
|
pub mod serviceworker_manager;
|
||||||
#[warn(deprecated)]
|
#[warn(deprecated)]
|
||||||
mod serviceworkerjob;
|
mod serviceworkerjob;
|
||||||
#[warn(deprecated)]
|
#[warn(deprecated)]
|
||||||
|
@ -115,7 +115,7 @@ mod unpremultiplytable;
|
||||||
#[warn(deprecated)]
|
#[warn(deprecated)]
|
||||||
mod webdriver_handlers;
|
mod webdriver_handlers;
|
||||||
|
|
||||||
pub use init::{init, init_service_workers};
|
pub use init::init;
|
||||||
pub use script_runtime::JSEngineSetup;
|
pub use script_runtime::JSEngineSetup;
|
||||||
|
|
||||||
/// A module with everything layout can use from script.
|
/// A module with everything layout can use from script.
|
||||||
|
|
|
@ -15,8 +15,12 @@ use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use net_traits::{CoreResourceMsg, CustomResponseMediator};
|
use net_traits::{CoreResourceMsg, CustomResponseMediator};
|
||||||
use script_traits::{DOMMessage, SWManagerMsg, SWManagerSenders, ScopeThings, ServiceWorkerMsg};
|
use script_traits::{
|
||||||
|
DOMMessage, SWManagerMsg, SWManagerSenders, ScopeThings, ServiceWorkerManagerFactory,
|
||||||
|
ServiceWorkerMsg,
|
||||||
|
};
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
|
use servo_url::ImmutableOrigin;
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -31,6 +35,9 @@ pub struct ServiceWorkerManager {
|
||||||
registered_workers: HashMap<ServoUrl, ScopeThings>,
|
registered_workers: HashMap<ServoUrl, ScopeThings>,
|
||||||
// map of active service worker descriptors
|
// map of active service worker descriptors
|
||||||
active_workers: HashMap<ServoUrl, Sender<ServiceWorkerScriptMsg>>,
|
active_workers: HashMap<ServoUrl, Sender<ServiceWorkerScriptMsg>>,
|
||||||
|
// Will be useful to implement posting a message to a client.
|
||||||
|
// See https://github.com/servo/servo/issues/24660
|
||||||
|
_constellation_sender: IpcSender<SWManagerMsg>,
|
||||||
// own sender to send messages here
|
// own sender to send messages here
|
||||||
own_sender: IpcSender<ServiceWorkerMsg>,
|
own_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
// receiver to receive messages from constellation
|
// receiver to receive messages from constellation
|
||||||
|
@ -44,6 +51,7 @@ impl ServiceWorkerManager {
|
||||||
own_sender: IpcSender<ServiceWorkerMsg>,
|
own_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
from_constellation_receiver: Receiver<ServiceWorkerMsg>,
|
from_constellation_receiver: Receiver<ServiceWorkerMsg>,
|
||||||
resource_port: Receiver<CustomResponseMediator>,
|
resource_port: Receiver<CustomResponseMediator>,
|
||||||
|
constellation_sender: IpcSender<SWManagerMsg>,
|
||||||
) -> ServiceWorkerManager {
|
) -> ServiceWorkerManager {
|
||||||
ServiceWorkerManager {
|
ServiceWorkerManager {
|
||||||
registered_workers: HashMap::new(),
|
registered_workers: HashMap::new(),
|
||||||
|
@ -51,30 +59,10 @@ impl ServiceWorkerManager {
|
||||||
own_sender: own_sender,
|
own_sender: own_sender,
|
||||||
own_port: from_constellation_receiver,
|
own_port: from_constellation_receiver,
|
||||||
resource_receiver: resource_port,
|
resource_receiver: resource_port,
|
||||||
|
_constellation_sender: constellation_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_manager(sw_senders: SWManagerSenders) {
|
|
||||||
let (own_sender, from_constellation_receiver) = ipc::channel().unwrap();
|
|
||||||
let (resource_chan, resource_port) = ipc::channel().unwrap();
|
|
||||||
let from_constellation =
|
|
||||||
ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(from_constellation_receiver);
|
|
||||||
let resource_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(resource_port);
|
|
||||||
let _ = sw_senders
|
|
||||||
.resource_sender
|
|
||||||
.send(CoreResourceMsg::NetworkMediator(resource_chan));
|
|
||||||
let _ = sw_senders
|
|
||||||
.swmanager_sender
|
|
||||||
.send(SWManagerMsg::OwnSender(own_sender.clone()));
|
|
||||||
thread::Builder::new()
|
|
||||||
.name("ServiceWorkerManager".to_owned())
|
|
||||||
.spawn(move || {
|
|
||||||
ServiceWorkerManager::new(own_sender, from_constellation, resource_port)
|
|
||||||
.handle_message();
|
|
||||||
})
|
|
||||||
.expect("Thread spawning failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_matching_scope(&self, load_url: &ServoUrl) -> Option<ServoUrl> {
|
pub fn get_matching_scope(&self, load_url: &ServoUrl) -> Option<ServoUrl> {
|
||||||
for scope in self.registered_workers.keys() {
|
for scope in self.registered_workers.keys() {
|
||||||
if longest_prefix_match(&scope, load_url) {
|
if longest_prefix_match(&scope, load_url) {
|
||||||
|
@ -203,6 +191,38 @@ impl ServiceWorkerManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ServiceWorkerManagerFactory for ServiceWorkerManager {
|
||||||
|
fn create(sw_senders: SWManagerSenders, origin: ImmutableOrigin) {
|
||||||
|
let (resource_chan, resource_port) = ipc::channel().unwrap();
|
||||||
|
|
||||||
|
let SWManagerSenders {
|
||||||
|
resource_sender,
|
||||||
|
own_sender,
|
||||||
|
receiver,
|
||||||
|
swmanager_sender: constellation_sender,
|
||||||
|
} = sw_senders;
|
||||||
|
|
||||||
|
let from_constellation = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(receiver);
|
||||||
|
let resource_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(resource_port);
|
||||||
|
let _ = resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan, origin));
|
||||||
|
if thread::Builder::new()
|
||||||
|
.name("ServiceWorkerManager".to_owned())
|
||||||
|
.spawn(move || {
|
||||||
|
ServiceWorkerManager::new(
|
||||||
|
own_sender,
|
||||||
|
from_constellation,
|
||||||
|
resource_port,
|
||||||
|
constellation_sender,
|
||||||
|
)
|
||||||
|
.handle_message();
|
||||||
|
})
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
warn!("ServiceWorkerManager thread spawning failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn serviceworker_enabled() -> bool {
|
pub fn serviceworker_enabled() -> bool {
|
||||||
pref!(dom.serviceworker.enabled)
|
pref!(dom.serviceworker.enabled)
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,6 +706,13 @@ pub trait ScriptThreadFactory {
|
||||||
) -> (Sender<Self::Message>, Receiver<Self::Message>);
|
) -> (Sender<Self::Message>, Receiver<Self::Message>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This trait allows creating a `ServiceWorkerManager` without depending on the `script`
|
||||||
|
/// crate.
|
||||||
|
pub trait ServiceWorkerManagerFactory {
|
||||||
|
/// Create a `ServiceWorkerManager`.
|
||||||
|
fn create(sw_senders: SWManagerSenders, origin: ImmutableOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the sandbox attribute is present for an iframe element
|
/// Whether the sandbox attribute is present for an iframe element
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
pub enum IFrameSandboxState {
|
pub enum IFrameSandboxState {
|
||||||
|
|
|
@ -370,11 +370,16 @@ pub struct DOMMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Channels to allow service worker manager to communicate with constellation and resource thread
|
/// Channels to allow service worker manager to communicate with constellation and resource thread
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct SWManagerSenders {
|
pub struct SWManagerSenders {
|
||||||
/// sender for communicating with constellation
|
/// Sender of messages to the constellation.
|
||||||
pub swmanager_sender: IpcSender<SWManagerMsg>,
|
pub swmanager_sender: IpcSender<SWManagerMsg>,
|
||||||
/// sender for communicating with resource thread
|
/// Sender for communicating with resource thread.
|
||||||
pub resource_sender: IpcSender<CoreResourceMsg>,
|
pub resource_sender: IpcSender<CoreResourceMsg>,
|
||||||
|
/// Sender of messages to the manager.
|
||||||
|
pub own_sender: IpcSender<ServiceWorkerMsg>,
|
||||||
|
/// Receiver of messages from the constellation.
|
||||||
|
pub receiver: IpcReceiver<ServiceWorkerMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages sent to Service Worker Manager thread
|
/// Messages sent to Service Worker Manager thread
|
||||||
|
@ -393,6 +398,8 @@ pub enum ServiceWorkerMsg {
|
||||||
/// Messages outgoing from the Service Worker Manager thread to constellation
|
/// Messages outgoing from the Service Worker Manager thread to constellation
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub enum SWManagerMsg {
|
pub enum SWManagerMsg {
|
||||||
/// Provide the constellation with a means of communicating with the Service Worker Manager
|
/// Placeholder to keep the enum,
|
||||||
OwnSender(IpcSender<ServiceWorkerMsg>),
|
/// as it will be needed when implementing
|
||||||
|
/// https://github.com/servo/servo/issues/24660
|
||||||
|
PostMessageToClient,
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ use compositing::{CompositingReason, ConstellationMsg, IOCompositor, ShutdownSta
|
||||||
not(target_arch = "aarch64")
|
not(target_arch = "aarch64")
|
||||||
))]
|
))]
|
||||||
use constellation::content_process_sandbox_profile;
|
use constellation::content_process_sandbox_profile;
|
||||||
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
|
use constellation::{Constellation, InitialConstellationState, UnprivilegedContent};
|
||||||
use constellation::{FromCompositorLogger, FromScriptLogger};
|
use constellation::{FromCompositorLogger, FromScriptLogger};
|
||||||
use crossbeam_channel::{unbounded, Sender};
|
use crossbeam_channel::{unbounded, Sender};
|
||||||
use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker};
|
use embedder_traits::{EmbedderMsg, EmbedderProxy, EmbedderReceiver, EventLoopWaker};
|
||||||
|
@ -105,8 +105,9 @@ use profile::mem as profile_mem;
|
||||||
use profile::time as profile_time;
|
use profile::time as profile_time;
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
use profile_traits::time;
|
use profile_traits::time;
|
||||||
|
use script::serviceworker_manager::ServiceWorkerManager;
|
||||||
use script::JSEngineSetup;
|
use script::JSEngineSetup;
|
||||||
use script_traits::{SWManagerSenders, ScriptToConstellationChan, WindowSizeData};
|
use script_traits::{ScriptToConstellationChan, WindowSizeData};
|
||||||
use servo_config::opts;
|
use servo_config::opts;
|
||||||
use servo_config::{pref, prefs};
|
use servo_config::{pref, prefs};
|
||||||
use servo_media::player::context::GlContext;
|
use servo_media::player::context::GlContext;
|
||||||
|
@ -519,7 +520,7 @@ where
|
||||||
// Create the constellation, which maintains the engine
|
// Create the constellation, which maintains the engine
|
||||||
// pipelines, including the script and layout threads, as well
|
// pipelines, including the script and layout threads, as well
|
||||||
// as the navigation context.
|
// as the navigation context.
|
||||||
let (constellation_chan, sw_senders) = create_constellation(
|
let constellation_chan = create_constellation(
|
||||||
opts.user_agent.clone(),
|
opts.user_agent.clone(),
|
||||||
opts.config_dir.clone(),
|
opts.config_dir.clone(),
|
||||||
embedder_proxy,
|
embedder_proxy,
|
||||||
|
@ -541,9 +542,6 @@ where
|
||||||
pending_wr_frame.clone(),
|
pending_wr_frame.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send the constellation's swmanager sender to service worker manager thread
|
|
||||||
script::init_service_workers(sw_senders);
|
|
||||||
|
|
||||||
if cfg!(feature = "webdriver") {
|
if cfg!(feature = "webdriver") {
|
||||||
if let Some(port) = opts.webdriver_port {
|
if let Some(port) = opts.webdriver_port {
|
||||||
webdriver(port, constellation_chan.clone());
|
webdriver(port, constellation_chan.clone());
|
||||||
|
@ -879,7 +877,7 @@ fn create_constellation(
|
||||||
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||||
initial_window_size: WindowSizeData,
|
initial_window_size: WindowSizeData,
|
||||||
pending_wr_frame: Arc<AtomicBool>,
|
pending_wr_frame: Arc<AtomicBool>,
|
||||||
) -> (Sender<ConstellationMsg>, SWManagerSenders) {
|
) -> Sender<ConstellationMsg> {
|
||||||
// Global configuration options, parsed from the command line.
|
// Global configuration options, parsed from the command line.
|
||||||
let opts = opts::get();
|
let opts = opts::get();
|
||||||
|
|
||||||
|
@ -900,8 +898,6 @@ fn create_constellation(
|
||||||
webrender_api_sender.create_api(),
|
webrender_api_sender.create_api(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let resource_sender = public_resource_threads.sender();
|
|
||||||
|
|
||||||
let initial_state = InitialConstellationState {
|
let initial_state = InitialConstellationState {
|
||||||
compositor_proxy,
|
compositor_proxy,
|
||||||
embedder_proxy,
|
embedder_proxy,
|
||||||
|
@ -926,10 +922,11 @@ fn create_constellation(
|
||||||
|
|
||||||
let (canvas_chan, ipc_canvas_chan) = canvas::canvas_paint_thread::CanvasPaintThread::start();
|
let (canvas_chan, ipc_canvas_chan) = canvas::canvas_paint_thread::CanvasPaintThread::start();
|
||||||
|
|
||||||
let (constellation_chan, from_swmanager_sender) = Constellation::<
|
let constellation_chan = Constellation::<
|
||||||
script_layout_interface::message::Msg,
|
script_layout_interface::message::Msg,
|
||||||
layout_thread::LayoutThread,
|
layout_thread::LayoutThread,
|
||||||
script::script_thread::ScriptThread,
|
script::script_thread::ScriptThread,
|
||||||
|
script::serviceworker_manager::ServiceWorkerManager,
|
||||||
>::start(
|
>::start(
|
||||||
initial_state,
|
initial_state,
|
||||||
initial_window_size,
|
initial_window_size,
|
||||||
|
@ -949,13 +946,7 @@ fn create_constellation(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// channels to communicate with Service Worker Manager
|
constellation_chan
|
||||||
let sw_senders = SWManagerSenders {
|
|
||||||
swmanager_sender: from_swmanager_sender,
|
|
||||||
resource_sender: resource_sender,
|
|
||||||
};
|
|
||||||
|
|
||||||
(constellation_chan, sw_senders)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A logger that logs to two downstream loggers.
|
// A logger that logs to two downstream loggers.
|
||||||
|
@ -997,45 +988,50 @@ pub fn set_logger(script_to_constellation_chan: ScriptToConstellationChan) {
|
||||||
/// Content process entry point.
|
/// Content process entry point.
|
||||||
pub fn run_content_process(token: String) {
|
pub fn run_content_process(token: String) {
|
||||||
let (unprivileged_content_sender, unprivileged_content_receiver) =
|
let (unprivileged_content_sender, unprivileged_content_receiver) =
|
||||||
ipc::channel::<UnprivilegedPipelineContent>().unwrap();
|
ipc::channel::<UnprivilegedContent>().unwrap();
|
||||||
let connection_bootstrap: IpcSender<IpcSender<UnprivilegedPipelineContent>> =
|
let connection_bootstrap: IpcSender<IpcSender<UnprivilegedContent>> =
|
||||||
IpcSender::connect(token).unwrap();
|
IpcSender::connect(token).unwrap();
|
||||||
connection_bootstrap
|
connection_bootstrap
|
||||||
.send(unprivileged_content_sender)
|
.send(unprivileged_content_sender)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut unprivileged_content = unprivileged_content_receiver.recv().unwrap();
|
let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
|
||||||
opts::set_options(unprivileged_content.opts());
|
opts::set_options(unprivileged_content.opts());
|
||||||
prefs::pref_map()
|
prefs::pref_map()
|
||||||
.set_all(unprivileged_content.prefs())
|
.set_all(unprivileged_content.prefs())
|
||||||
.expect("Failed to set preferences");
|
.expect("Failed to set preferences");
|
||||||
set_logger(unprivileged_content.script_to_constellation_chan().clone());
|
|
||||||
|
|
||||||
// Enter the sandbox if necessary.
|
// Enter the sandbox if necessary.
|
||||||
if opts::get().sandbox {
|
if opts::get().sandbox {
|
||||||
create_sandbox();
|
create_sandbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _js_engine_setup = script::init();
|
||||||
|
|
||||||
|
match unprivileged_content {
|
||||||
|
UnprivilegedContent::Pipeline(mut content) => {
|
||||||
|
media_platform::init();
|
||||||
|
|
||||||
|
set_logger(content.script_to_constellation_chan().clone());
|
||||||
|
|
||||||
let background_hang_monitor_register = if opts::get().background_hang_monitor {
|
let background_hang_monitor_register = if opts::get().background_hang_monitor {
|
||||||
unprivileged_content.register_with_background_hang_monitor()
|
content.register_with_background_hang_monitor()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// send the required channels to the service worker manager
|
content.start_all::<script_layout_interface::message::Msg,
|
||||||
let sw_senders = unprivileged_content.swmanager_senders();
|
|
||||||
let _js_engine_setup = script::init();
|
|
||||||
script::init_service_workers(sw_senders);
|
|
||||||
|
|
||||||
media_platform::init();
|
|
||||||
|
|
||||||
unprivileged_content.start_all::<script_layout_interface::message::Msg,
|
|
||||||
layout_thread::LayoutThread,
|
layout_thread::LayoutThread,
|
||||||
script::script_thread::ScriptThread>(
|
script::script_thread::ScriptThread>(
|
||||||
true,
|
true,
|
||||||
background_hang_monitor_register,
|
background_hang_monitor_register,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
UnprivilegedContent::ServiceWorker(content) => {
|
||||||
|
content.start::<ServiceWorkerManager>();
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue