diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 9ca2b758bff1..80214a67a992 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -1279,8 +1279,13 @@ where warn!("constellation got set final url message for dead pipeline"); } }, - FromScriptMsg::PostMessage(browsing_context_id, origin, data) => { - self.handle_post_message_msg(browsing_context_id, origin, data); + FromScriptMsg::PostMessage { + target: browsing_context_id, + source: source_pipeline_id, + target_origin: origin, + data, + } => { + self.handle_post_message_msg(browsing_context_id, source_pipeline_id, origin, data); }, FromScriptMsg::Focus => { self.handle_focus_msg(source_pipeline_id); @@ -2844,6 +2849,7 @@ where fn handle_post_message_msg( &mut self, browsing_context_id: BrowsingContextId, + source_pipeline: PipelineId, origin: Option, data: Vec, ) { @@ -2856,7 +2862,17 @@ where }, Some(browsing_context) => browsing_context.pipeline_id, }; - let msg = ConstellationControlMsg::PostMessage(pipeline_id, origin, data); + let source_browsing_context = match self.pipelines.get(&source_pipeline) { + Some(pipeline) => pipeline.top_level_browsing_context_id, + None => return warn!("PostMessage from closed pipeline {:?}", source_pipeline), + }; + let msg = ConstellationControlMsg::PostMessage { + target: pipeline_id, + source: source_pipeline, + source_browsing_context: source_browsing_context, + target_origin: origin, + data, + }; let result = match self.pipelines.get(&pipeline_id) { Some(pipeline) => pipeline.event_loop.send(msg), None => return warn!("postMessage to closed pipeline {}.", pipeline_id), diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index edcb07cd4a19..92e26bad3533 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -424,7 +424,7 @@ impl DedicatedWorkerGlobalScope { JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get()); rooted!(in(scope.get_cx()) let mut message = UndefinedValue()); data.read(scope.upcast(), message.handle_mut()); - MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None); + MessageEvent::dispatch_jsval(target, scope.upcast(), message.handle(), None, None); }, WorkerScriptMsg::Common(msg) => { self.upcast::().process_event(msg); diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs index 662b65b8ef53..4814862881a5 100644 --- a/components/script/dom/dissimilaroriginwindow.rs +++ b/components/script/dom/dissimilaroriginwindow.rs @@ -203,11 +203,12 @@ impl DissimilarOriginWindow { None => return warn!("postMessage called with no incumbent global"), Some(incumbent) => incumbent, }; - let msg = ScriptMsg::PostMessage( - self.window_proxy.browsing_context_id(), - origin, - data.move_to_arraybuffer(), - ); + let msg = ScriptMsg::PostMessage { + target: self.window_proxy.browsing_context_id(), + source: incumbent.pipeline_id(), + target_origin: origin, + data: data.move_to_arraybuffer(), + }; let _ = incumbent.script_to_constellation_chan().send(msg); } } diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs index 10c912fb8e4c..5daaf3a5f7b0 100644 --- a/components/script/dom/eventsource.rs +++ b/components/script/dom/eventsource.rs @@ -238,6 +238,7 @@ impl EventSourceContext { false, data.handle(), DOMString::from(self.origin.clone()), + None, event_source.last_event_id.borrow().clone(), ) }; diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs index 65c8203913a7..edde48f95e63 100644 --- a/components/script/dom/messageevent.rs +++ b/components/script/dom/messageevent.rs @@ -7,24 +7,27 @@ use crate::dom::bindings::codegen::Bindings::MessageEventBinding; use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::inheritance::Castable; -use crate::dom::bindings::reflector::reflect_dom_object; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::bindings::str::DOMString; use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; +use crate::dom::windowproxy::WindowProxy; use dom_struct::dom_struct; -use js::jsapi::{Heap, JSContext}; +use js::jsapi::{Heap, JSContext, JSObject}; use js::jsval::JSVal; use js::rust::HandleValue; use servo_atoms::Atom; +use std::ptr::NonNull; #[dom_struct] pub struct MessageEvent { event: Event, data: Heap, origin: DOMString, + source: Option>, lastEventId: DOMString, } @@ -34,6 +37,7 @@ impl MessageEvent { global, HandleValue::undefined(), DOMString::new(), + None, DOMString::new(), ) } @@ -42,12 +46,14 @@ impl MessageEvent { global: &GlobalScope, data: HandleValue, origin: DOMString, + source: Option<&WindowProxy>, lastEventId: DOMString, ) -> DomRoot { let ev = Box::new(MessageEvent { event: Event::new_inherited(), data: Heap::default(), origin: origin, + source: source.map(Dom::from_ref), lastEventId: lastEventId, }); let ev = reflect_dom_object(ev, global, MessageEventBinding::Wrap); @@ -63,9 +69,10 @@ impl MessageEvent { cancelable: bool, data: HandleValue, origin: DOMString, + source: Option<&WindowProxy>, lastEventId: DOMString, ) -> DomRoot { - let ev = MessageEvent::new_initialized(global, data, origin, lastEventId); + let ev = MessageEvent::new_initialized(global, data, origin, source, lastEventId); { let event = ev.upcast::(); event.init_event(type_, bubbles, cancelable); @@ -78,6 +85,10 @@ impl MessageEvent { type_: DOMString, init: RootedTraceableBox, ) -> Fallible> { + let source = init + .source + .as_ref() + .and_then(|inner| inner.as_ref().map(|source| source.window_proxy())); let ev = MessageEvent::new( global, Atom::from(type_), @@ -85,6 +96,7 @@ impl MessageEvent { init.parent.cancelable, init.data.handle(), init.origin.clone(), + source.as_ref().map(|source| &**source), init.lastEventId.clone(), ); Ok(ev) @@ -97,6 +109,7 @@ impl MessageEvent { scope: &GlobalScope, message: HandleValue, origin: Option<&str>, + source: Option<&WindowProxy>, ) { let messageevent = MessageEvent::new( scope, @@ -105,6 +118,7 @@ impl MessageEvent { false, message, DOMString::from(origin.unwrap_or("")), + source, DOMString::new(), ); messageevent.upcast::().fire(target); @@ -123,6 +137,14 @@ impl MessageEventMethods for MessageEvent { self.origin.clone() } + // https://html.spec.whatwg.org/multipage/#dom-messageevent-source + #[allow(unsafe_code)] + unsafe fn GetSource(&self, _cx: *mut JSContext) -> Option> { + self.source + .as_ref() + .and_then(|source| NonNull::new(source.reflector().get_jsobject().get())) + } + // https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid fn LastEventId(&self) -> DOMString { self.lastEventId.clone() diff --git a/components/script/dom/webidls/MessageEvent.webidl b/components/script/dom/webidls/MessageEvent.webidl index 1fa4c924901f..c2ef97320966 100644 --- a/components/script/dom/webidls/MessageEvent.webidl +++ b/components/script/dom/webidls/MessageEvent.webidl @@ -8,6 +8,8 @@ interface MessageEvent : Event { readonly attribute any data; readonly attribute DOMString origin; readonly attribute DOMString lastEventId; + // FIXME(#22617): WindowProxy is not exposed in Worker globals + readonly attribute object? source; //readonly attribute (WindowProxy or MessagePort)? source; //readonly attribute MessagePort[]? ports; }; @@ -17,6 +19,7 @@ dictionary MessageEventInit : EventInit { DOMString origin = ""; DOMString lastEventId = ""; //DOMString channel; + Window? source; //(WindowProxy or MessagePort)? source; //sequence ports; }; diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 4344078a0174..d03e168e3a13 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -599,6 +599,7 @@ impl TaskOnce for MessageReceivedTask { &global, message.handle(), Some(&ws.origin().ascii_serialization()), + None, ); } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 2993a95456ad..533db98e05bc 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -859,6 +859,9 @@ impl WindowMethods for Window { message: HandleValue, origin: DOMString, ) -> ErrorResult { + let source_global = GlobalScope::incumbent().expect("no incumbent global??"); + let source = source_global.as_window(); + // Step 3-5. let origin = match &origin[..] { "*" => None, @@ -878,7 +881,7 @@ impl WindowMethods for Window { let data = StructuredCloneData::write(cx, message)?; // Step 9. - self.post_message(origin, data); + self.post_message(origin, &*source.window_proxy(), data); Ok(()) } @@ -2194,11 +2197,14 @@ impl Window { pub fn post_message( &self, target_origin: Option, + source: &WindowProxy, serialize_with_transfer_result: StructuredCloneData, ) { let this = Trusted::new(self); + let source = Trusted::new(source); let task = task!(post_serialised_message: move || { let this = this.root(); + let source = source.root(); // Step 7.1. if let Some(target_origin) = target_origin { @@ -2226,7 +2232,8 @@ impl Window { this.upcast(), this.upcast(), message_clone.handle(), - None + None, + Some(&*source), ); }); // FIXME(nox): Why are errors silenced here? diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 7135e969c0ec..aeabbeb26453 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -140,7 +140,7 @@ impl Worker { let _ac = JSAutoCompartment::new(global.get_cx(), target.reflector().get_jsobject().get()); rooted!(in(global.get_cx()) let mut message = UndefinedValue()); data.read(&global, message.handle_mut()); - MessageEvent::dispatch_jsval(target, &global, message.handle(), None); + MessageEvent::dispatch_jsval(target, &global, message.handle(), None, None); } pub fn dispatch_simple_error(address: TrustedWorkerAddress) { diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 6114e353d971..9ef684b96c4b 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -1419,7 +1419,7 @@ impl ScriptThread { ChangeFrameVisibilityStatus(id, ..) => Some(id), NotifyVisibilityChange(id, ..) => Some(id), Navigate(id, ..) => Some(id), - PostMessage(id, ..) => Some(id), + PostMessage { target: id, .. } => Some(id), UpdatePipelineId(_, _, id, _) => Some(id), UpdateHistoryState(id, ..) => Some(id), RemoveHistoryStates(id, ..) => Some(id), @@ -1592,9 +1592,19 @@ impl ScriptThread { browsing_context_id, visible, ), - ConstellationControlMsg::PostMessage(pipeline_id, origin, data) => { - self.handle_post_message_msg(pipeline_id, origin, data) - }, + ConstellationControlMsg::PostMessage { + target: target_pipeline_id, + source: source_pipeline_id, + source_browsing_context, + target_origin: origin, + data, + } => self.handle_post_message_msg( + target_pipeline_id, + source_pipeline_id, + source_browsing_context, + origin, + data, + ), ConstellationControlMsg::UpdatePipelineId( parent_pipeline_id, browsing_context_id, @@ -2080,12 +2090,33 @@ impl ScriptThread { fn handle_post_message_msg( &self, pipeline_id: PipelineId, + source_pipeline_id: PipelineId, + source_browsing_context: TopLevelBrowsingContextId, origin: Option, data: Vec, ) { match { self.documents.borrow().find_window(pipeline_id) } { - None => return warn!("postMessage after pipeline {} closed.", pipeline_id), - Some(window) => window.post_message(origin, StructuredCloneData::Vector(data)), + None => return warn!("postMessage after target pipeline {} closed.", pipeline_id), + Some(window) => { + // FIXME: synchronously talks to constellation. + // send the required info as part of postmessage instead. + let source = match self.remote_window_proxy( + &*window.global(), + source_browsing_context, + source_pipeline_id, + None, + ) { + None => { + return warn!( + "postMessage after source pipeline {} closed.", + source_pipeline_id, + ); + }, + Some(source) => source, + }; + // FIXME(#22512): enqueues a task; unnecessary delay. + window.post_message(origin, &*source, StructuredCloneData::Vector(data)) + }, } } diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 788a206b63f0..b97544f92230 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -284,7 +284,18 @@ pub enum ConstellationControlMsg { /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context Navigate(PipelineId, BrowsingContextId, LoadData, bool), /// Post a message to a given window. - PostMessage(PipelineId, Option, Vec), + PostMessage { + /// The target of the message. + target: PipelineId, + /// The source of the message. + source: PipelineId, + /// The top level browsing context associated with the source pipeline. + source_browsing_context: TopLevelBrowsingContextId, + /// The expected origin of the target. + target_origin: Option, + /// The data to be posted. + data: Vec, + }, /// Updates the current pipeline ID of a given iframe. /// First PipelineId is for the parent, second is the new PipelineId for the frame. UpdatePipelineId( @@ -358,7 +369,7 @@ impl fmt::Debug for ConstellationControlMsg { ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus", NotifyVisibilityChange(..) => "NotifyVisibilityChange", Navigate(..) => "Navigate", - PostMessage(..) => "PostMessage", + PostMessage { .. } => "PostMessage", UpdatePipelineId(..) => "UpdatePipelineId", UpdateHistoryState(..) => "UpdateHistoryState", RemoveHistoryStates(..) => "RemoveHistoryStates", diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 54b52fb33d01..a63462fd83f0 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -134,7 +134,16 @@ pub enum ScriptMsg { /// Abort loading after sending a LoadUrl message. AbortLoadUrl, /// Post a message to the currently active window of a given browsing context. - PostMessage(BrowsingContextId, Option, Vec), + PostMessage { + /// The target of the posted message. + target: BrowsingContextId, + /// The source of the posted message. + source: PipelineId, + /// The expected origin of the target. + target_origin: Option, + /// The data to be posted. + data: Vec, + }, /// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation. NavigatedToFragment(ServoUrl, bool), /// HTMLIFrameElement Forward or Back traversal. @@ -209,7 +218,7 @@ impl fmt::Debug for ScriptMsg { LoadComplete => "LoadComplete", LoadUrl(..) => "LoadUrl", AbortLoadUrl => "AbortLoadUrl", - PostMessage(..) => "PostMessage", + PostMessage { .. } => "PostMessage", NavigatedToFragment(..) => "NavigatedToFragment", TraverseHistory(..) => "TraverseHistory", PushHistoryState(..) => "PushHistoryState",