mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Allow browsing contexts to resolve to cross-origin windows.
This commit is contained in:
parent
4a0b730caf
commit
e8d765557f
11 changed files with 598 additions and 16 deletions
|
@ -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());
|
||||
|
@ -332,6 +362,145 @@ static PROXY_HANDLER: ProxyTraps = ProxyTraps {
|
|||
isConstructor: None,
|
||||
};
|
||||
|
||||
#[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;
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue