Bug 1861467 - [wpt-sync] Update web-platform-tests to eedf737ce39c512d0ca3471f988972e...
[gecko.git] / dom / ipc / StructuredCloneData.h
blob0566a3b07f8bd5219415e1b29bb6babed0058d03
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 #ifndef mozilla_dom_ipc_StructuredCloneData_h
8 #define mozilla_dom_ipc_StructuredCloneData_h
10 #include <algorithm>
11 #include "mozilla/RefPtr.h"
12 #include "mozilla/dom/StructuredCloneHolder.h"
13 #include "nsISupportsImpl.h"
14 #include "nsIInputStream.h"
16 namespace IPC {
17 class Message;
18 class MessageReader;
19 class MessageWriter;
20 } // namespace IPC
21 class PickleIterator;
23 namespace mozilla {
24 namespace ipc {
26 class PBackgroundChild;
27 class PBackgroundParent;
29 } // namespace ipc
31 namespace dom {
33 class ContentChild;
34 class ContentParent;
36 namespace ipc {
38 /**
39 * Wraps the non-reference-counted JSStructuredCloneData class to have a
40 * reference count so that multiple StructuredCloneData instances can reference
41 * a single underlying serialized representation.
43 * As used by StructuredCloneData, it is an invariant that our
44 * JSStructuredCloneData owns its buffers. (For the non-owning case,
45 * StructuredCloneData uses mExternalData which holds a BufferList::Borrow()ed
46 * read-only view of the data.)
48 class SharedJSAllocatedData final {
49 public:
50 explicit SharedJSAllocatedData(JSStructuredCloneData&& aData)
51 : mData(std::move(aData)) {}
53 static already_AddRefed<SharedJSAllocatedData> CreateFromExternalData(
54 const char* aData, size_t aDataLength) {
55 JSStructuredCloneData buf(JS::StructuredCloneScope::DifferentProcess);
56 NS_ENSURE_TRUE(buf.AppendBytes(aData, aDataLength), nullptr);
57 RefPtr<SharedJSAllocatedData> sharedData =
58 new SharedJSAllocatedData(std::move(buf));
59 return sharedData.forget();
62 static already_AddRefed<SharedJSAllocatedData> CreateFromExternalData(
63 const JSStructuredCloneData& aData) {
64 JSStructuredCloneData buf(aData.scope());
65 NS_ENSURE_TRUE(buf.Append(aData), nullptr);
66 RefPtr<SharedJSAllocatedData> sharedData =
67 new SharedJSAllocatedData(std::move(buf));
68 return sharedData.forget();
71 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedJSAllocatedData)
73 JSStructuredCloneData& Data() { return mData; }
74 size_t DataLength() const { return mData.Size(); }
76 private:
77 ~SharedJSAllocatedData() = default;
79 JSStructuredCloneData mData;
82 /**
83 * IPC-aware StructuredCloneHolder subclass that serves as both a helper class
84 * for dealing with message data (blobs, transferables) and also an IPDL
85 * data-type in cases where message data is not needed. If your use-case does
86 * not (potentially) involve IPC, then you should use StructuredCloneHolder or
87 * one of its other subclasses instead.
89 * ## Usage ##
91 * The general recipe for using this class is:
92 * - In your IPDL definition, use the ClonedMessageData type whenever you want
93 * to send a structured clone that may include blobs or transferables such as
94 * message ports.
95 * - To send the data, instantiate a StructuredCloneData instance and Write()
96 * into it like a normal structure clone. When you are ready to send the
97 * ClonedMessageData-bearing IPC message, use the appropriate
98 * BuildClonedMessageDataFor{Parent,Child,BackgroundParent,BackgroundChild}
99 * method to populate the ClonedMessageData and then send it before your
100 * StructuredCloneData instance is destroyed. (Buffer borrowing is used
101 * under-the-hood to avoid duplicating the serialized data, requiring this.)
102 * - To receive the data, instantiate a StructuredCloneData and use the
103 * appropriate {Borrow,Copy,Steal}FromClonedMessageDataFor{Parent,Child,
104 * BackgroundParent,BackgroundChild} method. See the memory management
105 * section for more info.
107 * Variations:
108 * - If transferables are not allowed (ex: BroadcastChannel), then use the
109 * StructuredCloneDataNoTransfers subclass instead of StructuredCloneData.
111 * ## Memory Management ##
113 * Serialized structured clone representations can be quite large. So it's best
114 * to avoid wasteful duplication. When Write()ing into the StructuredCloneData,
115 * you don't need to worry about this[1], but when you already have serialized
116 * structured clone data you plan to Read(), you do need to. Similarly, if
117 * you're using StructuredCloneData as an IPDL type, it efficiently unmarshals.
119 * The from-ClonedMessageData memory management strategies available are:
120 * - Borrow: Create a JSStructuredCloneData that holds a non-owning, read-only
121 * BufferList::Borrow()ed copy of the source. Your StructuredCloneData needs
122 * to be destroyed before the source is. Commonly used when the
123 * StructuredCloneData instance is stack-allocated (and Read() is used before
124 * the function returns).
125 * - Copy: Makes a reference-counted copy of the source JSStructuredCloneData,
126 * making it safe for the StructuredCloneData to outlive the source data.
127 * - Steal: Steal the buffers from the underlying JSStructuredCloneData so that
128 * it's safe for the StructuredCloneData to outlive the source data. This is
129 * safe to use with IPC-provided ClonedMessageData instances because
130 * JSStructuredCloneData's IPC ParamTraits::Read method copies the relevant
131 * data into owned buffers. But if it's possible the ClonedMessageData came
132 * from a different source that might have borrowed the buffers itself, then
133 * things will crash. That would be a pretty strange implementation; if you
134 * see one, change it to use SharedJSAllocatedData.
136 * 1: Specifically, in the Write() case an owning SharedJSAllocatedData is
137 * created efficiently (by stealing from StructuredCloneHolder). The
138 * BuildClonedMessageDataFor* method can be called at any time and it will
139 * borrow the underlying memory. While it would be even better if
140 * SerializedStructuredCloneBuffer could hold a SharedJSAllocatedData ref,
141 * there's no reason you can't wait to BuildClonedMessageDataFor* until you
142 * need to make the IPC Send* call.
144 class StructuredCloneData : public StructuredCloneHolder {
145 public:
146 StructuredCloneData();
148 StructuredCloneData(const StructuredCloneData&) = delete;
150 StructuredCloneData(StructuredCloneData&& aOther);
152 // Only DifferentProcess and UnknownDestination scopes are supported.
153 StructuredCloneData(StructuredCloneScope aScope,
154 TransferringSupport aSupportsTransferring);
156 ~StructuredCloneData();
158 StructuredCloneData& operator=(const StructuredCloneData& aOther) = delete;
160 StructuredCloneData& operator=(StructuredCloneData&& aOther);
162 const nsTArray<RefPtr<BlobImpl>>& BlobImpls() const { return mBlobImplArray; }
164 nsTArray<RefPtr<BlobImpl>>& BlobImpls() { return mBlobImplArray; }
166 const nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() const {
167 return mInputStreamArray;
170 nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() {
171 return mInputStreamArray;
174 bool Copy(const StructuredCloneData& aData);
176 void Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
177 ErrorResult& aRv);
179 void Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
180 const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv);
182 // Write with no transfer objects and with the default CloneDataPolicy. With
183 // a default CloneDataPolicy, read and write will not be considered as part of
184 // the same agent cluster and shared memory objects will not be supported.
185 void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
186 ErrorResult& aRv) override;
188 // The most generic Write method, with tansfers and CloneDataPolicy.
189 void Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
190 JS::Handle<JS::Value> aTransfers,
191 const JS::CloneDataPolicy& aCloneDataPolicy,
192 ErrorResult& aRv) override;
194 // Method to convert the structured clone stored in this holder by a previous
195 // call to Write() into ClonedMessageData IPC representation.
196 bool BuildClonedMessageData(ClonedMessageData& aClonedData);
198 // Memory-management-strategy-varying methods to initialize this holder from a
199 // ClonedMessageData representation.
200 void BorrowFromClonedMessageData(const ClonedMessageData& aClonedData);
202 void CopyFromClonedMessageData(const ClonedMessageData& aClonedData);
204 // The steal variant of course takes a non-const ClonedMessageData.
205 void StealFromClonedMessageData(ClonedMessageData& aClonedData);
207 // Initialize this instance, borrowing the contents of the given
208 // JSStructuredCloneData. You are responsible for ensuring that this
209 // StructuredCloneData instance is destroyed before aData is destroyed.
210 bool UseExternalData(const JSStructuredCloneData& aData) {
211 auto iter = aData.Start();
212 bool success = false;
213 mExternalData = aData.Borrow(iter, aData.Size(), &success);
214 mInitialized = true;
215 return success;
218 // Initialize this instance by copying the given data that probably came from
219 // nsStructuredClone doing a base64 decode. Don't use this.
220 bool CopyExternalData(const char* aData, size_t aDataLength);
221 // Initialize this instance by copying the contents of an existing
222 // JSStructuredCloneData. Use when this StructuredCloneData instance may
223 // outlive aData.
224 bool CopyExternalData(const JSStructuredCloneData& aData);
226 // Initialize this instance by stealing the contents of aData via Move
227 // constructor, clearing the original aData as a side-effect. This is only
228 // safe if aData owns the underlying buffers. This is the case for instances
229 // provided by IPC to Recv calls.
230 bool StealExternalData(JSStructuredCloneData& aData);
232 JSStructuredCloneData& Data() {
233 return mSharedData ? mSharedData->Data() : mExternalData;
236 const JSStructuredCloneData& Data() const {
237 return mSharedData ? mSharedData->Data() : mExternalData;
240 void InitScope(JS::StructuredCloneScope aScope) { Data().initScope(aScope); }
242 size_t DataLength() const {
243 return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
246 SharedJSAllocatedData* SharedData() const { return mSharedData; }
248 bool SupportsTransferring() { return mSupportsTransferring; }
250 // For IPC serialization
251 void WriteIPCParams(IPC::MessageWriter* aWriter) const;
252 bool ReadIPCParams(IPC::MessageReader* aReader);
254 protected:
255 already_AddRefed<SharedJSAllocatedData> TakeSharedData();
257 private:
258 JSStructuredCloneData mExternalData;
259 RefPtr<SharedJSAllocatedData> mSharedData;
261 bool mInitialized;
264 } // namespace ipc
265 } // namespace dom
266 } // namespace mozilla
268 #endif // mozilla_dom_ipc_StructuredCloneData_h