aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/trace.rs4
-rw-r--r--components/script/dom/client.rs1
-rw-r--r--components/script/dom/globalscope.rs78
-rw-r--r--components/script/dom/navigationpreloadmanager.rs8
-rw-r--r--components/script/dom/serviceworker.rs17
-rw-r--r--components/script/dom/serviceworkercontainer.rs194
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs63
-rw-r--r--components/script/dom/serviceworkerregistration.rs68
-rw-r--r--components/script/dom/workerglobalscope.rs28
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(&registration_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));
}
}
},