mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
allow for a service worker manager per origin
This commit is contained in:
parent
9972aee81f
commit
db217d5575
11 changed files with 405 additions and 245 deletions
|
@ -96,6 +96,7 @@ use crate::browsingcontext::{
|
|||
use crate::event_loop::EventLoop;
|
||||
use crate::network_listener::NetworkListener;
|
||||
use crate::pipeline::{InitialPipelineState, Pipeline};
|
||||
use crate::serviceworker::ServiceWorkerUnprivilegedContent;
|
||||
use crate::session_history::{
|
||||
JointSessionHistory, NeedsToReload, SessionHistoryChange, SessionHistoryDiff,
|
||||
};
|
||||
|
@ -151,10 +152,15 @@ use script_traits::{HistoryEntryReplacement, IFrameSizeMsg, WindowSizeData, Wind
|
|||
use script_traits::{
|
||||
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::{MessagePortMsg, PortMessageTask, StructuredSerializedData};
|
||||
use script_traits::{SWManagerMsg, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg};
|
||||
use script_traits::{
|
||||
SWManagerMsg, SWManagerSenders, ScopeThings, UpdatePipelineIdReason, WebDriverCommandMsg,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_config::{opts, pref};
|
||||
use servo_rand::{random, Rng, ServoRng, SliceRandom};
|
||||
|
@ -259,7 +265,7 @@ struct BrowsingContextGroup {
|
|||
/// `LayoutThread` in the `layout` crate, and `ScriptThread` in
|
||||
/// the `script` crate). Script and layout communicate using a `Message`
|
||||
/// type.
|
||||
pub struct Constellation<Message, LTF, STF> {
|
||||
pub struct Constellation<Message, LTF, STF, SWF> {
|
||||
/// An ipc-sender/threaded-receiver pair
|
||||
/// to facilitate installing pipeline namespaces in threads
|
||||
/// via a per-process installer.
|
||||
|
@ -348,9 +354,8 @@ pub struct Constellation<Message, LTF, STF> {
|
|||
/// bluetooth thread.
|
||||
bluetooth_thread: IpcSender<BluetoothRequest>,
|
||||
|
||||
/// An IPC channel for the constellation to send messages to the
|
||||
/// Service Worker Manager thread.
|
||||
swmanager_chan: Option<IpcSender<ServiceWorkerMsg>>,
|
||||
/// A map of origin to sender to a Service worker manager.
|
||||
sw_managers: HashMap<ImmutableOrigin, IpcSender<ServiceWorkerMsg>>,
|
||||
|
||||
/// An IPC channel for Service Worker Manager threads to send
|
||||
/// 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)>,
|
||||
|
||||
/// 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.
|
||||
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
|
||||
LTF: LayoutThreadFactory<Message = Message>,
|
||||
STF: ScriptThreadFactory<Message = Message>,
|
||||
SWF: ServiceWorkerManagerFactory,
|
||||
{
|
||||
/// Create a new constellation thread.
|
||||
pub fn start(
|
||||
|
@ -829,12 +835,11 @@ where
|
|||
enable_canvas_antialiasing: bool,
|
||||
canvas_chan: Sender<ConstellationCanvasMsg>,
|
||||
ipc_canvas_chan: IpcSender<CanvasMsg>,
|
||||
) -> (Sender<FromCompositorMsg>, IpcSender<SWManagerMsg>) {
|
||||
) -> Sender<FromCompositorMsg> {
|
||||
let (compositor_sender, compositor_receiver) = unbounded();
|
||||
|
||||
// service worker manager to communicate with constellation
|
||||
let (swmanager_sender, swmanager_receiver) = ipc::channel().expect("ipc channel failure");
|
||||
let sw_mgr_clone = swmanager_sender.clone();
|
||||
|
||||
thread::Builder::new()
|
||||
.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_sender,
|
||||
script_sender: ipc_script_sender,
|
||||
|
@ -961,9 +966,9 @@ where
|
|||
public_resource_threads: state.public_resource_threads,
|
||||
private_resource_threads: state.private_resource_threads,
|
||||
font_cache_thread: state.font_cache_thread,
|
||||
swmanager_chan: None,
|
||||
sw_managers: Default::default(),
|
||||
swmanager_receiver: swmanager_receiver,
|
||||
swmanager_sender: sw_mgr_clone,
|
||||
swmanager_sender,
|
||||
browsing_context_group_set: Default::default(),
|
||||
browsing_context_group_next_id: Default::default(),
|
||||
message_ports: HashMap::new(),
|
||||
|
@ -1022,7 +1027,7 @@ where
|
|||
})
|
||||
.expect("Thread spawning failed");
|
||||
|
||||
(compositor_sender, swmanager_sender)
|
||||
compositor_sender
|
||||
}
|
||||
|
||||
/// The main event loop for the constellation.
|
||||
|
@ -1530,9 +1535,9 @@ where
|
|||
|
||||
fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
|
||||
match message {
|
||||
SWManagerMsg::OwnSender(sw_sender) => {
|
||||
// store service worker manager for communicating with it.
|
||||
self.swmanager_chan = Some(sw_sender);
|
||||
SWManagerMsg::PostMessageToClient => {
|
||||
// TODO: implement posting a message to a SW client.
|
||||
// https://github.com/servo/servo/issues/24660
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1965,7 +1970,7 @@ where
|
|||
self.handle_register_serviceworker(scope_things, scope);
|
||||
},
|
||||
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));
|
||||
} else {
|
||||
warn!("Unable to forward DOMMessage for postMessage call");
|
||||
|
@ -2621,11 +2626,32 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_register_serviceworker(&self, scope_things: ScopeThings, scope: ServoUrl) {
|
||||
if let Some(ref mgr) = self.swmanager_chan {
|
||||
fn handle_register_serviceworker(&mut self, scope_things: ScopeThings, scope: ServoUrl) {
|
||||
let origin = scope.origin();
|
||||
|
||||
if let Some(mgr) = self.sw_managers.get(&origin) {
|
||||
let _ = mgr.send(ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope));
|
||||
} 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.");
|
||||
if let Some(mgr) = self.swmanager_chan.as_ref() {
|
||||
for (_, mgr) in self.sw_managers.drain() {
|
||||
if let Err(e) = mgr.send(ServiceWorkerMsg::Exit) {
|
||||
warn!("Exit service worker manager failed ({})", e);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ mod pipeline;
|
|||
not(target_arch = "aarch64")
|
||||
))]
|
||||
mod sandboxing;
|
||||
mod serviceworker;
|
||||
mod session_history;
|
||||
mod timer_scheduler;
|
||||
|
||||
|
@ -38,4 +39,4 @@ pub use crate::pipeline::UnprivilegedPipelineContent;
|
|||
not(target_arch = "arm"),
|
||||
not(target_arch = "aarch64")
|
||||
))]
|
||||
pub use crate::sandboxing::content_process_sandbox_profile;
|
||||
pub use crate::sandboxing::{content_process_sandbox_profile, UnprivilegedContent};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::event_loop::EventLoop;
|
||||
use crate::sandboxing::{spawn_multiprocess, UnprivilegedContent};
|
||||
use background_hang_monitor::HangMonitorRegister;
|
||||
use bluetooth_traits::BluetoothRequest;
|
||||
use canvas_traits::webgl::WebGLPipeline;
|
||||
|
@ -27,7 +28,7 @@ use msg::constellation_msg::{
|
|||
};
|
||||
use net::image_cache::ImageCacheImpl;
|
||||
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::time;
|
||||
use script_traits::{
|
||||
|
@ -35,16 +36,12 @@ use script_traits::{
|
|||
};
|
||||
use script_traits::{DocumentActivity, InitialScriptState};
|
||||
use script_traits::{LayoutControlMsg, LayoutMsg, LoadData};
|
||||
use script_traits::{NewLayoutInfo, SWManagerMsg, SWManagerSenders};
|
||||
use script_traits::{NewLayoutInfo, SWManagerMsg};
|
||||
use script_traits::{ScriptThreadFactory, TimerSchedulerMsg, WindowSizeData};
|
||||
use servo_config::opts::{self, Opts};
|
||||
use servo_config::{prefs, prefs::PrefValue};
|
||||
use servo_url::ServoUrl;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
#[cfg(not(windows))]
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::process;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
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> {
|
||||
use ipc_channel::ipc::IpcOneShotServer;
|
||||
// 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);
|
||||
}
|
||||
spawn_multiprocess(UnprivilegedContent::Pipeline(self))
|
||||
}
|
||||
|
||||
pub fn register_with_background_hang_monitor(
|
||||
|
@ -763,42 +659,4 @@ impl UnprivilegedPipelineContent {
|
|||
pub fn prefs(&self) -> HashMap<String, PrefValue> {
|
||||
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
|
||||
* 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 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.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn content_process_sandbox_profile() -> Profile {
|
||||
use embedder_traits::resources;
|
||||
use gaol::platform;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let mut operations = vec![
|
||||
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.
|
||||
#[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 {
|
||||
use embedder_traits::resources;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let mut operations = vec![Operation::FileReadAll(PathPattern::Literal(PathBuf::from(
|
||||
"/dev/urandom",
|
||||
)))];
|
||||
|
@ -65,3 +114,150 @@ pub fn content_process_sandbox_profile() -> 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()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue