diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 5c9b52b7f72e..46e0109d0d51 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -738,12 +738,6 @@ impl Constellation // store service worker manager for communicating with it. self.swmanager_chan = Some(sw_sender); } - SWManagerMsg::ConnectServiceWorker(scope_url, pipeline_id, msg_chan) => { - if let Some(ref parent_info) = self.pipelines.get(&pipeline_id) { - let from_cons_msg = ConstellationControlMsg::ConnectServiceWorker(scope_url, msg_chan); - let _ = parent_info.script_chan.send(from_cons_msg); - } - } } } @@ -1006,6 +1000,13 @@ impl Constellation debug!("constellation got store registration scope message"); self.handle_register_serviceworker(scope_things, scope); } + FromScriptMsg::ForwardDOMMessage(msg_vec, scope_url) => { + if let Some(ref mgr) = self.swmanager_chan { + let _ = mgr.send(ServiceWorkerMsg::ForwardDOMMessage(msg_vec, scope_url)); + } else { + warn!("Unable to forward DOMMessage for postMessage call"); + } + } } } diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index cb0fbce3092a..1078ffcacc8e 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -11,6 +11,7 @@ use js::jsapi::{HandleValue, MutableHandleValue}; use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_STRUCTURED_CLONE_VERSION}; use js::jsapi::{JS_ClearPendingException, JS_WriteStructuredClone}; use libc::size_t; +use script_traits::DOMMessage; use std::ptr; use std::slice; @@ -46,15 +47,18 @@ impl StructuredCloneData { }) } - /// Converts a StructuredCloneData to Vec - pub fn move_to_arraybuffer(self) -> Vec { + /// Converts a StructuredCloneData to Vec for inter-thread sharing + pub fn move_to_arraybuffer(self) -> DOMMessage { unsafe { - slice::from_raw_parts(self.data, self.nbytes).to_vec() + DOMMessage(slice::from_raw_parts(self.data as *mut u8, self.nbytes).to_vec()) } } - /// Converts back to StructuredCloneData using a pointer and no of bytes - pub fn make_structured_clone(data: *mut u64, nbytes: size_t) -> StructuredCloneData { + /// Converts back to StructuredCloneData + pub fn make_structured_clone(data: DOMMessage) -> StructuredCloneData { + let DOMMessage(mut data) = data; + let nbytes = data.len(); + let data = data.as_mut_ptr() as *mut u64; StructuredCloneData { data: data, nbytes: nbytes diff --git a/components/script/dom/serviceworker.rs b/components/script/dom/serviceworker.rs index 5ae9025c7f12..e966173921f0 100644 --- a/components/script/dom/serviceworker.rs +++ b/components/script/dom/serviceworker.rs @@ -6,7 +6,7 @@ use dom::abstractworker::SimpleWorkerErrorHandler; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull; use dom::bindings::codegen::Bindings::ServiceWorkerBinding::{ServiceWorkerMethods, ServiceWorkerState, Wrap}; -use dom::bindings::error::ErrorResult; +use dom::bindings::error::{ErrorResult, Error}; use dom::bindings::global::GlobalRef; use dom::bindings::inheritance::Castable; use dom::bindings::js::Root; @@ -15,10 +15,9 @@ use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::USVString; use dom::bindings::structuredclone::StructuredCloneData; use dom::eventtarget::EventTarget; -use ipc_channel::ipc::IpcSender; use js::jsapi::{HandleValue, JSContext}; use script_thread::Runnable; -use script_traits::DOMMessage; +use script_traits::ScriptMsg; use std::cell::Cell; use url::Url; @@ -28,28 +27,29 @@ pub type TrustedServiceWorkerAddress = Trusted; pub struct ServiceWorker { eventtarget: EventTarget, script_url: DOMRefCell, + scope_url: DOMRefCell, state: Cell, - #[ignore_heap_size_of = "Defined in std"] - msg_sender: DOMRefCell>>, skip_waiting: Cell } impl ServiceWorker { fn new_inherited(script_url: &str, - skip_waiting: bool) -> ServiceWorker { + skip_waiting: bool, + scope_url: &str) -> ServiceWorker { ServiceWorker { eventtarget: EventTarget::new_inherited(), script_url: DOMRefCell::new(String::from(script_url)), state: Cell::new(ServiceWorkerState::Installing), - skip_waiting: Cell::new(skip_waiting), - msg_sender: DOMRefCell::new(None) + scope_url: DOMRefCell::new(String::from(scope_url)), + skip_waiting: Cell::new(skip_waiting) } } pub fn new(global: GlobalRef, script_url: &str, + scope_url: &str, skip_waiting: bool) -> Root { - reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting), global, Wrap) + reflect_dom_object(box ServiceWorker::new_inherited(script_url, skip_waiting, scope_url), global, Wrap) } pub fn dispatch_simple_error(address: TrustedServiceWorkerAddress) { @@ -68,18 +68,13 @@ impl ServiceWorker { pub fn install_serviceworker(global: GlobalRef, script_url: Url, + scope_url: &str, skip_waiting: bool) -> Root { ServiceWorker::new(global, script_url.as_str(), + scope_url, skip_waiting) } - - pub fn store_sender(trusted_worker: TrustedServiceWorkerAddress, sender: IpcSender) { - let worker = trusted_worker.root(); - // This channel is used for sending message from the ServiceWorker object to its - // corresponding ServiceWorkerGlobalScope - *worker.msg_sender.borrow_mut() = Some(sender); - } } impl ServiceWorkerMethods for ServiceWorker { @@ -95,13 +90,15 @@ impl ServiceWorkerMethods for ServiceWorker { // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/#service-worker-postmessage fn PostMessage(&self, cx: *mut JSContext, message: HandleValue) -> ErrorResult { - let data = try!(StructuredCloneData::write(cx, message)); - let msg_vec = DOMMessage(data.move_to_arraybuffer()); - if let Some(ref sender) = *self.msg_sender.borrow() { - let _ = sender.send(msg_vec); - } else { - warn!("Could not communicate message to ServiceWorkerGlobalScope"); + // Step 1 + if let ServiceWorkerState::Redundant = self.state.get() { + return Err(Error::InvalidState); } + // Step 7 + let data = try!(StructuredCloneData::write(cx, message)); + let msg_vec = data.move_to_arraybuffer(); + let scope_url = Url::parse(&*self.scope_url.borrow()).unwrap(); + let _ = self.global().r().constellation_chan().send(ScriptMsg::ForwardDOMMessage(msg_vec, scope_url)); Ok(()) } diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index f9c95d9af537..0403b66ae872 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -13,7 +13,6 @@ use dom::bindings::inheritance::Castable; use dom::bindings::js::{Root, RootCollection}; use dom::bindings::reflector::Reflectable; use dom::bindings::str::DOMString; -use dom::bindings::structuredclone::StructuredCloneData; use dom::eventtarget::EventTarget; use dom::messageevent::MessageEvent; use dom::workerglobalscope::WorkerGlobalScope; @@ -26,12 +25,11 @@ use msg::constellation_msg::PipelineId; use net_traits::{LoadContext, load_whole_resource, IpcSend, CustomResponseMediator}; use rand::random; use script_runtime::{CommonScriptMsg, StackRootTLS, get_reports, new_rt_and_cx, ScriptChan}; -use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg, DOMMessage}; +use script_traits::{TimerEvent, WorkerGlobalScopeInit, ScopeThings, ServiceWorkerMsg}; use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel}; use std::thread; use std::time::Duration; -use style::thread_state; -use style::thread_state::{IN_WORKER, SCRIPT}; +use style::thread_state::{self, IN_WORKER, SCRIPT}; use url::Url; use util::prefs::PREFS; use util::thread::spawn_named; @@ -47,11 +45,9 @@ pub enum ServiceWorkerScriptMsg { pub enum MixedMessage { FromServiceWorker(ServiceWorkerScriptMsg), FromDevtools(DevtoolScriptControlMsg), - FromTimeoutThread(()), - PostMessage(DOMMessage) + FromTimeoutThread(()) } -// Required for run_with_memory_reporting #[derive(JSTraceable, Clone)] pub struct ServiceWorkerChan { pub sender: Sender @@ -83,9 +79,6 @@ pub struct ServiceWorkerGlobalScope { timer_event_port: Receiver<()>, #[ignore_heap_size_of = "Defined in std"] swmanager_sender: IpcSender, - #[ignore_heap_size_of = "Defined in std"] - msg_port: Receiver, - #[ignore_heap_size_of = "Defined in std"] scope_url: Url, } @@ -100,8 +93,7 @@ impl ServiceWorkerGlobalScope { timer_event_chan: IpcSender, timer_event_port: Receiver<()>, swmanager_sender: IpcSender, - scope_url: Url, - msg_port: Receiver) + scope_url: Url) -> ServiceWorkerGlobalScope { ServiceWorkerGlobalScope { workerglobalscope: WorkerGlobalScope::new_inherited(init, @@ -115,8 +107,7 @@ impl ServiceWorkerGlobalScope { timer_event_port: timer_event_port, own_sender: own_sender, swmanager_sender: swmanager_sender, - scope_url: scope_url, - msg_port: msg_port + scope_url: scope_url } } @@ -130,8 +121,7 @@ impl ServiceWorkerGlobalScope { timer_event_chan: IpcSender, timer_event_port: Receiver<()>, swmanager_sender: IpcSender, - scope_url: Url, - msg_port: Receiver) + scope_url: Url) -> Root { let cx = runtime.cx(); let scope = box ServiceWorkerGlobalScope::new_inherited(init, @@ -144,8 +134,7 @@ impl ServiceWorkerGlobalScope { timer_event_chan, timer_event_port, swmanager_sender, - scope_url, - msg_port); + scope_url); ServiceWorkerGlobalScopeBinding::Wrap(cx, scope) } @@ -155,8 +144,7 @@ impl ServiceWorkerGlobalScope { receiver: Receiver, devtools_receiver: IpcReceiver, swmanager_sender: IpcSender, - scope_url: Url, - msg_port: Receiver) { + scope_url: Url) { let ScopeThings { script_url, pipeline_id, init, @@ -191,7 +179,7 @@ impl ServiceWorkerGlobalScope { let global = ServiceWorkerGlobalScope::new( init, url, pipeline_id, devtools_mpsc_port, runtime, own_sender, receiver, - timer_ipc_chan, timer_port, swmanager_sender, scope_url, msg_port); + timer_ipc_chan, timer_port, swmanager_sender, scope_url); let scope = global.upcast::(); unsafe { @@ -238,17 +226,6 @@ impl ServiceWorkerGlobalScope { self.handle_script_event(msg); true } - MixedMessage::PostMessage(data) => { - let DOMMessage(mut data) = data; - let data = StructuredCloneData::make_structured_clone(data.as_mut_ptr(), data.len()); - let scope = self.upcast::(); - let target = self.upcast(); - let _ac = JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get()); - rooted!(in(scope.get_cx()) let mut message = UndefinedValue()); - data.read(GlobalRef::Worker(scope), message.handle_mut()); - MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle()); - true - } MixedMessage::FromTimeoutThread(_) => { let _ = self.swmanager_sender.send(ServiceWorkerMsg::Timeout(self.scope_url.clone())); false @@ -260,7 +237,14 @@ impl ServiceWorkerGlobalScope { use self::ServiceWorkerScriptMsg::*; match msg { - CommonWorker(WorkerScriptMsg::DOMMessage(_)) => { }, + CommonWorker(WorkerScriptMsg::DOMMessage(data)) => { + let scope = self.upcast::(); + let target = self.upcast(); + let _ac = JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get()); + rooted!(in(scope.get_cx()) let mut message = UndefinedValue()); + data.read(GlobalRef::Worker(scope), message.handle_mut()); + MessageEvent::dispatch_jsval(target, GlobalRef::Worker(scope), message.handle()); + }, CommonWorker(WorkerScriptMsg::Common(CommonScriptMsg::RunnableMsg(_, runnable))) => { runnable.handler() }, @@ -287,20 +271,17 @@ impl ServiceWorkerGlobalScope { let worker_port = &self.receiver; let devtools_port = scope.from_devtools_receiver(); let timer_event_port = &self.timer_event_port; - let msg_port = &self.msg_port; let sel = Select::new(); let mut worker_handle = sel.handle(worker_port); let mut devtools_handle = sel.handle(devtools_port); let mut timer_port_handle = sel.handle(timer_event_port); - let mut msg_port_handle = sel.handle(msg_port); unsafe { worker_handle.add(); if scope.from_devtools_sender().is_some() { devtools_handle.add(); } timer_port_handle.add(); - msg_port_handle.add(); } let ret = sel.wait(); @@ -310,8 +291,6 @@ impl ServiceWorkerGlobalScope { Ok(MixedMessage::FromDevtools(try!(devtools_port.recv()))) } else if ret == timer_port_handle.id() { Ok(MixedMessage::FromTimeoutThread(try!(timer_event_port.recv()))) - } else if ret == msg_port_handle.id() { - Ok(MixedMessage::PostMessage(try!(msg_port.recv()))) } else { panic!("unexpected select result!") } diff --git a/components/script/dom/serviceworkerregistration.rs b/components/script/dom/serviceworkerregistration.rs index bb44c1e2f783..c95d68856e81 100644 --- a/components/script/dom/serviceworkerregistration.rs +++ b/components/script/dom/serviceworkerregistration.rs @@ -6,11 +6,10 @@ 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::refcounted::Trusted; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::str::USVString; use dom::eventtarget::EventTarget; -use dom::serviceworker::{ServiceWorker, TrustedServiceWorkerAddress}; +use dom::serviceworker::ServiceWorker; use dom::serviceworkercontainer::Controllable; use dom::workerglobalscope::prepare_workerscope_init; use script_traits::{WorkerScriptLoadOrigin, ScopeThings}; @@ -40,7 +39,7 @@ impl ServiceWorkerRegistration { script_url: Url, scope: String, container: &Controllable) -> Root { - let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), true); + let active_worker = ServiceWorker::install_serviceworker(global, script_url.clone(), &scope, 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) @@ -50,10 +49,6 @@ impl ServiceWorkerRegistration { self.active.as_ref().unwrap() } - pub fn get_trusted_worker(&self) -> TrustedServiceWorkerAddress { - Trusted::new(self.active.as_ref().unwrap()) - } - pub fn create_scope_things(global: GlobalRef, script_url: Url) -> ScopeThings { let worker_load_origin = WorkerScriptLoadOrigin { referrer_url: None, diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index 993321093b25..4e5f2b65a90b 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -399,7 +399,7 @@ impl WorkerGlobalScope { } else if let Some(service_worker) = service_worker { return service_worker.script_chan(); } else { - panic!("need to implement a sender for SharedWorker/ServiceWorker") + panic!("need to implement a sender for SharedWorker") } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index fb5abc005d89..1edeaa7bdf78 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -42,7 +42,7 @@ use dom::element::Element; use dom::event::{Event, EventBubbles, EventCancelable}; use dom::htmlanchorelement::HTMLAnchorElement; use dom::node::{Node, NodeDamage, window_from_node}; -use dom::serviceworker::{TrustedServiceWorkerAddress, ServiceWorker}; +use dom::serviceworker::TrustedServiceWorkerAddress; use dom::serviceworkerregistration::ServiceWorkerRegistration; use dom::servohtmlparser::ParserContext; use dom::uievent::UIEvent; @@ -84,7 +84,7 @@ use script_traits::CompositorEvent::{TouchEvent, TouchpadPressureEvent}; use script_traits::webdriver_msg::WebDriverScriptCommand; use script_traits::{CompositorEvent, ConstellationControlMsg, EventResult}; use script_traits::{InitialScriptState, MouseButton, MouseEventType, MozBrowserEvent}; -use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg, DOMMessage}; +use script_traits::{NewLayoutInfo, ScriptMsg as ConstellationMsg}; use script_traits::{ScriptThreadFactory, TimerEvent, TimerEventRequest, TimerSource}; use script_traits::{TouchEventType, TouchId, UntrustedNodeAddress, WindowSizeData}; use std::borrow::ToOwned; @@ -924,8 +924,6 @@ impl ScriptThread { self.handle_css_error_reporting(pipeline_id, filename, line, column, msg), ConstellationControlMsg::Reload(pipeline_id) => self.handle_reload(pipeline_id), - ConstellationControlMsg::ConnectServiceWorker(scope_url, chan) => - self.connect_serviceworker_to_scope(scope_url, chan), msg @ ConstellationControlMsg::AttachLayout(..) | msg @ ConstellationControlMsg::Viewport(..) | msg @ ConstellationControlMsg::SetScrollState(..) | @@ -1462,15 +1460,6 @@ impl ScriptThread { } } - // Set the sender to the corresponding scope of the service worker object. - fn connect_serviceworker_to_scope(&self, scope_url: Url, chan: IpcSender) { - let ref maybe_registration_ref = *self.registration_map.borrow(); - if let Some(ref registration) = maybe_registration_ref.get(&scope_url) { - let trusted_worker = registration.get_trusted_worker(); - ServiceWorker::store_sender(trusted_worker, chan); - } - } - /// Handles a request for the window title. fn handle_get_title_msg(&self, pipeline_id: PipelineId) { let document = match self.root_browsing_context().find(pipeline_id) { diff --git a/components/script/serviceworker_manager.rs b/components/script/serviceworker_manager.rs index 898bd2b63f30..2fb97b35b85b 100644 --- a/components/script/serviceworker_manager.rs +++ b/components/script/serviceworker_manager.rs @@ -8,12 +8,14 @@ //! active_workers map use devtools_traits::{DevtoolsPageInfo, ScriptToDevtoolsControlMsg}; +use dom::abstractworker::WorkerScriptMsg; +use dom::bindings::structuredclone::StructuredCloneData; use dom::serviceworkerglobalscope::{ServiceWorkerGlobalScope, ServiceWorkerScriptMsg}; use dom::serviceworkerregistration::longest_prefix_match; use ipc_channel::ipc::{self, IpcSender}; use ipc_channel::router::ROUTER; use net_traits::{CustomResponseMediator, CoreResourceMsg}; -use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders}; +use script_traits::{ServiceWorkerMsg, ScopeThings, SWManagerMsg, SWManagerSenders, DOMMessage}; use std::collections::HashMap; use std::sync::mpsc::{channel, Sender, Receiver, RecvError}; use url::Url; @@ -29,29 +31,25 @@ pub struct ServiceWorkerManager { // map of registered service worker descriptors registered_workers: HashMap, // map of active service worker descriptors - active_workers: HashMap, + active_workers: HashMap>, // own sender to send messages here own_sender: IpcSender, // receiver to receive messages from constellation own_port: Receiver, // to receive resource messages - resource_receiver: Receiver, - // to send message to constellation - constellation_sender: IpcSender + resource_receiver: Receiver } impl ServiceWorkerManager { fn new(own_sender: IpcSender, from_constellation_receiver: Receiver, - resource_port: Receiver, - constellation_sender: IpcSender) -> ServiceWorkerManager { + resource_port: Receiver) -> ServiceWorkerManager { ServiceWorkerManager { registered_workers: HashMap::new(), active_workers: HashMap::new(), own_sender: own_sender, own_port: from_constellation_receiver, - resource_receiver: resource_port, - constellation_sender: constellation_sender + resource_receiver: resource_port } } @@ -62,67 +60,51 @@ impl ServiceWorkerManager { let resource_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(resource_port); let _ = sw_senders.resource_sender.send(CoreResourceMsg::NetworkMediator(resource_chan)); let _ = sw_senders.swmanager_sender.send(SWManagerMsg::OwnSender(own_sender.clone())); - let constellation_sender = sw_senders.swmanager_sender.clone(); spawn_named("ServiceWorkerManager".to_owned(), move || { ServiceWorkerManager::new(own_sender, from_constellation, - resource_port, - constellation_sender).handle_message(); + resource_port).handle_message(); }); } - pub fn prepare_activation(&mut self, load_url: &Url) -> Option> { - let mut scope_url = None; + pub fn get_matching_scope(&self, load_url: &Url) -> Option { for scope in self.registered_workers.keys() { if longest_prefix_match(&scope, load_url) { - scope_url = Some(scope.clone()); - break; + return Some(scope.clone()); } } + None + } - if let Some(scope_url) = scope_url { - if self.active_workers.contains_key(&scope_url) { - // do not run the same worker if already active. - warn!("Service worker for {:?} already active", scope_url); - return None; - } - let scope_things = self.registered_workers.get(&scope_url); - if let Some(scope_things) = scope_things { - let (sender, receiver) = channel(); - let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); - if let Some(ref chan) = scope_things.devtools_chan { - let title = format!("ServiceWorker for {}", scope_things.script_url); - let page_info = DevtoolsPageInfo { - title: title, - url: scope_things.script_url.clone(), - }; - let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((scope_things.pipeline_id, - Some(scope_things.worker_id)), - devtools_sender.clone(), - page_info)); + pub fn wakeup_serviceworker(&mut self, scope_url: Url) -> Option> { + let scope_things = self.registered_workers.get(&scope_url); + if let Some(scope_things) = scope_things { + let (sender, receiver) = channel(); + let (devtools_sender, devtools_receiver) = ipc::channel().unwrap(); + if let Some(ref chan) = scope_things.devtools_chan { + let title = format!("ServiceWorker for {}", scope_things.script_url); + let page_info = DevtoolsPageInfo { + title: title, + url: scope_things.script_url.clone(), }; - let (msg_chan, msg_port) = ipc::channel().unwrap(); - let msg_port = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(msg_port); - ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(), - sender.clone(), - receiver, - devtools_receiver, - self.own_sender.clone(), - scope_url.clone(), - msg_port); - // Send the message to constellation which then talks to the script thread for storing this msg_chan - let connection_msg = SWManagerMsg::ConnectServiceWorker(scope_url.clone(), - scope_things.pipeline_id, - msg_chan); - let _ = self.constellation_sender.send(connection_msg); - // We store the activated worker - self.active_workers.insert(scope_url, scope_things.clone()); - return Some(sender); - } else { - warn!("Unable to activate service worker"); - } + let _ = chan.send(ScriptToDevtoolsControlMsg::NewGlobal((scope_things.pipeline_id, + Some(scope_things.worker_id)), + devtools_sender, + page_info)); + }; + ServiceWorkerGlobalScope::run_serviceworker_scope(scope_things.clone(), + sender.clone(), + receiver, + devtools_receiver, + self.own_sender.clone(), + scope_url.clone()); + // We store the activated worker + self.active_workers.insert(scope_url, sender.clone()); + return Some(sender); + } else { + warn!("Unable to activate service worker"); + None } - None } fn handle_message(&mut self) { @@ -141,6 +123,12 @@ impl ServiceWorkerManager { } } + #[inline(always)] + fn forward_message(&self, msg: DOMMessage, sender: &Sender) { + let data = StructuredCloneData::make_structured_clone(msg); + let _ = sender.send(ServiceWorkerScriptMsg::CommonWorker(WorkerScriptMsg::DOMMessage(data))); + } + fn handle_message_from_constellation(&mut self, msg: ServiceWorkerMsg) -> bool { match msg { ServiceWorkerMsg::RegisterServiceWorker(scope_things, scope) => { @@ -155,7 +143,19 @@ impl ServiceWorkerManager { if self.active_workers.contains_key(&scope) { let _ = self.active_workers.remove(&scope); } else { - warn!("ScopeThings for {:?} is not active", scope); + warn!("ServiceWorker for {:?} is not active", scope); + } + true + }, + ServiceWorkerMsg::ForwardDOMMessage(msg, scope_url) => { + if self.active_workers.contains_key(&scope_url) { + if let Some(ref sender) = self.active_workers.get(&scope_url) { + self.forward_message(msg, &sender); + } + } else { + if let Some(ref sender) = self.wakeup_serviceworker(scope_url) { + self.forward_message(msg, &sender); + } } true } @@ -163,12 +163,20 @@ impl ServiceWorkerManager { } } - #[inline] fn handle_message_from_resource(&mut self, mediator: CustomResponseMediator) -> bool { if serviceworker_enabled() { - let worker_sender = self.prepare_activation(&mediator.load_url); - if let Some(ref sender) = worker_sender { - let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator)); + if let Some(scope) = self.get_matching_scope(&mediator.load_url) { + if self.active_workers.contains_key(&scope) { + if let Some(sender) = self.active_workers.get(&scope) { + let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator)); + } + } else { + if let Some(sender) = self.wakeup_serviceworker(scope) { + let _ = sender.send(ServiceWorkerScriptMsg::Response(mediator)); + } + } + } else { + let _ = mediator.response_chan.send(None); } } else { let _ = mediator.response_chan.send(None); diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index ce708fd34ab1..d90444074106 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -207,9 +207,7 @@ pub enum ConstellationControlMsg { /// Report an error from a CSS parser for the given pipeline ReportCSSError(PipelineId, String, usize, usize, String), /// Reload the given page. - Reload(PipelineId), - /// Requests the script thread to connect service worker object to its scope - ConnectServiceWorker(Url, IpcSender) + Reload(PipelineId) } impl fmt::Debug for ConstellationControlMsg { @@ -238,8 +236,7 @@ impl fmt::Debug for ConstellationControlMsg { DispatchFrameLoadEvent { .. } => "DispatchFrameLoadEvent", FramedContentChanged(..) => "FramedContentChanged", ReportCSSError(..) => "ReportCSSError", - Reload(..) => "Reload", - ConnectServiceWorker(..) => "ConnectServiceWorker" + Reload(..) => "Reload" }) } } diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index b1a9f2e6a522..446aa1b186bd 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -135,6 +135,9 @@ pub enum ScriptMsg { LogEntry(Option, Option, LogEntry), /// Notifies the constellation that this pipeline has exited. PipelineExited(PipelineId), + /// Send messages from postMessage calls from serviceworker + /// to constellation for storing in service worker manager + ForwardDOMMessage(DOMMessage, Url), /// Store the data required to activate a service worker for the given scope RegisterServiceWorker(ScopeThings, Url), /// Requests that the compositor shut down. @@ -159,8 +162,8 @@ pub struct ScopeThings { } /// Message that gets passed to service worker scope on postMessage -#[derive(Deserialize, Serialize, Debug)] -pub struct DOMMessage(pub Vec); +#[derive(Deserialize, Serialize, Debug, Clone)] +pub struct DOMMessage(pub Vec); /// Channels to allow service worker manager to communicate with constellation and resource thread pub struct SWManagerSenders { @@ -177,6 +180,8 @@ pub enum ServiceWorkerMsg { RegisterServiceWorker(ScopeThings, Url), /// Timeout message sent by active service workers Timeout(Url), + /// Backup message + ForwardDOMMessage(DOMMessage, Url), /// Exit the service worker manager Exit, } @@ -185,8 +190,6 @@ pub enum ServiceWorkerMsg { #[derive(Deserialize, Serialize)] pub enum SWManagerMsg { /// Provide the constellation with a means of communicating with the Service Worker Manager - OwnSender(IpcSender), - /// Message to ask to get a Trusted to constellation - ConnectServiceWorker(Url, PipelineId, IpcSender) + OwnSender(IpcSender) } diff --git a/tests/html/service-worker/demo_iframe.html b/tests/html/service-worker/demo_iframe.html index 1da0e4d78827..c4da41ffe1fd 100644 --- a/tests/html/service-worker/demo_iframe.html +++ b/tests/html/service-worker/demo_iframe.html @@ -8,6 +8,5 @@ - diff --git a/tests/html/service-worker/dummy.js b/tests/html/service-worker/dummy.js new file mode 100644 index 000000000000..e9478cb299ec --- /dev/null +++ b/tests/html/service-worker/dummy.js @@ -0,0 +1,3 @@ +function test_importScripts() { + console.log('Hi from dummy.js'); +} \ No newline at end of file diff --git a/tests/html/service-worker/iframe_sw.js b/tests/html/service-worker/iframe_sw.js index 51bce022ffe8..64adbeaa9ab6 100644 --- a/tests/html/service-worker/iframe_sw.js +++ b/tests/html/service-worker/iframe_sw.js @@ -1,11 +1,11 @@ self.addEventListener('activate', function(e) { - console.log("iframe service worker active"); + console.log("iframe service worker active"); }); self.addEventListener('fetch', function(e) { - console.log("A fetch event detected by /iframe service worker"); + console.log("A fetch event detected by /iframe service worker"); }); self.addEventListener('message', function(e) { - console.log('Post message payload ' + e.data.msg); + console.log(e.data.payload.msg + ' from '+ e.data.payload.worker_id); }) diff --git a/tests/html/service-worker/index.html b/tests/html/service-worker/index.html index 72081e62a2d1..ef971d0a4612 100644 --- a/tests/html/service-worker/index.html +++ b/tests/html/service-worker/index.html @@ -16,43 +16,56 @@ + - diff --git a/tests/html/service-worker/sw.js b/tests/html/service-worker/sw.js index e69de29bb2d1..04649167e5a8 100644 --- a/tests/html/service-worker/sw.js +++ b/tests/html/service-worker/sw.js @@ -0,0 +1,11 @@ +self.addEventListener('activate', function(e) { + console.log('Root service worker active'); +}); + +self.addEventListener('fetch', function(e) { + console.log("A fetch event detected by / service worker"); +}); + +self.addEventListener('message', function(e) { + console.log(e.data.num); +}) diff --git a/tests/html/service-worker/sw_dashboard.js b/tests/html/service-worker/sw_dashboard.js index 472fe03cca1b..5789e0fc361a 100644 --- a/tests/html/service-worker/sw_dashboard.js +++ b/tests/html/service-worker/sw_dashboard.js @@ -1,9 +1,11 @@ -importScripts('dashboard_helper.js'); - self.addEventListener('activate', function(e) { - status_from_dashboard(); + console.log('Dashboard service worker active'); }); self.addEventListener('fetch', function(e) { - console.log("A fetch event detected by /dashboard service worker"); -}); \ No newline at end of file + console.log("A fetch event detected by /dashboard service worker"); +}); + +self.addEventListener('message', function(e) { + console.log(e.data.payload.msg + ' from '+ e.data.payload.worker_id); +}) diff --git a/tests/html/service-worker/sw_profile.js b/tests/html/service-worker/sw_profile.js index 8834ece77195..e1871f125c84 100644 --- a/tests/html/service-worker/sw_profile.js +++ b/tests/html/service-worker/sw_profile.js @@ -1,8 +1,12 @@ self.addEventListener('activate', function(e) { - console.log("profile service worker active"); + console.log("profile service worker active"); }); self.addEventListener('fetch', function(e) { - console.log("A fetch event detected by /profile service worker"); -}); \ No newline at end of file + console.log("A fetch event detected by /profile service worker"); +}); + +self.addEventListener('message', function(e) { + console.log(e.data.payload.msg + ' from '+ e.data.payload.worker_id); +})