no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / ipc / StructuredCloneData.cpp
blob7406083f603ebacc999339ea7e991981ad866f8e
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"
22 #include "jsapi.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),
50 mInitialized(false) {
51 MOZ_ASSERT(
52 aScope == StructuredCloneHolder::StructuredCloneScope::DifferentProcess ||
53 aScope ==
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;
67 return *this;
70 bool StructuredCloneData::Copy(const StructuredCloneData& aData) {
71 if (!aData.mInitialized) {
72 return true;
75 if (aData.SharedData()) {
76 mSharedData = aData.SharedData();
77 } else {
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());
95 mInitialized = true;
97 return true;
100 void StructuredCloneData::Read(JSContext* aCx,
101 JS::MutableHandle<JS::Value> aValue,
102 ErrorResult& aRv) {
103 Read(aCx, aValue, JS::CloneDataPolicy(), aRv);
106 void StructuredCloneData::Read(JSContext* aCx,
107 JS::MutableHandle<JS::Value> aValue,
108 const JS::CloneDataPolicy& aCloneDataPolicy,
109 ErrorResult& aRv) {
110 MOZ_ASSERT(mInitialized);
112 nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
113 MOZ_ASSERT(global);
115 ReadFromBuffer(global, aCx, Data(), aValue, aCloneDataPolicy, aRv);
118 void StructuredCloneData::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
119 ErrorResult& aRv) {
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,
126 ErrorResult& aRv) {
127 MOZ_ASSERT(!mInitialized);
129 StructuredCloneHolder::Write(aCx, aValue, aTransfer, aCloneDataPolicy, aRv);
130 if (NS_WARN_IF(aRv.Failed())) {
131 return;
134 JSStructuredCloneData data(mBuffer->scope());
135 mBuffer->giveTo(&data);
136 mBuffer = nullptr;
137 mSharedData = new SharedJSAllocatedData(std::move(data));
138 mInitialized = true;
141 bool StructuredCloneData::BuildClonedMessageData(
142 ClonedMessageData& aClonedData) {
143 SerializedStructuredCloneBuffer& buffer = aClonedData.data();
144 auto iter = Data().Start();
145 size_t size = Data().Size();
146 bool success;
147 buffer.data = Data().Borrow(iter, size, &success);
148 if (NS_WARN_IF(!success)) {
149 return false;
151 if (SupportsTransferring()) {
152 aClonedData.identifiers().AppendElements(PortIdentifiers());
155 const nsTArray<RefPtr<BlobImpl>>& blobImpls = BlobImpls();
157 if (!blobImpls.IsEmpty()) {
158 if (NS_WARN_IF(
159 !aClonedData.blobs().SetLength(blobImpls.Length(), fallible))) {
160 return false;
163 for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
164 nsresult rv =
165 IPCBlobUtils::Serialize(blobImpls[i], aClonedData.blobs()[i]);
166 if (NS_WARN_IF(NS_FAILED(rv))) {
167 return false;
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) {
178 IPCStream value;
179 if (!mozilla::ipc::SerializeIPCStream(do_AddRef(inputStreams[i]), value,
180 /* aAllowLazy */ false)) {
181 return false;
183 streams.AppendElement(value);
187 return true;
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 {};
196 template <>
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);
207 template <>
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);
218 template <>
219 struct MemoryTraits<StealMemory> {
220 // note: not const!
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)) {
293 return false;
295 mSharedData = new SharedJSAllocatedData(std::move(data));
296 mInitialized = true;
297 return true;
300 bool StructuredCloneData::CopyExternalData(const char* aData,
301 size_t aDataLength) {
302 MOZ_ASSERT(!mInitialized);
303 mSharedData =
304 SharedJSAllocatedData::CreateFromExternalData(aData, aDataLength);
305 NS_ENSURE_TRUE(mSharedData, false);
306 mInitialized = true;
307 return true;
310 bool StructuredCloneData::CopyExternalData(const JSStructuredCloneData& aData) {
311 MOZ_ASSERT(!mInitialized);
312 mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData);
313 NS_ENSURE_TRUE(mSharedData, false);
314 mInitialized = true;
315 return true;
318 bool StructuredCloneData::StealExternalData(JSStructuredCloneData& aData) {
319 MOZ_ASSERT(!mInitialized);
320 mSharedData = new SharedJSAllocatedData(std::move(aData));
321 mInitialized = true;
322 return true;
325 already_AddRefed<SharedJSAllocatedData> StructuredCloneData::TakeSharedData() {
326 return mSharedData.forget();
329 } // namespace mozilla::dom::ipc