tor-browser

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

SharedMessageBody.cpp (9869B)


      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 "SharedMessageBody.h"
      8 
      9 #include "mozilla/dom/File.h"
     10 #include "mozilla/dom/MessagePort.h"
     11 #include "mozilla/dom/PMessagePort.h"
     12 #include "mozilla/dom/RefMessageBodyService.h"
     13 #include "mozilla/ipc/BackgroundChild.h"
     14 #include "mozilla/ipc/BackgroundParent.h"
     15 #include "xpcpublic.h"
     16 
     17 namespace mozilla {
     18 
     19 using namespace ipc;
     20 
     21 namespace dom {
     22 
     23 SharedMessageBody::SharedMessageBody(
     24    StructuredCloneHolder::TransferringSupport aSupportsTransferring,
     25    const Maybe<nsID>& aAgentClusterId)
     26    : mRefDataId(Nothing()),
     27      mSupportsTransferring(aSupportsTransferring),
     28      mAgentClusterId(aAgentClusterId) {}
     29 
     30 void SharedMessageBody::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
     31                              JS::Handle<JS::Value> aTransfers, nsID& aPortID,
     32                              RefMessageBodyService* aRefMessageBodyService,
     33                              ErrorResult& aRv) {
     34  MOZ_ASSERT(!mCloneData && !mRefData);
     35  MOZ_ASSERT(aRefMessageBodyService);
     36 
     37  JS::CloneDataPolicy cloneDataPolicy;
     38  // During a writing, we don't know the destination, so we assume it is part of
     39  // the same agent cluster.
     40  cloneDataPolicy.allowIntraClusterClonableSharedObjects();
     41 
     42  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
     43  MOZ_ASSERT(global);
     44 
     45  if (global->IsSharedMemoryAllowed()) {
     46    cloneDataPolicy.allowSharedMemoryObjects();
     47  }
     48 
     49  mCloneData = MakeUnique<ipc::StructuredCloneData>(
     50      JS::StructuredCloneScope::UnknownDestination, mSupportsTransferring);
     51  mCloneData->Write(aCx, aValue, aTransfers, cloneDataPolicy, aRv);
     52  if (NS_WARN_IF(aRv.Failed())) {
     53    return;
     54  }
     55 
     56  if (mCloneData->CloneScope() == JS::StructuredCloneScope::DifferentProcess) {
     57    return;
     58  }
     59 
     60  MOZ_ASSERT(mCloneData->CloneScope() == JS::StructuredCloneScope::SameProcess);
     61  RefPtr<RefMessageBody> refData =
     62      new RefMessageBody(aPortID, std::move(mCloneData));
     63 
     64  mRefDataId.emplace(aRefMessageBodyService->Register(refData.forget(), aRv));
     65 }
     66 
     67 void SharedMessageBody::Read(JSContext* aCx,
     68                             JS::MutableHandle<JS::Value> aValue,
     69                             RefMessageBodyService* aRefMessageBodyService,
     70                             SharedMessageBody::ReadMethod aReadMethod,
     71                             ErrorResult& aRv) {
     72  MOZ_ASSERT(aRefMessageBodyService);
     73 
     74  if (mCloneData) {
     75    // Use a default cloneDataPolicy here, because SharedArrayBuffers and WASM
     76    // are not supported.
     77    return mCloneData->Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
     78  }
     79 
     80  JS::CloneDataPolicy cloneDataPolicy;
     81 
     82  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
     83  MOZ_ASSERT(global);
     84 
     85  // Clones within the same agent cluster are allowed to use shared array
     86  // buffers and WASM modules.
     87  if (mAgentClusterId.isSome()) {
     88    Maybe<nsID> agentClusterId = global->GetAgentClusterId();
     89    if (agentClusterId.isSome() &&
     90        mAgentClusterId.value().Equals(agentClusterId.value())) {
     91      cloneDataPolicy.allowIntraClusterClonableSharedObjects();
     92    }
     93  }
     94 
     95  if (global->IsSharedMemoryAllowed()) {
     96    cloneDataPolicy.allowSharedMemoryObjects();
     97  }
     98 
     99  MOZ_ASSERT(!mRefData);
    100  MOZ_ASSERT(mRefDataId.isSome());
    101 
    102  if (aReadMethod == SharedMessageBody::StealRefMessageBody) {
    103    mRefData = aRefMessageBodyService->Steal(mRefDataId.value());
    104  } else {
    105    MOZ_ASSERT(aReadMethod == SharedMessageBody::KeepRefMessageBody);
    106    mRefData = aRefMessageBodyService->GetAndCount(mRefDataId.value());
    107  }
    108 
    109  if (!mRefData) {
    110    aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
    111    return;
    112  }
    113 
    114  mRefData->Read(aCx, aValue, cloneDataPolicy, aRv);
    115 }
    116 
    117 bool SharedMessageBody::TakeTransferredPortsAsSequence(
    118    Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) {
    119  if (mCloneData) {
    120    return mCloneData->TakeTransferredPortsAsSequence(aPorts);
    121  }
    122 
    123  MOZ_ASSERT(mRefData);
    124  return mRefData->TakeTransferredPortsAsSequence(aPorts);
    125 }
    126 
    127 /* static */
    128 void SharedMessageBody::FromSharedToMessageChild(
    129    mozilla::ipc::PBackgroundChild* aManager, SharedMessageBody* aData,
    130    MessageData& aMessage) {
    131  MOZ_ASSERT(aManager);
    132  MOZ_ASSERT(aData);
    133 
    134  aMessage.agentClusterId() = aData->mAgentClusterId;
    135 
    136  if (aData->mCloneData) {
    137    ClonedMessageData clonedData;
    138    aData->mCloneData->BuildClonedMessageData(clonedData);
    139    aMessage.data() = std::move(clonedData);
    140    return;
    141  }
    142 
    143  MOZ_ASSERT(aData->mRefDataId.isSome());
    144  aMessage.data() = RefMessageData(aData->mRefDataId.value());
    145 }
    146 
    147 /* static */
    148 void SharedMessageBody::FromSharedToMessagesChild(
    149    PBackgroundChild* aManager,
    150    const nsTArray<RefPtr<SharedMessageBody>>& aData,
    151    nsTArray<MessageData>& aArray) {
    152  MOZ_ASSERT(aManager);
    153  MOZ_ASSERT(aArray.IsEmpty());
    154  aArray.SetCapacity(aData.Length());
    155 
    156  for (auto& data : aData) {
    157    MessageData* message = aArray.AppendElement();
    158    FromSharedToMessageChild(aManager, data, *message);
    159  }
    160 }
    161 
    162 /* static */
    163 already_AddRefed<SharedMessageBody> SharedMessageBody::FromMessageToSharedChild(
    164    MessageData& aMessage,
    165    StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
    166  RefPtr<SharedMessageBody> data =
    167      new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
    168 
    169  if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
    170    data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
    171        JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
    172    data->mCloneData->StealFromClonedMessageData(
    173        aMessage.data().get_ClonedMessageData());
    174  } else {
    175    MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
    176    data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
    177  }
    178 
    179  return data.forget();
    180 }
    181 
    182 /* static */
    183 already_AddRefed<SharedMessageBody> SharedMessageBody::FromMessageToSharedChild(
    184    const MessageData& aMessage,
    185    StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
    186  RefPtr<SharedMessageBody> data =
    187      new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
    188 
    189  if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
    190    data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
    191        JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
    192    data->mCloneData->BorrowFromClonedMessageData(
    193        aMessage.data().get_ClonedMessageData());
    194  } else {
    195    MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
    196    data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
    197  }
    198 
    199  return data.forget();
    200 }
    201 
    202 /* static */
    203 bool SharedMessageBody::FromMessagesToSharedChild(
    204    nsTArray<MessageData>& aArray,
    205    FallibleTArray<RefPtr<SharedMessageBody>>& aData,
    206    StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
    207  MOZ_ASSERT(aData.IsEmpty());
    208 
    209  if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
    210    return false;
    211  }
    212 
    213  for (auto& message : aArray) {
    214    RefPtr<SharedMessageBody> data =
    215        FromMessageToSharedChild(message, aSupportsTransferring);
    216    if (!data || !aData.AppendElement(data, mozilla::fallible)) {
    217      return false;
    218    }
    219  }
    220 
    221  return true;
    222 }
    223 
    224 /* static */
    225 bool SharedMessageBody::FromSharedToMessagesParent(
    226    PBackgroundParent* aManager,
    227    const nsTArray<RefPtr<SharedMessageBody>>& aData,
    228    nsTArray<MessageData>& aArray) {
    229  MOZ_ASSERT(aManager);
    230  MOZ_ASSERT(aArray.IsEmpty());
    231 
    232  if (NS_WARN_IF(!aArray.SetCapacity(aData.Length(), mozilla::fallible))) {
    233    return false;
    234  }
    235 
    236  for (auto& data : aData) {
    237    MessageData* message = aArray.AppendElement();
    238    message->agentClusterId() = data->mAgentClusterId;
    239 
    240    if (data->mCloneData) {
    241      ClonedMessageData clonedData;
    242      data->mCloneData->BuildClonedMessageData(clonedData);
    243      message->data() = std::move(clonedData);
    244      continue;
    245    }
    246 
    247    MOZ_ASSERT(data->mRefDataId.isSome());
    248    message->data() = RefMessageData(data->mRefDataId.value());
    249  }
    250 
    251  return true;
    252 }
    253 
    254 /* static */
    255 already_AddRefed<SharedMessageBody>
    256 SharedMessageBody::FromMessageToSharedParent(
    257    MessageData& aMessage,
    258    StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
    259  // TODO: This alloc is not fallible and there is no codepath that returns
    260  // nullptr. But the caller checks for nullptr and handles array allocations
    261  // for these items as fallible. See bug 1750497.
    262  RefPtr<SharedMessageBody> data =
    263      new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
    264 
    265  if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
    266    data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
    267        JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
    268    data->mCloneData->StealFromClonedMessageData(
    269        aMessage.data().get_ClonedMessageData());
    270  } else {
    271    MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
    272    data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
    273  }
    274 
    275  return data.forget();
    276 }
    277 
    278 bool SharedMessageBody::FromMessagesToSharedParent(
    279    nsTArray<MessageData>& aArray,
    280    FallibleTArray<RefPtr<SharedMessageBody>>& aData,
    281    StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
    282  MOZ_ASSERT(aData.IsEmpty());
    283 
    284  if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
    285    return false;
    286  }
    287 
    288  for (auto& message : aArray) {
    289    RefPtr<SharedMessageBody> data = FromMessageToSharedParent(message);
    290    if (!data || !aData.AppendElement(data, mozilla::fallible)) {
    291      return false;
    292    }
    293  }
    294 
    295  return true;
    296 }
    297 
    298 }  // namespace dom
    299 }  // namespace mozilla