diff options
Diffstat (limited to 'dom/bindings/RemoteObjectProxy.h')
-rw-r--r-- | dom/bindings/RemoteObjectProxy.h | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/dom/bindings/RemoteObjectProxy.h b/dom/bindings/RemoteObjectProxy.h new file mode 100644 index 0000000000..f9ba784769 --- /dev/null +++ b/dom/bindings/RemoteObjectProxy.h @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_RemoteObjectProxy_h +#define mozilla_dom_RemoteObjectProxy_h + +#include "js/Proxy.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/MaybeCrossOriginObject.h" +#include "mozilla/dom/PrototypeList.h" +#include "xpcpublic.h" + +namespace mozilla::dom { + +class BrowsingContext; + +/** + * Base class for RemoteObjectProxy. Implements the pieces of the handler that + * don't depend on properties/methods of the specific WebIDL interface that this + * proxy implements. + */ +class RemoteObjectProxyBase : public js::BaseProxyHandler, + public MaybeCrossOriginObjectMixins { + protected: + explicit constexpr RemoteObjectProxyBase(prototypes::ID aPrototypeID) + : BaseProxyHandler(&sCrossOriginProxyFamily, false), + mPrototypeID(aPrototypeID) {} + + public: + bool finalizeInBackground(const JS::Value& priv) const final { return false; } + + // Standard internal methods + bool getOwnPropertyDescriptor( + JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const override; + bool ownPropertyKeys(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const override; + bool defineProperty(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::Handle<jsid> aId, + JS::Handle<JS::PropertyDescriptor> aDesc, + JS::ObjectOpResult& result) const final; + bool delete_(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::Handle<jsid> aId, JS::ObjectOpResult& aResult) const final; + + bool getPrototypeIfOrdinary(JSContext* aCx, JS::Handle<JSObject*> aProxy, + bool* aIsOrdinary, + JS::MutableHandle<JSObject*> aProtop) const final; + + bool preventExtensions(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::ObjectOpResult& aResult) const final; + bool isExtensible(JSContext* aCx, JS::Handle<JSObject*> aProxy, + bool* aExtensible) const final; + + bool get(JSContext* cx, JS::Handle<JSObject*> aProxy, + JS::Handle<JS::Value> aReceiver, JS::Handle<jsid> aId, + JS::MutableHandle<JS::Value> aVp) const final; + bool set(JSContext* cx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aReceiver, + JS::ObjectOpResult& aResult) const final; + + // SpiderMonkey extensions + bool getOwnEnumerablePropertyKeys( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const override; + const char* className(JSContext* aCx, + JS::Handle<JSObject*> aProxy) const final; + + // Cross origin objects like RemoteWindowProxy should not participate in + // private fields. + virtual bool throwOnPrivateField() const override { return true; } + + bool isCallable(JSObject* aObj) const final { return false; } + bool isConstructor(JSObject* aObj) const final { return false; } + + virtual void NoteChildren(JSObject* aProxy, + nsCycleCollectionTraversalCallback& aCb) const = 0; + + static void* GetNative(JSObject* aProxy) { + return js::GetProxyPrivate(aProxy).toPrivate(); + } + + /** + * Returns true if aProxy is a cross-process proxy that represents + * an object implementing the WebIDL interface for aProtoID. aProxy + * should be a proxy object. + */ + static inline bool IsRemoteObjectProxy(JSObject* aProxy, + prototypes::ID aProtoID) { + const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy); + return handler->family() == &sCrossOriginProxyFamily && + static_cast<const RemoteObjectProxyBase*>(handler)->mPrototypeID == + aProtoID; + } + + /** + * Returns true if aProxy is a cross-process proxy, no matter which + * interface it represents. aProxy should be a proxy object. + */ + static inline bool IsRemoteObjectProxy(JSObject* aProxy) { + const js::BaseProxyHandler* handler = js::GetProxyHandler(aProxy); + return handler->family() == &sCrossOriginProxyFamily; + } + + protected: + /** + * Gets an existing cached proxy object, or creates a new one and caches it. + * aProxy will be null on failure. aNewObjectCreated is set to true if a new + * object was created, callers probably need to addref the native in that + * case. aNewObjectCreated can be true even if aProxy is null, if something + * failed after creating the object. + * + * If aTransplantTo is non-null, failure is assumed to be unrecoverable, so + * this will crash. + */ + void GetOrCreateProxyObject(JSContext* aCx, void* aNative, + const JSClass* aClasp, + JS::Handle<JSObject*> aTransplantTo, + JS::MutableHandle<JSObject*> aProxy, + bool& aNewObjectCreated) const; + + const prototypes::ID mPrototypeID; + + friend struct SetDOMProxyInformation; + static const char sCrossOriginProxyFamily; +}; + +/** + * Proxy handler for proxy objects that represent an object implementing a + * WebIDL interface that has cross-origin accessible properties/methods, and + * which lives in a different process. The WebIDL code generator will create + * arrays of cross-origin accessible properties/methods that can be used as + * arguments to this template. + * + * The properties and methods can be cached on a holder JSObject, stored in a + * reserved slot on the proxy object. + * + * The proxy objects that use a handler derived from this one are stored in a + * hash map in the JS compartment's private (@see + * xpc::CompartmentPrivate::GetRemoteProxyMap). + */ +template <class Native, const CrossOriginProperties& P> +class RemoteObjectProxy : public RemoteObjectProxyBase { + public: + void finalize(JS::GCContext* aGcx, JSObject* aProxy) const final { + auto native = static_cast<Native*>(GetNative(aProxy)); + RefPtr<Native> self(dont_AddRef(native)); + } + + void GetProxyObject(JSContext* aCx, Native* aNative, + JS::Handle<JSObject*> aTransplantTo, + JS::MutableHandle<JSObject*> aProxy) const { + bool objectCreated = false; + GetOrCreateProxyObject(aCx, aNative, &sClass, aTransplantTo, aProxy, + objectCreated); + if (objectCreated) { + NS_ADDREF(aNative); + } + } + + protected: + using RemoteObjectProxyBase::RemoteObjectProxyBase; + + private: + bool EnsureHolder(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandle<JSObject*> aHolder) const final { + return MaybeCrossOriginObjectMixins::EnsureHolder( + aCx, aProxy, /* slot = */ 0, P, aHolder); + } + + static const JSClass sClass; +}; + +/** + * Returns true if aObj is a cross-process proxy object that + * represents an object implementing the WebIDL interface for + * aProtoID. + */ +inline bool IsRemoteObjectProxy(JSObject* aObj, prototypes::ID aProtoID) { + if (!js::IsProxy(aObj)) { + return false; + } + return RemoteObjectProxyBase::IsRemoteObjectProxy(aObj, aProtoID); +} + +/** + * Returns true if aObj is a cross-process proxy object, no matter + * which WebIDL interface it corresponds to. + */ +inline bool IsRemoteObjectProxy(JSObject* aObj) { + if (!js::IsProxy(aObj)) { + return false; + } + return RemoteObjectProxyBase::IsRemoteObjectProxy(aObj); +} + +/** + * Return the browsing context for this remote outer window proxy. + * Only call this function on remote outer window proxies. + */ +BrowsingContext* GetBrowsingContext(JSObject* aProxy); + +} // namespace mozilla::dom + +#endif /* mozilla_dom_RemoteObjectProxy_h */ |