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 "StructuredCloneData.h"
9 #include "mozilla/dom/BindingUtils.h"
10 #include "mozilla/dom/BlobBinding.h"
11 #include "mozilla/dom/BlobImpl.h"
12 #include "mozilla/dom/DOMTypes.h"
13 #include "mozilla/dom/File.h"
14 #include "mozilla/dom/IPCBlobUtils.h"
15 #include "mozilla/ipc/BackgroundParent.h"
16 #include "mozilla/ipc/IPCStreamUtils.h"
17 #include "mozilla/ipc/SerializedStructuredCloneBuffer.h"
18 #include "nsContentUtils.h"
19 #include "nsJSEnvironment.h"
20 #include "MainThreadUtils.h"
21 #include "StructuredCloneTags.h"
24 using namespace mozilla::ipc
;
26 namespace mozilla::dom::ipc
{
28 using mozilla::ipc::IPCStream
;
29 using mozilla::ipc::PBackgroundChild
;
30 using mozilla::ipc::PBackgroundParent
;
32 StructuredCloneData::StructuredCloneData()
33 : StructuredCloneData(
34 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
,
35 StructuredCloneHolder::TransferringSupported
) {}
37 StructuredCloneData::StructuredCloneData(StructuredCloneData
&& aOther
)
38 : StructuredCloneData(
39 StructuredCloneHolder::StructuredCloneScope::DifferentProcess
,
40 StructuredCloneHolder::TransferringSupported
) {
41 *this = std::move(aOther
);
44 StructuredCloneData::StructuredCloneData(
45 StructuredCloneHolder::StructuredCloneScope aScope
,
46 TransferringSupport aSupportsTransferring
)
47 : StructuredCloneHolder(StructuredCloneHolder::CloningSupported
,
48 aSupportsTransferring
, aScope
),
49 mExternalData(JS::StructuredCloneScope::DifferentProcess
),
52 aScope
== StructuredCloneHolder::StructuredCloneScope::DifferentProcess
||
54 StructuredCloneHolder::StructuredCloneScope::UnknownDestination
);
57 StructuredCloneData::~StructuredCloneData() = default;
59 StructuredCloneData
& StructuredCloneData::operator=(
60 StructuredCloneData
&& aOther
) {
61 mBlobImplArray
= std::move(aOther
.mBlobImplArray
);
62 mExternalData
= std::move(aOther
.mExternalData
);
63 mSharedData
= std::move(aOther
.mSharedData
);
64 mPortIdentifiers
= std::move(aOther
.mPortIdentifiers
);
65 mInitialized
= aOther
.mInitialized
;
70 bool StructuredCloneData::Copy(const StructuredCloneData
& aData
) {
71 if (!aData
.mInitialized
) {
75 if (aData
.SharedData()) {
76 mSharedData
= aData
.SharedData();
78 mSharedData
= SharedJSAllocatedData::CreateFromExternalData(aData
.Data());
79 NS_ENSURE_TRUE(mSharedData
, false);
82 if (mSupportsTransferring
) {
83 PortIdentifiers().AppendElements(aData
.PortIdentifiers());
86 MOZ_ASSERT(BlobImpls().IsEmpty());
87 BlobImpls().AppendElements(aData
.BlobImpls());
89 MOZ_ASSERT(GetSurfaces().IsEmpty());
90 MOZ_ASSERT(WasmModules().IsEmpty());
92 MOZ_ASSERT(InputStreams().IsEmpty());
93 InputStreams().AppendElements(aData
.InputStreams());
100 void StructuredCloneData::Read(JSContext
* aCx
,
101 JS::MutableHandle
<JS::Value
> aValue
,
103 Read(aCx
, aValue
, JS::CloneDataPolicy(), aRv
);
106 void StructuredCloneData::Read(JSContext
* aCx
,
107 JS::MutableHandle
<JS::Value
> aValue
,
108 const JS::CloneDataPolicy
& aCloneDataPolicy
,
110 MOZ_ASSERT(mInitialized
);
112 nsIGlobalObject
* global
= xpc::CurrentNativeGlobal(aCx
);
115 ReadFromBuffer(global
, aCx
, Data(), aValue
, aCloneDataPolicy
, aRv
);
118 void StructuredCloneData::Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
120 Write(aCx
, aValue
, JS::UndefinedHandleValue
, JS::CloneDataPolicy(), aRv
);
123 void StructuredCloneData::Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
124 JS::Handle
<JS::Value
> aTransfer
,
125 const JS::CloneDataPolicy
& aCloneDataPolicy
,
127 MOZ_ASSERT(!mInitialized
);
129 StructuredCloneHolder::Write(aCx
, aValue
, aTransfer
, aCloneDataPolicy
, aRv
);
130 if (NS_WARN_IF(aRv
.Failed())) {
134 JSStructuredCloneData
data(mBuffer
->scope());
135 mBuffer
->giveTo(&data
);
137 mSharedData
= new SharedJSAllocatedData(std::move(data
));
141 bool StructuredCloneData::BuildClonedMessageData(
142 ClonedMessageData
& aClonedData
) {
143 SerializedStructuredCloneBuffer
& buffer
= aClonedData
.data();
144 auto iter
= Data().Start();
145 size_t size
= Data().Size();
147 buffer
.data
= Data().Borrow(iter
, size
, &success
);
148 if (NS_WARN_IF(!success
)) {
151 if (SupportsTransferring()) {
152 aClonedData
.identifiers().AppendElements(PortIdentifiers());
155 const nsTArray
<RefPtr
<BlobImpl
>>& blobImpls
= BlobImpls();
157 if (!blobImpls
.IsEmpty()) {
159 !aClonedData
.blobs().SetLength(blobImpls
.Length(), fallible
))) {
163 for (uint32_t i
= 0; i
< blobImpls
.Length(); ++i
) {
165 IPCBlobUtils::Serialize(blobImpls
[i
], aClonedData
.blobs()[i
]);
166 if (NS_WARN_IF(NS_FAILED(rv
))) {
172 const nsTArray
<nsCOMPtr
<nsIInputStream
>>& inputStreams
= InputStreams();
173 if (!inputStreams
.IsEmpty()) {
174 nsTArray
<IPCStream
>& streams
= aClonedData
.inputStreams();
175 uint32_t length
= inputStreams
.Length();
176 streams
.SetCapacity(length
);
177 for (uint32_t i
= 0; i
< length
; ++i
) {
179 if (!mozilla::ipc::SerializeIPCStream(do_AddRef(inputStreams
[i
]), value
,
180 /* aAllowLazy */ false)) {
183 streams
.AppendElement(value
);
190 // See the StructuredCloneData class block comment for the meanings of each val.
191 enum MemoryFlavorEnum
{ BorrowMemory
= 0, CopyMemory
, StealMemory
};
193 template <MemoryFlavorEnum
>
194 struct MemoryTraits
{};
197 struct MemoryTraits
<BorrowMemory
> {
198 using ClonedMessageType
= const mozilla::dom::ClonedMessageData
;
200 static void ProvideBuffer(const ClonedMessageData
& aClonedData
,
201 StructuredCloneData
& aData
) {
202 const SerializedStructuredCloneBuffer
& buffer
= aClonedData
.data();
203 aData
.UseExternalData(buffer
.data
);
208 struct MemoryTraits
<CopyMemory
> {
209 using ClonedMessageType
= const mozilla::dom::ClonedMessageData
;
211 static void ProvideBuffer(const ClonedMessageData
& aClonedData
,
212 StructuredCloneData
& aData
) {
213 const SerializedStructuredCloneBuffer
& buffer
= aClonedData
.data();
214 aData
.CopyExternalData(buffer
.data
);
219 struct MemoryTraits
<StealMemory
> {
221 using ClonedMessageType
= mozilla::dom::ClonedMessageData
;
223 static void ProvideBuffer(ClonedMessageData
& aClonedData
,
224 StructuredCloneData
& aData
) {
225 SerializedStructuredCloneBuffer
& buffer
= aClonedData
.data();
226 aData
.StealExternalData(buffer
.data
);
230 // Note that there isn't actually a difference between Parent/BackgroundParent
231 // and Child/BackgroundChild in this implementation. The calling methods,
232 // however, do maintain the distinction for code-reading purposes and are backed
233 // by assertions to enforce there is no misuse.
234 template <MemoryFlavorEnum MemoryFlavor
>
235 static void UnpackClonedMessageData(
236 typename MemoryTraits
<MemoryFlavor
>::ClonedMessageType
& aClonedData
,
237 StructuredCloneData
& aData
) {
238 const nsTArray
<MessagePortIdentifier
>& identifiers
=
239 aClonedData
.identifiers();
241 MemoryTraits
<MemoryFlavor
>::ProvideBuffer(aClonedData
, aData
);
243 if (aData
.SupportsTransferring()) {
244 aData
.PortIdentifiers().AppendElements(identifiers
);
247 const nsTArray
<IPCBlob
>& blobs
= aClonedData
.blobs();
248 if (!blobs
.IsEmpty()) {
249 uint32_t length
= blobs
.Length();
250 aData
.BlobImpls().SetCapacity(length
);
251 for (uint32_t i
= 0; i
< length
; ++i
) {
252 RefPtr
<BlobImpl
> blobImpl
= IPCBlobUtils::Deserialize(blobs
[i
]);
253 MOZ_ASSERT(blobImpl
);
255 aData
.BlobImpls().AppendElement(blobImpl
);
259 const nsTArray
<IPCStream
>& streams
= aClonedData
.inputStreams();
260 if (!streams
.IsEmpty()) {
261 uint32_t length
= streams
.Length();
262 aData
.InputStreams().SetCapacity(length
);
263 for (uint32_t i
= 0; i
< length
; ++i
) {
264 nsCOMPtr
<nsIInputStream
> stream
= DeserializeIPCStream(streams
[i
]);
265 aData
.InputStreams().AppendElement(stream
);
270 void StructuredCloneData::BorrowFromClonedMessageData(
271 const ClonedMessageData
& aClonedData
) {
272 UnpackClonedMessageData
<BorrowMemory
>(aClonedData
, *this);
275 void StructuredCloneData::CopyFromClonedMessageData(
276 const ClonedMessageData
& aClonedData
) {
277 UnpackClonedMessageData
<CopyMemory
>(aClonedData
, *this);
280 void StructuredCloneData::StealFromClonedMessageData(
281 ClonedMessageData
& aClonedData
) {
282 UnpackClonedMessageData
<StealMemory
>(aClonedData
, *this);
285 void StructuredCloneData::WriteIPCParams(IPC::MessageWriter
* aWriter
) const {
286 WriteParam(aWriter
, Data());
289 bool StructuredCloneData::ReadIPCParams(IPC::MessageReader
* aReader
) {
290 MOZ_ASSERT(!mInitialized
);
291 JSStructuredCloneData
data(JS::StructuredCloneScope::DifferentProcess
);
292 if (!ReadParam(aReader
, &data
)) {
295 mSharedData
= new SharedJSAllocatedData(std::move(data
));
300 bool StructuredCloneData::CopyExternalData(const char* aData
,
301 size_t aDataLength
) {
302 MOZ_ASSERT(!mInitialized
);
304 SharedJSAllocatedData::CreateFromExternalData(aData
, aDataLength
);
305 NS_ENSURE_TRUE(mSharedData
, false);
310 bool StructuredCloneData::CopyExternalData(const JSStructuredCloneData
& aData
) {
311 MOZ_ASSERT(!mInitialized
);
312 mSharedData
= SharedJSAllocatedData::CreateFromExternalData(aData
);
313 NS_ENSURE_TRUE(mSharedData
, false);
318 bool StructuredCloneData::StealExternalData(JSStructuredCloneData
& aData
) {
319 MOZ_ASSERT(!mInitialized
);
320 mSharedData
= new SharedJSAllocatedData(std::move(aData
));
325 already_AddRefed
<SharedJSAllocatedData
> StructuredCloneData::TakeSharedData() {
326 return mSharedData
.forget();
329 } // namespace mozilla::dom::ipc