aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2016-06-02 06:18:59 -0500
committerbors-servo <lbergstrom+bors@mozilla.com>2016-06-02 06:18:59 -0500
commitcc017fc0b8619726f0c82649f41fdcf5595b19e4 (patch)
treee77fdc04eef71792a28898da24eb564f48432fe5 /components/script/dom
parent196adaff07201deb273077213fa63c460cc11629 (diff)
parent15a2064c0d7b468724b43d1cb6157d506ad19093 (diff)
downloadservo-cc017fc0b8619726f0c82649f41fdcf5595b19e4.tar.gz
servo-cc017fc0b8619726f0c82649f41fdcf5595b19e4.zip
Auto merge of #11114 - creativcoder:nav-sw, r=jdm
implement related service worker interface and register method Fixes #11091 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11114) <!-- Reviewable:end -->
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/abstractworker.rs104
-rw-r--r--components/script/dom/abstractworkerglobalscope.rs65
-rw-r--r--components/script/dom/bindings/str.rs1
-rw-r--r--components/script/dom/bindings/trace.rs7
-rw-r--r--components/script/dom/client.rs59
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs69
-rw-r--r--components/script/dom/mod.rs7
-rw-r--r--components/script/dom/navigator.rs8
-rw-r--r--components/script/dom/serviceworker.rs172
-rw-r--r--components/script/dom/serviceworkercontainer.rs104
-rw-r--r--components/script/dom/serviceworkerglobalscope.rs382
-rw-r--r--components/script/dom/serviceworkerregistration.rs67
-rw-r--r--components/script/dom/webidls/Client.webidl21
-rw-r--r--components/script/dom/webidls/Navigator.webidl5
-rw-r--r--components/script/dom/webidls/ServiceWorker.webidl25
-rw-r--r--components/script/dom/webidls/ServiceWorkerContainer.webidl27
-rw-r--r--components/script/dom/webidls/ServiceWorkerGlobalScope.webidl23
-rw-r--r--components/script/dom/webidls/ServiceWorkerRegistration.webidl20
-rw-r--r--components/script/dom/worker.rs145
-rw-r--r--components/script/dom/workerglobalscope.rs90
20 files changed, 1186 insertions, 215 deletions
diff --git a/components/script/dom/abstractworker.rs b/components/script/dom/abstractworker.rs
new file mode 100644
index 00000000000..f9ff583a0dd
--- /dev/null
+++ b/components/script/dom/abstractworker.rs
@@ -0,0 +1,104 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::refcounted::Trusted;
+use dom::bindings::reflector::Reflectable;
+use dom::bindings::str::DOMString;
+use dom::bindings::structuredclone::StructuredCloneData;
+use js::jsapi::{JSRuntime, JS_RequestInterruptCallback};
+use js::rust::Runtime;
+use msg::constellation_msg::{PipelineId, ReferrerPolicy};
+use net_traits::{LoadOrigin, RequestSource};
+use script_runtime::CommonScriptMsg;
+use url::Url;
+
+/// Messages used to control the worker event loops
+pub enum WorkerScriptMsg {
+ /// Common variants associated with the script messages
+ Common(CommonScriptMsg),
+ /// Message sent through Worker.postMessage
+ DOMMessage(StructuredCloneData),
+}
+
+#[derive(Clone)]
+pub struct WorkerScriptLoadOrigin {
+ pub referrer_url: Option<Url>,
+ pub referrer_policy: Option<ReferrerPolicy>,
+ pub request_source: RequestSource,
+ pub pipeline_id: Option<PipelineId>
+}
+
+impl LoadOrigin for WorkerScriptLoadOrigin {
+ fn referrer_url(&self) -> Option<Url> {
+ self.referrer_url.clone()
+ }
+ fn referrer_policy(&self) -> Option<ReferrerPolicy> {
+ self.referrer_policy.clone()
+ }
+ fn request_source(&self) -> RequestSource {
+ self.request_source.clone()
+ }
+ fn pipeline_id(&self) -> Option<PipelineId> {
+ self.pipeline_id.clone()
+ }
+}
+
+pub struct SimpleWorkerErrorHandler<T: Reflectable> {
+ pub addr: Trusted<T>,
+}
+
+impl<T: Reflectable> SimpleWorkerErrorHandler<T> {
+ pub fn new(addr: Trusted<T>) -> SimpleWorkerErrorHandler<T> {
+ SimpleWorkerErrorHandler {
+ addr: addr
+ }
+ }
+}
+
+pub struct WorkerErrorHandler<T: Reflectable> {
+ pub addr: Trusted<T>,
+ pub msg: DOMString,
+ pub file_name: DOMString,
+ pub line_num: u32,
+ pub col_num: u32,
+}
+
+impl<T: Reflectable> WorkerErrorHandler<T> {
+ pub fn new(addr: Trusted<T>, msg: DOMString, file_name: DOMString, line_num: u32, col_num: u32)
+ -> WorkerErrorHandler<T> {
+ WorkerErrorHandler {
+ addr: addr,
+ msg: msg,
+ file_name: file_name,
+ line_num: line_num,
+ col_num: col_num,
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct SharedRt {
+ pub rt: *mut JSRuntime
+}
+
+impl SharedRt {
+ pub fn new(rt: &Runtime) -> SharedRt {
+ SharedRt {
+ rt: rt.rt()
+ }
+ }
+
+ #[allow(unsafe_code)]
+ pub fn request_interrupt(&self) {
+ unsafe {
+ JS_RequestInterruptCallback(self.rt);
+ }
+ }
+
+ pub fn rt(&self) -> *mut JSRuntime {
+ self.rt
+ }
+}
+#[allow(unsafe_code)]
+unsafe impl Send for SharedRt {}
diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs
new file mode 100644
index 00000000000..e584e41c62a
--- /dev/null
+++ b/components/script/dom/abstractworkerglobalscope.rs
@@ -0,0 +1,65 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::abstractworker::WorkerScriptMsg;
+use dom::bindings::refcounted::Trusted;
+use dom::bindings::reflector::Reflectable;
+use script_runtime::{ScriptChan, CommonScriptMsg, ScriptPort};
+use std::sync::mpsc::{Receiver, Sender};
+
+/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
+/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
+/// Worker object will remain alive.
+#[derive(JSTraceable, Clone)]
+pub struct SendableWorkerScriptChan<T: Reflectable> {
+ pub sender: Sender<(Trusted<T>, CommonScriptMsg)>,
+ pub worker: Trusted<T>,
+}
+
+impl<T: Reflectable + 'static> ScriptChan for SendableWorkerScriptChan<T> {
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ self.sender.send((self.worker.clone(), msg)).map_err(|_| ())
+ }
+
+ fn clone(&self) -> Box<ScriptChan + Send> {
+ box SendableWorkerScriptChan {
+ sender: self.sender.clone(),
+ worker: self.worker.clone(),
+ }
+ }
+}
+
+/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
+/// worker event loop messages. While this SendableWorkerScriptChan is alive, the associated
+/// Worker object will remain alive.
+#[derive(JSTraceable, Clone)]
+pub struct WorkerThreadWorkerChan<T: Reflectable> {
+ pub sender: Sender<(Trusted<T>, WorkerScriptMsg)>,
+ pub worker: Trusted<T>,
+}
+
+impl<T: Reflectable + 'static> ScriptChan for WorkerThreadWorkerChan<T> {
+ fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
+ self.sender
+ .send((self.worker.clone(), WorkerScriptMsg::Common(msg)))
+ .map_err(|_| ())
+ }
+
+ fn clone(&self) -> Box<ScriptChan + Send> {
+ box WorkerThreadWorkerChan {
+ sender: self.sender.clone(),
+ worker: self.worker.clone(),
+ }
+ }
+}
+
+impl<T: Reflectable> ScriptPort for Receiver<(Trusted<T>, WorkerScriptMsg)> {
+ fn recv(&self) -> Result<CommonScriptMsg, ()> {
+ match self.recv().map(|(_, msg)| msg) {
+ Ok(WorkerScriptMsg::Common(script_msg)) => Ok(script_msg),
+ Ok(WorkerScriptMsg::DOMMessage(_)) => panic!("unexpected worker event message!"),
+ Err(_) => Err(()),
+ }
+ }
+}
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index 4c5f4b4fd6a..3ee685fbe02 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -81,6 +81,7 @@ impl ops::Deref for ByteString {
/// A string that is constructed from a UCS-2 buffer by replacing invalid code
/// points with the replacement character.
+#[derive(Clone, HeapSizeOf)]
pub struct USVString(pub String);
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 10a815fffa7..8a4913bfe20 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -34,12 +34,12 @@ use canvas_traits::{CompositionOrBlending, LineCapStyle, LineJoinStyle, Repetiti
use cssparser::RGBA;
use devtools_traits::CSSError;
use devtools_traits::WorkerId;
+use dom::abstractworker::SharedRt;
use dom::bindings::js::{JS, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, Reflector};
-use dom::bindings::str::DOMString;
+use dom::bindings::str::{DOMString, USVString};
use dom::bindings::utils::WindowProxyHandler;
-use dom::worker::SharedRt;
use encoding::types::EncodingRef;
use euclid::length::Length as EuclidLength;
use euclid::matrix2d::Matrix2D;
@@ -81,6 +81,7 @@ use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::mpsc::{Receiver, Sender};
+use std::time::SystemTime;
use string_cache::{Atom, Namespace, QualName};
use style::attr::{AttrIdentifier, AttrValue};
use style::element_state::*;
@@ -320,8 +321,10 @@ no_jsmanaged_fields!(ElementSnapshot);
no_jsmanaged_fields!(HttpsState);
no_jsmanaged_fields!(SharedRt);
no_jsmanaged_fields!(TouchpadPressurePhase);
+no_jsmanaged_fields!(USVString);
no_jsmanaged_fields!(ReferrerPolicy);
no_jsmanaged_fields!(ResourceThreads);
+no_jsmanaged_fields!(SystemTime);
impl JSTraceable for Box<ScriptChan + Send> {
#[inline]
diff --git a/components/script/dom/client.rs b/components/script/dom/client.rs
new file mode 100644
index 00000000000..1039ff1a04a
--- /dev/null
+++ b/components/script/dom/client.rs
@@ -0,0 +1,59 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::ClientBinding::FrameType;
+use dom::bindings::codegen::Bindings::ClientBinding::{ClientMethods, Wrap};
+use dom::bindings::global::GlobalRef;
+use dom::bindings::js::JS;
+use dom::bindings::js::Root;
+use dom::bindings::reflector::{Reflector, reflect_dom_object};
+use dom::bindings::str::{DOMString, USVString};
+use dom::serviceworker::ServiceWorker;
+use dom::window::Window;
+use url::Url;
+use uuid::Uuid;
+
+#[dom_struct]
+pub struct Client {
+ reflector_: Reflector,
+ active_worker: Option<JS<ServiceWorker>>,
+ url: USVString,
+ frame_type: FrameType,
+ #[ignore_heap_size_of = "Defined in uuid"]
+ id: Uuid
+}
+
+impl Client {
+ fn new_inherited(url: Url) -> Client {
+ Client {
+ reflector_: Reflector::new(),
+ active_worker: None,
+ url: USVString(url.as_str().to_owned()),
+ frame_type: FrameType::None,
+ id: Uuid::new_v4()
+ }
+ }
+
+ pub fn new(window: &Window) -> Root<Client> {
+ reflect_dom_object(box Client::new_inherited(window.get_url()), GlobalRef::Window(window), Wrap)
+ }
+}
+
+impl ClientMethods for Client {
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#client-url-attribute
+ fn Url(&self) -> USVString {
+ self.url.clone()
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#client-frametype
+ fn FrameType(&self) -> FrameType {
+ self.frame_type
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#client-id
+ fn Id(&self) -> DOMString {
+ let uid_str = format!("{}", self.id);
+ DOMString::from_string(uid_str)
+ }
+}
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 3dae1d3cff4..dfa1672715b 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -4,6 +4,8 @@
use devtools;
use devtools_traits::DevtoolScriptControlMsg;
+use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt , SimpleWorkerErrorHandler};
+use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
@@ -17,8 +19,7 @@ use dom::bindings::reflector::Reflectable;
use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData;
use dom::messageevent::MessageEvent;
-use dom::worker::{SimpleWorkerErrorHandler, SharedRt, TrustedWorkerAddress};
-use dom::worker::{WorkerScriptLoadOrigin, WorkerMessageHandler};
+use dom::worker::{TrustedWorkerAddress, WorkerMessageHandler};
use dom::workerglobalscope::WorkerGlobalScope;
use dom::workerglobalscope::WorkerGlobalScopeInit;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
@@ -40,70 +41,6 @@ use url::Url;
use util::thread::spawn_named_with_send_on_panic;
use util::thread_state::{IN_WORKER, SCRIPT};
-/// Messages used to control the worker event loops
-pub enum WorkerScriptMsg {
- /// Common variants associated with the script messages
- Common(CommonScriptMsg),
- /// Message sent through Worker.postMessage
- DOMMessage(StructuredCloneData),
-}
-
-/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
-/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
-/// Worker object will remain alive.
-#[derive(JSTraceable, Clone)]
-pub struct SendableWorkerScriptChan {
- sender: Sender<(TrustedWorkerAddress, CommonScriptMsg)>,
- worker: TrustedWorkerAddress,
-}
-
-impl ScriptChan for SendableWorkerScriptChan {
- fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
- self.sender.send((self.worker.clone(), msg)).map_err(|_| ())
- }
-
- fn clone(&self) -> Box<ScriptChan + Send> {
- box SendableWorkerScriptChan {
- sender: self.sender.clone(),
- worker: self.worker.clone(),
- }
- }
-}
-
-/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
-/// worker event loop messages. While this SendableWorkerScriptChan is alive, the associated
-/// Worker object will remain alive.
-#[derive(JSTraceable, Clone)]
-pub struct WorkerThreadWorkerChan {
- sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- worker: TrustedWorkerAddress,
-}
-
-impl ScriptChan for WorkerThreadWorkerChan {
- fn send(&self, msg: CommonScriptMsg) -> Result<(), ()> {
- self.sender
- .send((self.worker.clone(), WorkerScriptMsg::Common(msg)))
- .map_err(|_| ())
- }
-
- fn clone(&self) -> Box<ScriptChan + Send> {
- box WorkerThreadWorkerChan {
- sender: self.sender.clone(),
- worker: self.worker.clone(),
- }
- }
-}
-
-impl ScriptPort for Receiver<(TrustedWorkerAddress, WorkerScriptMsg)> {
- fn recv(&self) -> Result<CommonScriptMsg, ()> {
- match self.recv().map(|(_, msg)| msg) {
- Ok(WorkerScriptMsg::Common(script_msg)) => Ok(script_msg),
- Ok(WorkerScriptMsg::DOMMessage(_)) => panic!("unexpected worker event message!"),
- Err(_) => Err(()),
- }
- }
-}
-
/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
/// value for the duration of this object's lifetime. This ensures that the related Worker
/// object only lives as long as necessary (ie. while events are being executed), while
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index a5d8e7a707a..ff1a4638998 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -209,6 +209,8 @@ pub mod types {
include!(concat!(env!("OUT_DIR"), "/InterfaceTypes.rs"));
}
+pub mod abstractworker;
+pub mod abstractworkerglobalscope;
pub mod activation;
pub mod attr;
pub mod beforeunloadevent;
@@ -231,6 +233,7 @@ pub mod canvasgradient;
pub mod canvaspattern;
pub mod canvasrenderingcontext2d;
pub mod characterdata;
+pub mod client;
pub mod closeevent;
pub mod comment;
pub mod console;
@@ -363,6 +366,10 @@ pub mod progressevent;
pub mod radionodelist;
pub mod range;
pub mod screen;
+pub mod serviceworker;
+pub mod serviceworkercontainer;
+pub mod serviceworkerglobalscope;
+pub mod serviceworkerregistration;
pub mod servohtmlparser;
pub mod servoxmlparser;
pub mod storage;
diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs
index 8a17b2dbc17..75bd2c13c23 100644
--- a/components/script/dom/navigator.rs
+++ b/components/script/dom/navigator.rs
@@ -12,6 +12,7 @@ use dom::bluetooth::Bluetooth;
use dom::mimetypearray::MimeTypeArray;
use dom::navigatorinfo;
use dom::pluginarray::PluginArray;
+use dom::serviceworkercontainer::ServiceWorkerContainer;
use dom::window::Window;
#[dom_struct]
@@ -20,6 +21,7 @@ pub struct Navigator {
bluetooth: MutNullableHeap<JS<Bluetooth>>,
plugins: MutNullableHeap<JS<PluginArray>>,
mime_types: MutNullableHeap<JS<MimeTypeArray>>,
+ serviceWorker: MutNullableHeap<JS<ServiceWorkerContainer>>,
}
impl Navigator {
@@ -29,6 +31,7 @@ impl Navigator {
bluetooth: Default::default(),
plugins: Default::default(),
mime_types: Default::default(),
+ serviceWorker: Default::default(),
}
}
@@ -99,4 +102,9 @@ impl NavigatorMethods for Navigator {
fn JavaEnabled(&self) -> bool {
false
}
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#navigator-service-worker-attribute
+ fn ServiceWorker(&self) -> Root<ServiceWorkerContainer> {
+ self.serviceWorker.or_init(|| ServiceWorkerContainer::new(self.global().r()))
+ }
}
diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs
new file mode 100644
index 00000000000..5122bcf5f0d
--- /dev/null
+++ b/components/script/dom/serviceworker.rs
@@ -0,0 +1,172 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerErrorHandler};
+use dom::abstractworker::{WorkerScriptMsg, WorkerScriptLoadOrigin, SharedRt};
+use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap};
+use dom::bindings::global::GlobalRef;
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::Root;
+use dom::bindings::refcounted::Trusted;
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
+use dom::bindings::str::{DOMString, USVString};
+use dom::client::Client;
+use dom::errorevent::ErrorEvent;
+use dom::event::{Event, EventBubbles, EventCancelable};
+use dom::eventtarget::EventTarget;
+use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
+use dom::workerglobalscope::prepare_workerscope_init;
+use ipc_channel::ipc;
+use js::jsapi::RootedValue;
+use js::jsval::UndefinedValue;
+use script_thread::Runnable;
+use std::cell::Cell;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::mpsc::{Sender, channel};
+use std::sync::{Arc, Mutex};
+use url::Url;
+
+pub type TrustedServiceWorkerAddress = Trusted<ServiceWorker>;
+
+#[dom_struct]
+pub struct ServiceWorker {
+ eventtarget: EventTarget,
+ script_url: DOMRefCell<String>,
+ state: Cell<ServiceWorkerState>,
+ closing: Arc<AtomicBool>,
+ #[ignore_heap_size_of = "Defined in std"]
+ sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ #[ignore_heap_size_of = "Defined in rust-mozjs"]
+ runtime: Arc<Mutex<Option<SharedRt>>>,
+ skip_waiting: Cell<bool>
+}
+
+impl ServiceWorker {
+ fn new_inherited(sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ closing: Arc<AtomicBool>,
+ script_url: &str,
+ skip_waiting: bool) -> ServiceWorker {
+ ServiceWorker {
+ eventtarget: EventTarget::new_inherited(),
+ closing: closing,
+ sender: sender,
+ script_url: DOMRefCell::new(String::from(script_url)),
+ state: Cell::new(ServiceWorkerState::Installing),
+ runtime: Arc::new(Mutex::new(None)),
+ skip_waiting: Cell::new(skip_waiting)
+ }
+ }
+
+ pub fn new(global: GlobalRef,
+ closing: Arc<AtomicBool>,
+ sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ script_url: &str,
+ skip_waiting: bool) -> Root<ServiceWorker> {
+ reflect_dom_object(box ServiceWorker::new_inherited(sender, closing, script_url, skip_waiting), global, Wrap)
+ }
+
+ pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) {
+ let service_worker = address.root();
+ service_worker.upcast().fire_simple_event("error");
+ }
+
+ pub fn is_closing(&self) -> bool {
+ self.closing.load(Ordering::SeqCst)
+ }
+
+ pub fn set_transition_state(&self, state: ServiceWorkerState) {
+ self.state.set(state);
+ self.upcast::<EventTarget>().fire_simple_event("statechange");
+ }
+
+ pub fn handle_error_message(address: TrustedServiceWorkerAddress, message: DOMString,
+ filename: DOMString, lineno: u32, colno: u32) {
+ let worker = address.root();
+
+ if worker.is_closing() {
+ return;
+ }
+
+ let global = worker.r().global();
+ let error = RootedValue::new(global.r().get_cx(), UndefinedValue());
+ let errorevent = ErrorEvent::new(global.r(), atom!("error"),
+ EventBubbles::Bubbles, EventCancelable::Cancelable,
+ message, filename, lineno, colno, error.handle());
+ errorevent.upcast::<Event>().fire(worker.upcast());
+ }
+
+ #[allow(unsafe_code)]
+ pub fn init_service_worker(global: GlobalRef,
+ script_url: Url,
+ skip_waiting: bool) -> Root<ServiceWorker> {
+ let (sender, receiver) = channel();
+ let closing = Arc::new(AtomicBool::new(false));
+ let worker = ServiceWorker::new(global,
+ closing.clone(),
+ sender.clone(),
+ script_url.as_str(),
+ skip_waiting);
+ let worker_ref = Trusted::new(worker.r());
+
+ let worker_load_origin = WorkerScriptLoadOrigin {
+ referrer_url: None,
+ referrer_policy: None,
+ request_source: global.request_source(),
+ pipeline_id: Some(global.pipeline())
+ };
+
+ let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
+ let init = prepare_workerscope_init(global,
+ "Service Worker".to_owned(),
+ script_url.clone(),
+ devtools_sender.clone(),
+ closing);
+
+ // represents a service worker client
+ let sw_client = Client::new(global.as_window());
+ let trusted_client = Trusted::new(&*sw_client);
+
+ ServiceWorkerGlobalScope::run_serviceworker_scope(
+ init, script_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref,
+ global.script_chan(), sender, receiver, trusted_client, worker_load_origin);
+
+ worker
+ }
+}
+
+impl ServiceWorkerMethods for ServiceWorker {
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-state-attribute
+ fn State(&self) -> ServiceWorkerState {
+ self.state.get()
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-url-attribute
+ fn ScriptURL(&self) -> USVString {
+ USVString(self.script_url.borrow().clone())
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-onerror-attribute
+ event_handler!(error, GetOnerror, SetOnerror);
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#ref-for-service-worker-onstatechange-attribute-1
+ event_handler!(statechange, GetOnstatechange, SetOnstatechange);
+}
+
+impl Runnable for SimpleWorkerErrorHandler<ServiceWorker> {
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<SimpleWorkerErrorHandler<ServiceWorker>>) {
+ let this = *self;
+ ServiceWorker::dispatch_simple_error(this.addr);
+ }
+}
+
+impl Runnable for WorkerErrorHandler<ServiceWorker> {
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<WorkerErrorHandler<ServiceWorker>>) {
+ let this = *self;
+ ServiceWorker::handle_error_message(this.addr, this.msg, this.file_name, this.line_num, this.col_num);
+ }
+}
diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs
new file mode 100644
index 00000000000..744daba7b91
--- /dev/null
+++ b/components/script/dom/serviceworkercontainer.rs
@@ -0,0 +1,104 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::RegistrationOptions;
+use dom::bindings::codegen::Bindings::ServiceWorkerContainerBinding::{ServiceWorkerContainerMethods, Wrap};
+use dom::bindings::error::{Error, Fallible};
+use dom::bindings::global::GlobalRef;
+use dom::bindings::js::{JS, MutNullableHeap, Root};
+use dom::bindings::reflector::{Reflectable, reflect_dom_object};
+use dom::bindings::str::USVString;
+use dom::eventtarget::EventTarget;
+use dom::serviceworker::ServiceWorker;
+use dom::serviceworkerregistration::ServiceWorkerRegistration;
+use script_thread::ScriptThread;
+use std::ascii::AsciiExt;
+use std::default::Default;
+
+#[dom_struct]
+pub struct ServiceWorkerContainer {
+ eventtarget: EventTarget,
+ controller: MutNullableHeap<JS<ServiceWorker>>,
+}
+
+impl ServiceWorkerContainer {
+ fn new_inherited() -> ServiceWorkerContainer {
+ ServiceWorkerContainer {
+ eventtarget: EventTarget::new_inherited(),
+ controller: Default::default(),
+ }
+ }
+
+ pub fn new(global: GlobalRef) -> Root<ServiceWorkerContainer> {
+ reflect_dom_object(box ServiceWorkerContainer::new_inherited(), global, Wrap)
+ }
+}
+
+pub trait Controllable {
+ fn set_controller(&self, active_worker: &ServiceWorker);
+}
+
+impl Controllable for ServiceWorkerContainer {
+ fn set_controller(&self, active_worker: &ServiceWorker) {
+ self.controller.set(Some(active_worker))
+ }
+}
+
+impl ServiceWorkerContainerMethods for ServiceWorkerContainer {
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-controller-attribute
+ fn GetController(&self) -> Option<Root<ServiceWorker>> {
+ return self.controller.get()
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container-register-method
+ fn Register(&self,
+ script_url: USVString,
+ options: &RegistrationOptions) -> Fallible<Root<ServiceWorkerRegistration>> {
+ let USVString(ref script_url) = script_url;
+ // Step 3-4
+ let script_url = match self.global().r().api_base_url().join(script_url) {
+ Ok(url) => url,
+ Err(_) => return Err(Error::Type("Invalid script URL".to_owned()))
+ };
+ // Step 5
+ match script_url.scheme() {
+ "https" | "http" => {},
+ _ => return Err(Error::Type("Only secure origins are allowed".to_owned()))
+ }
+ // Step 6
+ if script_url.path().to_ascii_lowercase().contains("%2f") ||
+ script_url.path().to_ascii_lowercase().contains("%5c") {
+ return Err(Error::Type("Script URL contains forbidden characters".to_owned()));
+ }
+ // Step 8-9
+ let scope = match options.scope {
+ Some(ref scope) => {
+ let &USVString(ref inner_scope) = scope;
+ match self.global().r().api_base_url().join(inner_scope) {
+ Ok(url) => url,
+ Err(_) => return Err(Error::Type("Invalid scope URL".to_owned()))
+ }
+ },
+ None => script_url.join("./").unwrap()
+ };
+ // Step 11
+ match scope.scheme() {
+ "https" | "http" => {},
+ _ => return Err(Error::Type("Only secure origins are allowed".to_owned()))
+ }
+ // Step 12
+ if scope.path().to_ascii_lowercase().contains("%2f") ||
+ scope.path().to_ascii_lowercase().contains("%5c") {
+ return Err(Error::Type("Scope URL contains forbidden characters".to_owned()));
+ }
+
+ let scope_str = scope.as_str().to_owned();
+ let worker_registration = ServiceWorkerRegistration::new(self.global().r(),
+ script_url,
+ scope_str.clone(),
+ self);
+ ScriptThread::set_registration(scope, &*worker_registration);
+ Ok(worker_registration)
+ }
+}
diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs
new file mode 100644
index 00000000000..4039be05403
--- /dev/null
+++ b/components/script/dom/serviceworkerglobalscope.rs
@@ -0,0 +1,382 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use devtools;
+use devtools_traits::DevtoolScriptControlMsg;
+use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg, SharedRt, SimpleWorkerErrorHandler};
+use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
+use dom::bindings::cell::DOMRefCell;
+use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
+use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding;
+use dom::bindings::codegen::Bindings::ServiceWorkerGlobalScopeBinding::ServiceWorkerGlobalScopeMethods;
+use dom::bindings::global::{GlobalRef, global_root_from_context};
+use dom::bindings::inheritance::Castable;
+use dom::bindings::js::{Root, RootCollection};
+use dom::bindings::refcounted::{Trusted, LiveDOMReferences};
+use dom::bindings::reflector::Reflectable;
+use dom::bindings::str::DOMString;
+use dom::client::Client;
+use dom::messageevent::MessageEvent;
+use dom::serviceworker::TrustedServiceWorkerAddress;
+use dom::workerglobalscope::WorkerGlobalScope;
+use dom::workerglobalscope::WorkerGlobalScopeInit;
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::router::ROUTER;
+use js::jsapi::{JS_SetInterruptCallback, JSAutoCompartment, JSContext, RootedValue};
+use js::jsval::UndefinedValue;
+use js::rust::Runtime;
+use msg::constellation_msg::PipelineId;
+use net_traits::{LoadContext, load_whole_resource, CustomResponse, IpcSend};
+use rand::random;
+use script_runtime::ScriptThreadEventCategory::ServiceWorkerEvent;
+use script_runtime::{CommonScriptMsg, ScriptChan, ScriptPort, StackRootTLS, get_reports, new_rt_and_cx};
+use script_traits::{TimerEvent, TimerSource};
+use std::mem::replace;
+use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
+use std::sync::{Arc, Mutex};
+use std::time::Instant;
+use url::Url;
+use util::prefs;
+use util::thread::spawn_named;
+use util::thread_state;
+use util::thread_state::{IN_WORKER, SCRIPT};
+
+/// Set the `worker` field of a related ServiceWorkerGlobalScope object to a particular
+/// value for the duration of this object's lifetime. This ensures that the related Worker
+/// object only lives as long as necessary (ie. while events are being executed), while
+/// providing a reference that can be cloned freely.
+struct AutoWorkerReset<'a> {
+ workerscope: &'a ServiceWorkerGlobalScope,
+ old_worker: Option<TrustedServiceWorkerAddress>,
+}
+
+impl<'a> AutoWorkerReset<'a> {
+ fn new(workerscope: &'a ServiceWorkerGlobalScope,
+ worker: TrustedServiceWorkerAddress)
+ -> AutoWorkerReset<'a> {
+ AutoWorkerReset {
+ workerscope: workerscope,
+ old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)),
+ }
+ }
+}
+
+impl<'a> Drop for AutoWorkerReset<'a> {
+ fn drop(&mut self) {
+ *self.workerscope.worker.borrow_mut() = self.old_worker.clone();
+ }
+}
+
+enum MixedMessage {
+ FromServiceWorker((TrustedServiceWorkerAddress, WorkerScriptMsg)),
+ FromScheduler((TrustedServiceWorkerAddress, TimerEvent)),
+ FromDevtools(DevtoolScriptControlMsg),
+ FromNetwork(IpcSender<Option<CustomResponse>>),
+}
+
+#[dom_struct]
+pub struct ServiceWorkerGlobalScope {
+ workerglobalscope: WorkerGlobalScope,
+ id: PipelineId,
+ #[ignore_heap_size_of = "Defined in std"]
+ receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ #[ignore_heap_size_of = "Defined in std"]
+ own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ #[ignore_heap_size_of = "Defined in std"]
+ timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
+ #[ignore_heap_size_of = "Trusted<T> has unclear ownership like JS<T>"]
+ worker: DOMRefCell<Option<TrustedServiceWorkerAddress>>,
+ #[ignore_heap_size_of = "Can't measure trait objects"]
+ /// Sender to the parent thread.
+ parent_sender: Box<ScriptChan + Send>,
+ #[ignore_heap_size_of = "Defined in std"]
+ service_worker_client: Trusted<Client>
+}
+
+impl ServiceWorkerGlobalScope {
+ fn new_inherited(init: WorkerGlobalScopeInit,
+ worker_url: Url,
+ id: PipelineId,
+ from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
+ runtime: Runtime,
+ parent_sender: Box<ScriptChan + Send>,
+ own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ timer_event_chan: IpcSender<TimerEvent>,
+ timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
+ client: Trusted<Client>)
+ -> ServiceWorkerGlobalScope {
+ ServiceWorkerGlobalScope {
+ workerglobalscope: WorkerGlobalScope::new_inherited(init,
+ worker_url,
+ runtime,
+ from_devtools_receiver,
+ timer_event_chan),
+ id: id,
+ receiver: receiver,
+ own_sender: own_sender,
+ timer_event_port: timer_event_port,
+ parent_sender: parent_sender,
+ worker: DOMRefCell::new(None),
+ service_worker_client: client
+ }
+ }
+
+ pub fn new(init: WorkerGlobalScopeInit,
+ worker_url: Url,
+ id: PipelineId,
+ from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
+ runtime: Runtime,
+ parent_sender: Box<ScriptChan + Send>,
+ own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ timer_event_chan: IpcSender<TimerEvent>,
+ timer_event_port: Receiver<(TrustedServiceWorkerAddress, TimerEvent)>,
+ client: Trusted<Client>)
+ -> Root<ServiceWorkerGlobalScope> {
+ let cx = runtime.cx();
+ let scope = box ServiceWorkerGlobalScope::new_inherited(init,
+ worker_url,
+ id,
+ from_devtools_receiver,
+ runtime,
+ parent_sender,
+ own_sender,
+ receiver,
+ timer_event_chan,
+ timer_event_port,
+ client);
+ ServiceWorkerGlobalScopeBinding::Wrap(cx, scope)
+ }
+
+ #[allow(unsafe_code)]
+ pub fn run_serviceworker_scope(init: WorkerGlobalScopeInit,
+ worker_url: Url,
+ id: PipelineId,
+ from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
+ main_thread_rt: Arc<Mutex<Option<SharedRt>>>,
+ worker: TrustedServiceWorkerAddress,
+ parent_sender: Box<ScriptChan + Send>,
+ own_sender: Sender<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ receiver: Receiver<(TrustedServiceWorkerAddress, WorkerScriptMsg)>,
+ client: Trusted<Client>,
+ worker_load_origin: WorkerScriptLoadOrigin) {
+ let serialized_worker_url = worker_url.to_string();
+ spawn_named(format!("ServiceWorker for {}", serialized_worker_url), move || {
+ thread_state::initialize(SCRIPT | IN_WORKER);
+
+ let roots = RootCollection::new();
+ let _stack_roots_tls = StackRootTLS::new(&roots);
+
+ let (url, source) = match load_whole_resource(LoadContext::Script,
+ &init.resource_threads.sender(),
+ worker_url,
+ &worker_load_origin) {
+ Err(_) => {
+ println!("error loading script {}", serialized_worker_url);
+ parent_sender.send(CommonScriptMsg::RunnableMsg(ServiceWorkerEvent,
+ box SimpleWorkerErrorHandler::new(worker))).unwrap();
+ return;
+ }
+ Ok((metadata, bytes)) => {
+ (metadata.final_url, String::from_utf8(bytes).unwrap())
+ }
+ };
+
+ let runtime = unsafe { new_rt_and_cx() };
+ *main_thread_rt.lock().unwrap() = Some(SharedRt::new(&runtime));
+
+ let (devtools_mpsc_chan, devtools_mpsc_port) = channel();
+ ROUTER.route_ipc_receiver_to_mpsc_sender(from_devtools_receiver, devtools_mpsc_chan);
+
+ let (timer_tx, timer_rx) = channel();
+ let (timer_ipc_chan, timer_ipc_port) = ipc::channel().unwrap();
+ let worker_for_route = worker.clone();
+ ROUTER.add_route(timer_ipc_port.to_opaque(), box move |message| {
+ let event = message.to().unwrap();
+ timer_tx.send((worker_for_route.clone(), event)).unwrap();
+ });
+
+ let global = ServiceWorkerGlobalScope::new(
+ init, url, id, devtools_mpsc_port, runtime,
+ parent_sender.clone(), own_sender, receiver,
+ timer_ipc_chan, timer_rx, client);
+ // FIXME(njn): workers currently don't have a unique ID suitable for using in reporter
+ // registration (#6631), so we instead use a random number and cross our fingers.
+ let scope = global.upcast::<WorkerGlobalScope>();
+
+ unsafe {
+ // Handle interrupt requests
+ JS_SetInterruptCallback(scope.runtime(), Some(interrupt_callback));
+ }
+
+ if scope.is_closing() {
+ return;
+ }
+
+ {
+ let _ar = AutoWorkerReset::new(global.r(), worker);
+ scope.execute_script(DOMString::from(source));
+ }
+
+
+ let reporter_name = format!("service-worker-reporter-{}", random::<u64>());
+ scope.mem_profiler_chan().run_with_memory_reporting(|| {
+ // Service workers are time limited
+ let sw_lifetime = Instant::now();
+ let sw_lifetime_timeout = prefs::get_pref("dom.serviceworker.timeout_seconds").as_u64().unwrap();
+ while let Ok(event) = global.receive_event() {
+ if scope.is_closing() {
+ break;
+ }
+ global.handle_event(event);
+ if sw_lifetime.elapsed().as_secs() == sw_lifetime_timeout {
+ break;
+ }
+ }
+ }, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
+ });
+ }
+
+ fn handle_event(&self, event: MixedMessage) {
+ match event {
+ MixedMessage::FromDevtools(msg) => {
+ let global_ref = GlobalRef::Worker(self.upcast());
+ match msg {
+ DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) =>
+ devtools::handle_evaluate_js(&global_ref, string, sender),
+ DevtoolScriptControlMsg::GetCachedMessages(pipe_id, message_types, sender) =>
+ devtools::handle_get_cached_messages(pipe_id, message_types, sender),
+ DevtoolScriptControlMsg::WantsLiveNotifications(_pipe_id, bool_val) =>
+ devtools::handle_wants_live_notifications(&global_ref, bool_val),
+ _ => debug!("got an unusable devtools control message inside the worker!"),
+ }
+ },
+ MixedMessage::FromScheduler((linked_worker, timer_event)) => {
+ match timer_event {
+ TimerEvent(TimerSource::FromWorker, id) => {
+ let _ar = AutoWorkerReset::new(self, linked_worker);
+ let scope = self.upcast::<WorkerGlobalScope>();
+ scope.handle_fire_timer(id);
+ },
+ TimerEvent(_, _) => {
+ panic!("The service worker received a TimerEvent from a window.")
+ }
+ }
+ }
+ MixedMessage::FromServiceWorker((linked_worker, msg)) => {
+ let _ar = AutoWorkerReset::new(self, linked_worker);
+ self.handle_script_event(msg);
+ },
+ MixedMessage::FromNetwork(network_sender) => {
+ // We send None as of now
+ let _ = network_sender.send(None);
+ }
+ }
+ }
+
+ fn handle_script_event(&self, msg: WorkerScriptMsg) {
+ match msg {
+ WorkerScriptMsg::DOMMessage(data) => {
+ let scope = self.upcast::<WorkerGlobalScope>();
+ let target = self.upcast();
+ let _ac = JSAutoCompartment::new(scope.get_cx(),
+ scope.reflector().get_jsobject().get());
+ let mut message = RootedValue::new(scope.get_cx(), UndefinedValue());
+ data.read(GlobalRef::Worker(scope), message.handle_mut());
+ MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle());
+ },
+ WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable)) => {
+ runnable.handler()
+ },
+ WorkerScriptMsg::Common(CommonScriptMsg::RefcountCleanup(addr)) => {
+ LiveDOMReferences::cleanup(addr);
+ },
+ WorkerScriptMsg::Common(CommonScriptMsg::CollectReports(reports_chan)) => {
+ let scope = self.upcast::<WorkerGlobalScope>();
+ let cx = scope.get_cx();
+ let path_seg = format!("url({})", scope.get_url());
+ let reports = get_reports(cx, path_seg);
+ reports_chan.send(reports);
+ },
+ }
+ }
+
+ #[allow(unsafe_code)]
+ fn receive_event(&self) -> Result<MixedMessage, RecvError> {
+ let scope = self.upcast::<WorkerGlobalScope>();
+ let worker_port = &self.receiver;
+ let timer_event_port = &self.timer_event_port;
+ let devtools_port = scope.from_devtools_receiver();
+ let msg_port = scope.custom_message_port();
+
+ let sel = Select::new();
+ let mut worker_handle = sel.handle(worker_port);
+ let mut timer_event_handle = sel.handle(timer_event_port);
+ let mut devtools_handle = sel.handle(devtools_port);
+ let mut msg_port_handle = sel.handle(msg_port);
+ unsafe {
+ worker_handle.add();
+ timer_event_handle.add();
+ if scope.from_devtools_sender().is_some() {
+ devtools_handle.add();
+ }
+ msg_port_handle.add();
+ }
+ let ret = sel.wait();
+ if ret == worker_handle.id() {
+ Ok(MixedMessage::FromServiceWorker(try!(worker_port.recv())))
+ } else if ret == timer_event_handle.id() {
+ Ok(MixedMessage::FromScheduler(try!(timer_event_port.recv())))
+ } else if ret == devtools_handle.id() {
+ Ok(MixedMessage::FromDevtools(try!(devtools_port.recv())))
+ } else if ret == msg_port_handle.id() {
+ Ok(MixedMessage::FromNetwork(try!(msg_port.recv())))
+ } else {
+ panic!("unexpected select result!")
+ }
+ }
+
+ pub fn script_chan(&self) -> Box<ScriptChan + Send> {
+ box WorkerThreadWorkerChan {
+ sender: self.own_sender.clone(),
+ worker: self.worker.borrow().as_ref().unwrap().clone(),
+ }
+ }
+
+ pub fn pipeline(&self) -> PipelineId {
+ self.id
+ }
+
+ pub fn process_event(&self, msg: CommonScriptMsg) {
+ self.handle_script_event(WorkerScriptMsg::Common(msg));
+ }
+
+ pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
+ let (tx, rx) = channel();
+ let chan = box SendableWorkerScriptChan {
+ sender: tx,
+ worker: self.worker.borrow().as_ref().unwrap().clone(),
+ };
+ (chan, box rx)
+ }
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn interrupt_callback(cx: *mut JSContext) -> bool {
+ let global = global_root_from_context(cx);
+ let worker = match global.r() {
+ GlobalRef::Worker(w) => w,
+ _ => panic!("global for worker is not a worker scope")
+ };
+ assert!(worker.is::<ServiceWorkerGlobalScope>());
+
+ // A false response causes the script to terminate
+ !worker.is_closing()
+}
+
+impl ServiceWorkerGlobalScopeMethods for ServiceWorkerGlobalScope {
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-global-scope-onmessage-attribute
+ event_handler!(message, GetOnmessage, SetOnmessage);
+}
diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs
new file mode 100644
index 00000000000..358331afffc
--- /dev/null
+++ b/components/script/dom/serviceworkerregistration.rs
@@ -0,0 +1,67 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::ServiceWorkerBinding::ServiceWorkerState;
+use dom::bindings::codegen::Bindings::ServiceWorkerRegistrationBinding::{ServiceWorkerRegistrationMethods, Wrap};
+use dom::bindings::global::GlobalRef;
+use dom::bindings::js::{JS, Root};
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::USVString;
+use dom::eventtarget::EventTarget;
+use dom::serviceworker::ServiceWorker;
+use dom::serviceworkercontainer::Controllable;
+use url::Url;
+
+#[dom_struct]
+pub struct ServiceWorkerRegistration {
+ eventtarget: EventTarget,
+ active: Option<JS<ServiceWorker>>,
+ installing: Option<JS<ServiceWorker>>,
+ waiting: Option<JS<ServiceWorker>>,
+ scope: String,
+}
+
+impl ServiceWorkerRegistration {
+ fn new_inherited(active_sw: &ServiceWorker, scope: String) -> ServiceWorkerRegistration {
+ ServiceWorkerRegistration {
+ eventtarget: EventTarget::new_inherited(),
+ active: Some(JS::from_ref(active_sw)),
+ installing: None,
+ waiting: None,
+ scope: scope
+ }
+ }
+ #[allow(unrooted_must_root)]
+ pub fn new(global: GlobalRef,
+ script_url: Url,
+ scope: String,
+ container: &Controllable) -> Root<ServiceWorkerRegistration> {
+ let active_worker = ServiceWorker::init_service_worker(global, script_url, true);
+ active_worker.set_transition_state(ServiceWorkerState::Installed);
+ container.set_controller(&*active_worker.clone());
+ reflect_dom_object(box ServiceWorkerRegistration::new_inherited(&*active_worker, scope), global, Wrap)
+ }
+}
+
+impl ServiceWorkerRegistrationMethods for ServiceWorkerRegistration {
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-registration-installing-attribute
+ fn GetInstalling(&self) -> Option<Root<ServiceWorker>> {
+ self.installing.as_ref().map(|sw| Root::from_ref(&**sw))
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-registration-active-attribute
+ fn GetActive(&self) -> Option<Root<ServiceWorker>> {
+ self.active.as_ref().map(|sw| Root::from_ref(&**sw))
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-registration-waiting-attribute
+ fn GetWaiting(&self) -> Option<Root<ServiceWorker>> {
+ self.waiting.as_ref().map(|sw| Root::from_ref(&**sw))
+ }
+
+ // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-registration-scope-attribute
+ fn Scope(&self) -> USVString {
+ USVString(self.scope.clone())
+ }
+}
diff --git a/components/script/dom/webidls/Client.webidl b/components/script/dom/webidls/Client.webidl
new file mode 100644
index 00000000000..b74218aa787
--- /dev/null
+++ b/components/script/dom/webidls/Client.webidl
@@ -0,0 +1,21 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#client
+
+// [Exposed=ServiceWorker]
+[Pref="dom.serviceworker.enabled"]
+interface Client {
+ readonly attribute USVString url;
+ readonly attribute FrameType frameType;
+ readonly attribute DOMString id;
+ //void postMessage(any message, optional sequence<Transferable> transfer);
+};
+
+enum FrameType {
+ "auxiliary",
+ "top-level",
+ "nested",
+ "none"
+};
diff --git a/components/script/dom/webidls/Navigator.webidl b/components/script/dom/webidls/Navigator.webidl
index 4d9ead9f7f9..ca9b4a36a4a 100644
--- a/components/script/dom/webidls/Navigator.webidl
+++ b/components/script/dom/webidls/Navigator.webidl
@@ -31,6 +31,11 @@ interface NavigatorBluetooth {
readonly attribute Bluetooth bluetooth;
};
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#navigator-service-worker
+partial interface Navigator {
+ [SameObject, Pref="dom.serviceworker.enabled"] readonly attribute ServiceWorkerContainer serviceWorker;
+};
+
// https://html.spec.whatwg.org/multipage/#navigatorlanguage
[NoInterfaceObject/*, Exposed=Window,Worker*/]
interface NavigatorLanguage {
diff --git a/components/script/dom/webidls/ServiceWorker.webidl b/components/script/dom/webidls/ServiceWorker.webidl
new file mode 100644
index 00000000000..4718b164ce0
--- /dev/null
+++ b/components/script/dom/webidls/ServiceWorker.webidl
@@ -0,0 +1,25 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// http://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-obj
+//[Exposed=(Window,Worker)]
+[Pref="dom.serviceworker.enabled"]
+interface ServiceWorker : EventTarget {
+ readonly attribute USVString scriptURL;
+ readonly attribute ServiceWorkerState state;
+ //[Throws] void postMessage(any message/*, optional sequence<Transferable> transfer*/);
+
+ // event
+ attribute EventHandler onstatechange;
+};
+
+ServiceWorker implements AbstractWorker;
+
+enum ServiceWorkerState {
+ "installing",
+ "installed",
+ "activating",
+ "activated",
+ "redundant"
+};
diff --git a/components/script/dom/webidls/ServiceWorkerContainer.webidl b/components/script/dom/webidls/ServiceWorkerContainer.webidl
new file mode 100644
index 00000000000..3c28bb8994d
--- /dev/null
+++ b/components/script/dom/webidls/ServiceWorkerContainer.webidl
@@ -0,0 +1,27 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-container
+// [Exposed=(Window,Worker)]
+[Pref="dom.serviceworker.enabled"]
+interface ServiceWorkerContainer : EventTarget {
+ [Unforgeable] readonly attribute ServiceWorker? controller;
+ //[SameObject] readonly attribute Promise<ServiceWorkerRegistration> ready;
+
+ [NewObject, Throws] ServiceWorkerRegistration register(USVString scriptURL, optional RegistrationOptions options);
+
+ //[NewObject] /*Promise<any>*/ any getRegistration(optional USVString clientURL = "");
+ //[NewObject] /* Promise */<sequence<ServiceWorkerRegistration>> getRegistrations();
+
+
+ // events
+ //attribute EventHandler oncontrollerchange;
+ //attribute EventHandler onerror;
+ //attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
+};
+
+dictionary RegistrationOptions {
+ USVString scope;
+ //WorkerType type = "classic";
+};
diff --git a/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl b/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl
new file mode 100644
index 00000000000..0b630fb3b1e
--- /dev/null
+++ b/components/script/dom/webidls/ServiceWorkerGlobalScope.webidl
@@ -0,0 +1,23 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-global-scope
+
+[Global, Pref="dom.serviceworker.enabled"/*=(Worker,ServiceWorker), Exposed=ServiceWorker*/]
+interface ServiceWorkerGlobalScope : WorkerGlobalScope {
+ // A container for a list of Client objects that correspond to
+ // browsing contexts (or shared workers) that are on the origin of this SW
+ //[SameObject] readonly attribute Clients clients;
+ //[SameObject] readonly attribute ServiceWorkerRegistration registration;
+
+ //[NewObject] Promise<void> skipWaiting();
+
+ //attribute EventHandler oninstall;
+ //attribute EventHandler onactivate;
+ //attribute EventHandler onfetch;
+ //attribute EventHandler onforeignfetch;
+
+ // event
+ attribute EventHandler onmessage; // event.source of the message events is Client object
+};
diff --git a/components/script/dom/webidls/ServiceWorkerRegistration.webidl b/components/script/dom/webidls/ServiceWorkerRegistration.webidl
new file mode 100644
index 00000000000..c6c36f22475
--- /dev/null
+++ b/components/script/dom/webidls/ServiceWorkerRegistration.webidl
@@ -0,0 +1,20 @@
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+// https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-registration-obj
+//[Exposed=(Window,Worker)]
+[Pref="dom.serviceworker.enabled"]
+interface ServiceWorkerRegistration : EventTarget {
+ [Unforgeable] readonly attribute ServiceWorker? installing;
+ [Unforgeable] readonly attribute ServiceWorker? waiting;
+ [Unforgeable] readonly attribute ServiceWorker? active;
+
+ readonly attribute USVString scope;
+
+ // [NewObject] Promise<void> update();
+ // [NewObject] Promise<boolean> unregister();
+
+ // event
+ // attribute EventHandler onupdatefound;
+};
diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs
index 11802a8e0b2..5762e2aa63f 100644
--- a/components/script/dom/worker.rs
+++ b/components/script/dom/worker.rs
@@ -2,7 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg};
+
+use dom::abstractworker::{SimpleWorkerErrorHandler, SharedRt, WorkerErrorHandler};
+use dom::abstractworker::{WorkerScriptLoadOrigin, WorkerScriptMsg};
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::WorkerBinding;
use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods;
@@ -14,24 +16,19 @@ use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bindings::structuredclone::StructuredCloneData;
-use dom::dedicatedworkerglobalscope::{DedicatedWorkerGlobalScope, WorkerScriptMsg};
+use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::errorevent::ErrorEvent;
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::messageevent::MessageEvent;
-use dom::workerglobalscope::WorkerGlobalScopeInit;
+use dom::workerglobalscope::prepare_workerscope_init;
use ipc_channel::ipc;
-use js::jsapi::{HandleValue, JSContext, JSRuntime, RootedValue};
-use js::jsapi::{JSAutoCompartment, JS_RequestInterruptCallback};
+use js::jsapi::{HandleValue, JSContext, RootedValue, JSAutoCompartment};
use js::jsval::UndefinedValue;
-use js::rust::Runtime;
-use msg::constellation_msg::{PipelineId, ReferrerPolicy};
-use net_traits::{RequestSource, LoadOrigin};
use script_thread::Runnable;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{Sender, channel};
use std::sync::{Arc, Mutex};
-use url::Url;
pub type TrustedWorkerAddress = Trusted<Worker>;
@@ -48,29 +45,6 @@ pub struct Worker {
runtime: Arc<Mutex<Option<SharedRt>>>
}
-#[derive(Clone)]
-pub struct WorkerScriptLoadOrigin {
- referrer_url: Option<Url>,
- referrer_policy: Option<ReferrerPolicy>,
- request_source: RequestSource,
- pipeline_id: Option<PipelineId>
-}
-
-impl LoadOrigin for WorkerScriptLoadOrigin {
- fn referrer_url(&self) -> Option<Url> {
- self.referrer_url.clone()
- }
- fn referrer_policy(&self) -> Option<ReferrerPolicy> {
- self.referrer_policy.clone()
- }
- fn request_source(&self) -> RequestSource {
- self.request_source.clone()
- }
- fn pipeline_id(&self) -> Option<PipelineId> {
- self.pipeline_id.clone()
- }
-}
-
impl Worker {
fn new_inherited(sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
closing: Arc<AtomicBool>) -> Worker {
@@ -99,15 +73,10 @@ impl Worker {
Err(_) => return Err(Error::Syntax),
};
- let resource_threads = global.resource_threads();
- let constellation_chan = global.constellation_chan().clone();
- let scheduler_chan = global.scheduler_chan().clone();
-
let (sender, receiver) = channel();
let closing = Arc::new(AtomicBool::new(false));
let worker = Worker::new(global, sender.clone(), closing.clone());
let worker_ref = Trusted::new(worker.r());
- let worker_id = global.get_next_worker_id();
let worker_load_origin = WorkerScriptLoadOrigin {
referrer_url: None,
@@ -117,34 +86,12 @@ impl Worker {
};
let (devtools_sender, devtools_receiver) = ipc::channel().unwrap();
- let optional_sender = match global.devtools_chan() {
- Some(ref chan) => {
- let pipeline_id = global.pipeline();
- let title = format!("Worker for {}", worker_url);
- let page_info = DevtoolsPageInfo {
- title: title,
- url: worker_url.clone(),
- };
- chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)),
- devtools_sender.clone(),
- page_info)).unwrap();
- Some(devtools_sender)
- },
- None => None,
- };
- let init = WorkerGlobalScopeInit {
- resource_threads: resource_threads,
- mem_profiler_chan: global.mem_profiler_chan().clone(),
- time_profiler_chan: global.time_profiler_chan().clone(),
- to_devtools_sender: global.devtools_chan(),
- from_devtools_sender: optional_sender,
- constellation_chan: constellation_chan,
- scheduler_chan: scheduler_chan,
- panic_chan: global.panic_chan().clone(),
- worker_id: worker_id,
- closing: closing,
- };
+ let init = prepare_workerscope_init(global,
+ "Worker".to_owned(),
+ worker_url.clone(),
+ devtools_sender.clone(),
+ closing);
DedicatedWorkerGlobalScope::run_worker_scope(
init, worker_url, global.pipeline(), devtools_receiver, worker.runtime.clone(), worker_ref,
@@ -245,76 +192,18 @@ impl Runnable for WorkerMessageHandler {
}
}
-pub struct SimpleWorkerErrorHandler {
- addr: TrustedWorkerAddress,
-}
-
-impl SimpleWorkerErrorHandler {
- pub fn new(addr: TrustedWorkerAddress) -> SimpleWorkerErrorHandler {
- SimpleWorkerErrorHandler {
- addr: addr
- }
- }
-}
-
-impl Runnable for SimpleWorkerErrorHandler {
- fn handler(self: Box<SimpleWorkerErrorHandler>) {
+impl Runnable for SimpleWorkerErrorHandler<Worker> {
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<SimpleWorkerErrorHandler<Worker>>) {
let this = *self;
Worker::dispatch_simple_error(this.addr);
}
}
-pub struct WorkerErrorHandler {
- addr: TrustedWorkerAddress,
- msg: DOMString,
- file_name: DOMString,
- line_num: u32,
- col_num: u32,
-}
-
-impl WorkerErrorHandler {
- pub fn new(addr: TrustedWorkerAddress, msg: DOMString, file_name: DOMString, line_num: u32, col_num: u32)
- -> WorkerErrorHandler {
- WorkerErrorHandler {
- addr: addr,
- msg: msg,
- file_name: file_name,
- line_num: line_num,
- col_num: col_num,
- }
- }
-}
-
-impl Runnable for WorkerErrorHandler {
- fn handler(self: Box<WorkerErrorHandler>) {
+impl Runnable for WorkerErrorHandler<Worker> {
+ #[allow(unrooted_must_root)]
+ fn handler(self: Box<WorkerErrorHandler<Worker>>) {
let this = *self;
Worker::handle_error_message(this.addr, this.msg, this.file_name, this.line_num, this.col_num);
}
}
-
-#[derive(Copy, Clone)]
-pub struct SharedRt {
- rt: *mut JSRuntime
-}
-
-impl SharedRt {
- pub fn new(rt: &Runtime) -> SharedRt {
- SharedRt {
- rt: rt.rt()
- }
- }
-
- #[allow(unsafe_code)]
- pub fn request_interrupt(&self) {
- unsafe {
- JS_RequestInterruptCallback(self.rt);
- }
- }
-
- pub fn rt(&self) -> *mut JSRuntime {
- self.rt
- }
-}
-
-#[allow(unsafe_code)]
-unsafe impl Send for SharedRt {}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index 95c476649b8..06b3894ded3 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
+use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId, DevtoolsPageInfo};
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
use dom::bindings::codegen::Bindings::WorkerGlobalScopeBinding::WorkerGlobalScopeMethods;
use dom::bindings::error::{Error, ErrorResult, Fallible, report_pending_exception};
@@ -15,6 +15,7 @@ use dom::console::Console;
use dom::crypto::Crypto;
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::eventtarget::EventTarget;
+use dom::serviceworkerglobalscope::ServiceWorkerGlobalScope;
use dom::window::{base64_atob, base64_btoa};
use dom::workerlocation::WorkerLocation;
use dom::workernavigator::WorkerNavigator;
@@ -57,6 +58,44 @@ pub struct WorkerGlobalScopeInit {
pub closing: Arc<AtomicBool>,
}
+pub fn prepare_workerscope_init(global: GlobalRef,
+ worker_type: String,
+ worker_url: Url,
+ devtools_sender: IpcSender<DevtoolScriptControlMsg>,
+ closing: Arc<AtomicBool>) -> WorkerGlobalScopeInit {
+ let worker_id = global.get_next_worker_id();
+ let optional_sender = match global.devtools_chan() {
+ Some(ref chan) => {
+ let pipeline_id = global.pipeline();
+ let title = format!("{} for {}", worker_type, worker_url);
+ let page_info = DevtoolsPageInfo {
+ title: title,
+ url: worker_url,
+ };
+ chan.send(ScriptToDevtoolsControlMsg::NewGlobal((pipeline_id, Some(worker_id)),
+ devtools_sender.clone(),
+ page_info)).unwrap();
+ Some(devtools_sender)
+ },
+ None => None,
+ };
+
+ let init = WorkerGlobalScopeInit {
+ resource_threads: global.resource_threads(),
+ mem_profiler_chan: global.mem_profiler_chan().clone(),
+ to_devtools_sender: global.devtools_chan(),
+ time_profiler_chan: global.time_profiler_chan().clone(),
+ from_devtools_sender: optional_sender,
+ constellation_chan: global.constellation_chan().clone(),
+ panic_chan: global.panic_chan().clone(),
+ scheduler_chan: global.scheduler_chan().clone(),
+ worker_id: worker_id,
+ closing: closing,
+ };
+
+ init
+}
+
// https://html.spec.whatwg.org/multipage/#the-workerglobalscope-common-interface
#[dom_struct]
pub struct WorkerGlobalScope {
@@ -392,36 +431,49 @@ impl WorkerGlobalScope {
pub fn script_chan(&self) -> Box<ScriptChan + Send> {
let dedicated =
self.downcast::<DedicatedWorkerGlobalScope>();
- match dedicated {
- Some(dedicated) => dedicated.script_chan(),
- None => panic!("need to implement a sender for SharedWorker"),
+ let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
+ if let Some(dedicated) = dedicated {
+ return dedicated.script_chan();
+ } else if let Some(service_worker) = service_worker {
+ return service_worker.script_chan();
+ } else {
+ panic!("need to implement a sender for SharedWorker")
}
}
pub fn pipeline(&self) -> PipelineId {
- let dedicated =
- self.downcast::<DedicatedWorkerGlobalScope>();
- match dedicated {
- Some(dedicated) => dedicated.pipeline(),
- None => panic!("need to add a pipeline for SharedWorker"),
+ let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
+ let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
+ if let Some(dedicated) = dedicated {
+ return dedicated.pipeline();
+ } else if let Some(service_worker) = service_worker {
+ return service_worker.pipeline();
+ } else {
+ panic!("need to implement a sender for SharedWorker")
}
}
pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
- let dedicated =
- self.downcast::<DedicatedWorkerGlobalScope>();
- match dedicated {
- Some(dedicated) => dedicated.new_script_pair(),
- None => panic!("need to implement creating isolated event loops for SharedWorker"),
+ let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
+ let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
+ if let Some(dedicated) = dedicated {
+ return dedicated.new_script_pair();
+ } else if let Some(service_worker) = service_worker {
+ return service_worker.new_script_pair();
+ } else {
+ panic!("need to implement a sender for SharedWorker")
}
}
pub fn process_event(&self, msg: CommonScriptMsg) {
- let dedicated =
- self.downcast::<DedicatedWorkerGlobalScope>();
- match dedicated {
- Some(dedicated) => dedicated.process_event(msg),
- None => panic!("need to implement processing single events for SharedWorker"),
+ let dedicated = self.downcast::<DedicatedWorkerGlobalScope>();
+ let service_worker = self.downcast::<ServiceWorkerGlobalScope>();
+ if let Some(dedicated) = dedicated {
+ return dedicated.process_event(msg);
+ } else if let Some(service_worker) = service_worker {
+ return service_worker.process_event(msg);
+ } else {
+ panic!("need to implement a sender for SharedWorker")
}
}