RemoteObjectProxy.h (8002B)
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/. */ 6 7 #ifndef mozilla_dom_RemoteObjectProxy_h 8 #define mozilla_dom_RemoteObjectProxy_h 9 10 #include "js/Proxy.h" 11 #include "mozilla/Maybe.h" 12 #include "mozilla/dom/MaybeCrossOriginObject.h" 13 #include "mozilla/dom/PrototypeList.h" 14 #include "xpcpublic.h" 15 16 namespace mozilla::dom { 17 18 class BrowsingContext; 19 20 /** 21 * Base class for RemoteObjectProxy. Implements the pieces of the handler that 22 * don't depend on properties/methods of the specific WebIDL interface that this 23 * proxy implements. 24 */ 25 class RemoteObjectProxyBase : public js::BaseProxyHandler, 26 public MaybeCrossOriginObjectMixins { 27 protected: 28 explicit constexpr RemoteObjectProxyBase(prototypes::ID aPrototypeID) 29 : BaseProxyHandler(&sCrossOriginProxyFamily, false), 30 mPrototypeID(aPrototypeID) {} 31 32 public: 33 bool finalizeInBackground(const JS::Value& priv) const final { return false; } 34 35 // Standard internal methods 36 bool getOwnPropertyDescriptor( 37 JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, 38 JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const override; 39 bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy, 40 JS::MutableHandleVector<jsid> aProps) const override; 41 bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy, 42 JS::Handle<jsid> aId, 43 JS::Handle<JS::PropertyDescriptor> aDesc, 44 JS::ObjectOpResult& result) const final; 45 bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, 46 JS::Handle<jsid> aId, JS::ObjectOpResult& aResult) const final; 47 48 bool getPrototypeIfOrdinary(JSContext* aCx, JS::Handle<JSObject*> aProxy, 49 bool* aIsOrdinary, 50 JS::MutableHandle<JSObject*> aProtop) const final; 51 52 bool preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy, 53 JS::ObjectOpResult& aResult) const final; 54 bool isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy, 55 bool* aExtensible) const final; 56 57 bool get(JSContext* cx, JS::Handle<JSObject*> aProxy, 58 JS::Handle<JS::Value> aReceiver, JS::Handle<jsid> aId, 59 JS::MutableHandle<JS::Value> aVp) const final; 60 bool set(JSContext* cx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, 61 JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aReceiver, 62 JS::ObjectOpResult& aResult) const final; 63 64 // SpiderMonkey extensions 65 bool getOwnEnumerablePropertyKeys( 66 JSContext* aCx, JS::Handle<JSObject*> aProxy, 67 JS::MutableHandleVector<jsid> aProps) const override; 68 const char* className(JSContext* aCx, 69 JS::Handle<JSObject*> aProxy) const final; 70 71 // Cross origin objects like RemoteWindowProxy should not participate in 72 // private fields. 73 virtual bool throwOnPrivateField() const override { return true; } 74 75 bool isCallable(JSObject* aObj) const final { return false; } 76 bool isConstructor(JSObject* aObj) const final { return false; } 77 78 virtual void NoteChildren(JSObject* aProxy, 79 nsCycleCollectionTraversalCallback& aCb) const = 0; 80 81 static void* GetNative(JSObject* aProxy) { 82 return js::GetProxyPrivate(aProxy).toPrivate(); 83 } 84 85 /** 86 * Returns true if aProxy is a cross-process proxy that represents 87 * an object implementing the WebIDL interface for aProtoID. aProxy 88 * should be a proxy object. 89 */ 90 static inline bool IsRemoteObjectProxy(JSObject* aProxy, 91 prototypes::ID aProtoID) { 92 const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy); 93 return handler->family() == &sCrossOriginProxyFamily && 94 static_cast<const RemoteObjectProxyBase*>(handler)->mPrototypeID == 95 aProtoID; 96 } 97 98 /** 99 * Returns true if aProxy is a cross-process proxy, no matter which 100 * interface it represents. aProxy should be a proxy object. 101 */ 102 static inline bool IsRemoteObjectProxy(JSObject* aProxy) { 103 const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy); 104 return handler->family() == &sCrossOriginProxyFamily; 105 } 106 107 protected: 108 /** 109 * Gets an existing cached proxy object, or creates a new one and caches it. 110 * aProxy will be null on failure. aNewObjectCreated is set to true if a new 111 * object was created, callers probably need to addref the native in that 112 * case. aNewObjectCreated can be true even if aProxy is null, if something 113 * failed after creating the object. 114 * 115 * If aTransplantTo is non-null, failure is assumed to be unrecoverable, so 116 * this will crash. 117 */ 118 void GetOrCreateProxyObject(JSContext* aCx, void* aNative, 119 const JSClass* aClasp, 120 JS::Handle<JSObject*> aTransplantTo, 121 JS::MutableHandle<JSObject*> aProxy, 122 bool& aNewObjectCreated) const; 123 124 const prototypes::ID mPrototypeID; 125 126 friend struct SetDOMProxyInformation; 127 static const char sCrossOriginProxyFamily; 128 }; 129 130 /** 131 * Proxy handler for proxy objects that represent an object implementing a 132 * WebIDL interface that has cross-origin accessible properties/methods, and 133 * which lives in a different process. The WebIDL code generator will create 134 * arrays of cross-origin accessible properties/methods that can be used as 135 * arguments to this template. 136 * 137 * The properties and methods can be cached on a holder JSObject, stored in a 138 * reserved slot on the proxy object. 139 * 140 * The proxy objects that use a handler derived from this one are stored in a 141 * hash map in the JS compartment's private (@see 142 * xpc::CompartmentPrivate::GetRemoteProxyMap). 143 */ 144 template <class Native, const CrossOriginProperties& P> 145 class RemoteObjectProxy : public RemoteObjectProxyBase { 146 public: 147 void finalize(JS::GCContext* aGcx, JSObject* aProxy) const final { 148 auto native = static_cast<Native*>(GetNative(aProxy)); 149 RefPtr<Native> self(dont_AddRef(native)); 150 } 151 152 void GetProxyObject(JSContext* aCx, Native* aNative, 153 JS::Handle<JSObject*> aTransplantTo, 154 JS::MutableHandle<JSObject*> aProxy) const { 155 bool objectCreated = false; 156 GetOrCreateProxyObject(aCx, aNative, &sClass, aTransplantTo, aProxy, 157 objectCreated); 158 if (objectCreated) { 159 NS_ADDREF(aNative); 160 } 161 } 162 163 protected: 164 using RemoteObjectProxyBase::RemoteObjectProxyBase; 165 166 private: 167 bool EnsureHolder(JSContext* aCx, JS::Handle<JSObject*> aProxy, 168 JS::MutableHandle<JSObject*> aHolder) const final { 169 return MaybeCrossOriginObjectMixins::EnsureHolder( 170 aCx, aProxy, /* slot = */ 0, P, aHolder); 171 } 172 173 static const JSClass sClass; 174 }; 175 176 /** 177 * Returns true if aObj is a cross-process proxy object that 178 * represents an object implementing the WebIDL interface for 179 * aProtoID. 180 */ 181 inline bool IsRemoteObjectProxy(JSObject* aObj, prototypes::ID aProtoID) { 182 if (!js::IsProxy(aObj)) { 183 return false; 184 } 185 return RemoteObjectProxyBase::IsRemoteObjectProxy(aObj, aProtoID); 186 } 187 188 /** 189 * Returns true if aObj is a cross-process proxy object, no matter 190 * which WebIDL interface it corresponds to. 191 */ 192 inline bool IsRemoteObjectProxy(JSObject* aObj) { 193 if (!js::IsProxy(aObj)) { 194 return false; 195 } 196 return RemoteObjectProxyBase::IsRemoteObjectProxy(aObj); 197 } 198 199 /** 200 * Return the browsing context for this remote outer window proxy. 201 * Only call this function on remote outer window proxies. 202 */ 203 BrowsingContext* GetBrowsingContext(JSObject* aProxy); 204 205 } // namespace mozilla::dom 206 207 #endif /* mozilla_dom_RemoteObjectProxy_h */