Skip to content

Commit

Permalink
Provide the source window as part of postMessage events.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdm committed Jan 8, 2019
1 parent 212ae3b commit 45619db
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 26 deletions.
22 changes: 19 additions & 3 deletions components/constellation/constellation.rs
Expand Up @@ -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);
Expand Down Expand Up @@ -2844,6 +2849,7 @@ where
fn handle_post_message_msg(
&mut self,
browsing_context_id: BrowsingContextId,
source_pipeline: PipelineId,
origin: Option<ImmutableOrigin>,
data: Vec<u8>,
) {
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/dedicatedworkerglobalscope.rs
Expand Up @@ -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::<WorkerGlobalScope>().process_event(msg);
Expand Down
11 changes: 6 additions & 5 deletions components/script/dom/dissimilaroriginwindow.rs
Expand Up @@ -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);
}
}
1 change: 1 addition & 0 deletions components/script/dom/eventsource.rs
Expand Up @@ -238,6 +238,7 @@ impl EventSourceContext {
false,
data.handle(),
DOMString::from(self.origin.clone()),
None,
event_source.last_event_id.borrow().clone(),
)
};
Expand Down
30 changes: 26 additions & 4 deletions components/script/dom/messageevent.rs
Expand Up @@ -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<JSVal>,
origin: DOMString,
source: Option<Dom<WindowProxy>>,
lastEventId: DOMString,
}

Expand All @@ -34,6 +37,7 @@ impl MessageEvent {
global,
HandleValue::undefined(),
DOMString::new(),
None,
DOMString::new(),
)
}
Expand All @@ -42,12 +46,14 @@ impl MessageEvent {
global: &GlobalScope,
data: HandleValue,
origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString,
) -> DomRoot<MessageEvent> {
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);
Expand All @@ -63,9 +69,10 @@ impl MessageEvent {
cancelable: bool,
data: HandleValue,
origin: DOMString,
source: Option<&WindowProxy>,
lastEventId: DOMString,
) -> 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>();
event.init_event(type_, bubbles, cancelable);
Expand All @@ -78,13 +85,18 @@ impl MessageEvent {
type_: DOMString,
init: RootedTraceableBox<MessageEventBinding::MessageEventInit>,
) -> Fallible<DomRoot<MessageEvent>> {
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_),
init.parent.bubbles,
init.parent.cancelable,
init.data.handle(),
init.origin.clone(),
source.as_ref().map(|source| &**source),
init.lastEventId.clone(),
);
Ok(ev)
Expand All @@ -97,6 +109,7 @@ impl MessageEvent {
scope: &GlobalScope,
message: HandleValue,
origin: Option<&str>,
source: Option<&WindowProxy>,
) {
let messageevent = MessageEvent::new(
scope,
Expand All @@ -105,6 +118,7 @@ impl MessageEvent {
false,
message,
DOMString::from(origin.unwrap_or("")),
source,
DOMString::new(),
);
messageevent.upcast::<Event>().fire(target);
Expand All @@ -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<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
fn LastEventId(&self) -> DOMString {
self.lastEventId.clone()
Expand Down
3 changes: 3 additions & 0 deletions components/script/dom/webidls/MessageEvent.webidl
Expand Up @@ -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;
};
Expand All @@ -17,6 +19,7 @@ dictionary MessageEventInit : EventInit {
DOMString origin = "";
DOMString lastEventId = "";
//DOMString channel;
Window? source;
//(WindowProxy or MessagePort)? source;
//sequence<MessagePort> ports;
};
1 change: 1 addition & 0 deletions components/script/dom/websocket.rs
Expand Up @@ -599,6 +599,7 @@ impl TaskOnce for MessageReceivedTask {
&global,
message.handle(),
Some(&ws.origin().ascii_serialization()),
None,
);
}
}
Expand Down
11 changes: 9 additions & 2 deletions components/script/dom/window.rs
Expand Up @@ -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,
Expand All @@ -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(())
}

Expand Down Expand Up @@ -2194,11 +2197,14 @@ impl Window {
pub fn post_message(
&self,
target_origin: Option<ImmutableOrigin>,
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 {
Expand Down Expand Up @@ -2226,7 +2232,8 @@ impl Window {
this.upcast(),
this.upcast(),
message_clone.handle(),
None
None,
Some(&*source),
);
});
// FIXME(nox): Why are errors silenced here?
Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/worker.rs
Expand Up @@ -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) {
Expand Down
43 changes: 37 additions & 6 deletions components/script/script_thread.rs
Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<ImmutableOrigin>,
data: Vec<u8>,
) {
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))
},
}
}

Expand Down
15 changes: 13 additions & 2 deletions components/script_traits/lib.rs
Expand Up @@ -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<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.
/// First PipelineId is for the parent, second is the new PipelineId for the frame.
UpdatePipelineId(
Expand Down Expand Up @@ -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",
Expand Down
13 changes: 11 additions & 2 deletions components/script_traits/script_msg.rs
Expand Up @@ -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<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.
NavigatedToFragment(ServoUrl, bool),
/// HTMLIFrameElement Forward or Back traversal.
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit 45619db

Please sign in to comment.