aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom
diff options
context:
space:
mode:
authoryvt <i@yvt.jp>2021-07-17 13:31:39 +0900
committeryvt <i@yvt.jp>2021-07-17 15:26:15 +0900
commit4bc345317439f8eabd4f1e4817407d2f62cebf6c (patch)
tree69fa8a260f5c3557c49259db6ffe5ac4549dbd1b /components/script/dom
parent80cda12a87aecdcdfd7e1fca3e7f172933e710e9 (diff)
downloadservo-4bc345317439f8eabd4f1e4817407d2f62cebf6c.tar.gz
servo-4bc345317439f8eabd4f1e4817407d2f62cebf6c.zip
feat(script): Implement `[[Set]]` for `Location`
Diffstat (limited to 'components/script/dom')
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py60
-rw-r--r--components/script/dom/bindings/proxyhandler.rs66
2 files changed, 123 insertions, 3 deletions
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index eb94029ccdd..f76be4619f0 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -3554,6 +3554,10 @@ class CGDefineProxyHandler(CGAbstractMethod):
# confused with ECMAScript's `[[SetImmutablePrototype]]`) always fails.
# This is the desired behavior, so we don't override it.
+ customSet = 'None'
+ if self.descriptor.isMaybeCrossOriginObject():
+ customSet = 'Some(set)'
+
getOwnEnumerablePropertyKeys = "own_property_keys"
if self.descriptor.interface.getExtendedAttribute("LegacyUnenumerableNamedProperties"):
getOwnEnumerablePropertyKeys = "getOwnEnumerablePropertyKeys"
@@ -3564,6 +3568,7 @@ class CGDefineProxyHandler(CGAbstractMethod):
"getPrototypeIfOrdinary": customGetPrototypeIfOrdinary,
"getPrototype": customGetPrototype,
"setPrototype": customSetPrototype,
+ "set": customSet,
"getOwnEnumerablePropertyKeys": getOwnEnumerablePropertyKeys,
"trace": TRACE_HOOK_NAME,
"finalize": FINALIZE_HOOK_NAME,
@@ -3585,7 +3590,7 @@ let traps = ProxyTraps {
isExtensible: Some(proxyhandler::is_extensible),
has: None,
get: Some(get),
- set: None,
+ set: %(set)s,
call: None,
construct: None,
hasOwn: Some(hasOwn),
@@ -5951,12 +5956,61 @@ return true;""" % (maybeCrossOriginGet, getIndexedOrExpando, getNamed)
return CGGeneric(self.getBody())
+class CGDOMJSProxyHandler_set(CGAbstractExternMethod):
+ def __init__(self, descriptor):
+ args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
+ Argument('RawHandleId', 'id'), Argument('RawHandleValue', 'v'),
+ Argument('RawHandleValue', 'receiver'),
+ Argument('*mut ObjectOpResult', 'opresult')]
+ CGAbstractExternMethod.__init__(self, descriptor, "set", "bool", args)
+ self.descriptor = descriptor
+
+ def getBody(self):
+ descriptor = self.descriptor
+
+ # `CGDOMJSProxyHandler_set` doesn't support legacy platform objects'
+ # `[[Set]]` (https://heycam.github.io/webidl/#legacy-platform-object-set) yet.
+ #
+ assert descriptor.isMaybeCrossOriginObject()
+ assert not descriptor.operations['IndexedGetter']
+ assert not descriptor.operations['NamedGetter']
+
+ maybeCrossOriginSet = dedent(
+ """
+ if !proxyhandler::is_platform_object_same_origin(cx, proxy) {
+ return proxyhandler::cross_origin_set(cx, proxy, id, v, receiver, opresult);
+ }
+
+ // Safe to enter the Realm of proxy now.
+ let _ac = JSAutoRealm::new(*cx, proxy.get());
+ """)
+
+ return dedent(
+ """
+ let cx = SafeJSContext::from_ptr(cx);
+ %(maybeCrossOriginSet)s
+
+ // OrdinarySet
+ // <https://tc39.es/ecma262/#sec-ordinaryset>
+ rooted!(in(*cx) let mut own_desc = PropertyDescriptor::default());
+ if !getOwnPropertyDescriptor(*cx, proxy, id, own_desc.handle_mut().into()) {
+ return false;
+ }
+
+ js::jsapi::SetPropertyIgnoringNamedGetter(
+ *cx, proxy, id, v, receiver, own_desc.handle().into(), opresult)
+ """) % { "maybeCrossOriginSet": maybeCrossOriginSet }
+
+ def definition_body(self):
+ return CGGeneric(self.getBody())
+
+
class CGDOMJSProxyHandler_getPrototype(CGAbstractExternMethod):
def __init__(self, descriptor):
args = [Argument('*mut JSContext', 'cx'), Argument('RawHandleObject', 'proxy'),
Argument('RawMutableHandleObject', 'proto')]
CGAbstractExternMethod.__init__(self, descriptor, "getPrototype", "bool", args)
- assert self.descriptor.isMaybeCrossOriginObject()
+ assert descriptor.isMaybeCrossOriginObject()
self.descriptor = descriptor
def getBody(self):
@@ -6636,7 +6690,7 @@ class CGDescriptor(CGThing):
if descriptor.isMaybeCrossOriginObject():
cgThings.append(CGDOMJSProxyHandler_getPrototype(descriptor))
- # TODO: CGDOMJSProxyHandler_set(descriptor),
+ cgThings.append(CGDOMJSProxyHandler_set(descriptor))
pass
# cgThings.append(CGDOMJSProxyHandler(descriptor))
diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs
index cbe97d66b9a..b460106af0d 100644
--- a/components/script/dom/bindings/proxyhandler.rs
+++ b/components/script/dom/bindings/proxyhandler.rs
@@ -436,12 +436,78 @@ pub unsafe fn cross_origin_get(
)
}
+/// Implementation of [`CrossOriginSet`].
+///
+/// [`CrossOriginSet`]: https://html.spec.whatwg.org/multipage/#crossoriginset-(-o,-p,-v,-receiver-)
+pub unsafe fn cross_origin_set(
+ cx: SafeJSContext,
+ proxy: RawHandleObject,
+ id: RawHandleId,
+ v: RawHandleValue,
+ receiver: RawHandleValue,
+ result: *mut ObjectOpResult,
+) -> bool {
+ // > 1. Let desc be ? O.[[GetOwnProperty]](P).
+ rooted!(in(*cx) let mut descriptor = PropertyDescriptor::default());
+ if !InvokeGetOwnPropertyDescriptor(
+ GetProxyHandler(*proxy),
+ *cx,
+ proxy,
+ id,
+ descriptor.handle_mut().into(),
+ ) {
+ return false;
+ }
+
+ // > 2. Assert: desc is not undefined.
+ assert!(
+ !descriptor.obj.is_null(),
+ "Callees should throw in all cases when they are not finding \
+ a property decriptor"
+ );
+
+ // > 3. If desc.[[Set]] is present and its value is not undefined,
+ // > then: [...]
+ rooted!(in(*cx) let mut setter = ptr::null_mut::<JSObject>());
+ get_setter_object(&descriptor, setter.handle_mut().into());
+ if setter.get().is_null() {
+ // > 4. Throw a "SecurityError" DOMException.
+ return report_cross_origin_denial(cx, id, "set");
+ }
+
+ rooted!(in(*cx) let mut setter_jsval = UndefinedValue());
+ setter.get().to_jsval(*cx, setter_jsval.handle_mut());
+
+ // > 3.1. Perform ? Call(setter, Receiver, «V»).
+ // >
+ // > 3.2. Return true.
+ rooted!(in(*cx) let mut ignored = UndefinedValue());
+ if !jsapi::Call(
+ *cx,
+ receiver,
+ setter_jsval.handle().into(),
+ &jsapi::HandleValueArray::from_rooted_slice(&[v.get()]),
+ ignored.handle_mut().into(),
+ ) {
+ return false;
+ }
+
+ (*result).code_ = 0 /* OkCode */;
+ true
+}
+
unsafe fn get_getter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
if (d.attrs & jsapi::JSPROP_GETTER as u32) != 0 {
out.set(std::mem::transmute(d.getter));
}
}
+unsafe fn get_setter_object(d: &PropertyDescriptor, out: RawMutableHandleObject) {
+ if (d.attrs & jsapi::JSPROP_SETTER as u32) != 0 {
+ out.set(std::mem::transmute(d.setter));
+ }
+}
+
/// <https://tc39.es/ecma262/#sec-isaccessordescriptor>
fn is_accessor_descriptor(d: &PropertyDescriptor) -> bool {
d.attrs & (jsapi::JSPROP_GETTER as u32 | jsapi::JSPROP_SETTER as u32) != 0