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/. */
7 #include "SharedMessageBody.h"
8 #include "mozilla/dom/File.h"
9 #include "mozilla/dom/MessagePort.h"
10 #include "mozilla/dom/RefMessageBodyService.h"
11 #include "mozilla/dom/PMessagePort.h"
12 #include "mozilla/ipc/BackgroundChild.h"
13 #include "mozilla/ipc/BackgroundParent.h"
14 #include "xpcpublic.h"
22 SharedMessageBody::SharedMessageBody(
23 StructuredCloneHolder::TransferringSupport aSupportsTransferring
,
24 const Maybe
<nsID
>& aAgentClusterId
)
25 : mRefDataId(Nothing()),
26 mSupportsTransferring(aSupportsTransferring
),
27 mAgentClusterId(aAgentClusterId
) {}
29 void SharedMessageBody::Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
30 JS::Handle
<JS::Value
> aTransfers
, nsID
& aPortID
,
31 RefMessageBodyService
* aRefMessageBodyService
,
33 MOZ_ASSERT(!mCloneData
&& !mRefData
);
34 MOZ_ASSERT(aRefMessageBodyService
);
36 JS::CloneDataPolicy cloneDataPolicy
;
37 // During a writing, we don't know the destination, so we assume it is part of
38 // the same agent cluster.
39 cloneDataPolicy
.allowIntraClusterClonableSharedObjects();
41 nsIGlobalObject
* global
= xpc::CurrentNativeGlobal(aCx
);
44 if (global
->IsSharedMemoryAllowed()) {
45 cloneDataPolicy
.allowSharedMemoryObjects();
48 mCloneData
= MakeUnique
<ipc::StructuredCloneData
>(
49 JS::StructuredCloneScope::UnknownDestination
, mSupportsTransferring
);
50 mCloneData
->Write(aCx
, aValue
, aTransfers
, cloneDataPolicy
, aRv
);
51 if (NS_WARN_IF(aRv
.Failed())) {
55 if (mCloneData
->CloneScope() == JS::StructuredCloneScope::DifferentProcess
) {
59 MOZ_ASSERT(mCloneData
->CloneScope() == JS::StructuredCloneScope::SameProcess
);
60 RefPtr
<RefMessageBody
> refData
=
61 new RefMessageBody(aPortID
, std::move(mCloneData
));
63 mRefDataId
.emplace(aRefMessageBodyService
->Register(refData
.forget(), aRv
));
66 void SharedMessageBody::Read(JSContext
* aCx
,
67 JS::MutableHandle
<JS::Value
> aValue
,
68 RefMessageBodyService
* aRefMessageBodyService
,
69 SharedMessageBody::ReadMethod aReadMethod
,
71 MOZ_ASSERT(aRefMessageBodyService
);
74 // Use a default cloneDataPolicy here, because SharedArrayBuffers and WASM
76 return mCloneData
->Read(aCx
, aValue
, JS::CloneDataPolicy(), aRv
);
79 JS::CloneDataPolicy cloneDataPolicy
;
81 nsIGlobalObject
* global
= xpc::CurrentNativeGlobal(aCx
);
84 // Clones within the same agent cluster are allowed to use shared array
85 // buffers and WASM modules.
86 if (mAgentClusterId
.isSome()) {
87 Maybe
<nsID
> agentClusterId
= global
->GetAgentClusterId();
88 if (agentClusterId
.isSome() &&
89 mAgentClusterId
.value().Equals(agentClusterId
.value())) {
90 cloneDataPolicy
.allowIntraClusterClonableSharedObjects();
94 if (global
->IsSharedMemoryAllowed()) {
95 cloneDataPolicy
.allowSharedMemoryObjects();
98 MOZ_ASSERT(!mRefData
);
99 MOZ_ASSERT(mRefDataId
.isSome());
101 if (aReadMethod
== SharedMessageBody::StealRefMessageBody
) {
102 mRefData
= aRefMessageBodyService
->Steal(mRefDataId
.value());
104 MOZ_ASSERT(aReadMethod
== SharedMessageBody::KeepRefMessageBody
);
105 mRefData
= aRefMessageBodyService
->GetAndCount(mRefDataId
.value());
109 aRv
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
113 mRefData
->Read(aCx
, aValue
, cloneDataPolicy
, aRv
);
116 bool SharedMessageBody::TakeTransferredPortsAsSequence(
117 Sequence
<OwningNonNull
<mozilla::dom::MessagePort
>>& aPorts
) {
119 return mCloneData
->TakeTransferredPortsAsSequence(aPorts
);
122 MOZ_ASSERT(mRefData
);
123 return mRefData
->TakeTransferredPortsAsSequence(aPorts
);
127 void SharedMessageBody::FromSharedToMessageChild(
128 mozilla::ipc::PBackgroundChild
* aManager
, SharedMessageBody
* aData
,
129 MessageData
& aMessage
) {
130 MOZ_ASSERT(aManager
);
133 aMessage
.agentClusterId() = aData
->mAgentClusterId
;
135 if (aData
->mCloneData
) {
136 ClonedMessageData clonedData
;
137 aData
->mCloneData
->BuildClonedMessageData(clonedData
);
138 aMessage
.data() = std::move(clonedData
);
142 MOZ_ASSERT(aData
->mRefDataId
.isSome());
143 aMessage
.data() = RefMessageData(aData
->mRefDataId
.value());
147 void SharedMessageBody::FromSharedToMessagesChild(
148 PBackgroundChild
* aManager
,
149 const nsTArray
<RefPtr
<SharedMessageBody
>>& aData
,
150 nsTArray
<MessageData
>& aArray
) {
151 MOZ_ASSERT(aManager
);
152 MOZ_ASSERT(aArray
.IsEmpty());
153 aArray
.SetCapacity(aData
.Length());
155 for (auto& data
: aData
) {
156 MessageData
* message
= aArray
.AppendElement();
157 FromSharedToMessageChild(aManager
, data
, *message
);
162 already_AddRefed
<SharedMessageBody
> SharedMessageBody::FromMessageToSharedChild(
163 MessageData
& aMessage
,
164 StructuredCloneHolder::TransferringSupport aSupportsTransferring
) {
165 RefPtr
<SharedMessageBody
> data
=
166 new SharedMessageBody(aSupportsTransferring
, aMessage
.agentClusterId());
168 if (aMessage
.data().type() == MessageDataType::TClonedMessageData
) {
169 data
->mCloneData
= MakeUnique
<ipc::StructuredCloneData
>(
170 JS::StructuredCloneScope::UnknownDestination
, aSupportsTransferring
);
171 data
->mCloneData
->StealFromClonedMessageData(
172 aMessage
.data().get_ClonedMessageData());
174 MOZ_ASSERT(aMessage
.data().type() == MessageDataType::TRefMessageData
);
175 data
->mRefDataId
.emplace(aMessage
.data().get_RefMessageData().uuid());
178 return data
.forget();
182 already_AddRefed
<SharedMessageBody
> SharedMessageBody::FromMessageToSharedChild(
183 const MessageData
& aMessage
,
184 StructuredCloneHolder::TransferringSupport aSupportsTransferring
) {
185 RefPtr
<SharedMessageBody
> data
=
186 new SharedMessageBody(aSupportsTransferring
, aMessage
.agentClusterId());
188 if (aMessage
.data().type() == MessageDataType::TClonedMessageData
) {
189 data
->mCloneData
= MakeUnique
<ipc::StructuredCloneData
>(
190 JS::StructuredCloneScope::UnknownDestination
, aSupportsTransferring
);
191 data
->mCloneData
->BorrowFromClonedMessageData(
192 aMessage
.data().get_ClonedMessageData());
194 MOZ_ASSERT(aMessage
.data().type() == MessageDataType::TRefMessageData
);
195 data
->mRefDataId
.emplace(aMessage
.data().get_RefMessageData().uuid());
198 return data
.forget();
202 bool SharedMessageBody::FromMessagesToSharedChild(
203 nsTArray
<MessageData
>& aArray
,
204 FallibleTArray
<RefPtr
<SharedMessageBody
>>& aData
,
205 StructuredCloneHolder::TransferringSupport aSupportsTransferring
) {
206 MOZ_ASSERT(aData
.IsEmpty());
208 if (NS_WARN_IF(!aData
.SetCapacity(aArray
.Length(), mozilla::fallible
))) {
212 for (auto& message
: aArray
) {
213 RefPtr
<SharedMessageBody
> data
=
214 FromMessageToSharedChild(message
, aSupportsTransferring
);
215 if (!data
|| !aData
.AppendElement(data
, mozilla::fallible
)) {
224 bool SharedMessageBody::FromSharedToMessagesParent(
225 PBackgroundParent
* aManager
,
226 const nsTArray
<RefPtr
<SharedMessageBody
>>& aData
,
227 nsTArray
<MessageData
>& aArray
) {
228 MOZ_ASSERT(aManager
);
229 MOZ_ASSERT(aArray
.IsEmpty());
231 if (NS_WARN_IF(!aArray
.SetCapacity(aData
.Length(), mozilla::fallible
))) {
235 for (auto& data
: aData
) {
236 MessageData
* message
= aArray
.AppendElement();
237 message
->agentClusterId() = data
->mAgentClusterId
;
239 if (data
->mCloneData
) {
240 ClonedMessageData clonedData
;
241 data
->mCloneData
->BuildClonedMessageData(clonedData
);
242 message
->data() = std::move(clonedData
);
246 MOZ_ASSERT(data
->mRefDataId
.isSome());
247 message
->data() = RefMessageData(data
->mRefDataId
.value());
254 already_AddRefed
<SharedMessageBody
>
255 SharedMessageBody::FromMessageToSharedParent(
256 MessageData
& aMessage
,
257 StructuredCloneHolder::TransferringSupport aSupportsTransferring
) {
258 // TODO: This alloc is not fallible and there is no codepath that returns
259 // nullptr. But the caller checks for nullptr and handles array allocations
260 // for these items as fallible. See bug 1750497.
261 RefPtr
<SharedMessageBody
> data
=
262 new SharedMessageBody(aSupportsTransferring
, aMessage
.agentClusterId());
264 if (aMessage
.data().type() == MessageDataType::TClonedMessageData
) {
265 data
->mCloneData
= MakeUnique
<ipc::StructuredCloneData
>(
266 JS::StructuredCloneScope::UnknownDestination
, aSupportsTransferring
);
267 data
->mCloneData
->StealFromClonedMessageData(
268 aMessage
.data().get_ClonedMessageData());
270 MOZ_ASSERT(aMessage
.data().type() == MessageDataType::TRefMessageData
);
271 data
->mRefDataId
.emplace(aMessage
.data().get_RefMessageData().uuid());
274 return data
.forget();
277 bool SharedMessageBody::FromMessagesToSharedParent(
278 nsTArray
<MessageData
>& aArray
,
279 FallibleTArray
<RefPtr
<SharedMessageBody
>>& aData
,
280 StructuredCloneHolder::TransferringSupport aSupportsTransferring
) {
281 MOZ_ASSERT(aData
.IsEmpty());
283 if (NS_WARN_IF(!aData
.SetCapacity(aArray
.Length(), mozilla::fallible
))) {
287 for (auto& message
: aArray
) {
288 RefPtr
<SharedMessageBody
> data
= FromMessageToSharedParent(message
);
289 if (!data
|| !aData
.AppendElement(data
, mozilla::fallible
)) {
298 } // namespace mozilla