New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement postMessage for ServiceWorkers #12910
Changes from 1 commit
File filter...
Jump to…
store senders instead of buffering messages
- Loading branch information
| @@ -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<u64> | ||
| pub fn move_to_arraybuffer(self) -> Vec<u64> { | ||
| /// Converts a StructuredCloneData to Vec<u8> 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, | ||
creativcoder
Author
Contributor
|
||
| nbytes: nbytes | ||
| @@ -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<ServiceWorker>; | ||
| pub struct ServiceWorker { | ||
| eventtarget: EventTarget, | ||
| script_url: DOMRefCell<String>, | ||
| scope_url: DOMRefCell<String>, | ||
| state: Cell<ServiceWorkerState>, | ||
| #[ignore_heap_size_of = "Defined in std"] | ||
| msg_sender: DOMRefCell<Option<IpcSender<DOMMessage>>>, | ||
| skip_waiting: Cell<bool> | ||
| } | ||
|
|
||
| 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<ServiceWorker> { | ||
| 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> { | ||
| ServiceWorker::new(global, | ||
| script_url.as_str(), | ||
| scope_url, | ||
creativcoder
Author
Contributor
|
||
| skip_waiting) | ||
| } | ||
|
|
||
| pub fn store_sender(trusted_worker: TrustedServiceWorkerAddress, sender: IpcSender<DOMMessage>) { | ||
| 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(()) | ||
| } | ||
|
|
||
This is unsafe - the actual Vec value goes out of scope when we return, so the
StructuredCloneDatacontains a pointer to freed memory. We should makeStructuredCloneDataan enum that can store a backingVecif necessary.