tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DOMJSProxyHandler.h (6807B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_DOMJSProxyHandler_h
      8 #define mozilla_dom_DOMJSProxyHandler_h
      9 
     10 #include "js/Proxy.h"
     11 #include "jsapi.h"
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/Maybe.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 /**
     18 * DOM proxies store the expando object in the private slot.
     19 *
     20 * The expando object is a plain JSObject whose properties correspond to
     21 * "expandos" (custom properties set by the script author).
     22 *
     23 * The exact value stored in the proxy's private slot depends on whether the
     24 * interface is annotated with the [OverrideBuiltins] extended attribute.
     25 *
     26 * If it is, the proxy is initialized with a PrivateValue, which contains a
     27 * pointer to a JS::ExpandoAndGeneration object; this contains a pointer to
     28 * the actual expando object as well as the "generation" of the object.  The
     29 * proxy handler will trace the expando object stored in the
     30 * JS::ExpandoAndGeneration while the proxy itself is alive.
     31 *
     32 * If it is not, the proxy is initialized with an UndefinedValue. In
     33 * EnsureExpandoObject, it is set to an ObjectValue that points to the
     34 * expando object directly. (It is set back to an UndefinedValue only when
     35 * the object is about to die.)
     36 */
     37 
     38 class BaseDOMProxyHandler : public js::BaseProxyHandler {
     39 public:
     40  explicit constexpr BaseDOMProxyHandler(const void* aProxyFamily,
     41                                         bool aHasPrototype = false)
     42      : js::BaseProxyHandler(aProxyFamily, aHasPrototype) {}
     43 
     44  // Implementations of methods that can be implemented in terms of
     45  // other lower-level methods.
     46  bool getOwnPropertyDescriptor(
     47      JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     48      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override;
     49  virtual bool ownPropertyKeys(
     50      JSContext* cx, JS::Handle<JSObject*> proxy,
     51      JS::MutableHandleVector<jsid> props) const override;
     52 
     53  virtual bool getPrototypeIfOrdinary(
     54      JSContext* cx, JS::Handle<JSObject*> proxy, bool* isOrdinary,
     55      JS::MutableHandle<JSObject*> proto) const override;
     56 
     57  // We override getOwnEnumerablePropertyKeys() and implement it directly
     58  // instead of using the default implementation, which would call
     59  // ownPropertyKeys and then filter out the non-enumerable ones. This avoids
     60  // unnecessary work during enumeration.
     61  virtual bool getOwnEnumerablePropertyKeys(
     62      JSContext* cx, JS::Handle<JSObject*> proxy,
     63      JS::MutableHandleVector<jsid> props) const override;
     64 
     65 protected:
     66  // Hook for subclasses to implement shared ownPropertyKeys()/keys()
     67  // functionality.  The "flags" argument is either JSITER_OWNONLY (for keys())
     68  // or JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS (for
     69  // ownPropertyKeys()).
     70  virtual bool ownPropNames(JSContext* cx, JS::Handle<JSObject*> proxy,
     71                            unsigned flags,
     72                            JS::MutableHandleVector<jsid> props) const = 0;
     73 
     74  // Hook for subclasses to allow set() to ignore named props while other things
     75  // that look at property descriptors see them.  This is intentionally not
     76  // named getOwnPropertyDescriptor to avoid subclasses that override it hiding
     77  // our public getOwnPropertyDescriptor.
     78  virtual bool getOwnPropDescriptor(
     79      JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
     80      bool ignoreNamedProps,
     81      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const = 0;
     82 };
     83 
     84 class DOMProxyHandler : public BaseDOMProxyHandler {
     85 public:
     86  constexpr DOMProxyHandler() : BaseDOMProxyHandler(&family) {}
     87 
     88  bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy,
     89                      JS::Handle<jsid> id,
     90                      JS::Handle<JS::PropertyDescriptor> desc,
     91                      JS::ObjectOpResult& result) const override {
     92    bool unused;
     93    return defineProperty(cx, proxy, id, desc, result, &unused);
     94  }
     95  virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy,
     96                              JS::Handle<jsid> id,
     97                              JS::Handle<JS::PropertyDescriptor> desc,
     98                              JS::ObjectOpResult& result, bool* done) const;
     99  bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    100               JS::ObjectOpResult& result) const override;
    101  bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
    102                         JS::ObjectOpResult& result) const override;
    103  bool isExtensible(JSContext* cx, JS::Handle<JSObject*> proxy,
    104                    bool* extensible) const override;
    105  bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    106           JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
    107           JS::ObjectOpResult& result) const override;
    108 
    109  /*
    110   * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
    111   * an indexed setter, call it and set *done to true on success. Otherwise, set
    112   * *done to false.
    113   */
    114  virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy,
    115                         JS::Handle<jsid> id, JS::Handle<JS::Value> v,
    116                         bool* done) const;
    117 
    118  /*
    119   * Get the expando object for the given DOM proxy.
    120   */
    121  static JSObject* GetExpandoObject(JSObject* obj);
    122 
    123  /*
    124   * Clear the expando object for the given DOM proxy and return it.  This
    125   * function will ensure that the returned object is exposed to active JS if
    126   * the given object is exposed.
    127   *
    128   * GetAndClearExpandoObject does not DROP or clear the preserving wrapper
    129   * flag.
    130   */
    131  static JSObject* GetAndClearExpandoObject(JSObject* obj);
    132 
    133  /*
    134   * Ensure that the given proxy (obj) has an expando object, and return it.
    135   * Returns null on failure.
    136   */
    137  static JSObject* EnsureExpandoObject(JSContext* cx,
    138                                       JS::Handle<JSObject*> obj);
    139 
    140  static const char family;
    141 };
    142 
    143 // Class used by shadowing handlers (the ones that have [OverrideBuiltins].
    144 // This handles tracing the expando in JS::ExpandoAndGeneration.
    145 class ShadowingDOMProxyHandler : public DOMProxyHandler {
    146 public:
    147  virtual void trace(JSTracer* trc, JSObject* proxy) const override;
    148 };
    149 
    150 inline bool IsDOMProxy(JSObject* obj) {
    151  return js::IsProxy(obj) &&
    152         js::GetProxyHandler(obj)->family() == &DOMProxyHandler::family;
    153 }
    154 
    155 inline const DOMProxyHandler* GetDOMProxyHandler(JSObject* obj) {
    156  MOZ_ASSERT(IsDOMProxy(obj));
    157  return static_cast<const DOMProxyHandler*>(js::GetProxyHandler(obj));
    158 }
    159 
    160 }  // namespace mozilla::dom
    161 
    162 #endif /* mozilla_dom_DOMProxyHandler_h */