Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / bindings / RemoteObjectProxy.cpp
blobba89d764e8e821585be1547ddf42ba820ef9bda3
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "RemoteObjectProxy.h"
8 #include "AccessCheck.h"
9 #include "jsfriendapi.h"
10 #include "js/Object.h" // JS::GetClass
11 #include "xpcprivate.h"
13 namespace mozilla::dom {
15 bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
16 JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
17 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const {
18 bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc);
19 if (!ok || aDesc.isSome()) {
20 return ok;
23 return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc);
26 bool RemoteObjectProxyBase::defineProperty(
27 JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId,
28 JS::Handle<JS::PropertyDescriptor> aDesc,
29 JS::ObjectOpResult& aResult) const {
30 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-defineownproperty
31 // step 3 and
32 // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty
33 // step 2
34 return ReportCrossOriginDenial(aCx, aId, "define"_ns);
37 bool RemoteObjectProxyBase::ownPropertyKeys(
38 JSContext* aCx, JS::Handle<JSObject*> aProxy,
39 JS::MutableHandleVector<jsid> aProps) const {
40 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
41 // step 2 and
42 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
43 JS::Rooted<JSObject*> holder(aCx);
44 if (!EnsureHolder(aCx, aProxy, &holder) ||
45 !js::GetPropertyKeys(aCx, holder,
46 JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS,
47 aProps)) {
48 return false;
51 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
52 // step 3 and 4
53 return xpc::AppendCrossOriginWhitelistedPropNames(aCx, aProps);
56 bool RemoteObjectProxyBase::delete_(JSContext* aCx,
57 JS::Handle<JSObject*> aProxy,
58 JS::Handle<jsid> aId,
59 JS::ObjectOpResult& aResult) const {
60 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-delete
61 // step 3 and
62 // https://html.spec.whatwg.org/multipage/browsers.html#location-delete step 2
63 return ReportCrossOriginDenial(aCx, aId, "delete"_ns);
66 bool RemoteObjectProxyBase::getPrototypeIfOrdinary(
67 JSContext* aCx, JS::Handle<JSObject*> aProxy, bool* aIsOrdinary,
68 JS::MutableHandle<JSObject*> aProtop) const {
69 // WindowProxy's and Location's [[GetPrototypeOf]] traps aren't the ordinary
70 // definition:
72 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
73 // https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof
75 // We nonetheless can implement it with a static [[Prototype]], because the
76 // [[GetPrototypeOf]] trap should always return null.
77 *aIsOrdinary = true;
78 aProtop.set(nullptr);
79 return true;
82 bool RemoteObjectProxyBase::preventExtensions(
83 JSContext* aCx, JS::Handle<JSObject*> aProxy,
84 JS::ObjectOpResult& aResult) const {
85 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-preventextensions
86 // and
87 // https://html.spec.whatwg.org/multipage/browsers.html#location-preventextensions
88 return aResult.failCantPreventExtensions();
91 bool RemoteObjectProxyBase::isExtensible(JSContext* aCx,
92 JS::Handle<JSObject*> aProxy,
93 bool* aExtensible) const {
94 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-isextensible
95 // and
96 // https://html.spec.whatwg.org/multipage/browsers.html#location-isextensible
97 *aExtensible = true;
98 return true;
101 bool RemoteObjectProxyBase::get(JSContext* aCx, JS::Handle<JSObject*> aProxy,
102 JS::Handle<JS::Value> aReceiver,
103 JS::Handle<jsid> aId,
104 JS::MutableHandle<JS::Value> aVp) const {
105 return CrossOriginGet(aCx, aProxy, aReceiver, aId, aVp);
108 bool RemoteObjectProxyBase::set(JSContext* aCx, JS::Handle<JSObject*> aProxy,
109 JS::Handle<jsid> aId,
110 JS::Handle<JS::Value> aValue,
111 JS::Handle<JS::Value> aReceiver,
112 JS::ObjectOpResult& aResult) const {
113 return CrossOriginSet(aCx, aProxy, aId, aValue, aReceiver, aResult);
116 bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
117 JSContext* aCx, JS::Handle<JSObject*> aProxy,
118 JS::MutableHandleVector<jsid> aProps) const {
119 return true;
122 const char* RemoteObjectProxyBase::className(
123 JSContext* aCx, JS::Handle<JSObject*> aProxy) const {
124 MOZ_ASSERT(js::IsProxy(aProxy));
126 return NamesOfInterfacesWithProtos(mPrototypeID);
129 void RemoteObjectProxyBase::GetOrCreateProxyObject(
130 JSContext* aCx, void* aNative, const JSClass* aClasp,
131 JS::Handle<JSObject*> aTransplantTo, JS::MutableHandle<JSObject*> aProxy,
132 bool& aNewObjectCreated) const {
133 xpc::CompartmentPrivate* priv =
134 xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx));
135 xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap();
136 if (auto result = map.lookup(aNative)) {
137 MOZ_RELEASE_ASSERT(!aTransplantTo,
138 "GOCPO failed by finding an existing value");
140 aProxy.set(result->value());
142 // During a transplant, we put an object that is temporarily not a
143 // proxy object into the map. Make sure that we don't return one of
144 // these objects in the middle of a transplant.
145 MOZ_RELEASE_ASSERT(JS::GetClass(aProxy) == aClasp);
147 return;
150 js::ProxyOptions options;
151 options.setClass(aClasp);
152 JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative));
153 JS::Rooted<JSObject*> obj(
154 aCx, js::NewProxyObject(aCx, this, native, nullptr, options));
155 if (!obj) {
156 MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at NewProxyObject");
157 return;
160 bool success;
161 if (!JS_SetImmutablePrototype(aCx, obj, &success)) {
162 MOZ_RELEASE_ASSERT(!aTransplantTo,
163 "GOCPO failed at JS_SetImmutablePrototype");
164 return;
166 MOZ_ASSERT(success);
168 aNewObjectCreated = true;
170 // If we're transplanting onto an object, we want to make sure that it does
171 // not have the same class as aClasp to ensure that the release assert earlier
172 // in this function will actually fire if we try to return a proxy object in
173 // the middle of a transplant.
174 MOZ_RELEASE_ASSERT(!aTransplantTo || (JS::GetClass(aTransplantTo) != aClasp),
175 "GOCPO failed by not changing the class");
177 if (!map.put(aNative, aTransplantTo ? aTransplantTo : obj)) {
178 MOZ_RELEASE_ASSERT(!aTransplantTo, "GOCPO failed at map.put");
179 return;
182 aProxy.set(obj);
185 const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0;
187 } // namespace mozilla::dom