aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/constellation/constellation.rs21
-rw-r--r--components/script/dom/browsingcontext.rs21
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs36
-rw-r--r--components/script/dom/webidls/DissimilarOriginWindow.webidl2
-rw-r--r--components/script/dom/window.rs14
-rw-r--r--components/script/script_thread.rs14
-rw-r--r--components/script_traits/lib.rs4
-rw-r--r--components/script_traits/script_msg.rs3
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json28
-rw-r--r--tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child1.html13
-rw-r--r--tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child2.html11
-rw-r--r--tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage.html37
12 files changed, 191 insertions, 13 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 213ae5f6ffd..124731f4bf8 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -108,7 +108,7 @@ use servo_config::opts;
use servo_config::prefs::PREFS;
use servo_rand::{Rng, SeedableRng, ServoRng, random};
use servo_remutex::ReentrantMutex;
-use servo_url::{Host, ServoUrl};
+use servo_url::{Host, ImmutableOrigin, ServoUrl};
use std::borrow::ToOwned;
use std::collections::{HashMap, VecDeque};
use std::iter::once;
@@ -980,6 +980,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
warn!("constellation got set final url message for dead pipeline");
}
}
+ FromScriptMsg::PostMessage(frame_id, origin, data) => {
+ debug!("constellation got postMessage message");
+ self.handle_post_message_msg(frame_id, origin, data);
+ }
FromScriptMsg::MozBrowserEvent(parent_pipeline_id, pipeline_id, event) => {
debug!("constellation got mozbrowser event message");
self.handle_mozbrowser_event_msg(parent_pipeline_id,
@@ -1795,6 +1799,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
+ fn handle_post_message_msg(&mut self, frame_id: FrameId, origin: Option<ImmutableOrigin>, data: Vec<u8>) {
+ let pipeline_id = match self.frames.get(&frame_id) {
+ None => return warn!("postMessage to closed frame {}.", frame_id),
+ Some(frame) => frame.pipeline_id,
+ };
+ let msg = ConstellationControlMsg::PostMessage(pipeline_id, 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),
+ };
+ if let Err(e) = result {
+ self.handle_send_error(pipeline_id, e);
+ }
+ }
+
fn handle_mozbrowser_event_msg(&mut self,
parent_pipeline_id: PipelineId,
pipeline_id: PipelineId,
diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs
index 77c6eac2941..6363e08095f 100644
--- a/components/script/dom/browsingcontext.rs
+++ b/components/script/dom/browsingcontext.rs
@@ -29,6 +29,7 @@ use js::jsapi::{MutableHandle, MutableHandleObject, MutableHandleValue};
use js::jsapi::{ObjectOpResult, PropertyDescriptor};
use js::jsval::{UndefinedValue, PrivateValue};
use js::rust::get_object_class;
+use msg::constellation_msg::FrameId;
use msg::constellation_msg::PipelineId;
use std::cell::Cell;
use std::ptr;
@@ -45,6 +46,11 @@ pub struct BrowsingContext {
/// changes Window.
reflector: Reflector,
+ /// The frame id of the browsing context.
+ /// In the case that this is a nested browsing context, this is the frame id
+ /// of the container.
+ frame_id: FrameId,
+
/// The pipeline id of the currently active document.
/// May be None, when the currently active document is in another script thread.
/// We do not try to keep the pipeline id for documents in other threads,
@@ -60,9 +66,14 @@ pub struct BrowsingContext {
}
impl BrowsingContext {
- pub fn new_inherited(currently_active: PipelineId, frame_element: Option<&Element>) -> BrowsingContext {
+ pub fn new_inherited(frame_id: FrameId,
+ currently_active: PipelineId,
+ frame_element: Option<&Element>)
+ -> BrowsingContext
+ {
BrowsingContext {
reflector: Reflector::new(),
+ frame_id: frame_id,
currently_active: Cell::new(Some(currently_active)),
discarded: Cell::new(false),
frame_element: frame_element.map(JS::from_ref),
@@ -70,7 +81,7 @@ impl BrowsingContext {
}
#[allow(unsafe_code)]
- pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
+ pub fn new(window: &Window, frame_id: FrameId, frame_element: Option<&Element>) -> Root<BrowsingContext> {
unsafe {
let WindowProxyHandler(handler) = window.windowproxy_handler();
assert!(!handler.is_null());
@@ -87,7 +98,7 @@ impl BrowsingContext {
// Create a new browsing context.
let currently_active = window.global().pipeline_id();
- let mut browsing_context = box BrowsingContext::new_inherited(currently_active, frame_element);
+ let mut browsing_context = box BrowsingContext::new_inherited(frame_id, currently_active, frame_element);
// The window proxy owns the browsing context.
// When we finalize the window proxy, it drops the browsing context it owns.
@@ -111,6 +122,10 @@ impl BrowsingContext {
self.discarded.get()
}
+ pub fn frame_id(&self) -> FrameId {
+ self.frame_id
+ }
+
pub fn frame_element(&self) -> Option<&Element> {
self.frame_element.r()
}
diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
index 9867e642906..96171ef3bf1 100644
--- a/components/script/dom/dissimilaroriginwindow.rs
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -4,9 +4,12 @@
use dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
use dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
+use dom::bindings::error::{Error, ErrorResult};
+use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableJS, Root};
use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
+use dom::bindings::structuredclone::StructuredCloneData;
use dom::browsingcontext::BrowsingContext;
use dom::dissimilaroriginlocation::DissimilarOriginLocation;
use dom::globalscope::GlobalScope;
@@ -15,6 +18,9 @@ use ipc_channel::ipc;
use js::jsapi::{JSContext, HandleValue};
use js::jsval::{JSVal, UndefinedValue};
use msg::constellation_msg::PipelineId;
+use script_traits::ScriptMsg as ConstellationMsg;
+use servo_url::ImmutableOrigin;
+use servo_url::ServoUrl;
/// Represents a dissimilar-origin `Window` that exists in another script thread.
///
@@ -107,8 +113,27 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
#[allow(unsafe_code)]
// https://html.spec.whatwg.org/multipage/#dom-window-postmessage
- unsafe fn PostMessage(&self, _: *mut JSContext, _: HandleValue, _: DOMString) {
- // TODO: Implement x-origin postMessage
+ unsafe fn PostMessage(&self, cx: *mut JSContext, message: HandleValue, origin: DOMString) -> ErrorResult {
+ // Step 3-5.
+ let origin = match &origin[..] {
+ "*" => None,
+ "/" => {
+ // TODO: Should be the origin of the incumbent settings object.
+ None
+ },
+ url => match ServoUrl::parse(&url) {
+ Ok(url) => Some(url.origin()),
+ Err(_) => return Err(Error::Syntax),
+ }
+ };
+
+ // Step 1-2, 6-8.
+ // TODO(#12717): Should implement the `transfer` argument.
+ let data = try!(StructuredCloneData::write(cx, message));
+
+ // Step 9.
+ self.post_message(origin, data);
+ Ok(())
}
#[allow(unsafe_code)]
@@ -139,3 +164,10 @@ impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
self.location.or_init(|| DissimilarOriginLocation::new(self))
}
}
+
+impl DissimilarOriginWindow {
+ pub fn post_message(&self, origin: Option<ImmutableOrigin>, data: StructuredCloneData) {
+ let msg = ConstellationMsg::PostMessage(self.browsing_context.frame_id(), origin, data.move_to_arraybuffer());
+ let _ = self.upcast::<GlobalScope>().constellation_chan().send(msg);
+ }
+}
diff --git a/components/script/dom/webidls/DissimilarOriginWindow.webidl b/components/script/dom/webidls/DissimilarOriginWindow.webidl
index 6aeb5c7d1b2..a1f3a2f8b6d 100644
--- a/components/script/dom/webidls/DissimilarOriginWindow.webidl
+++ b/components/script/dom/webidls/DissimilarOriginWindow.webidl
@@ -25,7 +25,7 @@ interface DissimilarOriginWindow : GlobalScope {
void close();
readonly attribute boolean closed;
- void postMessage(any message, DOMString targetOrigin);
+ [Throws] void postMessage(any message, DOMString targetOrigin);
attribute any opener;
void blur();
void focus();
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 50a2a57c41e..e778b451102 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -718,10 +718,7 @@ impl WindowMethods for Window {
let data = try!(StructuredCloneData::write(cx, message));
// Step 9.
- let runnable = PostMessageHandler::new(self, origin, data);
- let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::DomEvent, box runnable);
- // TODO(#12718): Use the "posted message task source".
- let _ = self.script_chan.send(msg);
+ self.post_message(origin, data);
Ok(())
}
@@ -1910,3 +1907,12 @@ impl Runnable for PostMessageHandler {
message.handle());
}
}
+
+impl Window {
+ pub fn post_message(&self, origin: Option<ImmutableOrigin>, data: StructuredCloneData) {
+ let runnable = PostMessageHandler::new(self, origin, data);
+ let msg = CommonScriptMsg::RunnableMsg(ScriptThreadEventCategory::DomEvent, box runnable);
+ // TODO(#12718): Use the "posted message task source".
+ let _ = self.script_chan.send(msg);
+ }
+}
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 97d1c36d637..0e8e4ceadca 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -36,6 +36,7 @@ use dom::bindings::js::{RootCollectionPtr, RootedReference};
use dom::bindings::num::Finite;
use dom::bindings::reflector::DomObject;
use dom::bindings::str::DOMString;
+use dom::bindings::structuredclone::StructuredCloneData;
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::WRAP_CALLBACKS;
use dom::browsingcontext::BrowsingContext;
@@ -93,7 +94,7 @@ use script_traits::WebVREventMsg;
use script_traits::webdriver_msg::WebDriverScriptCommand;
use serviceworkerjob::{Job, JobQueue, AsyncJobHandler};
use servo_config::opts;
-use servo_url::{MutableOrigin, ServoUrl};
+use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use std::cell::Cell;
use std::collections::{hash_map, HashMap, HashSet};
use std::default::Default;
@@ -1018,6 +1019,8 @@ impl ScriptThread {
self.handle_visibility_change_msg(pipeline_id, visible),
ConstellationControlMsg::NotifyVisibilityChange(parent_pipeline_id, frame_id, visible) =>
self.handle_visibility_change_complete_msg(parent_pipeline_id, frame_id, visible),
+ ConstellationControlMsg::PostMessage(pipeline_id, origin, data) =>
+ self.handle_post_message_msg(pipeline_id, origin, data),
ConstellationControlMsg::MozBrowserEvent(parent_pipeline_id,
frame_id,
event) =>
@@ -1396,6 +1399,13 @@ impl ScriptThread {
}
}
+ fn handle_post_message_msg(&self, pipeline_id: PipelineId, 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)),
+ }
+ }
+
/// Handles a mozbrowser event, for example see:
/// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserloadstart
fn handle_mozbrowser_event_msg(&self,
@@ -1705,7 +1715,7 @@ impl ScriptThread {
match self.browsing_contexts.borrow_mut().entry(incomplete.frame_id) {
hash_map::Entry::Vacant(entry) => {
- let browsing_context = BrowsingContext::new(&window, frame_element);
+ let browsing_context = BrowsingContext::new(&window, incomplete.frame_id, frame_element);
entry.insert(JS::from_ref(&*browsing_context));
window.init_browsing_context(&browsing_context);
},
diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs
index a1d97b8b232..96042083d39 100644
--- a/components/script_traits/lib.rs
+++ b/components/script_traits/lib.rs
@@ -63,6 +63,7 @@ use net_traits::storage_thread::StorageType;
use profile_traits::mem;
use profile_traits::time as profile_time;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
use std::collections::HashMap;
use std::fmt;
@@ -239,6 +240,8 @@ pub enum ConstellationControlMsg {
/// Notifies script thread that a url should be loaded in this iframe.
/// PipelineId is for the parent, FrameId is for the actual frame.
Navigate(PipelineId, FrameId, LoadData, bool),
+ /// Post a message to a given window.
+ PostMessage(PipelineId, Option<ImmutableOrigin>, Vec<u8>),
/// Requests the script thread forward a mozbrowser event to an iframe it owns,
/// or to the window if no child frame id is provided.
MozBrowserEvent(PipelineId, Option<FrameId>, MozBrowserEvent),
@@ -297,6 +300,7 @@ impl fmt::Debug for ConstellationControlMsg {
ChangeFrameVisibilityStatus(..) => "ChangeFrameVisibilityStatus",
NotifyVisibilityChange(..) => "NotifyVisibilityChange",
Navigate(..) => "Navigate",
+ PostMessage(..) => "PostMessage",
MozBrowserEvent(..) => "MozBrowserEvent",
UpdatePipelineId(..) => "UpdatePipelineId",
FocusIFrame(..) => "FocusIFrame",
diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs
index 8aa606c02c5..2fd70174368 100644
--- a/components/script_traits/script_msg.rs
+++ b/components/script_traits/script_msg.rs
@@ -23,6 +23,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use net_traits::CoreResourceMsg;
use net_traits::storage_thread::StorageType;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
+use servo_url::ImmutableOrigin;
use servo_url::ServoUrl;
use style_traits::CSSPixel;
use style_traits::cursor::Cursor;
@@ -93,6 +94,8 @@ pub enum ScriptMsg {
/// A new load has been requested, with an option to replace the current entry once loaded
/// instead of adding a new entry.
LoadUrl(PipelineId, LoadData, bool),
+ /// Post a message to the currently active window of a given browsing context.
+ PostMessage(FrameId, Option<ImmutableOrigin>, Vec<u8>),
/// Dispatch a mozbrowser event to the parent of this pipeline.
/// The first PipelineId is for the parent, the second is for the originating pipeline.
MozBrowserEvent(PipelineId, PipelineId, MozBrowserEvent),
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 366654cac25..5d7438c4e04 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -9378,6 +9378,16 @@
{}
]
],
+ "mozilla/cross-origin-objects/cross-origin-postMessage-child1.html": [
+ [
+ {}
+ ]
+ ],
+ "mozilla/cross-origin-objects/cross-origin-postMessage-child2.html": [
+ [
+ {}
+ ]
+ ],
"mozilla/details_ui_closed_ref.html": [
[
{}
@@ -12532,6 +12542,12 @@
}
]
],
+ "mozilla/cross-origin-objects/cross-origin-postMessage.html": [
+ [
+ "/_mozilla/mozilla/cross-origin-objects/cross-origin-postMessage.html",
+ {}
+ ]
+ ],
"mozilla/deterministic-raf.html": [
[
"/_mozilla/mozilla/deterministic-raf.html",
@@ -25101,6 +25117,18 @@
"5d5a3ba4099dfabddbed1ea98ad8fe1f5c00a3d3",
"testharness"
],
+ "mozilla/cross-origin-objects/cross-origin-postMessage-child1.html": [
+ "6669b133609e17e368a124ddfc52ace940e74156",
+ "support"
+ ],
+ "mozilla/cross-origin-objects/cross-origin-postMessage-child2.html": [
+ "a37cd21178fd25a829be30b0367bd0812db4c211",
+ "support"
+ ],
+ "mozilla/cross-origin-objects/cross-origin-postMessage.html": [
+ "0163758c92997c6723c9d21be49ef7f51d8b3daf",
+ "testharness"
+ ],
"mozilla/details_ui_closed.html": [
"2acbe3afbec267bad4dd986803e636740a707507",
"reftest"
diff --git a/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child1.html b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child1.html
new file mode 100644
index 00000000000..6097799bb60
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage to dissimilar-origin iframe </title>
+</head>
+<body>
+<script>
+ window.addEventListener("message", function(e) {
+ window.location.href = e.data;
+ });
+</script>
+</body>
+</html>
diff --git a/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child2.html b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child2.html
new file mode 100644
index 00000000000..a1395ad2b51
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage-child2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage to dissimilar-origin iframe </title>
+</head>
+<body>
+<script>
+ window.parent.postMessage("OK", "*");
+</script>
+</body>
+</html>
diff --git a/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage.html b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage.html
new file mode 100644
index 00000000000..143240c97aa
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-postMessage.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage to dissimilar-origin iframe </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+<iframe id="child"></iframe>
+
+<script>
+ async_test(function(t) {
+ // child1 is a dissimilar-origin document
+ var childURL1 = new URL("cross-origin-postMessage-child1.html", document.location);
+ childURL1.hostname = "127.0.0.1";
+ // child2 is a same-origin document
+ var childURL2 = new URL("cross-origin-postMessage-child2.html", document.location);
+ // Load child1 into the iframe
+ var childIframe = document.getElementById("child");
+ childIframe.src = childURL1;
+ // Once child1 has loaded, post a message to it, asking it to navigate to child2
+ childIframe.addEventListener("load", t.step_func(function() {
+ childIframe.contentWindow.postMessage(childURL2.toString(), "*");
+ }));
+ // Wait for child2 to post an OK message back to us.
+ // (We don't yet have support for event.source or window.parent,
+ // so we have to wait for the child to become same-origin.)
+ window.addEventListener("message", t.step_func(function(e) {
+ assert_equals(e.data, "OK");
+ assert_equals(childIframe.contentWindow.location.href, childURL2.toString());
+ t.done();
+ }));
+ });
+</script>
+</body>
+</html>