diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 4 | ||||
-rw-r--r-- | components/script/dom/client.rs | 1 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 78 | ||||
-rw-r--r-- | components/script/dom/navigationpreloadmanager.rs | 8 | ||||
-rw-r--r-- | components/script/dom/serviceworker.rs | 17 | ||||
-rw-r--r-- | components/script/dom/serviceworkercontainer.rs | 194 | ||||
-rw-r--r-- | components/script/dom/serviceworkerglobalscope.rs | 63 | ||||
-rw-r--r-- | components/script/dom/serviceworkerregistration.rs | 68 | ||||
-rw-r--r-- | components/script/dom/workerglobalscope.rs | 28 |
9 files changed, 348 insertions, 113 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 7534541a06d..ba174193cdf 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -86,6 +86,7 @@ use msg::constellation_msg::{ BlobId, BroadcastChannelRouterId, BrowsingContextId, HistoryStateId, MessagePortId, MessagePortRouterId, PipelineId, TopLevelBrowsingContextId, }; +use msg::constellation_msg::{ServiceWorkerId, ServiceWorkerRegistrationId}; use net_traits::filemanager_thread::RelativePos; use net_traits::image::base::{Image, ImageMetadata}; use net_traits::image_cache::{ImageCache, PendingImageId}; @@ -179,6 +180,9 @@ unsafe_no_jsmanaged_fields!(MessagePortImpl); unsafe_no_jsmanaged_fields!(MessagePortId); unsafe_no_jsmanaged_fields!(MessagePortRouterId); +unsafe_no_jsmanaged_fields!(ServiceWorkerId); +unsafe_no_jsmanaged_fields!(ServiceWorkerRegistrationId); + unsafe_no_jsmanaged_fields!(BroadcastChannelRouterId); unsafe_no_jsmanaged_fields!(BlobId); diff --git a/components/script/dom/client.rs b/components/script/dom/client.rs index 53c692d5591..2768ee7c9ba 100644 --- a/components/script/dom/client.rs +++ b/components/script/dom/client.rs @@ -47,6 +47,7 @@ impl Client { self.active_worker.get() } + #[allow(dead_code)] pub fn set_controller(&self, worker: &ServiceWorker) { self.active_worker.set(Some(worker)); } diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index e578f31c190..8e067e75de1 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -41,6 +41,8 @@ use crate::dom::paintworkletglobalscope::PaintWorkletGlobalScope; use crate::dom::performance::Performance; use crate::dom::performanceobserver::VALID_ENTRY_TYPES; use crate::dom::promise::Promise; +use crate::dom::serviceworker::ServiceWorker; +use crate::dom::serviceworkerregistration::ServiceWorkerRegistration; use crate::dom::window::Window; use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope; @@ -81,6 +83,7 @@ use js::rust::{HandleValue, MutableHandleValue}; use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL}; use msg::constellation_msg::{ BlobId, BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineId, + ServiceWorkerId, ServiceWorkerRegistrationId, }; use net_traits::blob_url_store::{get_blob_origin, BlobBuf}; use net_traits::filemanager_thread::{ @@ -135,6 +138,13 @@ pub struct GlobalScope { /// The blobs managed by this global, if any. blob_state: DomRefCell<BlobState>, + /// <https://w3c.github.io/ServiceWorker/#environment-settings-object-service-worker-registration-object-map> + registration_map: + DomRefCell<HashMap<ServiceWorkerRegistrationId, Dom<ServiceWorkerRegistration>>>, + + /// <https://w3c.github.io/ServiceWorker/#environment-settings-object-service-worker-object-map> + worker_map: DomRefCell<HashMap<ServiceWorkerId, Dom<ServiceWorker>>>, + /// Pipeline id associated with this global. pipeline_id: PipelineId, @@ -567,6 +577,8 @@ impl GlobalScope { blob_state: DomRefCell::new(BlobState::UnManaged), eventtarget: EventTarget::new_inherited(), crypto: Default::default(), + registration_map: DomRefCell::new(HashMap::new()), + worker_map: DomRefCell::new(HashMap::new()), pipeline_id, devtools_wants_updates: Default::default(), console_timers: DomRefCell::new(Default::default()), @@ -645,6 +657,72 @@ impl GlobalScope { ); } + /// <https://w3c.github.io/ServiceWorker/#get-the-service-worker-registration-object> + pub fn get_serviceworker_registration( + &self, + script_url: &ServoUrl, + scope: &ServoUrl, + registration_id: ServiceWorkerRegistrationId, + installing_worker: Option<ServiceWorkerId>, + _waiting_worker: Option<ServiceWorkerId>, + _active_worker: Option<ServiceWorkerId>, + ) -> DomRoot<ServiceWorkerRegistration> { + // Step 1 + let mut registrations = self.registration_map.borrow_mut(); + + if let Some(registration) = registrations.get(®istration_id) { + // Step 3 + return DomRoot::from_ref(&**registration); + } + + // Step 2.1 -> 2.5 + let new_registration = + ServiceWorkerRegistration::new(self, scope.clone(), registration_id.clone()); + + // Step 2.6 + if let Some(worker_id) = installing_worker { + let worker = self.get_serviceworker(script_url, scope, worker_id); + new_registration.set_installing(&*worker); + } + + // TODO: 2.7 (waiting worker) + + // TODO: 2.8 (active worker) + + // Step 2.9 + registrations.insert(registration_id, Dom::from_ref(&*new_registration)); + + // Step 3 + new_registration + } + + /// <https://w3c.github.io/ServiceWorker/#get-the-service-worker-object> + pub fn get_serviceworker( + &self, + script_url: &ServoUrl, + scope: &ServoUrl, + worker_id: ServiceWorkerId, + ) -> DomRoot<ServiceWorker> { + // Step 1 + let mut workers = self.worker_map.borrow_mut(); + + if let Some(worker) = workers.get(&worker_id) { + // Step 3 + DomRoot::from_ref(&**worker) + } else { + // Step 2.1 + // TODO: step 2.2, worker state. + let new_worker = + ServiceWorker::new(self, script_url.clone(), scope.clone(), worker_id.clone()); + + // Step 2.3 + workers.insert(worker_id, Dom::from_ref(&*new_worker)); + + // Step 3 + new_worker + } + } + /// Complete the transfer of a message-port. fn complete_port_transfer(&self, port_id: MessagePortId, tasks: VecDeque<PortMessageTask>) { let should_start = if let MessagePortState::Managed(_id, message_ports) = diff --git a/components/script/dom/navigationpreloadmanager.rs b/components/script/dom/navigationpreloadmanager.rs index 7586f0a040f..d45fa9ac5f8 100644 --- a/components/script/dom/navigationpreloadmanager.rs +++ b/components/script/dom/navigationpreloadmanager.rs @@ -46,7 +46,7 @@ impl NavigationPreloadManagerMethods for NavigationPreloadManager { let promise = Promise::new_in_current_realm(&*self.global(), comp); // 2. - if self.serviceworker_registration.active().is_none() { + if self.serviceworker_registration.is_active() { promise.reject_native(&DOMException::new( &self.global(), DOMErrorName::InvalidStateError, @@ -68,7 +68,7 @@ impl NavigationPreloadManagerMethods for NavigationPreloadManager { let promise = Promise::new_in_current_realm(&*self.global(), comp); // 2. - if self.serviceworker_registration.active().is_none() { + if self.serviceworker_registration.is_active() { promise.reject_native(&DOMException::new( &self.global(), DOMErrorName::InvalidStateError, @@ -90,7 +90,7 @@ impl NavigationPreloadManagerMethods for NavigationPreloadManager { let promise = Promise::new_in_current_realm(&*self.global(), comp); // 2. - if self.serviceworker_registration.active().is_none() { + if self.serviceworker_registration.is_active() { promise.reject_native(&DOMException::new( &self.global(), DOMErrorName::InvalidStateError, @@ -114,7 +114,7 @@ impl NavigationPreloadManagerMethods for NavigationPreloadManager { let mut state = NavigationPreloadState::empty(); // 3. - if let Some(_) = self.serviceworker_registration.active() { + if self.serviceworker_registration.is_active() { if self .serviceworker_registration .get_navigation_preload_enabled() diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs index fce07ab0809..bcbdd158a40 100644 --- a/components/script/dom/serviceworker.rs +++ b/components/script/dom/serviceworker.rs @@ -23,6 +23,7 @@ use crate::task::TaskOnce; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; use js::rust::{CustomAutoRooter, CustomAutoRooterGuard, HandleValue}; +use msg::constellation_msg::ServiceWorkerId; use script_traits::{DOMMessage, ScriptMsg}; use servo_url::ServoUrl; use std::cell::Cell; @@ -35,31 +36,35 @@ pub struct ServiceWorker { script_url: DomRefCell<String>, scope_url: ServoUrl, state: Cell<ServiceWorkerState>, - skip_waiting: Cell<bool>, + worker_id: ServiceWorkerId, } impl ServiceWorker { - fn new_inherited(script_url: &str, skip_waiting: bool, scope_url: ServoUrl) -> ServiceWorker { + fn new_inherited( + script_url: &str, + scope_url: ServoUrl, + worker_id: ServiceWorkerId, + ) -> ServiceWorker { ServiceWorker { eventtarget: EventTarget::new_inherited(), script_url: DomRefCell::new(String::from(script_url)), state: Cell::new(ServiceWorkerState::Installing), scope_url: scope_url, - skip_waiting: Cell::new(skip_waiting), + worker_id, } } - pub fn install_serviceworker( + pub fn new( global: &GlobalScope, script_url: ServoUrl, scope_url: ServoUrl, - skip_waiting: bool, + worker_id: ServiceWorkerId, ) -> DomRoot<ServiceWorker> { reflect_dom_object( Box::new(ServiceWorker::new_inherited( script_url.as_str(), - skip_waiting, scope_url, + worker_id, )), global, ) diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs index 8145729d857..b65dcd59b7d 100644 --- a/components/script/dom/serviceworkercontainer.rs +++ b/components/script/dom/serviceworkercontainer.rs @@ -5,6 +5,7 @@ use crate::dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::RegistrationOptions; use crate::dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::ServiceWorkerContainerMethods; use crate::dom::bindings::error::Error; +use crate::dom::bindings::refcounted::TrustedPromise; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::bindings::str::USVString; @@ -13,10 +14,17 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::serviceworker::ServiceWorker; +use crate::dom::serviceworkerregistration::ServiceWorkerRegistration; +use crate::realms::enter_realm; use crate::realms::InRealm; -use crate::script_thread::ScriptThread; -use crate::serviceworkerjob::{Job, JobType}; +use crate::task::TaskCanceller; +use crate::task_source::dom_manipulation::DOMManipulationTaskSource; +use crate::task_source::TaskSource; +use crate::task_source::TaskSourceName; use dom_struct::dom_struct; +use ipc_channel::ipc; +use ipc_channel::router::ROUTER; +use script_traits::{Job, JobError, JobResult, JobResultValue, JobType, ScriptMsg}; use std::default::Default; use std::rc::Rc; @@ -50,28 +58,50 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer { self.client.get_controller() } - #[allow(unrooted_must_root)] // Job is unrooted - /// https://w3c.github.io/ServiceWorker/#navigator-service-worker-register and - A - /// https://w3c.github.io/ServiceWorker/#start-register-algorithm - B + /// https://w3c.github.io/ServiceWorker/#dom-serviceworkercontainer-register - A + /// and https://w3c.github.io/ServiceWorker/#start-register - B fn Register( &self, script_url: USVString, options: &RegistrationOptions, comp: InRealm, ) -> Rc<Promise> { + // A: Step 2. + let global = self.client.global(); + // A: Step 1 - let promise = Promise::new_in_current_realm(&*self.global(), comp); + let promise = Promise::new_in_current_realm(&*global, comp); let USVString(ref script_url) = script_url; - let api_base_url = self.global().api_base_url(); - // A: Step 3-5 + + // A: Step 3 + let api_base_url = global.api_base_url(); let script_url = match api_base_url.join(script_url) { Ok(url) => url, Err(_) => { + // B: Step 1 promise.reject_error(Error::Type("Invalid script URL".to_owned())); return promise; }, }; - // B: Step 2 + + // A: Step 4-5 + let scope = match options.scope { + Some(ref scope) => { + let &USVString(ref inner_scope) = scope; + match api_base_url.join(inner_scope) { + Ok(url) => url, + Err(_) => { + promise.reject_error(Error::Type("Invalid scope URL".to_owned())); + return promise; + }, + } + }, + None => script_url.join("./").unwrap(), + }; + + // A: Step 6 -> invoke B. + + // B: Step 3 match script_url.scheme() { "https" | "http" => {}, _ => { @@ -79,7 +109,7 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer { return promise; }, } - // B: Step 3 + // B: Step 4 if script_url.path().to_ascii_lowercase().contains("%2f") || script_url.path().to_ascii_lowercase().contains("%5c") { @@ -88,20 +118,7 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer { )); return promise; } - // B: Step 4-5 - let scope = match options.scope { - Some(ref scope) => { - let &USVString(ref inner_scope) = scope; - match api_base_url.join(inner_scope) { - Ok(url) => url, - Err(_) => { - promise.reject_error(Error::Type("Invalid scope URL".to_owned())); - return promise; - }, - } - }, - None => script_url.join("./").unwrap(), - }; + // B: Step 6 match scope.scheme() { "https" | "http" => {}, @@ -120,17 +137,134 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContainer { return promise; } - // B: Step 8 + // Setup the callback for reject/resolve of the promise, + // from steps running "in-parallel" from here in the serviceworker manager. + let (task_source, task_canceller) = ( + global.dom_manipulation_task_source(), + global.task_canceller(TaskSourceName::DOMManipulation), + ); + + let mut handler = RegisterJobResultHandler { + trusted_promise: Some(TrustedPromise::new(promise.clone())), + task_source, + task_canceller, + }; + + let (job_result_sender, job_result_receiver) = ipc::channel().expect("ipc channel failure"); + + ROUTER.add_route( + job_result_receiver.to_opaque(), + Box::new(move |message| { + let msg = message.to(); + match msg { + Ok(msg) => handler.handle(msg), + Err(err) => warn!("Error receiving a JobResult: {:?}", err), + } + }), + ); + + let scope_things = + ServiceWorkerRegistration::create_scope_things(&*global, script_url.clone()); + + // B: Step 8 - 13 let job = Job::create_job( JobType::Register, scope, script_url, - promise.clone(), - options.type_, - &*self.client, + job_result_sender, + self.client.creation_url(), + Some(scope_things), ); - // Job is unrooted here, do not do anything other than immediately scheduling - ScriptThread::schedule_job(job); + + // B: Step 14: schedule job. + let _ = global + .script_to_constellation_chan() + .send(ScriptMsg::ScheduleJob(job)); + + // A: Step 7 promise } } + +/// Callback for resolve/reject job promise for Register. +/// <https://w3c.github.io/ServiceWorker/#register> +struct RegisterJobResultHandler { + trusted_promise: Option<TrustedPromise>, + task_source: DOMManipulationTaskSource, + task_canceller: TaskCanceller, +} + +impl RegisterJobResultHandler { + /// <https://w3c.github.io/ServiceWorker/#reject-job-promise> + /// <https://w3c.github.io/ServiceWorker/#resolve-job-promise> + /// Handle a result to either resolve or reject the register job promise. + pub fn handle(&mut self, result: JobResult) { + match result { + JobResult::RejectPromise(error) => { + let promise = self + .trusted_promise + .take() + .expect("No promise to resolve for SW Register job."); + + // Step 1 + let _ = self.task_source.queue_with_canceller( + task!(reject_promise_with_security_error: move || { + let promise = promise.root(); + let _ac = enter_realm(&*promise.global()); + match error { + JobError::TypeError => { + promise.reject_error(Error::Type("Failed to register a ServiceWorker".to_string())); + }, + JobError::SecurityError => { + promise.reject_error(Error::Security); + }, + } + + }), + &self.task_canceller, + ); + + // TODO: step 2, handle equivalent jobs. + }, + JobResult::ResolvePromise(job, value) => { + let promise = self + .trusted_promise + .take() + .expect("No promise to resolve for SW Register job."); + + // Step 1 + let _ = self.task_source.queue_with_canceller( + task!(resolve_promise: move || { + let promise = promise.root(); + let global = promise.global(); + let _ac = enter_realm(&*global); + + // Step 1.1 + let JobResultValue::Registration { + id, + installing_worker, + waiting_worker, + active_worker, + } = value; + + // Step 1.2 (Job type is "register"). + let registration = global.get_serviceworker_registration( + &job.script_url, + &job.scope_url, + id, + installing_worker, + waiting_worker, + active_worker, + ); + + // Step 1.4 + promise.resolve_native(&*registration); + }), + &self.task_canceller, + ); + + // TODO: step 2, handle equivalent jobs. + }, + } + } +} diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index 9699262a874..a605e744ead 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -268,15 +268,12 @@ impl ServiceWorkerGlobalScope { } = scope_things; let serialized_worker_url = script_url.to_string(); - let origin = GlobalScope::current() - .expect("No current global object") - .origin() - .immutable() - .clone(); + let origin = scope_url.origin(); thread::Builder::new() .name(format!("ServiceWorker for {}", serialized_worker_url)) .spawn(move || { thread_state::initialize(ThreadState::SCRIPT | ThreadState::IN_WORKER); + let runtime = new_rt_and_cx(None); let roots = RootCollection::new(); let _stack_roots = ThreadLocalStackRoots::new(&roots); @@ -298,34 +295,19 @@ impl ServiceWorkerGlobalScope { .referrer_policy(referrer_policy) .origin(origin); - let (url, source) = match load_whole_resource( - request, - &init.resource_threads.sender(), - &GlobalScope::current().expect("No current global object"), - ) { - Err(_) => { - println!("error loading script {}", serialized_worker_url); - return; - }, - Ok((metadata, bytes)) => { - (metadata.final_url, String::from_utf8(bytes).unwrap()) - }, - }; - - let runtime = new_rt_and_cx(None); - - let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded(); - ROUTER - .route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan); - // Service workers are time limited // https://w3c.github.io/ServiceWorker/#service-worker-lifetime let sw_lifetime_timeout = pref!(dom.serviceworker.timeout_seconds) as u64; let time_out_port = after(Duration::new(sw_lifetime_timeout, 0)); + let (devtools_mpsc_chan, devtools_mpsc_port) = unbounded(); + ROUTER + .route_ipc_receiver_to_crossbeam_sender(devtools_receiver, devtools_mpsc_chan); + + let resource_threads_sender = init.resource_threads.sender(); let global = ServiceWorkerGlobalScope::new( init, - url, + script_url, devtools_mpsc_port, runtime, own_sender, @@ -334,6 +316,19 @@ impl ServiceWorkerGlobalScope { swmanager_sender, scope_url, ); + + let (_url, source) = + match load_whole_resource(request, &resource_threads_sender, &*global.upcast()) + { + Err(_) => { + println!("error loading script {}", serialized_worker_url); + return; + }, + Ok((metadata, bytes)) => { + (metadata.final_url, String::from_utf8(bytes).unwrap()) + }, + }; + let scope = global.upcast::<WorkerGlobalScope>(); unsafe { @@ -356,7 +351,7 @@ impl ServiceWorkerGlobalScope { // until the event loop is destroyed, // which happens after the closing flag is set to true, // or until the worker has run beyond its allocated time. - while !scope.is_closing() || !global.has_timed_out() { + while !scope.is_closing() && !global.has_timed_out() { run_worker_event_loop(&*global, None); } }, @@ -364,6 +359,7 @@ impl ServiceWorkerGlobalScope { scope.script_chan(), CommonScriptMsg::CollectReports, ); + scope.clear_js_runtime(); }) .expect("Thread spawning failed"); } @@ -390,15 +386,10 @@ impl ServiceWorkerGlobalScope { } fn has_timed_out(&self) -> bool { - // Note: this should be included in the `select` inside `run_worker_event_loop`, - // otherwise a block on the select can prevent the timeout. - if self.time_out_port.try_recv().is_ok() { - let _ = self - .swmanager_sender - .send(ServiceWorkerMsg::Timeout(self.scope_url.clone())); - return true; - } - false + // TODO: https://w3c.github.io/ServiceWorker/#service-worker-lifetime + // Since we don't have a shutdown mechanism yet, see #26548 + // immediately stop the event-loop after executing the initial script. + true } fn handle_script_event(&self, msg: ServiceWorkerScriptMsg) { diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs index 9bb578e0d59..0c1734b41cc 100644 --- a/components/script/dom/serviceworkerregistration.rs +++ b/components/script/dom/serviceworkerregistration.rs @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::codegen::Bindings::ServiceWorkerBinding::ServiceWorkerState; use crate::dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::ServiceWorkerRegistrationMethods; use crate::dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::ServiceWorkerUpdateViaCache; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; @@ -16,6 +15,7 @@ use crate::dom::serviceworker::ServiceWorker; use crate::dom::workerglobalscope::prepare_workerscope_init; use devtools_traits::WorkerId; use dom_struct::dom_struct; +use msg::constellation_msg::ServiceWorkerRegistrationId; use script_traits::{ScopeThings, WorkerScriptLoadOrigin}; use servo_url::ServoUrl; use std::cell::Cell; @@ -24,58 +24,60 @@ use uuid::Uuid; #[dom_struct] pub struct ServiceWorkerRegistration { eventtarget: EventTarget, - active: Option<Dom<ServiceWorker>>, - installing: Option<Dom<ServiceWorker>>, - waiting: Option<Dom<ServiceWorker>>, + active: DomRefCell<Option<Dom<ServiceWorker>>>, + installing: DomRefCell<Option<Dom<ServiceWorker>>>, + waiting: DomRefCell<Option<Dom<ServiceWorker>>>, navigation_preload: MutNullableDom<NavigationPreloadManager>, scope: ServoUrl, navigation_preload_enabled: Cell<bool>, navigation_preload_header_value: DomRefCell<Option<ByteString>>, update_via_cache: ServiceWorkerUpdateViaCache, uninstalling: Cell<bool>, + registration_id: ServiceWorkerRegistrationId, } impl ServiceWorkerRegistration { - fn new_inherited(active_sw: &ServiceWorker, scope: ServoUrl) -> ServiceWorkerRegistration { + fn new_inherited( + scope: ServoUrl, + registration_id: ServiceWorkerRegistrationId, + ) -> ServiceWorkerRegistration { ServiceWorkerRegistration { eventtarget: EventTarget::new_inherited(), - active: Some(Dom::from_ref(active_sw)), - installing: None, - waiting: None, + active: DomRefCell::new(None), + installing: DomRefCell::new(None), + waiting: DomRefCell::new(None), navigation_preload: MutNullableDom::new(None), scope: scope, navigation_preload_enabled: Cell::new(false), navigation_preload_header_value: DomRefCell::new(None), update_via_cache: ServiceWorkerUpdateViaCache::Imports, uninstalling: Cell::new(false), + registration_id, } } #[allow(unrooted_must_root)] pub fn new( global: &GlobalScope, - script_url: &ServoUrl, scope: ServoUrl, + registration_id: ServiceWorkerRegistrationId, ) -> DomRoot<ServiceWorkerRegistration> { - let active_worker = - ServiceWorker::install_serviceworker(global, script_url.clone(), scope.clone(), true); - active_worker.set_transition_state(ServiceWorkerState::Installed); - reflect_dom_object( Box::new(ServiceWorkerRegistration::new_inherited( - &*active_worker, scope, + registration_id, )), global, ) } - pub fn active(&self) -> Option<&ServiceWorker> { - self.active.as_ref().map(|sw| &**sw) + /// Does this registration have an active worker? + pub fn is_active(&self) -> bool { + self.active.borrow().is_some() } - pub fn get_installed(&self) -> &ServiceWorker { - self.active.as_ref().unwrap() + pub fn set_installing(&self, worker: &ServiceWorker) { + *self.installing.borrow_mut() = Some(Dom::from_ref(worker)); } pub fn get_navigation_preload_header_value(&self) -> Option<ByteString> { @@ -124,13 +126,14 @@ impl ServiceWorkerRegistration { // https://w3c.github.io/ServiceWorker/#get-newest-worker-algorithm pub fn get_newest_worker(&self) -> Option<DomRoot<ServiceWorker>> { - if self.installing.as_ref().is_some() { - self.installing.as_ref().map(|sw| DomRoot::from_ref(&**sw)) - } else if self.waiting.as_ref().is_some() { - self.waiting.as_ref().map(|sw| DomRoot::from_ref(&**sw)) - } else { - self.active.as_ref().map(|sw| DomRoot::from_ref(&**sw)) - } + let installing = self.installing.borrow(); + let waiting = self.waiting.borrow(); + let active = self.active.borrow(); + installing + .as_ref() + .map(|sw| DomRoot::from_ref(&**sw)) + .or_else(|| waiting.as_ref().map(|sw| DomRoot::from_ref(&**sw))) + .or_else(|| active.as_ref().map(|sw| DomRoot::from_ref(&**sw))) } } @@ -154,17 +157,26 @@ pub fn longest_prefix_match(stored_scope: &ServoUrl, potential_match: &ServoUrl) impl ServiceWorkerRegistrationMethods for ServiceWorkerRegistration { // https://w3c.github.io/ServiceWorker/#service-worker-registration-installing-attribute fn GetInstalling(&self) -> Option<DomRoot<ServiceWorker>> { - self.installing.as_ref().map(|sw| DomRoot::from_ref(&**sw)) + self.installing + .borrow() + .as_ref() + .map(|sw| DomRoot::from_ref(&**sw)) } // https://w3c.github.io/ServiceWorker/#service-worker-registration-active-attribute fn GetActive(&self) -> Option<DomRoot<ServiceWorker>> { - self.active.as_ref().map(|sw| DomRoot::from_ref(&**sw)) + self.active + .borrow() + .as_ref() + .map(|sw| DomRoot::from_ref(&**sw)) } // https://w3c.github.io/ServiceWorker/#service-worker-registration-waiting-attribute fn GetWaiting(&self) -> Option<DomRoot<ServiceWorker>> { - self.waiting.as_ref().map(|sw| DomRoot::from_ref(&**sw)) + self.waiting + .borrow() + .as_ref() + .map(|sw| DomRoot::from_ref(&**sw)) } // https://w3c.github.io/ServiceWorker/#service-worker-registration-scope-attribute diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 6e9490cb2c7..8d54c3f7da4 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -100,7 +100,7 @@ pub struct WorkerGlobalScope { #[ignore_malloc_size_of = "Arc"] closing: Option<Arc<AtomicBool>>, #[ignore_malloc_size_of = "Defined in js"] - runtime: Runtime, + runtime: DomRefCell<Option<Runtime>>, location: MutNullableDom<WorkerLocation>, navigator: MutNullableDom<WorkerNavigator>, @@ -151,7 +151,7 @@ impl WorkerGlobalScope { worker_type, worker_url: DomRefCell::new(worker_url), closing, - runtime, + runtime: DomRefCell::new(Some(runtime)), location: Default::default(), navigator: Default::default(), from_devtools_sender: init.from_devtools_sender, @@ -161,8 +161,17 @@ impl WorkerGlobalScope { } } + pub fn clear_js_runtime(&self) { + let runtime = self.runtime.borrow_mut().take(); + drop(runtime); + } + pub fn runtime_handle(&self) -> ParentRuntime { - self.runtime.prepare_for_new_child() + self.runtime + .borrow() + .as_ref() + .unwrap() + .prepare_for_new_child() } pub fn from_devtools_sender(&self) -> Option<IpcSender<DevtoolScriptControlMsg>> { @@ -175,7 +184,7 @@ impl WorkerGlobalScope { #[allow(unsafe_code)] pub fn get_cx(&self) -> JSContext { - unsafe { JSContext::from_ptr(self.runtime.cx()) } + unsafe { JSContext::from_ptr(self.runtime.borrow().as_ref().unwrap().cx()) } } pub fn is_closing(&self) -> bool { @@ -235,7 +244,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { }; } - rooted!(in(self.runtime.cx()) let mut rval = UndefinedValue()); + rooted!(in(self.runtime.borrow().as_ref().unwrap().cx()) let mut rval = UndefinedValue()); for url in urls { let global_scope = self.upcast::<GlobalScope>(); let request = NetRequestInit::new(url.clone()) @@ -256,7 +265,7 @@ impl WorkerGlobalScopeMethods for WorkerGlobalScope { Ok((metadata, bytes)) => (metadata.final_url, String::from_utf8(bytes).unwrap()), }; - let result = self.runtime.evaluate_script( + let result = self.runtime.borrow().as_ref().unwrap().evaluate_script( self.reflector().get_jsobject(), &source, url.as_str(), @@ -401,8 +410,9 @@ impl WorkerGlobalScope { #[allow(unsafe_code)] pub fn execute_script(&self, source: DOMString) { let _aes = AutoEntryScript::new(self.upcast()); - rooted!(in(self.runtime.cx()) let mut rval = UndefinedValue()); - match self.runtime.evaluate_script( + let cx = self.runtime.borrow().as_ref().unwrap().cx(); + rooted!(in(cx) let mut rval = UndefinedValue()); + match self.runtime.borrow().as_ref().unwrap().evaluate_script( self.reflector().get_jsobject(), &source, self.worker_url.borrow().as_str(), @@ -419,7 +429,7 @@ impl WorkerGlobalScope { println!("evaluate_script failed"); unsafe { let ar = enter_realm(&*self); - report_pending_exception(self.runtime.cx(), true, InRealm::Entered(&ar)); + report_pending_exception(cx, true, InRealm::Entered(&ar)); } } }, |