StructuredCloneHolder.h (17461B)
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/. */ 6 7 #ifndef mozilla_dom_StructuredCloneHolder_h 8 #define mozilla_dom_StructuredCloneHolder_h 9 10 #include <cstddef> 11 #include <cstdint> 12 #include <utility> 13 14 #include "js/StructuredClone.h" 15 #include "js/TypeDecls.h" 16 #include "mozilla/Assertions.h" 17 #include "mozilla/Attributes.h" 18 #include "mozilla/MemoryReporting.h" 19 #include "mozilla/RefPtr.h" 20 #include "mozilla/UniquePtr.h" 21 #include "nsCOMPtr.h" 22 #include "nsString.h" 23 #include "nsTArray.h" 24 25 class nsIEventTarget; 26 class nsIGlobalObject; 27 class nsIInputStream; 28 struct JSStructuredCloneReader; 29 struct JSStructuredCloneWriter; 30 31 namespace JS { 32 class Value; 33 struct WasmModule; 34 } // namespace JS 35 36 namespace mozilla { 37 class ErrorResult; 38 template <class T> 39 class OwningNonNull; 40 41 namespace layers { 42 class Image; 43 } 44 45 namespace gfx { 46 class DataSourceSurface; 47 } 48 49 namespace dom { 50 51 class BlobImpl; 52 class MessagePort; 53 class MessagePortIdentifier; 54 template <typename T> 55 class Sequence; 56 57 class StructuredCloneHolderBase { 58 public: 59 typedef JS::StructuredCloneScope StructuredCloneScope; 60 61 StructuredCloneHolderBase( 62 StructuredCloneScope aScope = StructuredCloneScope::SameProcess); 63 virtual ~StructuredCloneHolderBase(); 64 65 // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw 66 // this pointer is passed to mBuffer as a callback closure. That must 67 // be fixed if you want to implement a move constructor here. 68 StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete; 69 70 // These methods should be implemented in order to clone data. 71 // Read more documentation in js/public/StructuredClone.h. 72 73 virtual JSObject* CustomReadHandler( 74 JSContext* aCx, JSStructuredCloneReader* aReader, 75 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, 76 uint32_t aIndex) = 0; 77 78 virtual bool CustomWriteHandler(JSContext* aCx, 79 JSStructuredCloneWriter* aWriter, 80 JS::Handle<JSObject*> aObj, 81 bool* aSameProcessScopeRequired) = 0; 82 83 // This method has to be called when this object is not needed anymore. 84 // It will free memory and the buffer. This has to be called because 85 // otherwise the buffer will be freed in the DTOR of this class and at that 86 // point we cannot use the overridden methods. 87 void Clear(); 88 89 // If these 3 methods are not implement, transfering objects will not be 90 // allowed. Otherwise only arrayBuffers will be transferred. 91 92 virtual bool CustomReadTransferHandler( 93 JSContext* aCx, JSStructuredCloneReader* aReader, 94 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, 95 void* aContent, uint64_t aExtraData, 96 JS::MutableHandle<JSObject*> aReturnObject); 97 98 virtual bool CustomWriteTransferHandler(JSContext* aCx, 99 JS::Handle<JSObject*> aObj, 100 // Output: 101 uint32_t* aTag, 102 JS::TransferableOwnership* aOwnership, 103 void** aContent, 104 uint64_t* aExtraData); 105 106 virtual void CustomFreeTransferHandler(uint32_t aTag, 107 JS::TransferableOwnership aOwnership, 108 void* aContent, uint64_t aExtraData); 109 110 virtual bool CustomCanTransferHandler(JSContext* aCx, 111 JS::Handle<JSObject*> aObj, 112 bool* aSameProcessScopeRequired); 113 114 // These methods are what you should use to read/write data. 115 116 // Execute the serialization of aValue using the Structured Clone Algorithm. 117 // The data can read back using Read(). 118 bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue); 119 120 // Like Write() but it supports the transferring of objects and handling 121 // of cloning policy. 122 bool Write(JSContext* aCx, JS::Handle<JS::Value> aValue, 123 JS::Handle<JS::Value> aTransfer, 124 const JS::CloneDataPolicy& aCloneDataPolicy); 125 126 // If Write() has been called, this method retrieves data and stores it into 127 // aValue. 128 bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue); 129 130 // Like Read() but it supports handling of clone policy. 131 bool Read(JSContext* aCx, JS::MutableHandle<JS::Value> aValue, 132 const JS::CloneDataPolicy& aCloneDataPolicy); 133 134 bool HasData() const { return !!mBuffer; } 135 136 JSStructuredCloneData& BufferData() const { 137 MOZ_ASSERT(mBuffer, "Write() has never been called."); 138 return mBuffer->data(); 139 } 140 141 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) { 142 size_t size = 0; 143 if (HasData()) { 144 size += mBuffer->sizeOfIncludingThis(aMallocSizeOf); 145 } 146 return size; 147 } 148 149 void SetErrorMessage(const char* aErrorMessage) { 150 mErrorMessage.Assign(aErrorMessage); 151 } 152 153 protected: 154 UniquePtr<JSAutoStructuredCloneBuffer> mBuffer; 155 156 StructuredCloneScope mStructuredCloneScope; 157 158 // Error message when a data clone error is about to throw. It's held while 159 // the error callback is fired and it will be throw with a data clone error 160 // later. 161 nsCString mErrorMessage; 162 163 #ifdef DEBUG 164 bool mClearCalled; 165 #endif 166 }; 167 168 class BlobImpl; 169 class EncodedAudioChunkData; 170 class EncodedVideoChunkData; 171 class MessagePort; 172 class MessagePortIdentifier; 173 struct VideoFrameSerializedData; 174 struct AudioDataSerializedData; 175 #ifdef MOZ_WEBRTC 176 struct RTCEncodedVideoFrameData; 177 struct RTCEncodedAudioFrameData; 178 #endif 179 180 class StructuredCloneHolder : public StructuredCloneHolderBase { 181 public: 182 enum CloningSupport { CloningSupported, CloningNotSupported }; 183 184 enum TransferringSupport { TransferringSupported, TransferringNotSupported }; 185 186 // If cloning is supported, this object will clone objects such as Blobs, 187 // FileList, ImageData, etc. 188 // If transferring is supported, we will transfer MessagePorts and in the 189 // future other transferrable objects. 190 // The StructuredCloneScope is useful to know where the cloned/transferred 191 // data can be read and written. Additional checks about the nature of the 192 // objects will be done based on this scope value because not all the 193 // objects can be sent between threads or processes. 194 explicit StructuredCloneHolder(CloningSupport aSupportsCloning, 195 TransferringSupport aSupportsTransferring, 196 StructuredCloneScope aStructuredCloneScope); 197 virtual ~StructuredCloneHolder(); 198 199 StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete; 200 201 // Normally you should just use Write() and Read(). 202 203 virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue, 204 ErrorResult& aRv); 205 206 virtual void Write(JSContext* aCx, JS::Handle<JS::Value> aValue, 207 JS::Handle<JS::Value> aTransfer, 208 const JS::CloneDataPolicy& aCloneDataPolicy, 209 ErrorResult& aRv); 210 211 void Read(nsIGlobalObject* aGlobal, JSContext* aCx, 212 JS::MutableHandle<JS::Value> aValue, ErrorResult& aRv); 213 214 void Read(nsIGlobalObject* aGlobal, JSContext* aCx, 215 JS::MutableHandle<JS::Value> aValue, 216 const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv); 217 218 #ifdef MOZ_WEBRTC 219 # define IF_WEBRTC(x) x 220 #else 221 # define IF_WEBRTC(x) 222 #endif 223 224 // Create a statement for each of the side DOM-ish data members. 225 // mTransferredPorts is not included because it is part of the 226 // deserialized state. 227 #define CLONED_DATA_MEMBERS \ 228 STMT(mBlobImplArray); \ 229 STMT(mWasmModuleArray); \ 230 STMT(mInputStreamArray); \ 231 STMT(mClonedSurfaces); \ 232 STMT(mVideoFrames); \ 233 STMT(mAudioData); \ 234 STMT(mEncodedVideoChunks); \ 235 STMT(mEncodedAudioChunks); \ 236 IF_WEBRTC(STMT(mRtcEncodedVideoFrames);) \ 237 IF_WEBRTC(STMT(mRtcEncodedAudioFrames);) \ 238 STMT(mPortIdentifiers); 239 240 // Call this method to know if this object is keeping some DOM object alive. 241 bool HasClonedDOMObjects() const { 242 #define STMT(_member) \ 243 if (!(_member).IsEmpty()) { \ 244 return true; \ 245 } 246 247 CLONED_DATA_MEMBERS 248 #undef STMT 249 return false; 250 } 251 252 nsTArray<RefPtr<BlobImpl>>& BlobImpls() { 253 MOZ_ASSERT(mSupportsCloning, 254 "Blobs cannot be taken/set if cloning is not supported."); 255 return mBlobImplArray; 256 } 257 258 nsTArray<RefPtr<JS::WasmModule>>& WasmModules() { 259 MOZ_ASSERT(mSupportsCloning, 260 "WasmModules cannot be taken/set if cloning is not supported."); 261 return mWasmModuleArray; 262 } 263 264 nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() { 265 MOZ_ASSERT(mSupportsCloning, 266 "InputStreams cannot be taken/set if cloning is not supported."); 267 return mInputStreamArray; 268 } 269 270 // This method returns the final scope. If the final scope is unknown, 271 // DifferentProcess is returned because it's the most restrictive one. 272 StructuredCloneScope CloneScope() const { 273 if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) { 274 return StructuredCloneScope::DifferentProcess; 275 } 276 return mStructuredCloneScope; 277 } 278 279 // The global object is set internally just during the Read(). This method 280 // can be used by read functions to retrieve it. 281 nsIGlobalObject* GlobalDuringRead() const { return mGlobal; } 282 283 // This must be called if the transferring has ports generated by Read(). 284 // MessagePorts are not thread-safe and they must be retrieved in the thread 285 // where they are created. 286 nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts() { 287 MOZ_ASSERT(mSupportsTransferring); 288 return std::move(mTransferredPorts); 289 } 290 291 // This method uses TakeTransferredPorts() to populate a sequence of 292 // MessagePorts for WebIDL binding classes. 293 bool TakeTransferredPortsAsSequence( 294 Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts); 295 296 nsTArray<MessagePortIdentifier>& PortIdentifiers() const { 297 MOZ_ASSERT(mSupportsTransferring); 298 return mPortIdentifiers; 299 } 300 301 nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces() { 302 return mClonedSurfaces; 303 } 304 305 nsTArray<VideoFrameSerializedData>& VideoFrames() { return mVideoFrames; } 306 307 nsTArray<AudioDataSerializedData>& AudioData() { return mAudioData; } 308 309 nsTArray<EncodedVideoChunkData>& EncodedVideoChunks() { 310 return mEncodedVideoChunks; 311 } 312 313 nsTArray<EncodedAudioChunkData>& EncodedAudioChunks() { 314 return mEncodedAudioChunks; 315 } 316 317 #ifdef MOZ_WEBRTC 318 nsTArray<RTCEncodedVideoFrameData>& RtcEncodedVideoFrames() { 319 return mRtcEncodedVideoFrames; 320 } 321 322 nsTArray<RTCEncodedAudioFrameData>& RtcEncodedAudioFrames() { 323 return mRtcEncodedAudioFrames; 324 } 325 #endif 326 327 // Implementations of the virtual methods to allow cloning of objects which 328 // JS engine itself doesn't clone. 329 330 virtual JSObject* CustomReadHandler( 331 JSContext* aCx, JSStructuredCloneReader* aReader, 332 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, 333 uint32_t aIndex) override; 334 335 virtual bool CustomWriteHandler(JSContext* aCx, 336 JSStructuredCloneWriter* aWriter, 337 JS::Handle<JSObject*> aObj, 338 bool* aSameProcessScopeRequired) override; 339 340 virtual bool CustomReadTransferHandler( 341 JSContext* aCx, JSStructuredCloneReader* aReader, 342 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, 343 void* aContent, uint64_t aExtraData, 344 JS::MutableHandle<JSObject*> aReturnObject) override; 345 346 virtual bool CustomWriteTransferHandler(JSContext* aCx, 347 JS::Handle<JSObject*> aObj, 348 uint32_t* aTag, 349 JS::TransferableOwnership* aOwnership, 350 void** aContent, 351 uint64_t* aExtraData) override; 352 353 virtual void CustomFreeTransferHandler(uint32_t aTag, 354 JS::TransferableOwnership aOwnership, 355 void* aContent, 356 uint64_t aExtraData) override; 357 358 virtual bool CustomCanTransferHandler( 359 JSContext* aCx, JS::Handle<JSObject*> aObj, 360 bool* aSameProcessScopeRequired) override; 361 362 // These 2 static methods are useful to read/write fully serializable objects. 363 // They can be used by custom StructuredCloneHolderBase classes to 364 // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc. 365 366 static JSObject* ReadFullySerializableObjects( 367 JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, 368 bool aIsForIndexedDB); 369 370 static bool WriteFullySerializableObjects(JSContext* aCx, 371 JSStructuredCloneWriter* aWriter, 372 JS::Handle<JSObject*> aObj); 373 374 // Helper functions for reading and writing strings. 375 static bool ReadString(JSStructuredCloneReader* aReader, nsString& aString); 376 static bool WriteString(JSStructuredCloneWriter* aWriter, 377 const nsAString& aString); 378 static bool ReadCString(JSStructuredCloneReader* aReader, nsCString& aString); 379 static bool WriteCString(JSStructuredCloneWriter* aWriter, 380 const nsACString& aString); 381 382 static const JSStructuredCloneCallbacks sCallbacks; 383 384 protected: 385 // If you receive a buffer from IPC, you can use this method to retrieve a 386 // JS::Value. It can happen that you want to pre-populate the array of Blobs 387 // and/or the PortIdentifiers. 388 void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx, 389 JSStructuredCloneData& aBuffer, 390 JS::MutableHandle<JS::Value> aValue, 391 const JS::CloneDataPolicy& aCloneDataPolicy, 392 ErrorResult& aRv); 393 394 void ReadFromBuffer(nsIGlobalObject* aGlobal, JSContext* aCx, 395 JSStructuredCloneData& aBuffer, 396 uint32_t aAlgorithmVersion, 397 JS::MutableHandle<JS::Value> aValue, 398 const JS::CloneDataPolicy& aCloneDataPolicy, 399 ErrorResult& aRv); 400 401 void SameProcessScopeRequired(bool* aSameProcessScopeRequired); 402 403 already_AddRefed<MessagePort> ReceiveMessagePort(uint64_t aIndex); 404 405 bool mSupportsCloning; 406 bool mSupportsTransferring; 407 408 // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't 409 // account for objects in the following arrays because a) they're not expected 410 // to be stored in long-lived StructuredCloneHolder objects, and b) in the 411 // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters, 412 // and the other types do not hold significant amounts of memory alive. 413 414 // Used for cloning blobs in the structured cloning algorithm. 415 nsTArray<RefPtr<BlobImpl>> mBlobImplArray; 416 417 // Used for cloning JS::WasmModules in the structured cloning algorithm. 418 nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray; 419 420 // Used for cloning InputStream in the structured cloning algorithm. 421 nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray; 422 423 // This is used for sharing the backend of ImageBitmaps. 424 // The DataSourceSurface object must be thread-safely reference-counted. 425 // The DataSourceSurface object will not be written ever via any ImageBitmap 426 // instance, so no race condition will occur. 427 nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces; 428 429 // Used for cloning VideoFrame in the structured cloning algorithm. 430 nsTArray<VideoFrameSerializedData> mVideoFrames; 431 432 // Used for cloning AudioData in the structured cloning algorithm. 433 nsTArray<AudioDataSerializedData> mAudioData; 434 435 // Used for cloning EncodedVideoChunk in the structured cloning algorithm. 436 nsTArray<EncodedVideoChunkData> mEncodedVideoChunks; 437 438 // Used for cloning EncodedAudioChunk in the structured cloning algorithm. 439 nsTArray<EncodedAudioChunkData> mEncodedAudioChunks; 440 441 #ifdef MOZ_WEBRTC 442 // Used for cloning RTCEncodedVideoFrame in the structured cloning algorithm. 443 nsTArray<RTCEncodedVideoFrameData> mRtcEncodedVideoFrames; 444 445 // Used for cloning RTCEncodedAudioFrame in the structured cloning algorithm. 446 nsTArray<RTCEncodedAudioFrameData> mRtcEncodedAudioFrames; 447 #endif 448 449 // This raw pointer is only set within ::Read() and is unset by the end. 450 nsIGlobalObject* MOZ_NON_OWNING_REF mGlobal; 451 452 // This array contains the ports once we've finished the reading. It's 453 // generated from the mPortIdentifiers array. 454 nsTArray<RefPtr<MessagePort>> mTransferredPorts; 455 456 // This array contains the identifiers of the MessagePorts. Based on these we 457 // are able to reconnect the new transferred ports with the other 458 // MessageChannel ports. 459 mutable nsTArray<MessagePortIdentifier> mPortIdentifiers; 460 461 #ifdef DEBUG 462 nsCOMPtr<nsIEventTarget> mCreationEventTarget; 463 #endif 464 }; 465 466 } // namespace dom 467 } // namespace mozilla 468 469 #endif // mozilla_dom_StructuredCloneHolder_h