/* 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/PMessagePort.h" #include "mozilla/dom/RefMessageBodyService.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& aAgentClusterId) : mRefDataId(Nothing()), mSupportsTransferring(aSupportsTransferring), mAgentClusterId(aAgentClusterId) {} SharedMessageBody::~SharedMessageBody() = default; void SharedMessageBody::Write(JSContext* aCx, JS::Handle aValue, JS::Handle 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 = MakeRefPtr( 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 refData = new RefMessageBody(aPortID, mCloneData); mCloneData = nullptr; mRefDataId.emplace(aRefMessageBodyService->Register(refData.forget(), aRv)); } void SharedMessageBody::Read(JSContext* aCx, JS::MutableHandle 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 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>& aPorts) { if (mCloneData) { return mCloneData->TakeTransferredPortsAsSequence(aPorts); } MOZ_ASSERT(mRefData); return mRefData->TakeTransferredPortsAsSequence(aPorts); } } // namespace dom } // namespace mozilla namespace IPC { void ParamTraits::Write( MessageWriter* aWriter, paramType* aParam) { bool isNull = aParam == nullptr; WriteParam(aWriter, isNull); if (isNull) { return; } bool supportsTransferring = aParam->mSupportsTransferring == mozilla::dom::StructuredCloneHolder::TransferringSupported; WriteParam(aWriter, supportsTransferring); WriteParam(aWriter, aParam->mAgentClusterId); WriteParam(aWriter, aParam->mCloneData); if (!aParam->mCloneData) { WriteParam(aWriter, aParam->mRefDataId); } } bool ParamTraits::Read( MessageReader* aReader, RefPtr* aResult) { bool isNull; if (!ReadParam(aReader, &isNull)) { return false; } if (isNull) { *aResult = nullptr; return true; } bool supportsTransferring; mozilla::Maybe agentClusterId; if (!ReadParam(aReader, &supportsTransferring) || !ReadParam(aReader, &agentClusterId)) { return false; } RefPtr result = new mozilla::dom::SharedMessageBody( supportsTransferring ? mozilla::dom::StructuredCloneHolder::TransferringSupported : mozilla::dom::StructuredCloneHolder::TransferringNotSupported, agentClusterId); if (!ReadParam(aReader, &result->mCloneData) || (!result->mCloneData && !ReadParam(aReader, &result->mRefDataId))) { return false; } *aResult = result.forget(); return true; } } // namespace IPC