summaryrefslogtreecommitdiffstats
path: root/dom/ipc/SharedMessageBody.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/ipc/SharedMessageBody.cpp')
-rw-r--r--dom/ipc/SharedMessageBody.cpp298
1 files changed, 298 insertions, 0 deletions
diff --git a/dom/ipc/SharedMessageBody.cpp b/dom/ipc/SharedMessageBody.cpp
new file mode 100644
index 0000000000..e09ff2fd55
--- /dev/null
+++ b/dom/ipc/SharedMessageBody.cpp
@@ -0,0 +1,298 @@
+/* -*- 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/. */
+
+#include "SharedMessageBody.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/RefMessageBodyService.h"
+#include "mozilla/dom/PMessagePort.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/BackgroundParent.h"
+#include "xpcpublic.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+namespace dom {
+
+SharedMessageBody::SharedMessageBody(
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring,
+ const Maybe<nsID>& aAgentClusterId)
+ : mRefDataId(Nothing()),
+ mSupportsTransferring(aSupportsTransferring),
+ mAgentClusterId(aAgentClusterId) {}
+
+void SharedMessageBody::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
+ JS::Handle<JS::Value> aTransfers, nsID& aPortID,
+ RefMessageBodyService* aRefMessageBodyService,
+ ErrorResult& aRv) {
+ MOZ_ASSERT(!mCloneData && !mRefData);
+ MOZ_ASSERT(aRefMessageBodyService);
+
+ JS::CloneDataPolicy cloneDataPolicy;
+ // During a writing, we don't know the destination, so we assume it is part of
+ // the same agent cluster.
+ cloneDataPolicy.allowIntraClusterClonableSharedObjects();
+
+ nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
+ MOZ_ASSERT(global);
+
+ if (global->IsSharedMemoryAllowed()) {
+ cloneDataPolicy.allowSharedMemoryObjects();
+ }
+
+ mCloneData = MakeUnique<ipc::StructuredCloneData>(
+ JS::StructuredCloneScope::UnknownDestination, mSupportsTransferring);
+ mCloneData->Write(aCx, aValue, aTransfers, cloneDataPolicy, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ if (mCloneData->CloneScope() == JS::StructuredCloneScope::DifferentProcess) {
+ return;
+ }
+
+ MOZ_ASSERT(mCloneData->CloneScope() == JS::StructuredCloneScope::SameProcess);
+ RefPtr<RefMessageBody> refData =
+ new RefMessageBody(aPortID, std::move(mCloneData));
+
+ mRefDataId.emplace(aRefMessageBodyService->Register(refData.forget(), aRv));
+}
+
+void SharedMessageBody::Read(JSContext* aCx,
+ JS::MutableHandle<JS::Value> aValue,
+ RefMessageBodyService* aRefMessageBodyService,
+ SharedMessageBody::ReadMethod aReadMethod,
+ ErrorResult& aRv) {
+ MOZ_ASSERT(aRefMessageBodyService);
+
+ if (mCloneData) {
+ // Use a default cloneDataPolicy here, because SharedArrayBuffers and WASM
+ // are not supported.
+ return mCloneData->Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
+ }
+
+ JS::CloneDataPolicy cloneDataPolicy;
+
+ nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
+ MOZ_ASSERT(global);
+
+ // Clones within the same agent cluster are allowed to use shared array
+ // buffers and WASM modules.
+ if (mAgentClusterId.isSome()) {
+ Maybe<nsID> agentClusterId = global->GetAgentClusterId();
+ if (agentClusterId.isSome() &&
+ mAgentClusterId.value().Equals(agentClusterId.value())) {
+ cloneDataPolicy.allowIntraClusterClonableSharedObjects();
+ }
+ }
+
+ if (global->IsSharedMemoryAllowed()) {
+ cloneDataPolicy.allowSharedMemoryObjects();
+ }
+
+ MOZ_ASSERT(!mRefData);
+ MOZ_ASSERT(mRefDataId.isSome());
+
+ if (aReadMethod == SharedMessageBody::StealRefMessageBody) {
+ mRefData = aRefMessageBodyService->Steal(mRefDataId.value());
+ } else {
+ MOZ_ASSERT(aReadMethod == SharedMessageBody::KeepRefMessageBody);
+ mRefData = aRefMessageBodyService->GetAndCount(mRefDataId.value());
+ }
+
+ if (!mRefData) {
+ aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
+ return;
+ }
+
+ mRefData->Read(aCx, aValue, cloneDataPolicy, aRv);
+}
+
+bool SharedMessageBody::TakeTransferredPortsAsSequence(
+ Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) {
+ if (mCloneData) {
+ return mCloneData->TakeTransferredPortsAsSequence(aPorts);
+ }
+
+ MOZ_ASSERT(mRefData);
+ return mRefData->TakeTransferredPortsAsSequence(aPorts);
+}
+
+/* static */
+void SharedMessageBody::FromSharedToMessageChild(
+ mozilla::ipc::PBackgroundChild* aManager, SharedMessageBody* aData,
+ MessageData& aMessage) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aData);
+
+ aMessage.agentClusterId() = aData->mAgentClusterId;
+
+ if (aData->mCloneData) {
+ ClonedMessageData clonedData;
+ aData->mCloneData->BuildClonedMessageData(clonedData);
+ aMessage.data() = std::move(clonedData);
+ return;
+ }
+
+ MOZ_ASSERT(aData->mRefDataId.isSome());
+ aMessage.data() = RefMessageData(aData->mRefDataId.value());
+}
+
+/* static */
+void SharedMessageBody::FromSharedToMessagesChild(
+ PBackgroundChild* aManager,
+ const nsTArray<RefPtr<SharedMessageBody>>& aData,
+ nsTArray<MessageData>& aArray) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aArray.IsEmpty());
+ aArray.SetCapacity(aData.Length());
+
+ for (auto& data : aData) {
+ MessageData* message = aArray.AppendElement();
+ FromSharedToMessageChild(aManager, data, *message);
+ }
+}
+
+/* static */
+already_AddRefed<SharedMessageBody> SharedMessageBody::FromMessageToSharedChild(
+ MessageData& aMessage,
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
+ RefPtr<SharedMessageBody> data =
+ new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
+
+ if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
+ data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
+ JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
+ data->mCloneData->StealFromClonedMessageData(
+ aMessage.data().get_ClonedMessageData());
+ } else {
+ MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
+ data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
+ }
+
+ return data.forget();
+}
+
+/* static */
+already_AddRefed<SharedMessageBody> SharedMessageBody::FromMessageToSharedChild(
+ const MessageData& aMessage,
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
+ RefPtr<SharedMessageBody> data =
+ new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
+
+ if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
+ data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
+ JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
+ data->mCloneData->BorrowFromClonedMessageData(
+ aMessage.data().get_ClonedMessageData());
+ } else {
+ MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
+ data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
+ }
+
+ return data.forget();
+}
+
+/* static */
+bool SharedMessageBody::FromMessagesToSharedChild(
+ nsTArray<MessageData>& aArray,
+ FallibleTArray<RefPtr<SharedMessageBody>>& aData,
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
+ MOZ_ASSERT(aData.IsEmpty());
+
+ if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
+ return false;
+ }
+
+ for (auto& message : aArray) {
+ RefPtr<SharedMessageBody> data =
+ FromMessageToSharedChild(message, aSupportsTransferring);
+ if (!data || !aData.AppendElement(data, mozilla::fallible)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* static */
+bool SharedMessageBody::FromSharedToMessagesParent(
+ PBackgroundParent* aManager,
+ const nsTArray<RefPtr<SharedMessageBody>>& aData,
+ nsTArray<MessageData>& aArray) {
+ MOZ_ASSERT(aManager);
+ MOZ_ASSERT(aArray.IsEmpty());
+
+ if (NS_WARN_IF(!aArray.SetCapacity(aData.Length(), mozilla::fallible))) {
+ return false;
+ }
+
+ for (auto& data : aData) {
+ MessageData* message = aArray.AppendElement();
+ message->agentClusterId() = data->mAgentClusterId;
+
+ if (data->mCloneData) {
+ ClonedMessageData clonedData;
+ data->mCloneData->BuildClonedMessageData(clonedData);
+ message->data() = std::move(clonedData);
+ continue;
+ }
+
+ MOZ_ASSERT(data->mRefDataId.isSome());
+ message->data() = RefMessageData(data->mRefDataId.value());
+ }
+
+ return true;
+}
+
+/* static */
+already_AddRefed<SharedMessageBody>
+SharedMessageBody::FromMessageToSharedParent(
+ MessageData& aMessage,
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
+ // TODO: This alloc is not fallible and there is no codepath that returns
+ // nullptr. But the caller checks for nullptr and handles array allocations
+ // for these items as fallible. See bug 1750497.
+ RefPtr<SharedMessageBody> data =
+ new SharedMessageBody(aSupportsTransferring, aMessage.agentClusterId());
+
+ if (aMessage.data().type() == MessageDataType::TClonedMessageData) {
+ data->mCloneData = MakeUnique<ipc::StructuredCloneData>(
+ JS::StructuredCloneScope::UnknownDestination, aSupportsTransferring);
+ data->mCloneData->StealFromClonedMessageData(
+ aMessage.data().get_ClonedMessageData());
+ } else {
+ MOZ_ASSERT(aMessage.data().type() == MessageDataType::TRefMessageData);
+ data->mRefDataId.emplace(aMessage.data().get_RefMessageData().uuid());
+ }
+
+ return data.forget();
+}
+
+bool SharedMessageBody::FromMessagesToSharedParent(
+ nsTArray<MessageData>& aArray,
+ FallibleTArray<RefPtr<SharedMessageBody>>& aData,
+ StructuredCloneHolder::TransferringSupport aSupportsTransferring) {
+ MOZ_ASSERT(aData.IsEmpty());
+
+ if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) {
+ return false;
+ }
+
+ for (auto& message : aArray) {
+ RefPtr<SharedMessageBody> data = FromMessageToSharedParent(message);
+ if (!data || !aData.AppendElement(data, mozilla::fallible)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace dom
+} // namespace mozilla