mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
feat(script): Implement [[{Get,Set}PrototypeOf]]
for Location
This commit is contained in:
parent
41cce140bc
commit
722a239715
2 changed files with 150 additions and 18 deletions
|
@ -9,6 +9,8 @@
|
|||
use crate::dom::bindings::conversions::is_dom_proxy;
|
||||
use crate::dom::bindings::error::{throw_dom_exception, Error};
|
||||
use crate::dom::bindings::principals::ServoJSPrincipalsRef;
|
||||
use crate::dom::bindings::reflector::DomObject;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::bindings::utils::delete_property_by_id;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::realms::{AlreadyInRealm, InRealm};
|
||||
|
@ -24,6 +26,7 @@ use js::jsapi::Handle as RawHandle;
|
|||
use js::jsapi::HandleId as RawHandleId;
|
||||
use js::jsapi::HandleObject as RawHandleObject;
|
||||
use js::jsapi::HandleValue as RawHandleValue;
|
||||
use js::jsapi::JSAutoRealm;
|
||||
use js::jsapi::JS_AtomizeAndPinString;
|
||||
use js::jsapi::JS_DefinePropertyById;
|
||||
use js::jsapi::JS_GetOwnPropertyDescriptorById;
|
||||
|
@ -139,7 +142,7 @@ pub unsafe extern "C" fn is_extensible(
|
|||
///
|
||||
/// This implementation always handles the case of the ordinary
|
||||
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
|
||||
/// necessary for the Location object.
|
||||
/// necessary for maybe-cross-origin objects.
|
||||
pub unsafe extern "C" fn get_prototype_if_ordinary(
|
||||
_: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
|
@ -203,13 +206,29 @@ pub unsafe fn is_platform_object_same_origin(cx: SafeJSContext, obj: RawHandleOb
|
|||
let obj_realm = GetObjectRealmOrNull(*obj);
|
||||
assert!(!obj_realm.is_null());
|
||||
|
||||
let subject = ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(subject_realm));
|
||||
let obj = ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(obj_realm));
|
||||
let subject_principals =
|
||||
ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(subject_realm));
|
||||
let obj_principals = ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(obj_realm));
|
||||
|
||||
let subject_origin = subject.origin();
|
||||
let obj_origin = obj.origin();
|
||||
let subject_origin = subject_principals.origin();
|
||||
let obj_origin = obj_principals.origin();
|
||||
|
||||
subject_origin.same_origin_domain(&obj_origin)
|
||||
let result = subject_origin.same_origin_domain(&obj_origin);
|
||||
log::trace!(
|
||||
"object {:p} (realm = {:p}, principalls = {:p}, origin = {:?}) is {} \
|
||||
with reference to the current Realm (realm = {:p}, principals = {:p}, \
|
||||
origin = {:?})",
|
||||
obj.get(),
|
||||
obj_realm,
|
||||
obj_principals.as_raw(),
|
||||
obj_origin.immutable(),
|
||||
["NOT same domain-origin", "same domain-origin"][result as usize],
|
||||
subject_realm,
|
||||
subject_principals.as_raw(),
|
||||
subject_origin.immutable()
|
||||
);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Report a cross-origin denial for a property, Always returns `false`, so it
|
||||
|
@ -218,11 +237,12 @@ pub unsafe fn is_platform_object_same_origin(cx: SafeJSContext, obj: RawHandleOb
|
|||
/// What this function does corresponds to the operations in
|
||||
/// <https://html.spec.whatwg.org/multipage/#the-location-interface> denoted as
|
||||
/// "Throw a `SecurityError` DOMException".
|
||||
pub unsafe fn report_cross_origin_denial(
|
||||
cx: SafeJSContext,
|
||||
_id: RawHandleId,
|
||||
_access: &str,
|
||||
) -> bool {
|
||||
pub unsafe fn report_cross_origin_denial(cx: SafeJSContext, id: RawHandleId, access: &str) -> bool {
|
||||
debug!(
|
||||
"permission denied to {} property {} on cross-origin object",
|
||||
access,
|
||||
id_to_source(cx, id).as_deref().unwrap_or("< error >"),
|
||||
);
|
||||
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
|
||||
if !JS_IsExceptionPending(*cx) {
|
||||
let global = GlobalScope::from_context(*cx, InRealm::Already(&in_realm_proof));
|
||||
|
@ -232,6 +252,18 @@ pub unsafe fn report_cross_origin_denial(
|
|||
false
|
||||
}
|
||||
|
||||
unsafe fn id_to_source(cx: SafeJSContext, id: RawHandleId) -> Option<DOMString> {
|
||||
rooted!(in(*cx) let mut value = UndefinedValue());
|
||||
rooted!(in(*cx) let mut jsstr = ptr::null_mut::<jsapi::JSString>());
|
||||
jsapi::JS_IdToValue(*cx, id.get(), value.handle_mut().into())
|
||||
.then(|| {
|
||||
jsstr.set(jsapi::JS_ValueToSource(*cx, value.handle().into()));
|
||||
jsstr.get()
|
||||
})
|
||||
.filter(|jsstr| !jsstr.is_null())
|
||||
.map(|jsstr| crate::dom::bindings::conversions::jsstring_to_str(*cx, jsstr))
|
||||
}
|
||||
|
||||
/// Property and method specs that correspond to the elements of
|
||||
/// [`CrossOriginProperties(O)`].
|
||||
///
|
||||
|
@ -272,6 +304,76 @@ pub unsafe fn cross_origin_own_property_keys(
|
|||
true
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
|
||||
_: *mut JSContext,
|
||||
_proxy: RawHandleObject,
|
||||
is_ordinary: *mut bool,
|
||||
_proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// We have a custom `[[GetPrototypeOf]]`, so return `false`
|
||||
*is_ordinary = false;
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[GetPrototypeOf]]` for [`History`].
|
||||
///
|
||||
/// [`History`]: https://html.spec.whatwg.org/multipage/#location-getprototypeof
|
||||
pub unsafe fn maybe_cross_origin_get_prototype(
|
||||
cx: SafeJSContext,
|
||||
proxy: RawHandleObject,
|
||||
get_proto_object: unsafe fn(cx: SafeJSContext, global: HandleObject, rval: MutableHandleObject),
|
||||
proto: RawMutableHandleObject,
|
||||
) -> bool {
|
||||
// > 1. If ! IsPlatformObjectSameOrigin(this) is true, then return ! OrdinaryGetPrototypeOf(this).
|
||||
if is_platform_object_same_origin(cx, proxy) {
|
||||
let ac = JSAutoRealm::new(*cx, proxy.get());
|
||||
let global = GlobalScope::from_context(*cx, InRealm::Entered(&ac));
|
||||
get_proto_object(
|
||||
cx,
|
||||
global.reflector().get_jsobject(),
|
||||
MutableHandleObject::from_raw(proto),
|
||||
);
|
||||
return !proto.is_null();
|
||||
}
|
||||
|
||||
// > 2. Return null.
|
||||
proto.set(ptr::null_mut());
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of `[[SetPrototypeOf]]` for [`History`] and [`WindowProxy`].
|
||||
///
|
||||
/// [`History`]: https://html.spec.whatwg.org/multipage/#location-setprototypeof
|
||||
/// [`WindowProxy`]: https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-setprototypeof
|
||||
pub unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
|
||||
cx: *mut JSContext,
|
||||
proxy: RawHandleObject,
|
||||
proto: RawHandleObject,
|
||||
result: *mut ObjectOpResult,
|
||||
) -> bool {
|
||||
// > 1. Return `! SetImmutablePrototype(this, V)`.
|
||||
//
|
||||
// <https://tc39.es/ecma262/#sec-set-immutable-prototype>
|
||||
//
|
||||
// > 1. Assert: Either `Type(V)` is Object or `Type(V)` is Null.
|
||||
//
|
||||
// > 2. Let current be `? O.[[GetPrototypeOf]]()`.
|
||||
rooted!(in(cx) let mut current = ptr::null_mut::<JSObject>());
|
||||
if !jsapi::GetObjectProto(cx, proxy, current.handle_mut().into()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// > 3. If `SameValue(V, current)` is true, return true.
|
||||
if proto.get() == current.get() {
|
||||
(*result).code_ = 0 /* OkCode */;
|
||||
return true;
|
||||
}
|
||||
|
||||
// > 4. Return false.
|
||||
(*result).code_ = JSErrNum::JSMSG_CANT_SET_PROTO as usize;
|
||||
true
|
||||
}
|
||||
|
||||
/// Implementation of [`CrossOriginGet`].
|
||||
///
|
||||
/// [`CrossOriginGet`]: https://html.spec.whatwg.org/multipage/#crossoriginget-(-o,-p,-receiver-)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue