Provide the source window as part of postMessage events.

This commit is contained in:
Josh Matthews 2018-12-20 16:16:51 -05:00
parent 212ae3b94a
commit 45619db0ba
12 changed files with 128 additions and 26 deletions

View file

@ -1279,8 +1279,13 @@ where
warn!("constellation got set final url message for dead pipeline"); warn!("constellation got set final url message for dead pipeline");
} }
}, },
FromScriptMsg::PostMessage(browsing_context_id, origin, data) => { FromScriptMsg::PostMessage {
self.handle_post_message_msg(browsing_context_id, origin, data); 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 => { FromScriptMsg::Focus => {
self.handle_focus_msg(source_pipeline_id); self.handle_focus_msg(source_pipeline_id);
@ -2844,6 +2849,7 @@ where
fn handle_post_message_msg( fn handle_post_message_msg(
&mut self, &mut self,
browsing_context_id: BrowsingContextId, browsing_context_id: BrowsingContextId,
source_pipeline: PipelineId,
origin: Option<ImmutableOrigin>, origin: Option<ImmutableOrigin>,
data: Vec<u8>, data: Vec<u8>,
) { ) {
@ -2856,7 +2862,17 @@ where
}, },
Some(browsing_context) => browsing_context.pipeline_id, 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) { let result = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.event_loop.send(msg), Some(pipeline) => pipeline.event_loop.send(msg),
None => return warn!("postMessage to closed pipeline {}.", pipeline_id), None => return warn!("postMessage to closed pipeline {}.", pipeline_id),

View file

@ -424,7 +424,7 @@ impl DedicatedWorkerGlobalScope {
JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get()); JSAutoCompartment::new(scope.get_cx(), scope.reflector().get_jsobject().get());
rooted!(in(scope.get_cx()) let mut message = UndefinedValue()); rooted!(in(scope.get_cx()) let mut message = UndefinedValue());
data.read(scope.upcast(), message.handle_mut()); 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) => { WorkerScriptMsg::Common(msg) => {
self.upcast::<WorkerGlobalScope>().process_event(msg); self.upcast::<WorkerGlobalScope>().process_event(msg);

View file

@ -203,11 +203,12 @@ impl DissimilarOriginWindow {
None => return warn!("postMessage called with no incumbent global"), None => return warn!("postMessage called with no incumbent global"),
Some(incumbent) => incumbent, Some(incumbent) => incumbent,
}; };
let msg = ScriptMsg::PostMessage( let msg = ScriptMsg::PostMessage {
self.window_proxy.browsing_context_id(), target: self.window_proxy.browsing_context_id(),
origin, source: incumbent.pipeline_id(),
data.move_to_arraybuffer(), target_origin: origin,
); data: data.move_to_arraybuffer(),
};
let _ = incumbent.script_to_constellation_chan().send(msg); let _ = incumbent.script_to_constellation_chan().send(msg);
} }
} }

View file

@ -238,6 +238,7 @@ impl EventSourceContext {
false, false,
data.handle(), data.handle(),
DOMString::from(self.origin.clone()), DOMString::from(self.origin.clone()),
None,
event_source.last_event_id.borrow().clone(), event_source.last_event_id.borrow().clone(),
) )
}; };

View file

