use std::ffi::{CStr, CString};
use std::ops::{Deref, DerefMut};
use std::os::raw::c_char;
use std::ptr;
use std::ptr::NonNull;
use js::context::{JSContext, RawJSContext};
use js::conversions::{ToJSValConvertible, jsstr_to_string};
use js::glue::{GetProxyHandler, GetProxyHandlerFamily, GetProxyPrivate, SetProxyPrivate};
use js::jsapi::{
DOMProxyShadowsResult, GetObjectRealmOrNull, GetRealmPrincipals, GetStaticPrototype,
Handle as RawHandle, HandleId as RawHandleId, HandleObject as RawHandleObject,
HandleValue as RawHandleValue, HandleValueArray, IsWindowProxy, JSErrNum, JSFunctionSpec,
JSITER_HIDDEN, JSITER_OWNONLY, JSITER_SYMBOLS, JSObject, JSPROP_READONLY, JSPropertySpec,
JSString, MutableHandleIdVector as RawMutableHandleIdVector,
MutableHandleObject as RawMutableHandleObject, ObjectOpResult, PropertyDescriptor,
SetDOMProxyInformation, SymbolCode, jsid,
};
use js::jsid::SymbolId;
use js::jsval::{ObjectValue, UndefinedValue};
use js::realm::{AutoRealm, CurrentRealm};
use js::rust::wrappers2::{
AppendToIdVector, Call, GetObjectProto, GetPropertyKeys, GetWellKnownSymbol,
InvokeGetOwnPropertyDescriptor, JS_AlreadyHasOwnPropertyById, JS_AtomizeAndPinString,
JS_DefineFunctions, JS_DefineProperties, JS_DefinePropertyById, JS_DeletePropertyById,
JS_GetOwnPropertyDescriptorById, JS_IdToValue, JS_IsExceptionPending,
JS_NewObjectWithGivenProto, JS_ValueToSource, RUST_INTERNED_STRING_TO_JSID, RUST_JSID_IS_VOID,
SetDataPropertyDescriptor, SetPropertyIgnoringNamedGetter, int_to_jsid,
};
use js::rust::{
Handle, HandleId, HandleObject, HandleValue, IntoHandle, MutableHandle, MutableHandleObject,
MutableHandleValue,
};
use crate::DomTypes;
use crate::conversions::{is_dom_proxy, jsid_to_string, native_from_object};
use crate::error::Error;
use crate::interfaces::{DomHelpers, GlobalScopeHelpers};
use crate::principals::ServoJSPrincipalsRef;
use crate::reflector::DomObject;
use crate::str::DOMString;
pub(crate) unsafe extern "C" fn shadow_check_callback(
cx: *mut RawJSContext,
object: RawHandleObject,
id: RawHandleId,
) -> DOMProxyShadowsResult {
let mut cx = JSContext::from_ptr(NonNull::new(cx).unwrap());
let cx = &mut cx;
let object = HandleObject::from_raw(object);
rooted!(&in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(object, expando.handle_mut());
if !expando.get().is_null() {
let mut has_own = false;
let raw_id = Handle::from_raw(id);
if !JS_AlreadyHasOwnPropertyById(cx, expando.handle(), raw_id, &mut has_own) {
return DOMProxyShadowsResult::ShadowCheckFailed;
}
if has_own {
return DOMProxyShadowsResult::ShadowsViaDirectExpando;
}
}
DOMProxyShadowsResult::DoesntShadow
}
pub fn init() {
unsafe {
SetDOMProxyInformation(
GetProxyHandlerFamily(),
Some(shadow_check_callback),
ptr::null(),
);
}
}
pub(crate) unsafe extern "C" fn define_property(
cx: *mut RawJSContext,
proxy: RawHandleObject,
id: RawHandleId,
desc: RawHandle<PropertyDescriptor>,
result: *mut ObjectOpResult,
) -> bool {
let mut cx = JSContext::from_ptr(NonNull::new(cx).unwrap());
let cx = &mut cx;
let proxy = Handle::from_raw(proxy);
let id = Handle::from_raw(id);
let desc = Handle::from_raw(desc);
rooted!(&in(cx) let mut expando = ptr::null_mut::<JSObject>());
ensure_expando_object(cx, proxy, expando.handle_mut());
JS_DefinePropertyById(cx, expando.handle(), id, desc, result)
}
pub(crate) unsafe extern "C" fn delete(
cx: *mut RawJSContext,
proxy: RawHandleObject,
id: RawHandleId,
bp: *mut ObjectOpResult,
) -> bool {
let mut cx = JSContext::from_ptr(NonNull::new(cx).unwrap());
let cx = &mut cx;
let proxy = Handle::from_raw(proxy);
let id = Handle::from_raw(id);
rooted!(&in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
if expando.is_null() {
(*bp).code_ = 0 ;
return true;
}
JS_DeletePropertyById(cx, expando.handle(), id, bp)
}
pub(crate) unsafe extern "C" fn prevent_extensions(
_cx: *mut RawJSContext,
_proxy: RawHandleObject,
result: *mut ObjectOpResult,
) -> bool {
(*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
true
}
pub(crate) unsafe extern "C" fn is_extensible(
_cx: *mut RawJSContext,
_proxy: RawHandleObject,
succeeded: *mut bool,
) -> bool {
*succeeded = true;
true
}
pub(crate) unsafe extern "C" fn get_prototype_if_ordinary(
_: *mut RawJSContext,
proxy: RawHandleObject,
is_ordinary: *mut bool,
proto: RawMutableHandleObject,
) -> bool {
*is_ordinary = true;
proto.set(GetStaticPrototype(proxy.get()));
true
}
pub(crate) fn get_expando_object(obj: HandleObject, mut expando: MutableHandleObject) {
unsafe {
assert!(is_dom_proxy(obj.get()));
let val = &mut UndefinedValue();
GetProxyPrivate(obj.get(), val);
expando.set(if val.is_undefined() {
ptr::null_mut()
} else {
val.to_object()
});
}
}
pub(crate) fn ensure_expando_object(
cx: &mut JSContext,
obj: HandleObject,
mut expando: MutableHandleObject,
) {
unsafe {
assert!(is_dom_proxy(obj.get()));
get_expando_object(obj, expando.reborrow());
if expando.is_null() {
expando.set(JS_NewObjectWithGivenProto(
cx,
ptr::null_mut(),
HandleObject::null(),
));
assert!(!expando.is_null());
SetProxyPrivate(obj.get(), &ObjectValue(expando.get()));
}
}
}
pub fn set_property_descriptor(
desc: MutableHandle<PropertyDescriptor>,
value: HandleValue,
attrs: u32,
is_none: &mut bool,
) {
unsafe { SetDataPropertyDescriptor(desc, value, attrs) };
*is_none = false;
}
fn id_to_source(cx: &mut JSContext, id: HandleId) -> Option<DOMString> {
unsafe {
if RUST_JSID_IS_VOID(id) {
return None;
}
rooted!(&in(cx) let mut value = UndefinedValue());
rooted!(&in(cx) let mut jsstr = ptr::null_mut::<JSString>());
JS_IdToValue(cx, id.get(), value.handle_mut())
.then(|| {
jsstr.set(JS_ValueToSource(cx, value.handle()));
jsstr.get()
})
.and_then(NonNull::new)
.map(|jsstr| jsstr_to_string(cx, jsstr).into())
}
}
pub(crate) struct CrossOriginProperties {
pub(crate) attributes: &'static [JSPropertySpec],
pub(crate) methods: &'static [JSFunctionSpec],
}
impl CrossOriginProperties {
fn keys(&self) -> impl Iterator<Item = *const c_char> + '_ {
self.attributes
.iter()
.map(|spec| unsafe { spec.name.string_ })
.chain(self.methods.iter().map(|spec| unsafe { spec.name.string_ }))
.filter(|ptr| !ptr.is_null())
}
}
fn cross_origin_own_property_keys(
cx: &mut JSContext,
_proxy: HandleObject,
cross_origin_properties: &'static CrossOriginProperties,
props: RawMutableHandleIdVector,
) -> bool {
for key in cross_origin_properties.keys() {
unsafe {
rooted!(&in(cx) let rooted = JS_AtomizeAndPinString(cx, key));
rooted!(&in(cx) let mut rooted_jsid: jsid);
RUST_INTERNED_STRING_TO_JSID(cx, rooted.handle().get(), rooted_jsid.handle_mut());
AppendToIdVector(props, rooted_jsid.handle());
}
}
append_cross_origin_allowlisted_prop_keys(cx, props);
true
}
pub(crate) unsafe extern "C" fn maybe_cross_origin_get_prototype_if_ordinary_rawcx(
_: *mut RawJSContext,
_proxy: RawHandleObject,
is_ordinary: *mut bool,
_proto: RawMutableHandleObject,
) -> bool {
*is_ordinary = false;
true
}
pub(crate) unsafe extern "C" fn maybe_cross_origin_set_prototype_rawcx(
cx: *mut RawJSContext,
proxy: RawHandleObject,
proto: RawHandleObject,
result: *mut ObjectOpResult,
) -> bool {
let mut cx = JSContext::from_ptr(NonNull::new(cx).unwrap());
let cx = &mut cx;
rooted!(&in(cx) let mut current = ptr::null_mut::<JSObject>());
if !GetObjectProto(cx, Handle::from_raw(proxy), current.handle_mut()) {
return false;
}
if proto.get() == current.get() {
(*result).code_ = 0 ;
return true;
}
(*result).code_ = JSErrNum::JSMSG_CANT_SET_PROTO as usize;
true
}
fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if d.hasGetter_() {
out.set(d.getter_);
}
}
fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if d.hasSetter_() {
out.set(d.setter_);
}
}
fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool {
d.hasSetter_() || d.hasGetter_()
}
fn is_data_descriptor(d: &PropertyDescriptor) -> bool {
d.hasWritable_() || d.hasValue_()
}
pub(crate) unsafe fn cross_origin_has_own(
cx: &mut CurrentRealm,
_proxy: HandleObject,
cross_origin_properties: &'static CrossOriginProperties,
id: HandleId,
bp: *mut bool,
) -> bool {
*bp = jsid_to_string(cx, id).is_some_and(|key| {
cross_origin_properties.keys().any(|defined_key| {
let defined_key = CStr::from_ptr(defined_key);
defined_key.to_bytes() == key.str().as_bytes()
})
});
true
}
pub(crate) fn cross_origin_get_own_property_helper(
cx: &mut CurrentRealm,
proxy: HandleObject,
cross_origin_properties: &'static CrossOriginProperties,
id: HandleId,
desc: MutableHandle<PropertyDescriptor>,
is_none: &mut bool,
) -> bool {
rooted!(&in(cx) let mut holder = ptr::null_mut::<JSObject>());
ensure_cross_origin_property_holder(cx, proxy, cross_origin_properties, holder.handle_mut());
unsafe { JS_GetOwnPropertyDescriptorById(cx, holder.handle(), id, desc, is_none) }
}
const ALLOWLISTED_SYMBOL_CODES: &[SymbolCode] = &[
SymbolCode::toStringTag,
SymbolCode::hasInstance,
SymbolCode::isConcatSpreadable,
];
fn is_cross_origin_allowlisted_prop(cx: &mut JSContext, id: HandleId) -> bool {
unsafe {
if jsid_to_string(cx, id).is_some_and(|st| st == "then") {
return true;
}
rooted!(&in(cx) let mut allowed_id: jsid);
ALLOWLISTED_SYMBOL_CODES.iter().any(|&allowed_code| {
allowed_id.set(SymbolId(GetWellKnownSymbol(cx, allowed_code)));
allowed_id.get().asBits_ == id.asBits_
})
}
}
fn append_cross_origin_allowlisted_prop_keys(cx: &mut JSContext, props: RawMutableHandleIdVector) {
unsafe {
rooted!(&in(cx) let mut id: jsid);
let jsstring = JS_AtomizeAndPinString(cx, c"then".as_ptr());
rooted!(&in(cx) let rooted = jsstring);
RUST_INTERNED_STRING_TO_JSID(cx, rooted.handle().get(), id.handle_mut());
AppendToIdVector(props, id.handle());
for &allowed_code in ALLOWLISTED_SYMBOL_CODES.iter() {
id.set(SymbolId(GetWellKnownSymbol(cx, allowed_code)));
AppendToIdVector(props, id.handle());
}
}
}
fn ensure_cross_origin_property_holder(
cx: &mut CurrentRealm,
_proxy: HandleObject,
cross_origin_properties: &'static CrossOriginProperties,
mut out_holder: MutableHandleObject,
) -> bool {
unsafe {
out_holder.set(JS_NewObjectWithGivenProto(
cx,
ptr::null_mut(),
HandleObject::null(),
));
if out_holder.get().is_null() ||
!JS_DefineProperties(
cx,
out_holder.handle(),
cross_origin_properties.attributes.as_ptr(),
) ||
!JS_DefineFunctions(
cx,
out_holder.handle(),
cross_origin_properties.methods.as_ptr(),
)
{
return false;
}
}
true
}
pub(crate) fn is_cross_origin_object<D: DomTypes>(cx: &mut JSContext, obj: HandleObject) -> bool {
unsafe {
IsWindowProxy(*obj) ||
native_from_object::<D::Location>(*obj, cx.raw_cx()).is_ok() ||
native_from_object::<D::DissimilarOriginLocation>(*obj, cx.raw_cx()).is_ok()
}
}
pub(crate) fn report_cross_origin_denial<D: DomTypes>(
cx: &mut CurrentRealm,
id: HandleId,
access: &str,
) -> bool {
if let Some(id) = id_to_source(cx, id) {
debug!(
"permission denied to {} property {} on cross-origin object",
access,
&*id.str(),
);
} else {
debug!("permission denied to {} on cross-origin object", access);
}
unsafe {
if !JS_IsExceptionPending(cx) {
let global = D::GlobalScope::from_current_realm(cx);
<D as DomHelpers<D>>::throw_dom_exception(cx, &global, Error::Security(None));
}
}
false
}
pub(crate) unsafe extern "C" fn maybe_cross_origin_set_rawcx<D: DomTypes>(
cx: *mut RawJSContext,
proxy: RawHandleObject,
id: RawHandleId,
v: RawHandleValue,
receiver: RawHandleValue,
result: *mut ObjectOpResult,
) -> bool {
unsafe {
let mut cx = JSContext::from_ptr(NonNull::new(cx).unwrap());
let mut realm = CurrentRealm::assert(&mut cx);
let proxy = HandleObject::from_raw(proxy);
let id = Handle::from_raw(id);
let v = Handle::from_raw(v);
let receiver = Handle::from_raw(receiver);
if !is_platform_object_same_origin(&realm, proxy) {
return cross_origin_set::<D>(&mut realm, proxy, id, v.into_handle(), receiver, result);
}
let mut realm = AutoRealm::new_from_handle(&mut realm, proxy);
rooted!(&in(&mut realm) let mut own_desc = PropertyDescriptor::default());
let mut is_none = false;
if !InvokeGetOwnPropertyDescriptor(
GetProxyHandler(*proxy),
&mut realm,
proxy,
id,
own_desc.handle_mut(),
&mut is_none,
) {
return false;
}
SetPropertyIgnoringNamedGetter(
&mut realm,
proxy,
id,
v,
receiver,
if is_none {
None
} else {
Some(own_desc.handle())
},
result,
)
}
}
pub(crate) fn maybe_cross_origin_get_prototype<D: DomTypes>(
cx: &mut CurrentRealm,
proxy: HandleObject,
get_proto_object: fn(cx: &mut JSContext, global: HandleObject, rval: MutableHandleObject),
mut proto: MutableHandleObject,
) -> bool {
if is_platform_object_same_origin(cx, proxy) {
let mut realm = AutoRealm::new_from_handle(cx, proxy);
let mut realm = realm.current_realm();
let global = D::GlobalScope::from_current_realm(&realm);
get_proto_object(
&mut realm,
global.reflector().get_jsobject(),
proto.reborrow(),
);
return !proto.is_null();
}
proto.set(ptr::null_mut());
true
}
pub(crate) fn cross_origin_get<D: DomTypes>(
cx: &mut CurrentRealm,
proxy: HandleObject,
receiver: HandleValue,
id: HandleId,
mut vp: MutableHandleValue,
) -> bool {
rooted!(&in(cx) let mut descriptor = PropertyDescriptor::default());
let mut is_none = false;
if !unsafe {
InvokeGetOwnPropertyDescriptor(
GetProxyHandler(*proxy),
cx,
proxy,
id,
descriptor.handle_mut(),
&mut is_none,
)
} {
return false;
}
assert!(
!is_none,
"Callees should throw in all cases when they are not finding \
a property decriptor"
);
if is_data_descriptor(&descriptor) {
vp.set(descriptor.value_);
return true;
}
assert!(is_accessor_descriptor(&descriptor));
rooted!(&in(cx) let mut getter = ptr::null_mut::<JSObject>());
get_getter_object(&descriptor, getter.handle_mut().into());
if getter.get().is_null() {
return report_cross_origin_denial::<D>(cx, id, "get");
}
rooted!(&in(cx) let mut getter_jsval = UndefinedValue());
unsafe {
getter
.get()
.to_jsval(cx.raw_cx(), getter_jsval.handle_mut());
}
unsafe {
Call(
cx,
receiver,
getter_jsval.handle(),
&HandleValueArray::empty(),
vp,
)
}
}
unsafe fn cross_origin_set<D: DomTypes>(
cx: &mut CurrentRealm,
proxy: HandleObject,
id: HandleId,
v: RawHandleValue,
receiver: HandleValue,
result: *mut ObjectOpResult,
) -> bool {
rooted!(&in(cx) let mut descriptor = PropertyDescriptor::default());
let mut is_none = false;
if !InvokeGetOwnPropertyDescriptor(
GetProxyHandler(*proxy),
cx,
proxy,
id,
descriptor.handle_mut(),
&mut is_none,
) {
return false;
}
assert!(
!is_none,
"Callees should throw in all cases when they are not finding \
a property decriptor"
);
rooted!(&in(cx) let mut setter = ptr::null_mut::<JSObject>());
get_setter_object(&descriptor, setter.handle_mut().into());
if setter.get().is_null() {
return report_cross_origin_denial::<D>(cx, id, "set");
}
rooted!(&in(cx) let mut setter_jsval = UndefinedValue());
setter
.get()
.to_jsval(cx.raw_cx(), setter_jsval.handle_mut());
rooted!(&in(cx) let mut ignored = UndefinedValue());
if !Call(
cx,
receiver,
setter_jsval.handle(),
&HandleValueArray {
length_: 1,
elements_: v.ptr,
},
ignored.handle_mut(),
) {
return false;
}
(*result).code_ = 0 ;
true
}
pub(crate) fn cross_origin_property_fallback<D: DomTypes>(
cx: &mut CurrentRealm,
_proxy: HandleObject,
id: HandleId,
desc: MutableHandle<PropertyDescriptor>,
is_none: &mut bool,
) -> bool {
assert!(*is_none, "why are we being called?");
if is_cross_origin_allowlisted_prop(cx, id) {
set_property_descriptor(
desc,
HandleValue::undefined(),
JSPROP_READONLY as u32,
is_none,
);
return true;
}
report_cross_origin_denial::<D>(cx, id, "access")
}
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
pub(crate) struct JSProxyHandlerOwnPropertyKeysConfig<T: DomObject> {
pub(crate) indexed_getter_and_length: Option<fn(&T, &mut JSContext) -> u32>,
pub(crate) cross_origin: Option<&'static CrossOriginProperties>,
pub(crate) unwrapped_proxy: unsafe fn(RawHandleObject) -> *const T,
pub(crate) supported_named_properties: Option<fn(*const T, &mut JSContext) -> Vec<DOMString>>,
}
enum Realm<'a> {
AutoRealm(AutoRealm<'a>),
CurrentRealm(&'a mut CurrentRealm<'a>),
}
impl<'cx> Deref for Realm<'cx> {
type Target = JSContext;
fn deref(&'_ self) -> &'_ Self::Target {
match self {
Realm::AutoRealm(auto_realm) => auto_realm,
Realm::CurrentRealm(current_realm) => current_realm,
}
}
}
impl<'cx> DerefMut for Realm<'cx> {
fn deref_mut(&'_ mut self) -> &'_ mut Self::Target {
match self {
Realm::AutoRealm(auto_realm) => auto_realm,
Realm::CurrentRealm(current_realm) => current_realm,
}
}
}
#[expect(non_snake_case)]
pub(crate) unsafe fn JSProxyHandlerOwnPropertyKeys<T>(
config: JSProxyHandlerOwnPropertyKeysConfig<T>,
cx: *mut RawJSContext,
proxy: RawHandleObject,
props: RawMutableHandleIdVector,
) -> bool
where
T: DomObject,
{
unsafe {
let mut cx = JSContext::from_ptr(ptr::NonNull::new(cx).unwrap());
let mut cx = CurrentRealm::assert(&mut cx);
let current_realm = &mut cx;
let unwrapped_proxy = (config.unwrapped_proxy)(proxy);
let proxy = Handle::from_raw(proxy);
let mut cx = if let Some(cross_origin_properties) = config.cross_origin {
if !is_platform_object_same_origin(current_realm, proxy) {
return cross_origin_own_property_keys(
current_realm,
proxy,
cross_origin_properties,
props,
);
}
let cx = AutoRealm::new_from_handle(current_realm, proxy);
Realm::AutoRealm(cx)
} else {
Realm::CurrentRealm(current_realm)
};
if let Some(length_fn) = config.indexed_getter_and_length {
let length = (length_fn)(&*unwrapped_proxy, &mut cx);
rooted!(&in(cx) let mut rooted_jsid: jsid);
for i in 0..length {
int_to_jsid(i as i32, rooted_jsid.handle_mut());
AppendToIdVector(props, rooted_jsid.handle());
}
}
if let Some(properties) = config.supported_named_properties {
for name in properties(unwrapped_proxy, &mut cx) {
let cstring = CString::new(name).unwrap();
let jsstring = JS_AtomizeAndPinString(&cx, cstring.as_ptr());
rooted!(&in(cx) let rooted = jsstring);
rooted!(&in(cx) let mut rooted_jsid: jsid);
RUST_INTERNED_STRING_TO_JSID(
&mut cx,
rooted.handle().get(),
rooted_jsid.handle_mut(),
);
AppendToIdVector(props, rooted_jsid.handle());
}
}
rooted!(&in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
if !expando.is_null() &&
!GetPropertyKeys(
&mut cx,
expando.handle(),
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
props,
)
{
return false;
}
}
true
}
#[cfg_attr(crown, crown::unrooted_must_root_lint::allow_unrooted_interior)]
pub(crate) struct JSProxyHandlerOwnEnumerablePropertyKeysConfig<T: DomObject> {
pub(crate) unwrapped_proxy: unsafe fn(RawHandleObject) -> *const T,
#[expect(clippy::type_complexity)]
pub(crate) indexed_getter_and_length: Option<Box<dyn Fn(&T, &mut JSContext) -> u32>>,
pub(crate) cross_origin: bool,
}
#[expect(non_snake_case)]
pub(crate) fn JSProxyHandlerGetOwnEnumerablePropertyKeys<T>(
config: JSProxyHandlerOwnEnumerablePropertyKeysConfig<T>,
cx: *mut RawJSContext,
proxy: RawHandleObject,
props: RawMutableHandleIdVector,
) -> bool
where
T: DomObject,
{
unsafe {
let mut cx = JSContext::from_ptr(ptr::NonNull::new(cx).unwrap());
let unwrapped_proxy = (config.unwrapped_proxy)(proxy);
let mut cx = CurrentRealm::assert(&mut cx);
let current_realm = &mut cx;
let proxy = Handle::from_raw(proxy);
let mut cx = if config.cross_origin {
if !is_platform_object_same_origin(current_realm, proxy) {
return true;
}
let cx = AutoRealm::new_from_handle(current_realm, proxy);
Realm::AutoRealm(cx)
} else {
Realm::CurrentRealm(current_realm)
};
if let Some(length_fn) = config.indexed_getter_and_length {
let length = (length_fn)(&*unwrapped_proxy, &mut cx);
rooted!(&in(cx) let mut rooted_jsid: jsid);
for i in 0..length {
int_to_jsid(i as i32, rooted_jsid.handle_mut());
AppendToIdVector(props, rooted_jsid.handle());
}
}
rooted!(&in(cx) let mut expando = ptr::null_mut::<JSObject>());
get_expando_object(proxy, expando.handle_mut());
if !expando.is_null() &&
!GetPropertyKeys(
&mut cx,
expando.handle(),
JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
props,
)
{
return false;
}
}
true
}
pub(crate) fn is_platform_object_same_origin(realm: &CurrentRealm, obj: HandleObject) -> bool {
let subject_realm = realm.realm().as_ptr();
let obj_realm = unsafe { GetObjectRealmOrNull(*obj) };
assert!(!obj_realm.is_null());
let subject_principals =
unsafe { ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(subject_realm)) };
let obj_principals =
unsafe { ServoJSPrincipalsRef::from_raw_unchecked(GetRealmPrincipals(obj_realm)) };
let subject_origin = subject_principals.origin();
let obj_origin = obj_principals.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
}