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_StructuredCloneHolder_h
8 #define mozilla_dom_StructuredCloneHolder_h
13 #include "js/StructuredClone.h"
14 #include "js/TypeDecls.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Attributes.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/RefPtr.h"
19 #include "mozilla/UniquePtr.h"
25 class nsIGlobalObject
;
27 struct JSStructuredCloneReader
;
28 struct JSStructuredCloneWriter
;
45 class DataSourceSurface
;
52 class MessagePortIdentifier
;
56 class StructuredCloneHolderBase
{
58 typedef JS::StructuredCloneScope StructuredCloneScope
;
60 StructuredCloneHolderBase(
61 StructuredCloneScope aScope
= StructuredCloneScope::SameProcess
);
62 virtual ~StructuredCloneHolderBase();
64 // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw
65 // this pointer is passed to mBuffer as a callback closure. That must
66 // be fixed if you want to implement a move constructor here.
67 StructuredCloneHolderBase(StructuredCloneHolderBase
&& aOther
) = delete;
69 // These methods should be implemented in order to clone data.
70 // Read more documentation in js/public/StructuredClone.h.
72 virtual JSObject
* CustomReadHandler(
73 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
74 const JS::CloneDataPolicy
& aCloneDataPolicy
, uint32_t aTag
,
77 virtual bool CustomWriteHandler(JSContext
* aCx
,
78 JSStructuredCloneWriter
* aWriter
,
79 JS::Handle
<JSObject
*> aObj
,
80 bool* aSameProcessScopeRequired
) = 0;
82 // This method has to be called when this object is not needed anymore.
83 // It will free memory and the buffer. This has to be called because
84 // otherwise the buffer will be freed in the DTOR of this class and at that
85 // point we cannot use the overridden methods.
88 // If these 3 methods are not implement, transfering objects will not be
89 // allowed. Otherwise only arrayBuffers will be transferred.
91 virtual bool CustomReadTransferHandler(
92 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
93 const JS::CloneDataPolicy
& aCloneDataPolicy
, uint32_t aTag
,
94 void* aContent
, uint64_t aExtraData
,
95 JS::MutableHandle
<JSObject
*> aReturnObject
);
97 virtual bool CustomWriteTransferHandler(JSContext
* aCx
,
98 JS::Handle
<JSObject
*> aObj
,
101 JS::TransferableOwnership
* aOwnership
,
103 uint64_t* aExtraData
);
105 virtual void CustomFreeTransferHandler(uint32_t aTag
,
106 JS::TransferableOwnership aOwnership
,
107 void* aContent
, uint64_t aExtraData
);
109 virtual bool CustomCanTransferHandler(JSContext
* aCx
,
110 JS::Handle
<JSObject
*> aObj
,
111 bool* aSameProcessScopeRequired
);
113 // These methods are what you should use to read/write data.
115 // Execute the serialization of aValue using the Structured Clone Algorithm.
116 // The data can read back using Read().
117 bool Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
);
119 // Like Write() but it supports the transferring of objects and handling
120 // of cloning policy.
121 bool Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
122 JS::Handle
<JS::Value
> aTransfer
,
123 const JS::CloneDataPolicy
& aCloneDataPolicy
);
125 // If Write() has been called, this method retrieves data and stores it into
127 bool Read(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aValue
);
129 // Like Read() but it supports handling of clone policy.
130 bool Read(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aValue
,
131 const JS::CloneDataPolicy
& aCloneDataPolicy
);
133 bool HasData() const { return !!mBuffer
; }
135 JSStructuredCloneData
& BufferData() const {
136 MOZ_ASSERT(mBuffer
, "Write() has never been called.");
137 return mBuffer
->data();
140 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) {
143 size
+= mBuffer
->sizeOfIncludingThis(aMallocSizeOf
);
148 void SetErrorMessage(const char* aErrorMessage
) {
149 mErrorMessage
.Assign(aErrorMessage
);
153 UniquePtr
<JSAutoStructuredCloneBuffer
> mBuffer
;
155 StructuredCloneScope mStructuredCloneScope
;
157 // Error message when a data clone error is about to throw. It's held while
158 // the error callback is fired and it will be throw with a data clone error
160 nsCString mErrorMessage
;
168 class EncodedVideoChunkData
;
170 class MessagePortIdentifier
;
171 struct VideoFrameSerializedData
;
173 class StructuredCloneHolder
: public StructuredCloneHolderBase
{
175 enum CloningSupport
{ CloningSupported
, CloningNotSupported
};
177 enum TransferringSupport
{ TransferringSupported
, TransferringNotSupported
};
179 // If cloning is supported, this object will clone objects such as Blobs,
180 // FileList, ImageData, etc.
181 // If transferring is supported, we will transfer MessagePorts and in the
182 // future other transferrable objects.
183 // The StructuredCloneScope is useful to know where the cloned/transferred
184 // data can be read and written. Additional checks about the nature of the
185 // objects will be done based on this scope value because not all the
186 // objects can be sent between threads or processes.
187 explicit StructuredCloneHolder(CloningSupport aSupportsCloning
,
188 TransferringSupport aSupportsTransferring
,
189 StructuredCloneScope aStructuredCloneScope
);
190 virtual ~StructuredCloneHolder();
192 StructuredCloneHolder(StructuredCloneHolder
&& aOther
) = delete;
194 // Normally you should just use Write() and Read().
196 virtual void Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
199 virtual void Write(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
200 JS::Handle
<JS::Value
> aTransfer
,
201 const JS::CloneDataPolicy
& aCloneDataPolicy
,
204 void Read(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
205 JS::MutableHandle
<JS::Value
> aValue
, ErrorResult
& aRv
);
207 void Read(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
208 JS::MutableHandle
<JS::Value
> aValue
,
209 const JS::CloneDataPolicy
& aCloneDataPolicy
, ErrorResult
& aRv
);
211 // Call this method to know if this object is keeping some DOM object alive.
212 bool HasClonedDOMObjects() const {
213 return !mBlobImplArray
.IsEmpty() || !mWasmModuleArray
.IsEmpty() ||
214 !mClonedSurfaces
.IsEmpty() || !mInputStreamArray
.IsEmpty() ||
215 !mVideoFrames
.IsEmpty() || !mEncodedVideoChunks
.IsEmpty();
218 nsTArray
<RefPtr
<BlobImpl
>>& BlobImpls() {
219 MOZ_ASSERT(mSupportsCloning
,
220 "Blobs cannot be taken/set if cloning is not supported.");
221 return mBlobImplArray
;
224 nsTArray
<RefPtr
<JS::WasmModule
>>& WasmModules() {
225 MOZ_ASSERT(mSupportsCloning
,
226 "WasmModules cannot be taken/set if cloning is not supported.");
227 return mWasmModuleArray
;
230 nsTArray
<nsCOMPtr
<nsIInputStream
>>& InputStreams() {
231 MOZ_ASSERT(mSupportsCloning
,
232 "InputStreams cannot be taken/set if cloning is not supported.");
233 return mInputStreamArray
;
236 // This method returns the final scope. If the final scope is unknown,
237 // DifferentProcess is returned because it's the most restrictive one.
238 StructuredCloneScope
CloneScope() const {
239 if (mStructuredCloneScope
== StructuredCloneScope::UnknownDestination
) {
240 return StructuredCloneScope::DifferentProcess
;
242 return mStructuredCloneScope
;
245 // The global object is set internally just during the Read(). This method
246 // can be used by read functions to retrieve it.
247 nsIGlobalObject
* GlobalDuringRead() const { return mGlobal
; }
249 // This must be called if the transferring has ports generated by Read().
250 // MessagePorts are not thread-safe and they must be retrieved in the thread
251 // where they are created.
252 nsTArray
<RefPtr
<MessagePort
>>&& TakeTransferredPorts() {
253 MOZ_ASSERT(mSupportsTransferring
);
254 return std::move(mTransferredPorts
);
257 // This method uses TakeTransferredPorts() to populate a sequence of
258 // MessagePorts for WebIDL binding classes.
259 bool TakeTransferredPortsAsSequence(
260 Sequence
<OwningNonNull
<mozilla::dom::MessagePort
>>& aPorts
);
262 nsTArray
<MessagePortIdentifier
>& PortIdentifiers() const {
263 MOZ_ASSERT(mSupportsTransferring
);
264 return mPortIdentifiers
;
267 nsTArray
<RefPtr
<gfx::DataSourceSurface
>>& GetSurfaces() {
268 return mClonedSurfaces
;
271 nsTArray
<VideoFrameSerializedData
>& VideoFrames() { return mVideoFrames
; }
273 nsTArray
<EncodedVideoChunkData
>& EncodedVideoChunks() {
274 return mEncodedVideoChunks
;
277 // Implementations of the virtual methods to allow cloning of objects which
278 // JS engine itself doesn't clone.
280 virtual JSObject
* CustomReadHandler(
281 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
282 const JS::CloneDataPolicy
& aCloneDataPolicy
, uint32_t aTag
,
283 uint32_t aIndex
) override
;
285 virtual bool CustomWriteHandler(JSContext
* aCx
,
286 JSStructuredCloneWriter
* aWriter
,
287 JS::Handle
<JSObject
*> aObj
,
288 bool* aSameProcessScopeRequired
) override
;
290 virtual bool CustomReadTransferHandler(
291 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
292 const JS::CloneDataPolicy
& aCloneDataPolicy
, uint32_t aTag
,
293 void* aContent
, uint64_t aExtraData
,
294 JS::MutableHandle
<JSObject
*> aReturnObject
) override
;
296 virtual bool CustomWriteTransferHandler(JSContext
* aCx
,
297 JS::Handle
<JSObject
*> aObj
,
299 JS::TransferableOwnership
* aOwnership
,
301 uint64_t* aExtraData
) override
;
303 virtual void CustomFreeTransferHandler(uint32_t aTag
,
304 JS::TransferableOwnership aOwnership
,
306 uint64_t aExtraData
) override
;
308 virtual bool CustomCanTransferHandler(
309 JSContext
* aCx
, JS::Handle
<JSObject
*> aObj
,
310 bool* aSameProcessScopeRequired
) override
;
312 // These 2 static methods are useful to read/write fully serializable objects.
313 // They can be used by custom StructuredCloneHolderBase classes to
314 // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
316 static JSObject
* ReadFullySerializableObjects(
317 JSContext
* aCx
, JSStructuredCloneReader
* aReader
, uint32_t aTag
,
318 bool aIsForIndexedDB
);
320 static bool WriteFullySerializableObjects(JSContext
* aCx
,
321 JSStructuredCloneWriter
* aWriter
,
322 JS::Handle
<JSObject
*> aObj
);
324 // Helper functions for reading and writing strings.
325 static bool ReadString(JSStructuredCloneReader
* aReader
, nsString
& aString
);
326 static bool WriteString(JSStructuredCloneWriter
* aWriter
,
327 const nsAString
& aString
);
328 static bool ReadCString(JSStructuredCloneReader
* aReader
, nsCString
& aString
);
329 static bool WriteCString(JSStructuredCloneWriter
* aWriter
,
330 const nsACString
& aString
);
332 static const JSStructuredCloneCallbacks sCallbacks
;
335 // If you receive a buffer from IPC, you can use this method to retrieve a
336 // JS::Value. It can happen that you want to pre-populate the array of Blobs
337 // and/or the PortIdentifiers.
338 void ReadFromBuffer(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
339 JSStructuredCloneData
& aBuffer
,
340 JS::MutableHandle
<JS::Value
> aValue
,
341 const JS::CloneDataPolicy
& aCloneDataPolicy
,
344 void ReadFromBuffer(nsIGlobalObject
* aGlobal
, JSContext
* aCx
,
345 JSStructuredCloneData
& aBuffer
,
346 uint32_t aAlgorithmVersion
,
347 JS::MutableHandle
<JS::Value
> aValue
,
348 const JS::CloneDataPolicy
& aCloneDataPolicy
,
351 void SameProcessScopeRequired(bool* aSameProcessScopeRequired
);
353 already_AddRefed
<MessagePort
> ReceiveMessagePort(uint64_t aIndex
);
355 bool mSupportsCloning
;
356 bool mSupportsTransferring
;
358 // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
359 // account for objects in the following arrays because a) they're not expected
360 // to be stored in long-lived StructuredCloneHolder objects, and b) in the
361 // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
362 // and the other types do not hold significant amounts of memory alive.
364 // Used for cloning blobs in the structured cloning algorithm.
365 nsTArray
<RefPtr
<BlobImpl
>> mBlobImplArray
;
367 // Used for cloning JS::WasmModules in the structured cloning algorithm.
368 nsTArray
<RefPtr
<JS::WasmModule
>> mWasmModuleArray
;
370 // Used for cloning InputStream in the structured cloning algorithm.
371 nsTArray
<nsCOMPtr
<nsIInputStream
>> mInputStreamArray
;
373 // This is used for sharing the backend of ImageBitmaps.
374 // The DataSourceSurface object must be thread-safely reference-counted.
375 // The DataSourceSurface object will not be written ever via any ImageBitmap
376 // instance, so no race condition will occur.
377 nsTArray
<RefPtr
<gfx::DataSourceSurface
>> mClonedSurfaces
;
379 // Used for cloning VideoFrame in the structured cloning algorithm.
380 nsTArray
<VideoFrameSerializedData
> mVideoFrames
;
382 // Used for cloning EncodedVideoChunk in the structured cloning algorithm.
383 nsTArray
<EncodedVideoChunkData
> mEncodedVideoChunks
;
385 // This raw pointer is only set within ::Read() and is unset by the end.
386 nsIGlobalObject
* MOZ_NON_OWNING_REF mGlobal
;
388 // This array contains the ports once we've finished the reading. It's
389 // generated from the mPortIdentifiers array.
390 nsTArray
<RefPtr
<MessagePort
>> mTransferredPorts
;
392 // This array contains the identifiers of the MessagePorts. Based on these we
393 // are able to reconnect the new transferred ports with the other
394 // MessageChannel ports.
395 mutable nsTArray
<MessagePortIdentifier
> mPortIdentifiers
;
398 nsCOMPtr
<nsIEventTarget
> mCreationEventTarget
;
403 } // namespace mozilla
405 #endif // mozilla_dom_StructuredCloneHolder_h