tor-browser

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

StructuredCloneData.cpp (10067B)


      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 #include "StructuredCloneData.h"
      8 
      9 #include "MainThreadUtils.h"
     10 #include "StructuredCloneTags.h"
     11 #include "jsapi.h"
     12 #include "mozilla/dom/BindingUtils.h"
     13 #include "mozilla/dom/BlobBinding.h"
     14 #include "mozilla/dom/BlobImpl.h"
     15 #include "mozilla/dom/DOMTypes.h"
     16 #include "mozilla/dom/File.h"
     17 #include "mozilla/dom/IPCBlobUtils.h"
     18 #include "mozilla/ipc/BackgroundParent.h"
     19 #include "mozilla/ipc/IPCStreamUtils.h"
     20 #include "mozilla/ipc/SerializedStructuredCloneBuffer.h"
     21 #include "nsContentUtils.h"
     22 #include "nsJSEnvironment.h"
     23 
     24 using namespace mozilla::ipc;
     25 
     26 namespace mozilla::dom::ipc {
     27 
     28 using mozilla::ipc::IPCStream;
     29 using mozilla::ipc::PBackgroundChild;
     30 using mozilla::ipc::PBackgroundParent;
     31 
     32 StructuredCloneData::StructuredCloneData()
     33    : StructuredCloneData(
     34          StructuredCloneHolder::StructuredCloneScope::DifferentProcess,
     35          StructuredCloneHolder::TransferringSupported) {}
     36 
     37 StructuredCloneData::StructuredCloneData(
     38    StructuredCloneHolder::StructuredCloneScope aScope,
     39    TransferringSupport aSupportsTransferring)
     40    : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
     41                            aSupportsTransferring, aScope),
     42      mExternalData(JS::StructuredCloneScope::DifferentProcess),
     43      mInitialized(false) {
     44  MOZ_ASSERT(
     45      aScope == StructuredCloneHolder::StructuredCloneScope::DifferentProcess ||
     46      aScope ==
     47          StructuredCloneHolder::StructuredCloneScope::UnknownDestination);
     48 }
     49 
     50 StructuredCloneData::~StructuredCloneData() = default;
     51 
     52 bool StructuredCloneData::Copy(const StructuredCloneData& aData) {
     53  if (!aData.mInitialized) {
     54    return true;
     55  }
     56 
     57  if (aData.SharedData()) {
     58    mSharedData = aData.SharedData();
     59  } else {
     60    mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData.Data());
     61    NS_ENSURE_TRUE(mSharedData, false);
     62  }
     63 
     64  if (mSupportsTransferring) {
     65    PortIdentifiers().AppendElements(aData.PortIdentifiers());
     66  }
     67 
     68  MOZ_ASSERT(BlobImpls().IsEmpty());
     69  BlobImpls().AppendElements(aData.BlobImpls());
     70 
     71  MOZ_ASSERT(GetSurfaces().IsEmpty());
     72  MOZ_ASSERT(WasmModules().IsEmpty());
     73 
     74  MOZ_ASSERT(InputStreams().IsEmpty());
     75  InputStreams().AppendElements(aData.InputStreams());
     76 
     77  mInitialized = true;
     78 
     79  return true;
     80 }
     81 
     82 void StructuredCloneData::Read(JSContext* aCx,
     83                               JS::MutableHandle<JS::Value> aValue,
     84                               ErrorResult& aRv) {
     85  Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
     86 }
     87 
     88 void StructuredCloneData::Read(JSContext* aCx,
     89                               JS::MutableHandle<JS::Value> aValue,
     90                               const JS::CloneDataPolicy& aCloneDataPolicy,
     91                               ErrorResult& aRv) {
     92  MOZ_ASSERT(mInitialized);
     93 
     94  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
     95  MOZ_ASSERT(global);
     96 
     97  ReadFromBuffer(global, aCx, Data(), aValue, aCloneDataPolicy, aRv);
     98 }
     99 
    100 void StructuredCloneData::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
    101                                ErrorResult& aRv) {
    102  Write(aCx, aValue, JS::UndefinedHandleValue, JS::CloneDataPolicy(), aRv);
    103 }
    104 
    105 void StructuredCloneData::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
    106                                JS::Handle<JS::Value> aTransfer,
    107                                const JS::CloneDataPolicy& aCloneDataPolicy,
    108                                ErrorResult& aRv) {
    109  MOZ_ASSERT(!mInitialized);
    110 
    111  StructuredCloneHolder::Write(aCx, aValue, aTransfer, aCloneDataPolicy, aRv);
    112  if (NS_WARN_IF(aRv.Failed())) {
    113    return;
    114  }
    115 
    116  JSStructuredCloneData data(mBuffer->scope());
    117  mBuffer->giveTo(&data);
    118  mBuffer = nullptr;
    119  mSharedData = new SharedJSAllocatedData(std::move(data));
    120  mInitialized = true;
    121 }
    122 
    123 bool StructuredCloneData::BuildClonedMessageData(
    124    ClonedMessageData& aClonedData) {
    125  SerializedStructuredCloneBuffer& buffer = aClonedData.data();
    126  auto iter = Data().Start();
    127  size_t size = Data().Size();
    128  bool success;
    129  buffer.data = Data().Borrow(iter, size, &success);
    130  if (NS_WARN_IF(!success)) {
    131    return false;
    132  }
    133  if (SupportsTransferring()) {
    134    aClonedData.identifiers().AppendElements(PortIdentifiers());
    135  }
    136 
    137  const nsTArray<RefPtr<BlobImpl>>& blobImpls = BlobImpls();
    138 
    139  if (!blobImpls.IsEmpty()) {
    140    if (NS_WARN_IF(
    141            !aClonedData.blobs().SetLength(blobImpls.Length(), fallible))) {
    142      return false;
    143    }
    144 
    145    for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
    146      nsresult rv =
    147          IPCBlobUtils::Serialize(blobImpls[i], aClonedData.blobs()[i]);
    148      if (NS_WARN_IF(NS_FAILED(rv))) {
    149        return false;
    150      }
    151    }
    152  }
    153 
    154  const nsTArray<nsCOMPtr<nsIInputStream>>& inputStreams = InputStreams();
    155  if (!inputStreams.IsEmpty()) {
    156    nsTArray<IPCStream>& streams = aClonedData.inputStreams();
    157    uint32_t length = inputStreams.Length();
    158    streams.SetCapacity(length);
    159    for (uint32_t i = 0; i < length; ++i) {
    160      IPCStream value;
    161      if (!mozilla::ipc::SerializeIPCStream(do_AddRef(inputStreams[i]), value,
    162                                            /* aAllowLazy */ false)) {
    163        return false;
    164      }
    165      streams.AppendElement(value);
    166    }
    167  }
    168 
    169  return true;
    170 }
    171 
    172 // See the StructuredCloneData class block comment for the meanings of each val.
    173 enum MemoryFlavorEnum { BorrowMemory = 0, CopyMemory, StealMemory };
    174 
    175 template <MemoryFlavorEnum>
    176 struct MemoryTraits {};
    177 
    178 template <>
    179 struct MemoryTraits<BorrowMemory> {
    180  using ClonedMessageType = const mozilla::dom::ClonedMessageData;
    181 
    182  static void ProvideBuffer(const ClonedMessageData& aClonedData,
    183                            StructuredCloneData& aData) {
    184    const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
    185    aData.UseExternalData(buffer.data);
    186  }
    187 };
    188 
    189 template <>
    190 struct MemoryTraits<CopyMemory> {
    191  using ClonedMessageType = const mozilla::dom::ClonedMessageData;
    192 
    193  static void ProvideBuffer(const ClonedMessageData& aClonedData,
    194                            StructuredCloneData& aData) {
    195    const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
    196    aData.CopyExternalData(buffer.data);
    197  }
    198 };
    199 
    200 template <>
    201 struct MemoryTraits<StealMemory> {
    202  // note: not const!
    203  using ClonedMessageType = mozilla::dom::ClonedMessageData;
    204 
    205  static void ProvideBuffer(ClonedMessageData& aClonedData,
    206                            StructuredCloneData& aData) {
    207    SerializedStructuredCloneBuffer& buffer = aClonedData.data();
    208    aData.StealExternalData(buffer.data);
    209  }
    210 };
    211 
    212 // Note that there isn't actually a difference between Parent/BackgroundParent
    213 // and Child/BackgroundChild in this implementation.  The calling methods,
    214 // however, do maintain the distinction for code-reading purposes and are backed
    215 // by assertions to enforce there is no misuse.
    216 template <MemoryFlavorEnum MemoryFlavor>
    217 static void UnpackClonedMessageData(
    218    typename MemoryTraits<MemoryFlavor>::ClonedMessageType& aClonedData,
    219    StructuredCloneData& aData) {
    220  const nsTArray<MessagePortIdentifier>& identifiers =
    221      aClonedData.identifiers();
    222 
    223  MemoryTraits<MemoryFlavor>::ProvideBuffer(aClonedData, aData);
    224 
    225  if (aData.SupportsTransferring()) {
    226    aData.PortIdentifiers().AppendElements(identifiers);
    227  }
    228 
    229  const nsTArray<IPCBlob>& blobs = aClonedData.blobs();
    230  if (!blobs.IsEmpty()) {
    231    uint32_t length = blobs.Length();
    232    aData.BlobImpls().SetCapacity(length);
    233    for (uint32_t i = 0; i < length; ++i) {
    234      RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(blobs[i]);
    235      MOZ_ASSERT(blobImpl);
    236 
    237      aData.BlobImpls().AppendElement(blobImpl);
    238    }
    239  }
    240 
    241  const nsTArray<IPCStream>& streams = aClonedData.inputStreams();
    242  if (!streams.IsEmpty()) {
    243    uint32_t length = streams.Length();
    244    aData.InputStreams().SetCapacity(length);
    245    for (uint32_t i = 0; i < length; ++i) {
    246      nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(streams[i]);
    247      aData.InputStreams().AppendElement(stream);
    248    }
    249  }
    250 }
    251 
    252 void StructuredCloneData::BorrowFromClonedMessageData(
    253    const ClonedMessageData& aClonedData) {
    254  UnpackClonedMessageData<BorrowMemory>(aClonedData, *this);
    255 }
    256 
    257 void StructuredCloneData::CopyFromClonedMessageData(
    258    const ClonedMessageData& aClonedData) {
    259  UnpackClonedMessageData<CopyMemory>(aClonedData, *this);
    260 }
    261 
    262 void StructuredCloneData::StealFromClonedMessageData(
    263    ClonedMessageData& aClonedData) {
    264  UnpackClonedMessageData<StealMemory>(aClonedData, *this);
    265 }
    266 
    267 void StructuredCloneData::WriteIPCParams(IPC::MessageWriter* aWriter) const {
    268  WriteParam(aWriter, Data());
    269 }
    270 
    271 bool StructuredCloneData::ReadIPCParams(IPC::MessageReader* aReader) {
    272  MOZ_ASSERT(!mInitialized);
    273  JSStructuredCloneData data(JS::StructuredCloneScope::DifferentProcess);
    274  if (!ReadParam(aReader, &data)) {
    275    return false;
    276  }
    277  mSharedData = new SharedJSAllocatedData(std::move(data));
    278  mInitialized = true;
    279  return true;
    280 }
    281 
    282 bool StructuredCloneData::CopyExternalData(const char* aData,
    283                                           size_t aDataLength) {
    284  MOZ_ASSERT(!mInitialized);
    285  mSharedData =
    286      SharedJSAllocatedData::CreateFromExternalData(aData, aDataLength);
    287  NS_ENSURE_TRUE(mSharedData, false);
    288  mInitialized = true;
    289  return true;
    290 }
    291 
    292 bool StructuredCloneData::CopyExternalData(const JSStructuredCloneData& aData) {
    293  MOZ_ASSERT(!mInitialized);
    294  mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData);
    295  NS_ENSURE_TRUE(mSharedData, false);
    296  mInitialized = true;
    297  return true;
    298 }
    299 
    300 bool StructuredCloneData::StealExternalData(JSStructuredCloneData& aData) {
    301  MOZ_ASSERT(!mInitialized);
    302  mSharedData = new SharedJSAllocatedData(std::move(aData));
    303  mInitialized = true;
    304  return true;
    305 }
    306 
    307 already_AddRefed<SharedJSAllocatedData> StructuredCloneData::TakeSharedData() {
    308  return mSharedData.forget();
    309 }
    310 
    311 }  // namespace mozilla::dom::ipc