@ -7,24 +7,27 @@ use crate::dom::bindings::codegen::Bindings::MessageEventBinding;
use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods; use crate::dom::bindings::codegen::Bindings::MessageEventBinding::MessageEventMethods;
use crate::dom::bindings::error::Fallible; use crate::dom::bindings::error::Fallible;
use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::reflect_dom_object; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::event::Event; use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget; use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::windowproxy::WindowProxy;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSContext}; use js::jsapi::{Heap, JSContext, JSObject};
use js::jsval::JSVal; use js::jsval::JSVal;
use js::rust::HandleValue; use js::rust::HandleValue;
use servo_atoms::Atom; use servo_atoms::Atom;
use std::ptr::NonNull;
#[dom_struct] #[dom_struct]
pub struct MessageEvent { pub struct MessageEvent {
event: Event, event: Event,
data: Heap<JSVal>, data: Heap<JSVal>,
origin: DOMString, origin: DOMString,
source: Option<Dom<WindowProxy>>,
lastEventId: DOMString, lastEventId: DOMString,
} }
@ -34,6 +37,7 @@ impl MessageEvent {
global, global,
HandleValue::undefined(), HandleValue::undefined(),
DOMString::new(), DOMString::new(),
None,
DOMString::new(), DOMString::new(),
) )
} }
@ -42,12 +46,14 @@ impl MessageEvent {
global: &GlobalScope, global: &GlobalScope,
data: HandleValue, data: HandleValue,
origin: DOMString, origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString, lastEventId: DOMString,
) -> DomRoot<MessageEvent> { ) -> DomRoot<MessageEvent> {
let ev = Box::new(MessageEvent { let ev = Box::new(MessageEvent {
event: Event::new_inherited(), event: Event::new_inherited(),
data: Heap::default(), data: Heap::default(),
origin: origin, origin: origin,
source: source.map(Dom::from_ref),
lastEventId: lastEventId, lastEventId: lastEventId,
}); });
let ev = reflect_dom_object(ev, global, MessageEventBinding::Wrap); let ev = reflect_dom_object(ev, global, MessageEventBinding::Wrap);
@ -63,9 +69,10 @@ impl MessageEvent {
cancelable: bool, cancelable: bool,
data: HandleValue, data: HandleValue,
origin: DOMString, origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString, lastEventId: DOMString,
) -> DomRoot<MessageEvent> { ) -> DomRoot<MessageEvent> {
let ev = MessageEvent::new_initialized(global, data, origin, lastEventId); let ev = MessageEvent::new_initialized(global, data, origin, source, lastEventId);
{ {
let event = ev.upcast::<Event>(); let event = ev.upcast::<Event>();
event.init_event(type_, bubbles, cancelable); event.init_event(type_, bubbles, cancelable);
@ -78,6 +85,10 @@ impl MessageEvent {
type_: DOMString, type_: DOMString,
init: RootedTraceableBox<MessageEventBinding::MessageEventInit>, init: RootedTraceableBox<MessageEventBinding::MessageEventInit>,
) -> Fallible<DomRoot<MessageEvent>> { ) -> Fallible<DomRoot<MessageEvent>> {
let source = init
.source
.as_ref()
.and_then(|inner| inner.as_ref().map(|source| source.window_proxy()));
let ev = MessageEvent::new( let ev = MessageEvent::new(
global, global,
Atom::from(type_), Atom::from(type_),
@ -85,6 +96,7 @@ impl MessageEvent {
init.parent.cancelable, init.parent.cancelable,
init.data.handle(), init.data.handle(),
init.origin.clone(), init.origin.clone(),
source.as_ref().map(|source| &**source),
init.lastEventId.clone(), init.lastEventId.clone(),
); );
Ok(ev) Ok(ev)
@ -97,6 +109,7 @@ impl MessageEvent {
scope: &GlobalScope, scope: &GlobalScope,
message: HandleValue, message: HandleValue,
origin: Option<&str>, origin: Option<&str>,
source: Option<&WindowProxy>,
) { ) {
let messageevent = MessageEvent::new( let messageevent = MessageEvent::new(
scope, scope,
@ -105,6 +118,7 @@ impl MessageEvent {
false, false,
message, message,
DOMString::from(origin.unwrap_or("")), DOMString::from(origin.unwrap_or("")),
source,
DOMString::new(), DOMString::new(),
); );
messageevent.upcast::<Event>().fire(target); messageevent.upcast::<Event>().fire(target);
@ -123,6 +137,14 @@ impl MessageEventMethods for MessageEvent {
self.origin.clone() self.origin.clone()
} }
// https://html.spec.whatwg.org/multipage/#dom-messageevent-source
#[allow(unsafe_code)]
unsafe fn GetSource(&self, _cx: *mut JSContext) -> Option<NonNull<JSObject>> {
self.source
.as_ref()
.and_then(|source| NonNull::new(source.reflector().get_jsobject().get()))
}
// https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid // https://html.spec.whatwg.org/multipage/#dom-messageevent-lasteventid
fn LastEventId(&self) -> DOMString { fn LastEventId(&self) -> DOMString {
self.lastEventId.clone() self.lastEventId.clone()

View file

@ -8,6 +8,8 @@ interface MessageEvent : Event {
readonly attribute any data; readonly attribute any data;
readonly attribute DOMString origin; readonly attribute DOMString origin;
readonly attribute DOMString lastEventId; 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 (WindowProxy or MessagePort)? source;
//readonly attribute MessagePort[]? ports; //readonly attribute MessagePort[]? ports;
}; };
@ -17,6 +19,7 @@ dictionary MessageEventInit : EventInit {
DOMString origin = ""; DOMString origin = "";
DOMString lastEventId = ""; DOMString lastEventId = "";
//DOMString channel; //DOMString channel;
Window? source;
//(WindowProxy or MessagePort)? source; //(WindowProxy or MessagePort)? source;
//sequence<MessagePort> ports; //sequence<MessagePort> ports;
}; };

View file

@ -599,6 +599,7 @@ impl TaskOnce for MessageReceivedTask {
&global, &global,
message.handle(), message.handle(),
Some(&ws.origin().ascii_serialization()), Some(&ws.origin().ascii_serialization()),
None,
); );
} }
} }

View file

@ -859,6 +859,9 @@ impl WindowMethods for Window {
message: HandleValue, message: HandleValue,
origin: DOMString, origin: DOMString,
) -> ErrorResult { ) -> ErrorResult {
let source_global = GlobalScope::incumbent().expect("no incumbent global??");
let source = source_global.as_window();
// Step 3-5. // Step 3-5.
let origin = match &origin[..] { let origin = match &origin[..] {
"*" => None, "*" => None,
@ -878,7 +881,7 @@ impl WindowMethods for Window {
let data = StructuredCloneData::write(cx, message)?; let data = StructuredCloneData::write(cx, message)?;
// Step 9. // Step 9.
self.post_message(origin, data); self.post_message(origin, &*source.window_proxy(), data);
Ok(()) Ok(())
} }
@ -2194,11 +2197,14 @@ impl Window {
pub fn post_message( pub fn post_message(
&self, &self,
target_origin: Option<ImmutableOrigin>, target_origin: Option<ImmutableOrigin>,
source: &WindowProxy,
serialize_with_transfer_result: StructuredCloneData, serialize_with_transfer_result: StructuredCloneData,
) { ) {
let this = Trusted::new(self); let this = Trusted::new(self);
let source = Trusted::new(source);
let task = task!(post_serialised_message: move || { let task = task!(post_serialised_message: move || {
let this = this.root(); let this = this.root();
let source = source.root();
// Step 7.1. // Step 7.1.
if let Some(target_origin) = target_origin { if let Some(target_origin) = target_origin {
@ -2226,7 +2232,8 @@ impl Window {
this.upcast(), this.upcast(),
this.upcast(), this.upcast(),
message_clone.handle(), message_clone.handle(),
None None,
Some(&*source),
); );
}); });
// FIXME(nox): Why are errors silenced here? // FIXME(nox): Why are errors silenced here?

View file

@ -140,7 +140,7 @@ impl Worker {
let _ac = JSAutoCompartment::new(global.get_cx(), target.reflector().get_jsobject().get()); let _ac = JSAutoCompartment::new(global.get_cx(), target.reflector().get_jsobject().get());
rooted!(in(global.get_cx()) let mut message = UndefinedValue()); rooted!(in(global.get_cx()) let mut message = UndefinedValue());
data.read(&global, message.handle_mut()); 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) { pub fn dispatch_simple_error(address: TrustedWorkerAddress) {

View file

@ -1419,7 +1419,7 @@ impl ScriptThread {
ChangeFrameVisibilityStatus(id, ..) => Some(id), ChangeFrameVisibilityStatus(id, ..) => Some(id),
NotifyVisibilityChange(id, ..) => Some(id), NotifyVisibilityChange(id, ..) => Some(id),
Navigate(id, ..) => Some(id), Navigate(id, ..) => Some(id),
PostMessage(id, ..) => Some(id), PostMessage { target: id, .. } => Some(id),
UpdatePipelineId(_, _, id, _) => Some(id), UpdatePipelineId(_, _, id, _) => Some(id),
UpdateHistoryState(id, ..) => Some(id), UpdateHistoryState(id, ..) => Some(id),
RemoveHistoryStates(id, ..) => Some(id), RemoveHistoryStates(id, ..) => Some(id),
@ -1592,9 +1592,19 @@ impl ScriptThread {
browsing_context_id, browsing_context_id,
visible, visible,
), ),
ConstellationControlMsg::PostMessage(pipeline_id, origin, data) => { ConstellationControlMsg::PostMessage {
self.handle_post_message_msg(pipeline_id, origin, data) 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( ConstellationControlMsg::UpdatePipelineId(
parent_pipeline_id, parent_pipeline_id,
browsing_context_id, browsing_context_id,
@ -2080,12 +2090,33 @@ impl ScriptThread {
fn handle_post_message_msg( fn handle_post_message_msg(
&self, &self,
pipeline_id: PipelineId, pipeline_id: PipelineId,
source_pipeline_id: PipelineId,
source_browsing_context: TopLevelBrowsingContextId,
origin: Option<ImmutableOrigin>, origin: Option<ImmutableOrigin>,
data: Vec<u8>, data: Vec<u8>,
) { ) {
match { self.documents.borrow().find_window(pipeline_id) } { match { self.documents.borrow().find_window(pipeline_id) } {
None => return warn!("postMessage after pipeline {} closed.", pipeline_id), None => return warn!("postMessage after target pipeline {} closed.", pipeline_id),
Some(window) => window.post_message(origin, StructuredCloneData::Vector(data)), 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))
},
} }
} }

View file

@ -284,7 +284,18 @@ pub enum ConstellationControlMsg {
/// PipelineId is for the parent, BrowsingContextId is for the nested browsing context /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
Navigate(PipelineId, BrowsingContextId, LoadData, bool), Navigate(PipelineId, BrowsingContextId, LoadData, bool),
/// Post a message to a given window. /// Post a message to a given window.
PostMessage(PipelineId, Option<ImmutableOrigin>, Vec<u8>), 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<ImmutableOrigin>,
/// The data to be posted.
data: Vec<u8>,
},
/// Updates the current pipeline ID of a given iframe. /// Updates the current pipeline ID of a given iframe.
/// First PipelineId is for the parent, second is the new PipelineId for the frame. /// First PipelineId is for the parent, second is the new PipelineId for the frame.
UpdatePipelineId( UpdatePipelineId(
@ -358,7 +369,7 @@ impl fmt::Debug for ConstellationControlMsg {
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus", ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
NotifyVisibilityChange(..) => "NotifyVisibilityChange", NotifyVisibilityChange(..) => "NotifyVisibilityChange",
Navigate(..) => "Navigate", Navigate(..) => "Navigate",
PostMessage(..) => "PostMessage", PostMessage { .. } => "PostMessage",
UpdatePipelineId(..) => "UpdatePipelineId", UpdatePipelineId(..) => "UpdatePipelineId",
UpdateHistoryState(..) => "UpdateHistoryState", UpdateHistoryState(..) => "UpdateHistoryState",
RemoveHistoryStates(..) => "RemoveHistoryStates", RemoveHistoryStates(..) => "RemoveHistoryStates",

View file

@ -134,7 +134,16 @@ pub enum ScriptMsg {
/// Abort loading after sending a LoadUrl message. /// Abort loading after sending a LoadUrl message.
AbortLoadUrl, AbortLoadUrl,
/// Post a message to the currently active window of a given browsing context. /// Post a message to the currently active window of a given browsing context.
PostMessage(BrowsingContextId, Option<ImmutableOrigin>, Vec<u8>), 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<ImmutableOrigin>,
/// The data to be posted.
data: Vec<u8>,
},
/// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation. /// Inform the constellation that a fragment was navigated to and whether or not it was a replacement navigation.
NavigatedToFragment(ServoUrl, bool), NavigatedToFragment(ServoUrl, bool),
/// HTMLIFrameElement Forward or Back traversal. /// HTMLIFrameElement Forward or Back traversal.
@ -209,7 +218,7 @@ impl fmt::Debug for ScriptMsg {
LoadComplete => "LoadComplete", LoadComplete => "LoadComplete",
LoadUrl(..) => "LoadUrl", LoadUrl(..) => "LoadUrl",
AbortLoadUrl => "AbortLoadUrl", AbortLoadUrl => "AbortLoadUrl",
PostMessage(..) => "PostMessage", PostMessage { .. } => "PostMessage",
NavigatedToFragment(..) => "NavigatedToFragment", NavigatedToFragment(..) => "NavigatedToFragment",
TraverseHistory(..) => "TraverseHistory", TraverseHistory(..) => "TraverseHistory",
PushHistoryState(..) => "PushHistoryState", PushHistoryState(..) => "PushHistoryState",