aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/browsingcontext.rs187
-rw-r--r--components/script/dom/dissimilaroriginlocation.rs80
-rw-r--r--components/script/dom/dissimilaroriginwindow.rs140
-rw-r--r--components/script/dom/mod.rs2
-rw-r--r--components/script/dom/webidls/DissimilarOriginLocation.webidl25
-rw-r--r--components/script/dom/webidls/DissimilarOriginWindow.webidl32
-rw-r--r--components/script/dom/window.rs7
-rw-r--r--components/script/script_thread.rs6
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json12
-rw-r--r--tests/wpt/mozilla/meta/mozilla/cross-origin-objects/cross-origin-objects.html.ini5
-rw-r--r--tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-objects.html118
11 files changed, 598 insertions, 16 deletions
diff --git a/components/script/dom/browsingcontext.rs b/components/script/dom/browsingcontext.rs
index 9f0be02e484..5e523d6982a 100644
--- a/components/script/dom/browsingcontext.rs
+++ b/components/script/dom/browsingcontext.rs
@@ -3,13 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
+use dom::bindings::error::{Error, throw_dom_exception};
+use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::reflector::{DomObject, Reflector};
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::WindowProxyHandler;
use dom::bindings::utils::get_array_index_from_id;
+use dom::dissimilaroriginwindow::DissimilarOriginWindow;
use dom::element::Element;
+use dom::globalscope::GlobalScope;
use dom::window::Window;
use js::JSCLASS_IS_GLOBAL;
use js::glue::{CreateWrapperProxyHandler, ProxyTraps, NewWindowProxy};
@@ -18,12 +22,13 @@ use js::jsapi::{Handle, HandleId, HandleObject, HandleValue};
use js::jsapi::{JSAutoCompartment, JSContext, JSErrNum, JSFreeOp, JSObject};
use js::jsapi::{JSPROP_READONLY, JSTracer, JS_DefinePropertyById};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo};
-use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById};
-use js::jsapi::{JS_TransplantObject, SetWindowProxy};
+use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, JS_HasOwnPropertyById};
+use js::jsapi::{JS_IsExceptionPending, JS_TransplantObject, SetWindowProxy};
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::PipelineId;
use std::cell::Cell;
use std::ptr;
@@ -39,6 +44,13 @@ pub struct BrowsingContext {
/// changes Window.
reflector: Reflector,
+ /// 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,
+ /// as this would require the constellation notifying many script threads about
+ /// the change, which could be expensive.
+ currently_active: Cell<Option<PipelineId>>,
+
/// Has this browsing context been discarded?
discarded: Cell<bool>,
@@ -47,9 +59,10 @@ pub struct BrowsingContext {
}
impl BrowsingContext {
- pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
+ pub fn new_inherited(currently_active: PipelineId, frame_element: Option<&Element>) -> BrowsingContext {
BrowsingContext {
reflector: Reflector::new(),
+ currently_active: Cell::new(Some(currently_active)),
discarded: Cell::new(false),
frame_element: frame_element.map(JS::from_ref),
}
@@ -72,7 +85,8 @@ impl BrowsingContext {
assert!(!window_proxy.is_null());
// Create a new browsing context.
- let mut browsing_context = box BrowsingContext::new_inherited(frame_element);
+ let currently_active = window.global().pipeline_id();
+ let mut browsing_context = box BrowsingContext::new_inherited(currently_active, frame_element);
// The window proxy owns the browsing context.
// When we finalize the window proxy, it drops the browsing context it owns.
@@ -104,10 +118,10 @@ impl BrowsingContext {
/// Change the Window that this browsing context's WindowProxy resolves to.
// TODO: support setting the window proxy to a dummy value,
// to handle the case when the active document is in another script thread.
- pub fn set_window_proxy(&self, window: &Window) {
+ fn set_window_proxy(&self, window: &GlobalScope, traps: &ProxyTraps) {
unsafe {
debug!("Setting window proxy of {:p}.", self);
- let WindowProxyHandler(handler) = window.windowproxy_handler();
+ let handler = CreateWrapperProxyHandler(traps);
assert!(!handler.is_null());
let cx = window.get_cx();
@@ -144,6 +158,22 @@ impl BrowsingContext {
}
}
+ pub fn set_currently_active(&self, window: &Window) {
+ let globalscope = window.upcast();
+ self.set_window_proxy(&*globalscope, &PROXY_HANDLER);
+ self.currently_active.set(Some(globalscope.pipeline_id()));
+ }
+
+ pub fn unset_currently_active(&self) {
+ let window = DissimilarOriginWindow::new(self);
+ self.set_window_proxy(&*window.upcast(), &XORIGIN_PROXY_HANDLER);
+ self.currently_active.set(None);
+ }
+
+ pub fn currently_active(&self) -> Option<PipelineId> {
+ self.currently_active.get()
+ }
+
pub fn window_proxy(&self) -> *mut JSObject {
let window_proxy = self.reflector.get_jsobject();
assert!(!window_proxy.get().is_null());
@@ -333,6 +363,145 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps {
};
#[allow(unsafe_code)]
+pub fn new_window_proxy_handler() -> WindowProxyHandler {
+ unsafe {
+ WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
+ }
+}
+
+// The proxy traps for cross-origin windows.
+// These traps often throw security errors, and only pass on calls to methods
+// defined in the DissimilarOriginWindow IDL.
+
+#[allow(unsafe_code)]
+unsafe fn throw_security_error(cx: *mut JSContext) -> bool {
+ if !JS_IsExceptionPending(cx) {
+ let global = GlobalScope::from_context(cx);
+ throw_dom_exception(cx, &*global, Error::Security);
+ }
+ false
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn has_xorigin(cx: *mut JSContext,
+ proxy: HandleObject,
+ id: HandleId,
+ bp: *mut bool)
+ -> bool
+{
+ rooted!(in(cx) let target = GetProxyPrivate(*proxy.ptr).to_object());
+ let mut found = false;
+ JS_HasOwnPropertyById(cx, target.handle(), id, &mut found);
+ if found {
+ *bp = true;
+ true
+ } else {
+ throw_security_error(cx)
+ }
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn get_xorigin(cx: *mut JSContext,
+ proxy: HandleObject,
+ receiver: HandleValue,
+ id: HandleId,
+ vp: MutableHandleValue)
+ -> bool
+{
+ let mut found = false;
+ has_xorigin(cx, proxy, id, &mut found);
+ found && get(cx, proxy, receiver, id, vp)
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn set_xorigin(cx: *mut JSContext,
+ _: HandleObject,
+ _: HandleId,
+ _: HandleValue,
+ _: HandleValue,
+ _: *mut ObjectOpResult)
+ -> bool
+{
+ throw_security_error(cx)
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn delete_xorigin(cx: *mut JSContext,
+ _: HandleObject,
+ _: HandleId,
+ _: *mut ObjectOpResult)
+ -> bool
+{
+ throw_security_error(cx)
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn getOwnPropertyDescriptor_xorigin(cx: *mut JSContext,
+ proxy: HandleObject,
+ id: HandleId,
+ desc: MutableHandle<PropertyDescriptor>)
+ -> bool
+{
+ let mut found = false;
+ has_xorigin(cx, proxy, id, &mut found);
+ found && getOwnPropertyDescriptor(cx, proxy, id, desc)
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn defineProperty_xorigin(cx: *mut JSContext,
+ _: HandleObject,
+ _: HandleId,
+ _: Handle<PropertyDescriptor>,
+ _: *mut ObjectOpResult)
+ -> bool
+{
+ throw_security_error(cx)
+}
+
+#[allow(unsafe_code)]
+unsafe extern "C" fn preventExtensions_xorigin(cx: *mut JSContext,
+ _: HandleObject,
+ _: *mut ObjectOpResult)
+ -> bool
+{
+ throw_security_error(cx)
+}
+
+static XORIGIN_PROXY_HANDLER: ProxyTraps = ProxyTraps {
+ enter: None,
+ getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor_xorigin),
+ defineProperty: Some(defineProperty_xorigin),
+ ownPropertyKeys: None,
+ delete_: Some(delete_xorigin),
+ enumerate: None,
+ getPrototypeIfOrdinary: None,
+ preventExtensions: Some(preventExtensions_xorigin),
+ isExtensible: None,
+ has: Some(has_xorigin),
+ get: Some(get_xorigin),
+ set: Some(set_xorigin),
+ call: None,
+ construct: None,
+ getPropertyDescriptor: Some(getOwnPropertyDescriptor_xorigin),
+ hasOwn: Some(has_xorigin),
+ getOwnEnumerablePropertyKeys: None,
+ nativeCall: None,
+ hasInstance: None,
+ objectClassIs: None,
+ className: None,
+ fun_toString: None,
+ boxedValue_unbox: None,
+ defaultValue: None,
+ trace: Some(trace),
+ finalize: Some(finalize),
+ objectMoved: None,
+ isCallable: None,
+ isConstructor: None,
+};
+
+// How WindowProxy objects are garbage collected.
+
+#[allow(unsafe_code)]
unsafe extern fn finalize(_fop: *mut JSFreeOp, obj: *mut JSObject) {
let this = GetProxyExtra(obj, 0).to_private() as *mut BrowsingContext;
if this.is_null() {
@@ -354,9 +523,3 @@ unsafe extern fn trace(trc: *mut JSTracer, obj: *mut JSObject) {
(*this).trace(trc);
}
-#[allow(unsafe_code)]
-pub fn new_window_proxy_handler() -> WindowProxyHandler {
- unsafe {
- WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
- }
-}
diff --git a/components/script/dom/dissimilaroriginlocation.rs b/components/script/dom/dissimilaroriginlocation.rs
new file mode 100644
index 00000000000..6f5eda8c402
--- /dev/null
+++ b/components/script/dom/dissimilaroriginlocation.rs
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::DissimilarOriginLocationBinding;
+use dom::bindings::codegen::Bindings::DissimilarOriginLocationBinding::DissimilarOriginLocationMethods;
+use dom::bindings::error::{Error, ErrorResult, Fallible};
+use dom::bindings::js::{JS, Root};
+use dom::bindings::reflector::Reflector;
+use dom::bindings::reflector::reflect_dom_object;
+use dom::bindings::str::DOMString;
+use dom::bindings::str::USVString;
+use dom::dissimilaroriginwindow::DissimilarOriginWindow;
+
+/// Represents a dissimilar-origin `Location` that exists in another script thread.
+///
+/// Since the `Location` is in a different script thread, we cannot access it
+/// directly, but some of its accessors (for example setting `location.href`)
+/// still need to function.
+
+#[dom_struct]
+pub struct DissimilarOriginLocation {
+ /// The reflector. Once we have XOWs, this will have a cross-origin
+ /// wrapper placed around it.
+ reflector: Reflector,
+
+ /// The window associated with this location.
+ window: JS<DissimilarOriginWindow>,
+}
+
+impl DissimilarOriginLocation {
+ #[allow(unrooted_must_root)]
+ fn new_inherited(window: &DissimilarOriginWindow) -> DissimilarOriginLocation {
+ DissimilarOriginLocation {
+ reflector: Reflector::new(),
+ window: JS::from_ref(window),
+ }
+ }
+
+ pub fn new(window: &DissimilarOriginWindow) -> Root<DissimilarOriginLocation> {
+ reflect_dom_object(box DissimilarOriginLocation::new_inherited(window),
+ window,
+ DissimilarOriginLocationBinding::Wrap)
+ }
+}
+
+impl DissimilarOriginLocationMethods for DissimilarOriginLocation {
+ // https://html.spec.whatwg.org/multipage/#dom-location-href
+ fn GetHref(&self) -> Fallible<USVString> {
+ Err(Error::Security)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location-href
+ fn SetHref(&self, _: USVString) -> ErrorResult {
+ // TODO: setting href on a cross-origin window should succeed?
+ Err(Error::Security)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location-assign
+ fn Assign(&self, _: USVString) -> Fallible<()> {
+ // TODO: setting href on a cross-origin window should succeed?
+ Err(Error::Security)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location-replace
+ fn Replace(&self, _: USVString) -> Fallible<()> {
+ // TODO: replacing href on a cross-origin window should succeed?
+ Err(Error::Security)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location-reload
+ fn Reload(&self) -> Fallible<()> {
+ Err(Error::Security)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location-href
+ fn Stringifier(&self) -> Fallible<DOMString> {
+ Err(Error::Security)
+ }
+}
diff --git a/components/script/dom/dissimilaroriginwindow.rs b/components/script/dom/dissimilaroriginwindow.rs
new file mode 100644
index 00000000000..518adb0f341
--- /dev/null
+++ b/components/script/dom/dissimilaroriginwindow.rs
@@ -0,0 +1,140 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding;
+use dom::bindings::codegen::Bindings::DissimilarOriginWindowBinding::DissimilarOriginWindowMethods;
+use dom::bindings::js::{JS, MutNullableJS, Root};
+use dom::bindings::reflector::DomObject;
+use dom::bindings::str::DOMString;
+use dom::browsingcontext::BrowsingContext;
+use dom::dissimilaroriginlocation::DissimilarOriginLocation;
+use dom::globalscope::GlobalScope;
+use ipc_channel::ipc;
+use js::jsapi::{JSContext, HandleValue};
+use js::jsval::{JSVal, UndefinedValue};
+use msg::constellation_msg::PipelineId;
+
+/// Represents a dissimilar-origin `Window` that exists in another script thread.
+///
+/// Since the `Window` is in a different script thread, we cannot access it
+/// directly, but some of its accessors (for example `window.parent`)
+/// still need to function.
+///
+/// In `browsingcontext.rs`, we create a custom window proxy for these windows,
+/// that throws security exceptions for most accessors. This is not a replacement
+/// for XOWs, but provides belt-and-braces security.
+#[dom_struct]
+pub struct DissimilarOriginWindow {
+ /// The global for this window.
+ globalscope: GlobalScope,
+
+ /// The browsing context this window is part of.
+ browsing_context: JS<BrowsingContext>,
+
+ /// The location of this window, initialized lazily.
+ location: MutNullableJS<DissimilarOriginLocation>,
+}
+
+impl DissimilarOriginWindow {
+ #[allow(unsafe_code)]
+ pub fn new(browsing_context: &BrowsingContext) -> Root<DissimilarOriginWindow> {
+ let globalscope = browsing_context.global();
+ let cx = globalscope.get_cx();
+ // Any timer events fired on this window are ignored.
+ let (timer_event_chan, _) = ipc::channel().unwrap();
+ let win = box DissimilarOriginWindow {
+ globalscope: GlobalScope::new_inherited(PipelineId::new(),
+ globalscope.devtools_chan().cloned(),
+ globalscope.mem_profiler_chan().clone(),
+ globalscope.time_profiler_chan().clone(),
+ globalscope.constellation_chan().clone(),
+ globalscope.scheduler_chan().clone(),
+ globalscope.resource_threads().clone(),
+ timer_event_chan),
+ browsing_context: JS::from_ref(browsing_context),
+ location: MutNullableJS::new(None),
+ };
+ unsafe { DissimilarOriginWindowBinding::Wrap(cx, win) }
+ }
+}
+
+impl DissimilarOriginWindowMethods for DissimilarOriginWindow {
+ // https://html.spec.whatwg.org/multipage/#dom-window
+ fn Window(&self) -> Root<BrowsingContext> {
+ Root::from_ref(&*self.browsing_context)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-self
+ fn Self_(&self) -> Root<BrowsingContext> {
+ Root::from_ref(&*self.browsing_context)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-frames
+ fn Frames(&self) -> Root<BrowsingContext> {
+ Root::from_ref(&*self.browsing_context)
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-parent
+ fn GetParent(&self) -> Option<Root<BrowsingContext>> {
+ // TODO: implement window.parent correctly for x-origin windows.
+ Some(Root::from_ref(&*self.browsing_context))
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-top
+ fn GetTop(&self) -> Option<Root<BrowsingContext>> {
+ // TODO: implement window.top correctly for x-origin windows.
+ Some(Root::from_ref(&*self.browsing_context))
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-length
+ fn Length(&self) -> u32 {
+ // TODO: Implement x-origin length
+ 0
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-window-close
+ fn Close(&self) {
+ // TODO: Implement x-origin close
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-window-closed
+ fn Closed(&self) -> bool {
+ // TODO: Implement x-origin close
+ false
+ }
+
+ #[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
+ }
+
+ #[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#dom-opener
+ unsafe fn Opener(&self, _: *mut JSContext) -> JSVal {
+ // TODO: Implement x-origin opener
+ UndefinedValue()
+ }
+
+ #[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#dom-opener
+ unsafe fn SetOpener(&self, _: *mut JSContext, _: HandleValue) {
+ // TODO: Implement x-origin opener
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-window-blur
+ fn Blur(&self) {
+ // TODO: Implement x-origin blur
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-focus
+ fn Focus(&self) {
+ // TODO: Implement x-origin focus
+ }
+
+ // https://html.spec.whatwg.org/multipage/#dom-location
+ fn Location(&self) -> Root<DissimilarOriginLocation> {
+ self.location.or_init(|| DissimilarOriginLocation::new(self))
+ }
+}
diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs
index 4b3c0c02cbb..7b96ea2523d 100644
--- a/components/script/dom/mod.rs
+++ b/components/script/dom/mod.rs
@@ -258,6 +258,8 @@ pub mod csssupportsrule;
pub mod cssviewportrule;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
+pub mod dissimilaroriginlocation;
+pub mod dissimilaroriginwindow;
pub mod document;
pub mod documentfragment;
pub mod documenttype;
diff --git a/components/script/dom/webidls/DissimilarOriginLocation.webidl b/components/script/dom/webidls/DissimilarOriginLocation.webidl
new file mode 100644
index 00000000000..8eca6a790ac
--- /dev/null
+++ b/components/script/dom/webidls/DissimilarOriginLocation.webidl
@@ -0,0 +1,25 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+// This is a Servo-specific interface, used to represent locations
+// that are not similar-origin, so live in another script thread.
+// It is based on the interface for Window, but only contains the
+// accessors that do not throw security exceptions when called
+// cross-origin.
+//
+// Note that similar-origin locations are kept in the same script
+// thread, so this mechanism cannot be relied upon as the only
+// way to enforce security policy.
+
+// https://html.spec.whatwg.org/multipage/#location
+[Unforgeable, NoInterfaceObject] interface DissimilarOriginLocation {
+ [Throws] attribute USVString href;
+ [Throws] void assign(USVString url);
+ [Throws] void replace(USVString url);
+ [Throws] void reload();
+ [Throws] stringifier;
+
+ // TODO: finish this interface
+};
diff --git a/components/script/dom/webidls/DissimilarOriginWindow.webidl b/components/script/dom/webidls/DissimilarOriginWindow.webidl
new file mode 100644
index 00000000000..6aeb5c7d1b2
--- /dev/null
+++ b/components/script/dom/webidls/DissimilarOriginWindow.webidl
@@ -0,0 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This is a Servo-specific interface, used to represent windows
+// that are not similar-origin, so live in another script thread.
+// It is based on the interface for Window, but only contains the
+// accessors that do not throw security exceptions when called
+// cross-origin.
+//
+// Note that similar-origin windows are kept in the same script
+// thread, so this mechanism cannot be relied upon as the only
+// way to enforce security policy.
+
+// https://html.spec.whatwg.org/multipage/#window
+[Global, NoInterfaceObject]
+interface DissimilarOriginWindow : GlobalScope {
+ [Unforgeable] readonly attribute WindowProxy window;
+ [BinaryName="Self_", Replaceable] readonly attribute WindowProxy self;
+ [Unforgeable] readonly attribute WindowProxy? parent;
+ [Unforgeable] readonly attribute WindowProxy? top;
+ [Replaceable] readonly attribute WindowProxy frames;
+ [Replaceable] readonly attribute unsigned long length;
+ [Unforgeable] readonly attribute DissimilarOriginLocation location;
+
+ void close();
+ readonly attribute boolean closed;
+ 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 d1eba0245e0..1fbe57ba165 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1514,7 +1514,10 @@ impl Window {
// Suspend timer events.
self.upcast::<GlobalScope>().suspend();
- // TODO: set the window proxy to resolve to an object which throws security errors. #15233
+ // Set the window proxy to be a cross-origin window.
+ if self.browsing_context().currently_active() == Some(self.global().pipeline_id()) {
+ self.browsing_context().unset_currently_active();
+ }
// A hint to the JS runtime that now would be a good time to
// GC any unreachable objects generated by user script,
@@ -1528,7 +1531,7 @@ impl Window {
self.upcast::<GlobalScope>().resume();
// Set the window proxy to be this object.
- self.browsing_context().set_window_proxy(&self);
+ self.browsing_context().set_currently_active(self);
// Push the document title to the compositor since we are
// activating this document due to a navigation.
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index fa83eaed631..ac093a7a5df 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -1678,7 +1678,7 @@ impl ScriptThread {
},
hash_map::Entry::Occupied(entry) => {
let browsing_context = entry.get();
- browsing_context.set_window_proxy(&window);
+ browsing_context.set_currently_active(&*window);
window.init_browsing_context(browsing_context);
},
}
@@ -1782,7 +1782,9 @@ impl ScriptThread {
ServoParser::parse_html_document(&document, parse_input, final_url);
}
- if incomplete.activity != DocumentActivity::FullyActive {
+ if incomplete.activity == DocumentActivity::FullyActive {
+ window.resume();
+ } else {
window.suspend();
}
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index c73fdd4a390..0862b709f6b 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -12721,6 +12721,14 @@
{}
]
],
+ "mozilla/cross-origin-objects/cross-origin-objects.html": [
+ [
+ "/_mozilla/mozilla/cross-origin-objects/cross-origin-objects.html",
+ {
+ "timeout": "long"
+ }
+ ]
+ ],
"mozilla/deterministic-raf.html": [
[
"/_mozilla/mozilla/deterministic-raf.html",
@@ -25350,6 +25358,10 @@
"f1029d519aa7017a1a3d18a891a0774b9a39f847",
"testharness"
],
+ "mozilla/cross-origin-objects/cross-origin-objects.html": [
+ "5d5a3ba4099dfabddbed1ea98ad8fe1f5c00a3d3",
+ "testharness"
+ ],
"mozilla/details_ui_closed.html": [
"2acbe3afbec267bad4dd986803e636740a707507",
"reftest"
diff --git a/tests/wpt/mozilla/meta/mozilla/cross-origin-objects/cross-origin-objects.html.ini b/tests/wpt/mozilla/meta/mozilla/cross-origin-objects/cross-origin-objects.html.ini
new file mode 100644
index 00000000000..6c0df60a409
--- /dev/null
+++ b/tests/wpt/mozilla/meta/mozilla/cross-origin-objects/cross-origin-objects.html.ini
@@ -0,0 +1,5 @@
+[cross-origin-objects.html]
+ type: testharness
+
+ [Parentage of cross-origin windows]
+ expected: FAIL
diff --git a/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-objects.html b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-objects.html
new file mode 100644
index 00000000000..d7b0e0da1ac
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/cross-origin-objects/cross-origin-objects.html
@@ -0,0 +1,118 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>Cross-origin behavior of Window and Location</title>
+<link rel="author" title="Bobby Holley (:bholley)" href="bobbyholley@gmail.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#security-window">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#security-location">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+
+/*
+ * This is a stripped down version of
+ * /html/browsers/origin/cross-origin-objects/cross-origin-objects.html,
+ * which runs the tests in a dissimilar-origin iframe.
+ * This is a temporary work-around until the web-platform-tests supports
+ * more than one domain.
+ */
+
+var UrlB = "/common/blank.html";
+var UrlC = "http://127.0.0.1:8000/common/blank.html";
+
+/*
+ * Parentage
+ */
+
+async_test(function(t) {
+ var IframeB = document.createElement("iframe");
+ var IframeC = document.createElement("iframe");
+ var B = null;
+ var C = null;
+ IframeC.onload = t.step_func(function() {
+ if (!B || !C) {
+ B = IframeB.contentWindow;
+ C = IframeC.contentWindow;
+ IframeB.src = UrlB;
+ IframeC.src = UrlC;
+ } else {
+ assert_equals(B.parent, window, "window.parent works same-origin");
+ assert_equals(C.parent, window, "window.parent works cross-origin");
+ assert_equals(B.top, window, "window.top works same-origin");
+ assert_equals(C.top, window, "window.top works cross-origin");
+ t.done();
+ }
+ });
+ document.body.appendChild(IframeB);
+ document.body.appendChild(IframeC);
+},"Parentage of cross-origin windows");
+
+/*
+ * Whitelist behavior.
+ *
+ * Also tests for [[GetOwnProperty]] and [[HasOwnProperty]] behavior.
+ */
+
+var whitelistedWindowIndices = ['0', '1'];
+var whitelistedWindowPropNames = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent',
+ 'opener', 'closed', 'close', 'blur', 'focus', 'length'];
+whitelistedWindowPropNames = whitelistedWindowPropNames.concat(whitelistedWindowIndices);
+whitelistedWindowPropNames.sort();
+var whitelistedLocationPropNames = ['href', 'replace'];
+whitelistedLocationPropNames.sort();
+var whitelistedSymbols = [Symbol.toStringTag, Symbol.hasInstance,
+ Symbol.isConcatSpreadable];
+var whitelistedWindowProps = whitelistedWindowPropNames.concat(whitelistedSymbols);
+
+async_test(function(t) {
+ var IframeB = document.createElement("iframe");
+ var IframeC = document.createElement("iframe");
+ var B = null;
+ var C = null;
+ IframeC.onload = t.step_func(function() {
+ if (!B || !C) {
+ B = IframeB.contentWindow;
+ C = IframeC.contentWindow;
+ IframeB.src = UrlB;
+ IframeC.src = UrlC;
+ } else {
+ for (var prop in window) {
+ if (whitelistedWindowProps.indexOf(prop) != -1) {
+ C[prop]; // Shouldn't throw.
+ Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw.
+ assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + String(prop));
+ } else {
+ assert_throws("SecurityError", function() { C[prop]; }, "Should throw when accessing " + String(prop) + " on Window");
+ assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); },
+ "Should throw when accessing property descriptor for " + prop + " on Window");
+ assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); },
+ "Should throw when invoking hasOwnProperty for " + prop + " on Window");
+ }
+ if (prop != 'location')
+ assert_throws("SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window");
+ }
+ for (var prop in location) {
+ if (prop == 'replace') {
+ C.location[prop]; // Shouldn't throw.
+ Object.getOwnPropertyDescriptor(C.location, prop); // Shouldn't throw.
+ assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop);
+ }
+ else {
+ assert_throws("SecurityError", function() { C[prop]; }, "Should throw when accessing " + prop + " on Location");
+ assert_throws("SecurityError", function() { Object.getOwnPropertyDescriptor(C, prop); },
+ "Should throw when accessing property descriptor for " + prop + " on Location");
+ assert_throws("SecurityError", function() { Object.prototype.hasOwnProperty.call(C, prop); },
+ "Should throw when invoking hasOwnProperty for " + prop + " on Location");
+ }
+ if (prop != 'href')
+ assert_throws("SecurityError", function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
+ }
+ t.done();
+ }
+ });
+ document.body.appendChild(IframeB);
+ document.body.appendChild(IframeC);
+}, "Only whitelisted properties are accessible cross-origin");
+
+</script>