diff options
author | yvt <i@yvt.jp> | 2021-07-17 13:31:39 +0900 |
---|---|---|
committer | yvt <i@yvt.jp> | 2021-07-17 15:26:15 +0900 |
commit | 4bc345317439f8eabd4f1e4817407d2f62cebf6c (patch) | |
tree | 69fa8a260f5c3557c49259db6ffe5ac4549dbd1b /components/script/dom | |
parent | 80cda12a87aecdcdfd7e1fca3e7f172933e710e9 (diff) | |
download | servo-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.py | 60 | ||||
-rw-r--r-- | components/script/dom/bindings/proxyhandler.rs | 66 |
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 |