tor-browser

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

StructuredCloneHolder.h (17461B)


      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_StructuredCloneHolder_h
      8 #define mozilla_dom_StructuredCloneHolder_h
      9 
     10 #include <cstddef>
     11 #include <cstdint>
     12 #include <utility>
     13 
     14 #include "js/StructuredClone.h"
     15 #include "js/TypeDecls.h"
     16 #include "mozilla/Assertions.h"
     17 #include "mozilla/Attributes.h"
     18 #include "mozilla/MemoryReporting.h"
     19 #include "mozilla/RefPtr.h"
     20 #include "mozilla/UniquePtr.h"
     21 #include "nsCOMPtr.h"
     22 #include "nsString.h"
     23 #include "nsTArray.h"
     24 
     25 class nsIEventTarget;
     26 class nsIGlobalObject;
     27 class nsIInputStream;
     28 struct JSStructuredCloneReader;
     29 struct JSStructuredCloneWriter;
     30 
     31 namespace JS {
     32 class Value;
     33 struct WasmModule;
     34 }  // namespace JS
     35 
     36 namespace mozilla {
     37 class ErrorResult;
     38 template <class T>
     39 class OwningNonNull;
     40 
     41 namespace layers {
     42 class Image;
     43 }
     44 
     45 namespace gfx {
     46 class DataSourceSurface;
     47 }
     48 
     49 namespace dom {
     50 
     51 class BlobImpl;
     52 class MessagePort;
     53 class MessagePortIdentifier;
     54 template <typename T>
     55 class Sequence;
     56 
     57 class StructuredCloneHolderBase {
     58 public:
     59  typedef JS::StructuredCloneScope StructuredCloneScope;
     60 
     61  StructuredCloneHolderBase(
     62      StructuredCloneScope aScope = StructuredCloneScope::SameProcess);
     63  virtual ~StructuredCloneHolderBase();
     64 
     65  // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw
     66  // this pointer is passed to mBuffer as a callback closure.  That must
     67  // be fixed if you want to implement a move constructor here.
     68  StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete;
     69 
     70  // These methods should be implemented in order to clone data.
     71  // Read more documentation in js/public/StructuredClone.h.
     72 
     73  virtual JSObject* CustomReadHandler(
     74      JSContext* aCx, JSStructuredCloneReader* aReader,
     75      const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
     76      uint32_t aIndex) = 0;
     77 
     78  virtual bool CustomWriteHandler(JSContext* aCx,
     79                                  JSStructuredCloneWriter* aWriter,
     80                                  JS::Handle<JSObject*> aObj,
     81                                  bool* aSameProcessScopeRequired) = 0;
     82 
     83  // This method has to be called when this object is not needed anymore.
     84  // It will free memory and the buffer. This has to be called because
     85  // otherwise the buffer will be freed in the DTOR of this class and at that
     86  // point we cannot use the overridden methods.
     87  void Clear();
     88 
     89  // If these 3 methods are not implement, transfering objects will not be
     90  // allowed. Otherwise only arrayBuffers will be transferred.
     91 
     92  virtual bool CustomReadTransferHandler(
     93      JSContext* aCx, JSStructuredCloneReader* aReader,
     94      const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
     95      void* aContent, uint64_t aExtraData,
     96      JS::MutableHandle<JSObject*> aReturnObject);
     97 
     98  virtual bool CustomWriteTransferHandler(JSContext* aCx,
     99                                          JS::Handle<JSObject*> aObj,
    100                                          // Output:
    101                                          uint32_t* aTag,
    102                                          JS::TransferableOwnership* aOwnership,
    103                                          void** aContent,
    104                                          uint64_t* aExtraData);
    105 
    106  virtual void CustomFreeTransferHandler(uint32_t aTag,
    107                                         JS::TransferableOwnership aOwnership,
    108                                         void* aContent, uint64_t aExtraData);
    109 
    110  virtual bool CustomCanTransferHandler(JSContext* aCx,
    111                                        JS::Handle<JSObject*> aObj,
    112                                        bool* aSameProcessScopeRequired);
    113 
    114  // These methods are what you should use to read/write data.
    115 
    116  // Execute the serialization of aValue using the Structured Clone Algorithm.
    117  // The data can read back using Read().
    118  bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue);
    119 
    120  // Like Write() but it supports the transferring of objects and handling
    121  // of cloning policy.
    122  bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
    123             JS::Handle<JS::Value> aTransfer,
    124             const JS::CloneDataPolicy& aCloneDataPolicy);
    125 
    126  // If Write() has been called, this method retrieves data and stores it into
    127  // aValue.
    128  bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue);
    129 
    130  // Like Read() but it supports handling of clone policy.
    131  bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
    132            const JS::CloneDataPolicy& aCloneDataPolicy);
    133 
    134  bool HasData() const { return !!mBuffer; }
    135 
    136  JSStructuredCloneData& BufferData() const {
    137    MOZ_ASSERT(mBuffer, "Write() has never been called.");
    138    return mBuffer->data();
    139  }
    140 
    141  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
    142    size_t size = 0;
    143    if (HasData()) {
    144      size += mBuffer->sizeOfIncludingThis(aMallocSizeOf);
    145    }
    146    return size;
    147  }
    148 
    149  void SetErrorMessage(const char* aErrorMessage) {
    150    mErrorMessage.Assign(aErrorMessage);
    151  }
    152 
    153 protected:
    154  UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
    155 
    156  StructuredCloneScope mStructuredCloneScope;
    157 
    158  // Error message when a data clone error is about to throw. It's held while
    159  // the error callback is fired and it will be throw with a data clone error
    160  // later.
    161  nsCString mErrorMessage;
    162 
    163 #ifdef DEBUG
    164  bool mClearCalled;
    165 #endif
    166 };
    167 
    168 class BlobImpl;
    169 class EncodedAudioChunkData;
    170 class EncodedVideoChunkData;
    171 class MessagePort;
    172 class MessagePortIdentifier;
    173 struct VideoFrameSerializedData;
    174 struct AudioDataSerializedData;
    175 #ifdef MOZ_WEBRTC
    176 struct RTCEncodedVideoFrameData;
    177 struct RTCEncodedAudioFrameData;
    178 #endif
    179 
    180 class StructuredCloneHolder : public StructuredCloneHolderBase {
    181 public:
    182  enum CloningSupport { CloningSupported, CloningNotSupported };
    183 
    184  enum TransferringSupport { TransferringSupported, TransferringNotSupported };
    185 
    186  // If cloning is supported, this object will clone objects such as Blobs,
    187  // FileList, ImageData, etc.
    188  // If transferring is supported, we will transfer MessagePorts and in the
    189  // future other transferrable objects.
    190  // The StructuredCloneScope is useful to know where the cloned/transferred
    191  // data can be read and written. Additional checks about the nature of the
    192  // objects will be done based on this scope value because not all the
    193  // objects can be sent between threads or processes.
    194  explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
    195                                 TransferringSupport aSupportsTransferring,
    196                                 StructuredCloneScope aStructuredCloneScope);
    197  virtual ~StructuredCloneHolder();
    198 
    199  StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete;
    200 
    201  // Normally you should just use Write() and Read().
    202 
    203  virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
    204                     ErrorResult& aRv);
    205 
    206  virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
    207                     JS::Handle<JS::Value> aTransfer,
    208                     const JS::CloneDataPolicy& aCloneDataPolicy,
    209                     ErrorResult& aRv);
    210 
    211  void Read(nsIGlobalObject* aGlobal, JSContext* aCx,
    212            JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv);
    213 
    214  void Read(nsIGlobalObject* aGlobal, JSContext* aCx,
    215            JS::MutableHandle<JS::Value> aValue,
    216            const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv);
    217 
    218 #ifdef MOZ_WEBRTC
    219 #  define IF_WEBRTC(x) x
    220 #else
    221 #  define IF_WEBRTC(x)
    222 #endif
    223 
    224 // Create a statement for each of the side DOM-ish data members.
    225 // mTransferredPorts is not included because it is part of the
    226 // deserialized state.
    227 #define CLONED_DATA_MEMBERS                \
    228  STMT(mBlobImplArray);                    \
    229  STMT(mWasmModuleArray);                  \
    230  STMT(mInputStreamArray);                 \
    231  STMT(mClonedSurfaces);                   \
    232  STMT(mVideoFrames);                      \
    233  STMT(mAudioData);                        \
    234  STMT(mEncodedVideoChunks);               \
    235  STMT(mEncodedAudioChunks);               \
    236  IF_WEBRTC(STMT(mRtcEncodedVideoFrames);) \
    237  IF_WEBRTC(STMT(mRtcEncodedAudioFrames);) \
    238  STMT(mPortIdentifiers);
    239 
    240  // Call this method to know if this object is keeping some DOM object alive.
    241  bool HasClonedDOMObjects() const {
    242 #define STMT(_member)         \
    243  if (!(_member).IsEmpty()) { \
    244    return true;              \
    245  }
    246 
    247    CLONED_DATA_MEMBERS
    248 #undef STMT
    249    return false;
    250  }
    251 
    252  nsTArray<RefPtr<BlobImpl>>& BlobImpls() {
    253    MOZ_ASSERT(mSupportsCloning,
    254               "Blobs cannot be taken/set if cloning is not supported.");
    255    return mBlobImplArray;
    256  }
    257 
    258  nsTArray<RefPtr<JS::WasmModule>>& WasmModules() {
    259    MOZ_ASSERT(mSupportsCloning,
    260               "WasmModules cannot be taken/set if cloning is not supported.");
    261    return mWasmModuleArray;
    262  }
    263 
    264  nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() {
    265    MOZ_ASSERT(mSupportsCloning,
    266               "InputStreams cannot be taken/set if cloning is not supported.");
    267    return mInputStreamArray;
    268  }
    269 
    270  // This method returns the final scope. If the final scope is unknown,
    271  // DifferentProcess is returned because it's the most restrictive one.
    272  StructuredCloneScope CloneScope() const {
    273    if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) {
    274      return StructuredCloneScope::DifferentProcess;
    275    }
    276    return mStructuredCloneScope;
    277  }
    278 
    279  // The global object is set internally just during the Read(). This method
    280  // can be used by read functions to retrieve it.
    281  nsIGlobalObject* GlobalDuringRead() const { return mGlobal; }
    282 
    283  // This must be called if the transferring has ports generated by Read().
    284  // MessagePorts are not thread-safe and they must be retrieved in the thread
    285  // where they are created.
    286  nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts() {
    287    MOZ_ASSERT(mSupportsTransferring);
    288    return std::move(mTransferredPorts);
    289  }
    290 
    291  // This method uses TakeTransferredPorts() to populate a sequence of
    292  // MessagePorts for WebIDL binding classes.
    293  bool TakeTransferredPortsAsSequence(
    294      Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
    295 
    296  nsTArray<MessagePortIdentifier>& PortIdentifiers() const {
    297    MOZ_ASSERT(mSupportsTransferring);
    298    return mPortIdentifiers;
    299  }
    300 
    301  nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces() {
    302    return mClonedSurfaces;
    303  }
    304 
    305  nsTArray<VideoFrameSerializedData>& VideoFrames() { return mVideoFrames; }
    306 
    307  nsTArray<AudioDataSerializedData>& AudioData() { return mAudioData; }
    308 
    309  nsTArray<EncodedVideoChunkData>& EncodedVideoChunks() {
    310    return mEncodedVideoChunks;
    311  }
    312 
    313  nsTArray<EncodedAudioChunkData>& EncodedAudioChunks() {
    314    return mEncodedAudioChunks;
    315  }
    316 
    317 #ifdef MOZ_WEBRTC
    318  nsTArray<RTCEncodedVideoFrameData>& RtcEncodedVideoFrames() {
    319    return mRtcEncodedVideoFrames;
    320  }
    321 
    322  nsTArray<RTCEncodedAudioFrameData>& RtcEncodedAudioFrames() {
    323    return mRtcEncodedAudioFrames;
    324  }
    325 #endif
    326 
    327  // Implementations of the virtual methods to allow cloning of objects which
    328  // JS engine itself doesn't clone.
    329 
    330  virtual JSObject* CustomReadHandler(
    331      JSContext* aCx, JSStructuredCloneReader* aReader,
    332      const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
    333      uint32_t aIndex) override;
    334 
    335  virtual bool CustomWriteHandler(JSContext* aCx,
    336                                  JSStructuredCloneWriter* aWriter,
    337                                  JS::Handle<JSObject*> aObj,
    338                                  bool* aSameProcessScopeRequired) override;
    339 
    340  virtual bool CustomReadTransferHandler(
    341      JSContext* aCx, JSStructuredCloneReader* aReader,
    342      const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
    343      void* aContent, uint64_t aExtraData,
    344      JS::MutableHandle<JSObject*> aReturnObject) override;
    345 
    346  virtual bool CustomWriteTransferHandler(JSContext* aCx,
    347                                          JS::Handle<JSObject*> aObj,
    348                                          uint32_t* aTag,
    349                                          JS::TransferableOwnership* aOwnership,
    350                                          void** aContent,
    351                                          uint64_t* aExtraData) override;
    352 
    353  virtual void CustomFreeTransferHandler(uint32_t aTag,
    354                                         JS::TransferableOwnership aOwnership,
    355                                         void* aContent,
    356                                         uint64_t aExtraData) override;
    357 
    358  virtual bool CustomCanTransferHandler(
    359      JSContext* aCx, JS::Handle<JSObject*> aObj,
    360      bool* aSameProcessScopeRequired) override;
    361 
    362  // These 2 static methods are useful to read/write fully serializable objects.
    363  // They can be used by custom StructuredCloneHolderBase classes to
    364  // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
    365 
    366  static JSObject* ReadFullySerializableObjects(
    367      JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
    368      bool aIsForIndexedDB);
    369 
    370  static bool WriteFullySerializableObjects(JSContext* aCx,
    371                                            JSStructuredCloneWriter* aWriter,
    372                                            JS::Handle<JSObject*> aObj);
    373 
    374  // Helper functions for reading and writing strings.
    375  static bool ReadString(JSStructuredCloneReader* aReader, nsString& aString);
    376  static bool WriteString(JSStructuredCloneWriter* aWriter,
    377                          const nsAString& aString);
    378  static bool ReadCString(JSStructuredCloneReader* aReader, nsCString& aString);
    379  static bool WriteCString(JSStructuredCloneWriter* aWriter,
    380                           const nsACString& aString);
    381 
    382  static const JSStructuredCloneCallbacks sCallbacks;
    383 
    384 protected:
    385  // If you receive a buffer from IPC, you can use this method to retrieve a
    386  // JS::Value. It can happen that you want to pre-populate the array of Blobs
    387  // and/or the PortIdentifiers.
    388  void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
    389                      JSStructuredCloneData& aBuffer,
    390                      JS::MutableHandle<JS::Value> aValue,
    391                      const JS::CloneDataPolicy& aCloneDataPolicy,
    392                      ErrorResult& aRv);
    393 
    394  void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx,
    395                      JSStructuredCloneData& aBuffer,
    396                      uint32_t aAlgorithmVersion,
    397                      JS::MutableHandle<JS::Value> aValue,
    398                      const JS::CloneDataPolicy& aCloneDataPolicy,
    399                      ErrorResult& aRv);
    400 
    401  void SameProcessScopeRequired(bool* aSameProcessScopeRequired);
    402 
    403  already_AddRefed<MessagePort> ReceiveMessagePort(uint64_t aIndex);
    404 
    405  bool mSupportsCloning;
    406  bool mSupportsTransferring;
    407 
    408  // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
    409  // account for objects in the following arrays because a) they're not expected
    410  // to be stored in long-lived StructuredCloneHolder objects, and b) in the
    411  // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
    412  // and the other types do not hold significant amounts of memory alive.
    413 
    414  // Used for cloning blobs in the structured cloning algorithm.
    415  nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
    416 
    417  // Used for cloning JS::WasmModules in the structured cloning algorithm.
    418  nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
    419 
    420  // Used for cloning InputStream in the structured cloning algorithm.
    421  nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
    422 
    423  // This is used for sharing the backend of ImageBitmaps.
    424  // The DataSourceSurface object must be thread-safely reference-counted.
    425  // The DataSourceSurface object will not be written ever via any ImageBitmap
    426  // instance, so no race condition will occur.
    427  nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces;
    428 
    429  // Used for cloning VideoFrame in the structured cloning algorithm.
    430  nsTArray<VideoFrameSerializedData> mVideoFrames;
    431 
    432  // Used for cloning AudioData in the structured cloning algorithm.
    433  nsTArray<AudioDataSerializedData> mAudioData;
    434 
    435  // Used for cloning EncodedVideoChunk in the structured cloning algorithm.
    436  nsTArray<EncodedVideoChunkData> mEncodedVideoChunks;
    437 
    438  // Used for cloning EncodedAudioChunk in the structured cloning algorithm.
    439  nsTArray<EncodedAudioChunkData> mEncodedAudioChunks;
    440 
    441 #ifdef MOZ_WEBRTC
    442  // Used for cloning RTCEncodedVideoFrame in the structured cloning algorithm.
    443  nsTArray<RTCEncodedVideoFrameData> mRtcEncodedVideoFrames;
    444 
    445  // Used for cloning RTCEncodedAudioFrame in the structured cloning algorithm.
    446  nsTArray<RTCEncodedAudioFrameData> mRtcEncodedAudioFrames;
    447 #endif
    448 
    449  // This raw pointer is only set within ::Read() and is unset by the end.
    450  nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal;
    451 
    452  // This array contains the ports once we've finished the reading. It's
    453  // generated from the mPortIdentifiers array.
    454  nsTArray<RefPtr<MessagePort>> mTransferredPorts;
    455 
    456  // This array contains the identifiers of the MessagePorts. Based on these we
    457  // are able to reconnect the new transferred ports with the other
    458  // MessageChannel ports.
    459  mutable nsTArray<MessagePortIdentifier> mPortIdentifiers;
    460 
    461 #ifdef DEBUG
    462  nsCOMPtr<nsIEventTarget> mCreationEventTarget;
    463 #endif
    464 };
    465 
    466 }  // namespace dom
    467 }  // namespace mozilla
    468 
    469 #endif  // mozilla_dom_StructuredCloneHolder_h