Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / StructuredCloneHolder.cpp
blobf3e2bea46bb2d474dc8df9edb1db4d059c96ddbd
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 "mozilla/dom/StructuredCloneHolder.h"
9 #include <new>
10 #include "ErrorList.h"
11 #include "MainThreadUtils.h"
12 #include "js/CallArgs.h"
13 #include "js/Value.h"
14 #include "js/WasmModule.h"
15 #include "js/Wrapper.h"
16 #include "jsapi.h"
17 #include "mozilla/AlreadyAddRefed.h"
18 #include "mozilla/AutoRestore.h"
19 #include "mozilla/ErrorResult.h"
20 #include "mozilla/OwningNonNull.h"
21 #include "mozilla/RefPtr.h"
22 #include "mozilla/ScopeExit.h"
23 #include "mozilla/StaticPrefs_dom.h"
24 #include "mozilla/dom/BindingDeclarations.h"
25 #include "mozilla/dom/BindingUtils.h"
26 #include "mozilla/dom/Blob.h"
27 #include "mozilla/dom/BlobBinding.h"
28 #include "mozilla/dom/BlobImpl.h"
29 #include "mozilla/dom/BrowsingContext.h"
30 #include "mozilla/dom/ClonedErrorHolder.h"
31 #include "mozilla/dom/ClonedErrorHolderBinding.h"
32 #include "mozilla/dom/DirectoryBinding.h"
33 #include "mozilla/dom/DOMJSClass.h"
34 #include "mozilla/dom/DOMTypes.h"
35 #include "mozilla/dom/Directory.h"
36 #include "mozilla/dom/DocGroup.h"
37 #include "mozilla/dom/EncodedAudioChunk.h"
38 #include "mozilla/dom/EncodedAudioChunkBinding.h"
39 #include "mozilla/dom/EncodedVideoChunk.h"
40 #include "mozilla/dom/EncodedVideoChunkBinding.h"
41 #include "mozilla/dom/File.h"
42 #include "mozilla/dom/FileList.h"
43 #include "mozilla/dom/FileListBinding.h"
44 #include "mozilla/dom/FormData.h"
45 #include "mozilla/dom/FormDataBinding.h"
46 #include "mozilla/dom/ImageBitmap.h"
47 #include "mozilla/dom/ImageBitmapBinding.h"
48 #include "mozilla/dom/JSExecutionManager.h"
49 #include "mozilla/dom/MessagePort.h"
50 #include "mozilla/dom/MessagePortBinding.h"
51 #include "mozilla/dom/OffscreenCanvas.h"
52 #include "mozilla/dom/OffscreenCanvasBinding.h"
53 #include "mozilla/dom/ReadableStream.h"
54 #include "mozilla/dom/ReadableStreamBinding.h"
55 #include "mozilla/dom/ScriptSettings.h"
56 #include "mozilla/dom/StructuredCloneBlob.h"
57 #include "mozilla/dom/StructuredCloneHolderBinding.h"
58 #include "mozilla/dom/StructuredCloneTags.h"
59 #include "mozilla/dom/ToJSValue.h"
60 #include "mozilla/dom/TransformStream.h"
61 #include "mozilla/dom/TransformStreamBinding.h"
62 #include "mozilla/dom/VideoFrame.h"
63 #include "mozilla/dom/AudioData.h"
64 #include "mozilla/dom/VideoFrameBinding.h"
65 #include "mozilla/dom/WebIDLSerializable.h"
66 #include "mozilla/dom/WritableStream.h"
67 #include "mozilla/dom/WritableStreamBinding.h"
68 #include "mozilla/dom/WorkerCommon.h"
69 #include "mozilla/dom/WorkerPrivate.h"
70 #include "mozilla/fallible.h"
71 #include "mozilla/gfx/2D.h"
72 #include "nsContentUtils.h"
73 #include "nsDebug.h"
74 #include "nsError.h"
75 #include "nsID.h"
76 #include "nsIEventTarget.h"
77 #include "nsIFile.h"
78 #include "nsIGlobalObject.h"
79 #include "nsIInputStream.h"
80 #include "nsIPrincipal.h"
81 #include "nsISupports.h"
82 #include "nsJSPrincipals.h"
83 #include "nsPIDOMWindow.h"
84 #include "nsString.h"
85 #include "nsThreadUtils.h"
86 #include "nsXPCOM.h"
87 #include "xpcpublic.h"
89 using namespace mozilla::ipc;
91 namespace mozilla::dom {
93 namespace {
95 JSObject* StructuredCloneCallbacksRead(
96 JSContext* aCx, JSStructuredCloneReader* aReader,
97 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, uint32_t aIndex,
98 void* aClosure) {
99 StructuredCloneHolderBase* holder =
100 static_cast<StructuredCloneHolderBase*>(aClosure);
101 MOZ_ASSERT(holder);
102 return holder->CustomReadHandler(aCx, aReader, aCloneDataPolicy, aTag,
103 aIndex);
106 bool StructuredCloneCallbacksWrite(JSContext* aCx,
107 JSStructuredCloneWriter* aWriter,
108 JS::Handle<JSObject*> aObj,
109 bool* aSameProcessScopeRequired,
110 void* aClosure) {
111 StructuredCloneHolderBase* holder =
112 static_cast<StructuredCloneHolderBase*>(aClosure);
113 MOZ_ASSERT(holder);
114 return holder->CustomWriteHandler(aCx, aWriter, aObj,
115 aSameProcessScopeRequired);
118 bool StructuredCloneCallbacksReadTransfer(
119 JSContext* aCx, JSStructuredCloneReader* aReader,
120 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, void* aContent,
121 uint64_t aExtraData, void* aClosure,
122 JS::MutableHandle<JSObject*> aReturnObject) {
123 StructuredCloneHolderBase* holder =
124 static_cast<StructuredCloneHolderBase*>(aClosure);
125 MOZ_ASSERT(holder);
126 return holder->CustomReadTransferHandler(aCx, aReader, aCloneDataPolicy, aTag,
127 aContent, aExtraData, aReturnObject);
130 bool StructuredCloneCallbacksWriteTransfer(
131 JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure,
132 // Output:
133 uint32_t* aTag, JS::TransferableOwnership* aOwnership, void** aContent,
134 uint64_t* aExtraData) {
135 StructuredCloneHolderBase* holder =
136 static_cast<StructuredCloneHolderBase*>(aClosure);
137 MOZ_ASSERT(holder);
138 return holder->CustomWriteTransferHandler(aCx, aObj, aTag, aOwnership,
139 aContent, aExtraData);
142 void StructuredCloneCallbacksFreeTransfer(uint32_t aTag,
143 JS::TransferableOwnership aOwnership,
144 void* aContent, uint64_t aExtraData,
145 void* aClosure) {
146 StructuredCloneHolderBase* holder =
147 static_cast<StructuredCloneHolderBase*>(aClosure);
148 MOZ_ASSERT(holder);
149 return holder->CustomFreeTransferHandler(aTag, aOwnership, aContent,
150 aExtraData);
153 bool StructuredCloneCallbacksCanTransfer(JSContext* aCx,
154 JS::Handle<JSObject*> aObject,
155 bool* aSameProcessScopeRequired,
156 void* aClosure) {
157 StructuredCloneHolderBase* holder =
158 static_cast<StructuredCloneHolderBase*>(aClosure);
159 MOZ_ASSERT(holder);
160 return holder->CustomCanTransferHandler(aCx, aObject,
161 aSameProcessScopeRequired);
164 bool StructuredCloneCallbacksSharedArrayBuffer(JSContext* cx, bool aReceiving,
165 void* aClosure) {
166 if (!StaticPrefs::dom_workers_serialized_sab_access()) {
167 return true;
170 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
172 if (workerPrivate) {
173 workerPrivate->SetExecutionManager(
174 JSExecutionManager::GetSABSerializationManager());
175 } else if (NS_IsMainThread()) {
176 nsIGlobalObject* global = GetCurrentGlobal();
178 nsPIDOMWindowInner* innerWindow = nullptr;
179 if (global) {
180 innerWindow = global->GetAsInnerWindow();
183 DocGroup* docGroup = nullptr;
184 if (innerWindow) {
185 docGroup = innerWindow->GetDocGroup();
188 if (docGroup) {
189 docGroup->SetExecutionManager(
190 JSExecutionManager::GetSABSerializationManager());
193 return true;
196 void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId,
197 void* aClosure, const char* aErrorMessage) {
198 NS_WARNING("Failed to clone data.");
199 StructuredCloneHolderBase* holder =
200 static_cast<StructuredCloneHolderBase*>(aClosure);
201 MOZ_ASSERT(holder);
202 return holder->SetErrorMessage(aErrorMessage);
205 void AssertTagValues() {
206 static_assert(SCTAG_DOM_IMAGEDATA == 0xffff8007 &&
207 SCTAG_DOM_DOMPOINT == 0xffff8008 &&
208 SCTAG_DOM_DOMPOINTREADONLY == 0xffff8009 &&
209 SCTAG_DOM_CRYPTOKEY == 0xffff800a &&
210 SCTAG_DOM_NULL_PRINCIPAL == 0xffff800b &&
211 SCTAG_DOM_SYSTEM_PRINCIPAL == 0xffff800c &&
212 SCTAG_DOM_CONTENT_PRINCIPAL == 0xffff800d &&
213 SCTAG_DOM_DOMQUAD == 0xffff800e &&
214 SCTAG_DOM_RTCCERTIFICATE == 0xffff800f &&
215 SCTAG_DOM_DOMRECT == 0xffff8010 &&
216 SCTAG_DOM_DOMRECTREADONLY == 0xffff8011 &&
217 SCTAG_DOM_EXPANDED_PRINCIPAL == 0xffff8012 &&
218 SCTAG_DOM_DOMMATRIX == 0xffff8013 &&
219 SCTAG_DOM_URLSEARCHPARAMS == 0xffff8014 &&
220 SCTAG_DOM_DOMMATRIXREADONLY == 0xffff8015 &&
221 SCTAG_DOM_STRUCTUREDCLONETESTER == 0xffff8018 &&
222 SCTAG_DOM_FILESYSTEMHANDLE == 0xffff8019 &&
223 SCTAG_DOM_FILESYSTEMFILEHANDLE == 0xffff801a &&
224 SCTAG_DOM_FILESYSTEMDIRECTORYHANDLE == 0xffff801b,
225 "Something has changed the sctag values. This is wrong!");
228 } // anonymous namespace
230 const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = {
231 StructuredCloneCallbacksRead,
232 StructuredCloneCallbacksWrite,
233 StructuredCloneCallbacksError,
234 StructuredCloneCallbacksReadTransfer,
235 StructuredCloneCallbacksWriteTransfer,
236 StructuredCloneCallbacksFreeTransfer,
237 StructuredCloneCallbacksCanTransfer,
238 StructuredCloneCallbacksSharedArrayBuffer,
241 // StructuredCloneHolderBase class
243 StructuredCloneHolderBase::StructuredCloneHolderBase(
244 StructuredCloneScope aScope)
245 : mStructuredCloneScope(aScope)
246 #ifdef DEBUG
248 mClearCalled(false)
249 #endif
253 StructuredCloneHolderBase::~StructuredCloneHolderBase() {
254 #ifdef DEBUG
255 MOZ_ASSERT(mClearCalled);
256 #endif
259 void StructuredCloneHolderBase::Clear() {
260 #ifdef DEBUG
261 mClearCalled = true;
262 #endif
264 mBuffer = nullptr;
267 bool StructuredCloneHolderBase::Write(JSContext* aCx,
268 JS::Handle<JS::Value> aValue) {
269 return Write(aCx, aValue, JS::UndefinedHandleValue, JS::CloneDataPolicy());
272 bool StructuredCloneHolderBase::Write(
273 JSContext* aCx, JS::Handle<JS::Value> aValue,
274 JS::Handle<JS::Value> aTransfer,
275 const JS::CloneDataPolicy& aCloneDataPolicy) {
276 MOZ_ASSERT(!mBuffer, "Double Write is not allowed");
277 MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
279 mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(
280 mStructuredCloneScope, &StructuredCloneHolder::sCallbacks, this);
282 if (!mBuffer->write(aCx, aValue, aTransfer, aCloneDataPolicy,
283 &StructuredCloneHolder::sCallbacks, this)) {
284 mBuffer = nullptr;
285 return false;
288 // Let's update our scope to the final one. The new one could be more
289 // restrictive of the current one.
290 MOZ_ASSERT(mStructuredCloneScope >= mBuffer->scope());
291 mStructuredCloneScope = mBuffer->scope();
292 return true;
295 bool StructuredCloneHolderBase::Read(JSContext* aCx,
296 JS::MutableHandle<JS::Value> aValue) {
297 return Read(aCx, aValue, JS::CloneDataPolicy());
300 bool StructuredCloneHolderBase::Read(
301 JSContext* aCx, JS::MutableHandle<JS::Value> aValue,
302 const JS::CloneDataPolicy& aCloneDataPolicy) {
303 MOZ_ASSERT(mBuffer, "Read() without Write() is not allowed.");
304 MOZ_ASSERT(!mClearCalled, "This method cannot be called after Clear.");
306 bool ok = mBuffer->read(aCx, aValue, aCloneDataPolicy,
307 &StructuredCloneHolder::sCallbacks, this);
308 return ok;
311 bool StructuredCloneHolderBase::CustomReadTransferHandler(
312 JSContext* aCx, JSStructuredCloneReader* aReader,
313 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, void* aContent,
314 uint64_t aExtraData, JS::MutableHandle<JSObject*> aReturnObject) {
315 MOZ_CRASH("Nothing to read.");
316 return false;
319 bool StructuredCloneHolderBase::CustomWriteTransferHandler(
320 JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag,
321 JS::TransferableOwnership* aOwnership, void** aContent,
322 uint64_t* aExtraData) {
323 // No transfers are supported by default.
324 return false;
327 void StructuredCloneHolderBase::CustomFreeTransferHandler(
328 uint32_t aTag, JS::TransferableOwnership aOwnership, void* aContent,
329 uint64_t aExtraData) {
330 MOZ_CRASH("Nothing to free.");
333 bool StructuredCloneHolderBase::CustomCanTransferHandler(
334 JSContext* aCx, JS::Handle<JSObject*> aObj,
335 bool* aSameProcessScopeRequired) {
336 return false;
339 // StructuredCloneHolder class
341 StructuredCloneHolder::StructuredCloneHolder(
342 CloningSupport aSupportsCloning, TransferringSupport aSupportsTransferring,
343 StructuredCloneScope aScope)
344 : StructuredCloneHolderBase(aScope),
345 mSupportsCloning(aSupportsCloning == CloningSupported),
346 mSupportsTransferring(aSupportsTransferring == TransferringSupported),
347 mGlobal(nullptr)
348 #ifdef DEBUG
350 mCreationEventTarget(GetCurrentSerialEventTarget())
351 #endif
355 StructuredCloneHolder::~StructuredCloneHolder() {
356 Clear();
357 MOZ_ASSERT(mTransferredPorts.IsEmpty());
360 void StructuredCloneHolder::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
361 ErrorResult& aRv) {
362 Write(aCx, aValue, JS::UndefinedHandleValue, JS::CloneDataPolicy(), aRv);
365 void StructuredCloneHolder::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
366 JS::Handle<JS::Value> aTransfer,
367 const JS::CloneDataPolicy& aCloneDataPolicy,
368 ErrorResult& aRv) {
369 if (!StructuredCloneHolderBase::Write(aCx, aValue, aTransfer,
370 aCloneDataPolicy)) {
371 aRv.ThrowDataCloneError(mErrorMessage);
372 return;
376 void StructuredCloneHolder::Read(nsIGlobalObject* aGlobal, JSContext* aCx,
377 JS::MutableHandle<JS::Value> aValue,
378 ErrorResult& aRv) {
379 return Read(aGlobal, aCx, aValue, JS::CloneDataPolicy(), aRv);
382 void StructuredCloneHolder::Read(nsIGlobalObject* aGlobal, JSContext* aCx,
383 JS::MutableHandle<JS::Value> aValue,
384 const JS::CloneDataPolicy& aCloneDataPolicy,
385 ErrorResult& aRv) {
386 MOZ_ASSERT(aGlobal);
388 mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
389 auto errorMessageGuard = MakeScopeExit([&] { mErrorMessage.Truncate(); });
390 mGlobal = aGlobal;
392 if (!StructuredCloneHolderBase::Read(aCx, aValue, aCloneDataPolicy)) {
393 JS_ClearPendingException(aCx);
394 aRv.ThrowDataCloneError(mErrorMessage);
395 return;
398 // If we are tranferring something, we cannot call 'Read()' more than once.
399 if (mSupportsTransferring) {
400 mBlobImplArray.Clear();
401 mWasmModuleArray.Clear();
402 mClonedSurfaces.Clear();
403 mInputStreamArray.Clear();
404 mVideoFrames.Clear();
405 mEncodedAudioChunks.Clear();
406 mEncodedVideoChunks.Clear();
407 Clear();
411 void StructuredCloneHolder::ReadFromBuffer(
412 nsIGlobalObject* aGlobal, JSContext* aCx, JSStructuredCloneData& aBuffer,
413 JS::MutableHandle<JS::Value> aValue,
414 const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv) {
415 ReadFromBuffer(aGlobal, aCx, aBuffer, JS_STRUCTURED_CLONE_VERSION, aValue,
416 aCloneDataPolicy, aRv);
419 void StructuredCloneHolder::ReadFromBuffer(
420 nsIGlobalObject* aGlobal, JSContext* aCx, JSStructuredCloneData& aBuffer,
421 uint32_t aAlgorithmVersion, JS::MutableHandle<JS::Value> aValue,
422 const JS::CloneDataPolicy& aCloneDataPolicy, ErrorResult& aRv) {
423 MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
425 mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
426 auto errorMessageGuard = MakeScopeExit([&] { mErrorMessage.Truncate(); });
427 mGlobal = aGlobal;
429 if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, CloneScope(),
430 aValue, aCloneDataPolicy, &sCallbacks, this)) {
431 JS_ClearPendingException(aCx);
432 aRv.ThrowDataCloneError(mErrorMessage);
433 return;
437 static bool CheckExposedGlobals(JSContext* aCx, nsIGlobalObject* aGlobal,
438 uint16_t aExposedGlobals) {
439 JS::Rooted<JSObject*> global(aCx, aGlobal->GetGlobalJSObject());
441 // Sandboxes aren't really DOM globals (though they do set the
442 // JSCLASS_DOM_GLOBAL flag), and so we can't simply do the exposure check.
443 // Some sandboxes do have a DOM global as their prototype, so using the
444 // prototype to check for exposure will at least make it work for those
445 // specific cases.
447 JSObject* proto = xpc::SandboxPrototypeOrNull(aCx, global);
448 if (proto) {
449 global = proto;
453 if (!IsGlobalInExposureSet(aCx, global, aExposedGlobals)) {
454 ErrorResult error;
455 error.ThrowDataCloneError("Interface is not exposed.");
456 MOZ_ALWAYS_TRUE(error.MaybeSetPendingException(aCx));
457 return false;
459 return true;
462 /* static */
463 JSObject* StructuredCloneHolder::ReadFullySerializableObjects(
464 JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
465 bool aIsForIndexedDB) {
466 AssertTagValues();
468 nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
469 if (!global) {
470 return nullptr;
473 Maybe<std::pair<uint16_t, WebIDLDeserializer>> deserializer =
474 LookupDeserializer(StructuredCloneTags(aTag));
475 if (deserializer.isSome()) {
476 uint16_t exposedGlobals;
477 WebIDLDeserializer deserialize;
478 std::tie(exposedGlobals, deserialize) = deserializer.ref();
480 // https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize
482 // 22. Otherwise:
484 // 1. Let interfaceName be serialized.[[Type]].
485 // 2. If the interface identified by interfaceName is not exposed in
486 // targetRealm, then throw a "DataCloneError" DOMException.
488 // The special-casing for IndexedDB is because it uses a sandbox to
489 // deserialize, which means we don't actually have access to exposure
490 // information.
491 if (!aIsForIndexedDB && !CheckExposedGlobals(aCx, global, exposedGlobals)) {
492 return nullptr;
495 return deserialize(aCx, global, aReader);
498 if (aTag == SCTAG_DOM_NULL_PRINCIPAL || aTag == SCTAG_DOM_SYSTEM_PRINCIPAL ||
499 aTag == SCTAG_DOM_CONTENT_PRINCIPAL ||
500 aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) {
501 JSPrincipals* prin;
502 if (!nsJSPrincipals::ReadKnownPrincipalType(aCx, aReader, aTag, &prin)) {
503 return nullptr;
506 JS::Rooted<JS::Value> result(aCx);
508 // nsJSPrincipals::ReadKnownPrincipalType addrefs for us, but because of
509 // the casting between JSPrincipals* and nsIPrincipal* we can't use
510 // getter_AddRefs above and have to already_AddRefed here.
511 nsCOMPtr<nsIPrincipal> principal =
512 already_AddRefed<nsIPrincipal>(nsJSPrincipals::get(prin));
514 nsresult rv = nsContentUtils::WrapNative(
515 aCx, principal, &NS_GET_IID(nsIPrincipal), &result);
516 if (NS_FAILED(rv)) {
517 xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
518 return nullptr;
521 return result.toObjectOrNull();
524 // Don't know what this is. Bail.
525 xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
526 return nullptr;
529 /* static */
530 bool StructuredCloneHolder::WriteFullySerializableObjects(
531 JSContext* aCx, JSStructuredCloneWriter* aWriter,
532 JS::Handle<JSObject*> aObj) {
533 AssertTagValues();
535 // Window and Location are not serializable, so it's OK to just do a static
536 // unwrap here.
537 JS::Rooted<JSObject*> obj(aCx, js::CheckedUnwrapStatic(aObj));
538 if (!obj) {
539 return xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
542 const DOMJSClass* domClass = GetDOMClass(obj);
543 if (domClass && domClass->mSerializer) {
544 return domClass->mSerializer(aCx, aWriter, obj);
547 if (NS_IsMainThread() && xpc::IsReflector(obj, aCx)) {
548 // We only care about principals, so ReflectorToISupportsStatic is fine.
549 nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(obj);
550 nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
551 if (principal) {
552 auto nsjsprincipals = nsJSPrincipals::get(principal);
553 return nsjsprincipals->write(aCx, aWriter);
557 // Don't know what this is
558 ErrorResult rv;
559 const char* className = JS::GetClass(obj)->name;
560 rv.ThrowDataCloneError(nsDependentCString(className) +
561 " object could not be cloned."_ns);
562 MOZ_ALWAYS_TRUE(rv.MaybeSetPendingException(aCx));
563 return false;
566 template <typename char_type>
567 static bool ReadTString(JSStructuredCloneReader* aReader,
568 nsTString<char_type>& aString) {
569 uint32_t length, zero;
570 if (!JS_ReadUint32Pair(aReader, &length, &zero)) {
571 return false;
574 if (NS_WARN_IF(!aString.SetLength(length, fallible))) {
575 return false;
577 size_t charSize = sizeof(char_type);
578 return JS_ReadBytes(aReader, (void*)aString.BeginWriting(),
579 length * charSize);
582 template <typename char_type>
583 static bool WriteTString(JSStructuredCloneWriter* aWriter,
584 const nsTSubstring<char_type>& aString) {
585 size_t charSize = sizeof(char_type);
586 return JS_WriteUint32Pair(aWriter, aString.Length(), 0) &&
587 JS_WriteBytes(aWriter, aString.BeginReading(),
588 aString.Length() * charSize);
591 /* static */
592 bool StructuredCloneHolder::ReadString(JSStructuredCloneReader* aReader,
593 nsString& aString) {
594 return ReadTString(aReader, aString);
597 /* static */
598 bool StructuredCloneHolder::WriteString(JSStructuredCloneWriter* aWriter,
599 const nsAString& aString) {
600 return WriteTString(aWriter, aString);
603 /* static */
604 bool StructuredCloneHolder::ReadCString(JSStructuredCloneReader* aReader,
605 nsCString& aString) {
606 return ReadTString(aReader, aString);
609 /* static */
610 bool StructuredCloneHolder::WriteCString(JSStructuredCloneWriter* aWriter,
611 const nsACString& aString) {
612 return WriteTString(aWriter, aString);
615 namespace {
617 JSObject* ReadBlob(JSContext* aCx, uint32_t aIndex,
618 StructuredCloneHolder* aHolder) {
619 MOZ_ASSERT(aHolder);
620 #ifdef FUZZING
621 if (aIndex >= aHolder->BlobImpls().Length()) {
622 return nullptr;
624 #endif
625 MOZ_ASSERT(aIndex < aHolder->BlobImpls().Length());
626 JS::Rooted<JS::Value> val(aCx);
628 // RefPtr<File> and RefPtr<BlobImpl> need to go out of scope before
629 // toObject() is called because the static analysis thinks releasing XPCOM
630 // objects can GC (because in some cases it can!), and a return statement
631 // with a JSObject* type means that JSObject* is on the stack as a raw
632 // pointer while destructors are running.
633 RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[aIndex];
635 RefPtr<Blob> blob = Blob::Create(aHolder->GlobalDuringRead(), blobImpl);
636 if (NS_WARN_IF(!blob)) {
637 return nullptr;
640 if (!ToJSValue(aCx, blob, &val)) {
641 return nullptr;
645 return &val.toObject();
648 bool WriteBlob(JSStructuredCloneWriter* aWriter, Blob* aBlob,
649 StructuredCloneHolder* aHolder) {
650 MOZ_ASSERT(aWriter);
651 MOZ_ASSERT(aBlob);
652 MOZ_ASSERT(aHolder);
654 RefPtr<BlobImpl> blobImpl = aBlob->Impl();
656 // We store the position of the blobImpl in the array as index.
657 if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
658 aHolder->BlobImpls().Length())) {
659 aHolder->BlobImpls().AppendElement(blobImpl);
660 return true;
663 return false;
666 // A directory is serialized as:
667 // - pair of ints: SCTAG_DOM_DIRECTORY, path length
668 // - path as string
669 bool WriteDirectory(JSStructuredCloneWriter* aWriter, Directory* aDirectory) {
670 MOZ_ASSERT(aWriter);
671 MOZ_ASSERT(aDirectory);
673 nsAutoString path;
674 aDirectory->GetFullRealPath(path);
676 size_t charSize = sizeof(nsString::char_type);
677 return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, path.Length()) &&
678 JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
681 already_AddRefed<Directory> ReadDirectoryInternal(
682 JSStructuredCloneReader* aReader, uint32_t aPathLength,
683 StructuredCloneHolder* aHolder) {
684 MOZ_ASSERT(aReader);
685 MOZ_ASSERT(aHolder);
687 nsAutoString path;
688 if (NS_WARN_IF(!path.SetLength(aPathLength, fallible))) {
689 return nullptr;
691 size_t charSize = sizeof(nsString::char_type);
692 if (!JS_ReadBytes(aReader, (void*)path.BeginWriting(),
693 aPathLength * charSize)) {
694 return nullptr;
697 nsCOMPtr<nsIFile> file;
698 nsresult rv = NS_NewLocalFile(path, true, getter_AddRefs(file));
699 if (NS_WARN_IF(NS_FAILED(rv))) {
700 return nullptr;
703 RefPtr<Directory> directory =
704 Directory::Create(aHolder->GlobalDuringRead(), file);
705 return directory.forget();
708 JSObject* ReadDirectory(JSContext* aCx, JSStructuredCloneReader* aReader,
709 uint32_t aPathLength, StructuredCloneHolder* aHolder) {
710 MOZ_ASSERT(aCx);
711 MOZ_ASSERT(aReader);
712 MOZ_ASSERT(aHolder);
714 // RefPtr<Directory> needs to go out of scope before toObject() is
715 // called because the static analysis thinks dereferencing XPCOM objects
716 // can GC (because in some cases it can!), and a return statement with a
717 // JSObject* type means that JSObject* is on the stack as a raw pointer
718 // while destructors are running.
719 JS::Rooted<JS::Value> val(aCx);
721 RefPtr<Directory> directory =
722 ReadDirectoryInternal(aReader, aPathLength, aHolder);
723 if (!directory) {
724 return nullptr;
727 if (!ToJSValue(aCx, directory, &val)) {
728 return nullptr;
732 return &val.toObject();
735 // Read the WriteFileList for the format.
736 JSObject* ReadFileList(JSContext* aCx, JSStructuredCloneReader* aReader,
737 uint32_t aCount, StructuredCloneHolder* aHolder) {
738 MOZ_ASSERT(aCx);
739 MOZ_ASSERT(aReader);
741 JS::Rooted<JS::Value> val(aCx);
743 RefPtr<FileList> fileList = new FileList(aHolder->GlobalDuringRead());
745 uint32_t zero, index;
746 // |index| is the index of the first blobImpl.
747 if (!JS_ReadUint32Pair(aReader, &zero, &index) || zero != 0) {
748 return nullptr;
751 // |aCount| is the number of BlobImpls to use from the |index|.
752 for (uint32_t i = 0; i < aCount; ++i) {
753 uint32_t pos = index + i;
754 #ifdef FUZZING
755 if (pos >= aHolder->BlobImpls().Length()) {
756 return nullptr;
758 #endif
759 MOZ_ASSERT(pos < aHolder->BlobImpls().Length());
761 RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[pos];
762 MOZ_ASSERT(blobImpl->IsFile());
764 RefPtr<File> file = File::Create(aHolder->GlobalDuringRead(), blobImpl);
765 if (NS_WARN_IF(!file)) {
766 return nullptr;
769 if (!fileList->Append(file)) {
770 return nullptr;
774 if (!ToJSValue(aCx, fileList, &val)) {
775 return nullptr;
779 return &val.toObject();
782 // The format of the FileList serialization is:
783 // - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
784 // - pair of ints: 0, The offset of the BlobImpl array
785 bool WriteFileList(JSStructuredCloneWriter* aWriter, FileList* aFileList,
786 StructuredCloneHolder* aHolder) {
787 MOZ_ASSERT(aWriter);
788 MOZ_ASSERT(aFileList);
789 MOZ_ASSERT(aHolder);
791 // A FileList is serialized writing the X number of elements and the offset
792 // from mBlobImplArray. The Read will take X elements from mBlobImplArray
793 // starting from the offset.
794 if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, aFileList->Length()) ||
795 !JS_WriteUint32Pair(aWriter, 0, aHolder->BlobImpls().Length())) {
796 return false;
799 nsTArray<RefPtr<BlobImpl>> blobImpls;
801 for (uint32_t i = 0; i < aFileList->Length(); ++i) {
802 RefPtr<BlobImpl> blobImpl = aFileList->Item(i)->Impl();
803 blobImpls.AppendElement(blobImpl);
806 aHolder->BlobImpls().AppendElements(blobImpls);
807 return true;
810 // Read the WriteFormData for the format.
811 JSObject* ReadFormData(JSContext* aCx, JSStructuredCloneReader* aReader,
812 uint32_t aCount, StructuredCloneHolder* aHolder) {
813 MOZ_ASSERT(aCx);
814 MOZ_ASSERT(aReader);
815 MOZ_ASSERT(aHolder);
817 // See the serialization of the FormData for the format.
818 JS::Rooted<JS::Value> val(aCx);
820 RefPtr<FormData> formData = new FormData(aHolder->GlobalDuringRead());
822 Optional<nsAString> thirdArg;
823 for (uint32_t i = 0; i < aCount; ++i) {
824 nsAutoString name;
825 if (!StructuredCloneHolder::ReadString(aReader, name)) {
826 return nullptr;
829 uint32_t tag, indexOrLengthOfString;
830 if (!JS_ReadUint32Pair(aReader, &tag, &indexOrLengthOfString)) {
831 return nullptr;
834 if (tag == SCTAG_DOM_BLOB) {
835 #ifdef FUZZING
836 if (indexOrLengthOfString >= aHolder->BlobImpls().Length()) {
837 return nullptr;
839 #endif
840 MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
842 RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[indexOrLengthOfString];
844 RefPtr<Blob> blob = Blob::Create(aHolder->GlobalDuringRead(), blobImpl);
845 if (NS_WARN_IF(!blob)) {
846 return nullptr;
849 ErrorResult rv;
850 formData->Append(name, *blob, thirdArg, rv);
851 if (NS_WARN_IF(rv.Failed())) {
852 rv.SuppressException();
853 return nullptr;
856 } else if (tag == SCTAG_DOM_DIRECTORY) {
857 RefPtr<Directory> directory =
858 ReadDirectoryInternal(aReader, indexOrLengthOfString, aHolder);
859 if (!directory) {
860 return nullptr;
863 formData->Append(name, directory);
865 } else {
866 if (NS_WARN_IF(tag != 0)) {
867 return nullptr;
870 nsAutoString value;
871 if (NS_WARN_IF(!value.SetLength(indexOrLengthOfString, fallible))) {
872 return nullptr;
874 size_t charSize = sizeof(nsString::char_type);
875 if (!JS_ReadBytes(aReader, (void*)value.BeginWriting(),
876 indexOrLengthOfString * charSize)) {
877 return nullptr;
880 ErrorResult rv;
881 formData->Append(name, value, rv);
882 if (NS_WARN_IF(rv.Failed())) {
883 rv.SuppressException();
884 return nullptr;
889 if (!ToJSValue(aCx, formData, &val)) {
890 return nullptr;
894 return &val.toObject();
897 // The format of the FormData serialization is:
898 // - pair of ints: SCTAG_DOM_FORMDATA, Length of the FormData elements
899 // - for each Element element:
900 // - name string
901 // - if it's a blob:
902 // - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
903 // mBlobImplArray.
904 // - if it's a directory (See WriteDirectory):
905 // - pair of ints: SCTAG_DOM_DIRECTORY, path length
906 // - path as string
907 // - else:
908 // - pair of ints: 0, string length
909 // - value string
910 bool WriteFormData(JSStructuredCloneWriter* aWriter, FormData* aFormData,
911 StructuredCloneHolder* aHolder) {
912 MOZ_ASSERT(aWriter);
913 MOZ_ASSERT(aFormData);
914 MOZ_ASSERT(aHolder);
916 if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FORMDATA, aFormData->Length())) {
917 return false;
920 auto write = [aWriter, aHolder](
921 const nsString& aName,
922 const OwningBlobOrDirectoryOrUSVString& aValue) {
923 if (!StructuredCloneHolder::WriteString(aWriter, aName)) {
924 return false;
927 if (aValue.IsBlob()) {
928 if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
929 aHolder->BlobImpls().Length())) {
930 return false;
933 RefPtr<BlobImpl> blobImpl = aValue.GetAsBlob()->Impl();
935 aHolder->BlobImpls().AppendElement(blobImpl);
936 return true;
939 if (aValue.IsDirectory()) {
940 Directory* directory = aValue.GetAsDirectory();
941 return WriteDirectory(aWriter, directory);
944 const size_t charSize = sizeof(nsString::char_type);
945 return JS_WriteUint32Pair(aWriter, 0, aValue.GetAsUSVString().Length()) &&
946 JS_WriteBytes(aWriter, aValue.GetAsUSVString().get(),
947 aValue.GetAsUSVString().Length() * charSize);
949 return aFormData->ForEach(write);
952 JSObject* ReadWasmModule(JSContext* aCx, uint32_t aIndex,
953 StructuredCloneHolder* aHolder) {
954 MOZ_ASSERT(aHolder);
955 MOZ_ASSERT(aHolder->CloneScope() ==
956 StructuredCloneHolder::StructuredCloneScope::SameProcess);
957 #ifdef FUZZING
958 if (aIndex >= aHolder->WasmModules().Length()) {
959 return nullptr;
961 #endif
962 MOZ_ASSERT(aIndex < aHolder->WasmModules().Length());
964 return aHolder->WasmModules()[aIndex]->createObject(aCx);
967 bool WriteWasmModule(JSStructuredCloneWriter* aWriter,
968 JS::WasmModule* aWasmModule,
969 StructuredCloneHolder* aHolder) {
970 MOZ_ASSERT(aWriter);
971 MOZ_ASSERT(aWasmModule);
972 MOZ_ASSERT(aHolder);
973 MOZ_ASSERT(aHolder->CloneScope() ==
974 StructuredCloneHolder::StructuredCloneScope::SameProcess);
976 // We store the position of the wasmModule in the array as index.
977 if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM_MODULE,
978 aHolder->WasmModules().Length())) {
979 aHolder->WasmModules().AppendElement(aWasmModule);
980 return true;
983 return false;
986 JSObject* ReadInputStream(JSContext* aCx, uint32_t aIndex,
987 StructuredCloneHolder* aHolder) {
988 MOZ_ASSERT(aHolder);
989 #ifdef FUZZING
990 if (aIndex >= aHolder->InputStreams().Length()) {
991 return nullptr;
993 #endif
994 MOZ_ASSERT(aIndex < aHolder->InputStreams().Length());
995 JS::Rooted<JS::Value> result(aCx);
997 nsCOMPtr<nsIInputStream> inputStream = aHolder->InputStreams()[aIndex];
999 nsresult rv = nsContentUtils::WrapNative(
1000 aCx, inputStream, &NS_GET_IID(nsIInputStream), &result);
1001 if (NS_FAILED(rv)) {
1002 return nullptr;
1006 return &result.toObject();
1009 bool WriteInputStream(JSStructuredCloneWriter* aWriter,
1010 nsIInputStream* aInputStream,
1011 StructuredCloneHolder* aHolder) {
1012 MOZ_ASSERT(aWriter);
1013 MOZ_ASSERT(aInputStream);
1014 MOZ_ASSERT(aHolder);
1016 // We store the position of the inputStream in the array as index.
1017 if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_INPUTSTREAM,
1018 aHolder->InputStreams().Length())) {
1019 aHolder->InputStreams().AppendElement(aInputStream);
1020 return true;
1023 return false;
1026 } // anonymous namespace
1028 static const uint16_t sWindowOrWorker =
1029 GlobalNames::DedicatedWorkerGlobalScope |
1030 GlobalNames::ServiceWorkerGlobalScope |
1031 GlobalNames::SharedWorkerGlobalScope | GlobalNames::Window |
1032 GlobalNames::WorkerDebuggerGlobalScope;
1034 JSObject* StructuredCloneHolder::CustomReadHandler(
1035 JSContext* aCx, JSStructuredCloneReader* aReader,
1036 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag,
1037 uint32_t aIndex) {
1038 MOZ_ASSERT(mSupportsCloning);
1040 if (aTag == SCTAG_DOM_BLOB) {
1041 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1042 return nullptr;
1044 return ReadBlob(aCx, aIndex, this);
1047 if (aTag == SCTAG_DOM_DIRECTORY) {
1048 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1049 return nullptr;
1051 return ReadDirectory(aCx, aReader, aIndex, this);
1054 if (aTag == SCTAG_DOM_FILELIST) {
1055 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1056 return nullptr;
1058 return ReadFileList(aCx, aReader, aIndex, this);
1061 if (aTag == SCTAG_DOM_FORMDATA) {
1062 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1063 return nullptr;
1065 return ReadFormData(aCx, aReader, aIndex, this);
1068 if (aTag == SCTAG_DOM_IMAGEBITMAP &&
1069 CloneScope() == StructuredCloneScope::SameProcess) {
1070 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1071 return nullptr;
1073 // Get the current global object.
1074 // This can be null.
1075 JS::Rooted<JSObject*> result(aCx);
1077 // aIndex is the index of the cloned image.
1078 result = ImageBitmap::ReadStructuredClone(aCx, aReader, mGlobal,
1079 GetSurfaces(), aIndex);
1081 return result;
1084 if (aTag == SCTAG_DOM_STRUCTURED_CLONE_HOLDER) {
1085 return StructuredCloneBlob::ReadStructuredClone(aCx, aReader, this);
1088 if (aTag == SCTAG_DOM_WASM_MODULE &&
1089 CloneScope() == StructuredCloneScope::SameProcess &&
1090 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1091 return ReadWasmModule(aCx, aIndex, this);
1094 if (aTag == SCTAG_DOM_INPUTSTREAM) {
1095 return ReadInputStream(aCx, aIndex, this);
1098 if (aTag == SCTAG_DOM_BROWSING_CONTEXT) {
1099 if (!CheckExposedGlobals(aCx, mGlobal, GlobalNames::Window)) {
1100 return nullptr;
1102 return BrowsingContext::ReadStructuredClone(aCx, aReader, this);
1105 if (aTag == SCTAG_DOM_CLONED_ERROR_OBJECT) {
1106 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1107 return nullptr;
1109 return ClonedErrorHolder::ReadStructuredClone(aCx, aReader, this);
1112 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1113 aTag == SCTAG_DOM_VIDEOFRAME &&
1114 CloneScope() == StructuredCloneScope::SameProcess &&
1115 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1116 JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
1117 if (VideoFrame_Binding::ConstructorEnabled(aCx, global)) {
1118 return VideoFrame::ReadStructuredClone(aCx, mGlobal, aReader,
1119 VideoFrames()[aIndex]);
1123 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1124 aTag == SCTAG_DOM_ENCODEDVIDEOCHUNK &&
1125 CloneScope() == StructuredCloneScope::SameProcess &&
1126 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1127 JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
1128 if (EncodedVideoChunk_Binding::ConstructorEnabled(aCx, global)) {
1129 return EncodedVideoChunk::ReadStructuredClone(
1130 aCx, mGlobal, aReader, EncodedVideoChunks()[aIndex]);
1134 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1135 aTag == SCTAG_DOM_AUDIODATA &&
1136 CloneScope() == StructuredCloneScope::SameProcess &&
1137 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1138 JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
1139 if (AudioData_Binding::ConstructorEnabled(aCx, global)) {
1140 return AudioData::ReadStructuredClone(aCx, mGlobal, aReader,
1141 AudioData()[aIndex]);
1145 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1146 aTag == SCTAG_DOM_ENCODEDAUDIOCHUNK &&
1147 CloneScope() == StructuredCloneScope::SameProcess &&
1148 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1149 JS::Rooted<JSObject*> global(aCx, mGlobal->GetGlobalJSObject());
1150 if (EncodedAudioChunk_Binding::ConstructorEnabled(aCx, global)) {
1151 return EncodedAudioChunk::ReadStructuredClone(
1152 aCx, mGlobal, aReader, EncodedAudioChunks()[aIndex]);
1156 return ReadFullySerializableObjects(aCx, aReader, aTag, false);
1159 bool StructuredCloneHolder::CustomWriteHandler(
1160 JSContext* aCx, JSStructuredCloneWriter* aWriter,
1161 JS::Handle<JSObject*> aObj, bool* aSameProcessScopeRequired) {
1162 if (!mSupportsCloning) {
1163 return false;
1166 JS::Rooted<JSObject*> obj(aCx, aObj);
1168 // See if this is a File/Blob object.
1170 Blob* blob = nullptr;
1171 if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
1172 return WriteBlob(aWriter, blob, this);
1176 // See if this is a Directory object.
1178 Directory* directory = nullptr;
1179 if (NS_SUCCEEDED(UNWRAP_OBJECT(Directory, &obj, directory))) {
1180 return WriteDirectory(aWriter, directory);
1184 // See if this is a FileList object.
1186 FileList* fileList = nullptr;
1187 if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, &obj, fileList))) {
1188 return WriteFileList(aWriter, fileList, this);
1192 // See if this is a FormData object.
1194 FormData* formData = nullptr;
1195 if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, &obj, formData))) {
1196 return WriteFormData(aWriter, formData, this);
1200 // See if this is an ImageBitmap object.
1202 ImageBitmap* imageBitmap = nullptr;
1203 if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, &obj, imageBitmap))) {
1204 SameProcessScopeRequired(aSameProcessScopeRequired);
1206 if (CloneScope() == StructuredCloneScope::SameProcess) {
1207 ErrorResult rv;
1208 ImageBitmap::WriteStructuredClone(aWriter, GetSurfaces(), imageBitmap,
1209 rv);
1210 return !rv.MaybeSetPendingException(aCx);
1212 return false;
1216 // See if this is a StructuredCloneBlob object.
1218 StructuredCloneBlob* holder = nullptr;
1219 if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneHolder, &obj, holder))) {
1220 return holder->WriteStructuredClone(aCx, aWriter, this);
1224 // See if this is a BrowsingContext object.
1226 BrowsingContext* holder = nullptr;
1227 if (NS_SUCCEEDED(UNWRAP_OBJECT(BrowsingContext, &obj, holder))) {
1228 return holder->WriteStructuredClone(aCx, aWriter, this);
1232 // See if this is a ClonedErrorHolder object.
1234 ClonedErrorHolder* holder = nullptr;
1235 if (NS_SUCCEEDED(UNWRAP_OBJECT(ClonedErrorHolder, &obj, holder))) {
1236 return holder->WriteStructuredClone(aCx, aWriter, this);
1240 // See if this is a WasmModule.
1241 if (JS::IsWasmModuleObject(obj)) {
1242 SameProcessScopeRequired(aSameProcessScopeRequired);
1243 if (CloneScope() == StructuredCloneScope::SameProcess) {
1244 RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
1245 MOZ_ASSERT(module);
1247 return WriteWasmModule(aWriter, module, this);
1249 return false;
1252 // See if this is a VideoFrame object.
1253 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1254 VideoFrame* videoFrame = nullptr;
1255 if (NS_SUCCEEDED(UNWRAP_OBJECT(VideoFrame, &obj, videoFrame))) {
1256 SameProcessScopeRequired(aSameProcessScopeRequired);
1257 return CloneScope() == StructuredCloneScope::SameProcess
1258 ? videoFrame->WriteStructuredClone(aWriter, this)
1259 : false;
1263 // See if this is a EncodedVideoChunk object.
1264 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1265 EncodedVideoChunk* encodedVideoChunk = nullptr;
1266 if (NS_SUCCEEDED(
1267 UNWRAP_OBJECT(EncodedVideoChunk, &obj, encodedVideoChunk))) {
1268 SameProcessScopeRequired(aSameProcessScopeRequired);
1269 return CloneScope() == StructuredCloneScope::SameProcess
1270 ? encodedVideoChunk->WriteStructuredClone(aWriter, this)
1271 : false;
1275 // See if this is an AudioData object.
1276 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1277 mozilla::dom::AudioData* audioData = nullptr;
1278 if (NS_SUCCEEDED(UNWRAP_OBJECT(AudioData, &obj, audioData))) {
1279 SameProcessScopeRequired(aSameProcessScopeRequired);
1280 return CloneScope() == StructuredCloneScope::SameProcess
1281 ? audioData->WriteStructuredClone(aWriter, this)
1282 : false;
1286 // See if this is a EncodedAudioChunk object.
1287 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1288 EncodedAudioChunk* encodedAudioChunk = nullptr;
1289 if (NS_SUCCEEDED(
1290 UNWRAP_OBJECT(EncodedAudioChunk, &obj, encodedAudioChunk))) {
1291 SameProcessScopeRequired(aSameProcessScopeRequired);
1292 return CloneScope() == StructuredCloneScope::SameProcess
1293 ? encodedAudioChunk->WriteStructuredClone(aWriter, this)
1294 : false;
1299 // We only care about streams, so ReflectorToISupportsStatic is fine.
1300 nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(aObj);
1301 nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(base);
1302 if (inputStream) {
1303 return WriteInputStream(aWriter, inputStream, this);
1307 return WriteFullySerializableObjects(aCx, aWriter, aObj);
1310 already_AddRefed<MessagePort> StructuredCloneHolder::ReceiveMessagePort(
1311 uint64_t aIndex) {
1312 if (NS_WARN_IF(aIndex >= mPortIdentifiers.Length())) {
1313 return nullptr;
1315 UniqueMessagePortId portId(mPortIdentifiers[aIndex]);
1317 ErrorResult rv;
1318 RefPtr<MessagePort> port = MessagePort::Create(mGlobal, portId, rv);
1319 if (NS_WARN_IF(rv.Failed())) {
1320 rv.SuppressException();
1321 return nullptr;
1324 return port.forget();
1327 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
1328 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool
1329 StructuredCloneHolder::CustomReadTransferHandler(
1330 JSContext* aCx, JSStructuredCloneReader* aReader,
1331 const JS::CloneDataPolicy& aCloneDataPolicy, uint32_t aTag, void* aContent,
1332 uint64_t aExtraData, JS::MutableHandle<JSObject*> aReturnObject) {
1333 MOZ_ASSERT(mSupportsTransferring);
1335 if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
1336 if (!CheckExposedGlobals(
1337 aCx, mGlobal,
1338 sWindowOrWorker | GlobalNames::AudioWorkletGlobalScope)) {
1339 return false;
1341 #ifdef FUZZING
1342 if (aExtraData >= mPortIdentifiers.Length()) {
1343 return false;
1345 #endif
1346 RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
1347 if (!port) {
1348 return false;
1350 mTransferredPorts.AppendElement(port);
1352 JS::Rooted<JS::Value> value(aCx);
1353 if (!GetOrCreateDOMReflector(aCx, port, &value)) {
1354 JS_ClearPendingException(aCx);
1355 return false;
1358 aReturnObject.set(&value.toObject());
1359 return true;
1362 if (aTag == SCTAG_DOM_CANVAS &&
1363 CloneScope() == StructuredCloneScope::SameProcess) {
1364 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1365 return false;
1367 MOZ_ASSERT(aContent);
1368 OffscreenCanvasCloneData* data =
1369 static_cast<OffscreenCanvasCloneData*>(aContent);
1370 RefPtr<OffscreenCanvas> canvas =
1371 OffscreenCanvas::CreateFromCloneData(mGlobal, data);
1372 delete data;
1374 JS::Rooted<JS::Value> value(aCx);
1375 if (!GetOrCreateDOMReflector(aCx, canvas, &value)) {
1376 JS_ClearPendingException(aCx);
1377 return false;
1380 aReturnObject.set(&value.toObject());
1381 return true;
1384 if (aTag == SCTAG_DOM_IMAGEBITMAP &&
1385 CloneScope() == StructuredCloneScope::SameProcess) {
1386 if (!CheckExposedGlobals(aCx, mGlobal, sWindowOrWorker)) {
1387 return false;
1389 MOZ_ASSERT(aContent);
1390 ImageBitmapCloneData* data = static_cast<ImageBitmapCloneData*>(aContent);
1391 RefPtr<ImageBitmap> bitmap =
1392 ImageBitmap::CreateFromCloneData(mGlobal, data);
1393 delete data;
1395 JS::Rooted<JS::Value> value(aCx);
1396 if (!GetOrCreateDOMReflector(aCx, bitmap, &value)) {
1397 JS_ClearPendingException(aCx);
1398 return false;
1401 aReturnObject.set(&value.toObject());
1402 return true;
1405 if (aTag == SCTAG_DOM_READABLESTREAM) {
1406 #ifdef FUZZING
1407 if (aExtraData >= mPortIdentifiers.Length()) {
1408 return false;
1410 #endif
1411 RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
1412 if (!port) {
1413 return false;
1415 nsCOMPtr<nsIGlobalObject> global = mGlobal;
1416 return ReadableStream::ReceiveTransfer(aCx, global, *port, aReturnObject);
1419 if (aTag == SCTAG_DOM_WRITABLESTREAM) {
1420 #ifdef FUZZING
1421 if (aExtraData >= mPortIdentifiers.Length()) {
1422 return false;
1424 #endif
1425 RefPtr<MessagePort> port = ReceiveMessagePort(aExtraData);
1426 if (!port) {
1427 return false;
1429 nsCOMPtr<nsIGlobalObject> global = mGlobal;
1430 return WritableStream::ReceiveTransfer(aCx, global, *port, aReturnObject);
1433 if (aTag == SCTAG_DOM_TRANSFORMSTREAM) {
1434 #ifdef FUZZING
1435 if (aExtraData + 1 >= mPortIdentifiers.Length()) {
1436 return false;
1438 #endif
1439 RefPtr<MessagePort> port1 = ReceiveMessagePort(aExtraData);
1440 RefPtr<MessagePort> port2 = ReceiveMessagePort(aExtraData + 1);
1441 if (!port1 || !port2) {
1442 return false;
1444 nsCOMPtr<nsIGlobalObject> global = mGlobal;
1445 return TransformStream::ReceiveTransfer(aCx, global, *port1, *port2,
1446 aReturnObject);
1449 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1450 aTag == SCTAG_DOM_VIDEOFRAME &&
1451 CloneScope() == StructuredCloneScope::SameProcess &&
1452 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1453 MOZ_ASSERT(aContent);
1455 JS::Rooted<JSObject*> globalObj(aCx, mGlobal->GetGlobalJSObject());
1456 // aContent will be released in CustomFreeTransferHandler.
1457 if (!VideoFrame_Binding::ConstructorEnabled(aCx, globalObj)) {
1458 return false;
1461 VideoFrame::TransferredData* data =
1462 static_cast<VideoFrame::TransferredData*>(aContent);
1463 nsCOMPtr<nsIGlobalObject> global = mGlobal;
1464 RefPtr<VideoFrame> frame = VideoFrame::FromTransferred(global.get(), data);
1465 // aContent will be released in CustomFreeTransferHandler if frame is null.
1466 if (!frame) {
1467 return false;
1469 delete data;
1470 aContent = nullptr;
1472 JS::Rooted<JS::Value> value(aCx);
1473 if (!GetOrCreateDOMReflector(aCx, frame, &value)) {
1474 JS_ClearPendingException(aCx);
1475 return false;
1477 aReturnObject.set(&value.toObject());
1478 return true;
1481 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1482 aTag == SCTAG_DOM_AUDIODATA &&
1483 CloneScope() == StructuredCloneScope::SameProcess &&
1484 aCloneDataPolicy.areIntraClusterClonableSharedObjectsAllowed()) {
1485 MOZ_ASSERT(aContent);
1487 JS::Rooted<JSObject*> globalObj(aCx, mGlobal->GetGlobalJSObject());
1488 // aContent will be released in CustomFreeTransferHandler.
1489 if (!AudioData_Binding::ConstructorEnabled(aCx, globalObj)) {
1490 return false;
1493 AudioData::TransferredData* data =
1494 static_cast<AudioData::TransferredData*>(aContent);
1495 nsCOMPtr<nsIGlobalObject> global = mGlobal;
1496 RefPtr<mozilla::dom::AudioData> audioData =
1497 AudioData::FromTransferred(global.get(), data);
1498 // aContent will be released in CustomFreeTransferHandler if frame is null.
1499 if (!audioData) {
1500 return false;
1502 delete data;
1503 aContent = nullptr;
1505 JS::Rooted<JS::Value> value(aCx);
1506 if (!GetOrCreateDOMReflector(aCx, audioData, &value)) {
1507 JS_ClearPendingException(aCx);
1508 return false;
1510 aReturnObject.set(&value.toObject());
1511 return true;
1514 return false;
1517 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
1518 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool
1519 StructuredCloneHolder::CustomWriteTransferHandler(
1520 JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag,
1521 JS::TransferableOwnership* aOwnership, void** aContent,
1522 uint64_t* aExtraData) {
1523 if (!mSupportsTransferring) {
1524 return false;
1527 JS::Rooted<JSObject*> obj(aCx, aObj);
1530 MessagePort* port = nullptr;
1531 nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
1532 if (NS_SUCCEEDED(rv)) {
1533 if (!port->CanBeCloned()) {
1534 return false;
1537 UniqueMessagePortId identifier;
1538 port->CloneAndDisentangle(identifier);
1540 // We use aExtraData to store the index of this new port identifier.
1541 *aExtraData = mPortIdentifiers.Length();
1542 mPortIdentifiers.AppendElement(identifier.release());
1544 *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
1545 *aContent = nullptr;
1546 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1548 return true;
1551 if (CloneScope() == StructuredCloneScope::SameProcess) {
1552 OffscreenCanvas* canvas = nullptr;
1553 rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
1554 if (NS_SUCCEEDED(rv)) {
1555 MOZ_ASSERT(canvas);
1557 UniquePtr<OffscreenCanvasCloneData> clonedCanvas =
1558 canvas->ToCloneData(aCx);
1559 if (!clonedCanvas) {
1560 return false;
1563 *aExtraData = 0;
1564 *aTag = SCTAG_DOM_CANVAS;
1565 *aContent = clonedCanvas.release();
1566 MOZ_ASSERT(*aContent);
1567 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1569 return true;
1572 ImageBitmap* bitmap = nullptr;
1573 rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
1574 if (NS_SUCCEEDED(rv)) {
1575 MOZ_ASSERT(bitmap);
1576 MOZ_ASSERT(!bitmap->IsWriteOnly());
1578 *aExtraData = 0;
1579 *aTag = SCTAG_DOM_IMAGEBITMAP;
1581 UniquePtr<ImageBitmapCloneData> clonedBitmap = bitmap->ToCloneData();
1582 if (!clonedBitmap) {
1583 return false;
1586 *aContent = clonedBitmap.release();
1587 MOZ_ASSERT(*aContent);
1588 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1590 bitmap->Close();
1592 return true;
1595 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1596 VideoFrame* videoFrame = nullptr;
1597 rv = UNWRAP_OBJECT(VideoFrame, &obj, videoFrame);
1598 if (NS_SUCCEEDED(rv)) {
1599 MOZ_ASSERT(videoFrame);
1601 *aExtraData = 0;
1602 *aTag = SCTAG_DOM_VIDEOFRAME;
1603 *aContent = nullptr;
1605 UniquePtr<VideoFrame::TransferredData> data = videoFrame->Transfer();
1606 if (!data) {
1607 return false;
1609 *aContent = data.release();
1610 MOZ_ASSERT(*aContent);
1611 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1612 return true;
1615 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1616 mozilla::dom::AudioData* audioData = nullptr;
1617 rv = UNWRAP_OBJECT(AudioData, &obj, audioData);
1618 if (NS_SUCCEEDED(rv)) {
1619 MOZ_ASSERT(audioData);
1621 *aExtraData = 0;
1622 *aTag = SCTAG_DOM_AUDIODATA;
1623 *aContent = nullptr;
1625 UniquePtr<AudioData::TransferredData> data = audioData->Transfer();
1626 if (!data) {
1627 return false;
1629 *aContent = data.release();
1630 MOZ_ASSERT(*aContent);
1631 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1632 return true;
1638 RefPtr<ReadableStream> stream;
1639 rv = UNWRAP_OBJECT(ReadableStream, &obj, stream);
1640 if (NS_SUCCEEDED(rv)) {
1641 MOZ_ASSERT(stream);
1643 *aTag = SCTAG_DOM_READABLESTREAM;
1644 *aContent = nullptr;
1646 UniqueMessagePortId id;
1647 if (!stream->Transfer(aCx, id)) {
1648 return false;
1650 *aExtraData = mPortIdentifiers.Length();
1651 mPortIdentifiers.AppendElement(id.release());
1652 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1653 return true;
1658 RefPtr<WritableStream> stream;
1659 rv = UNWRAP_OBJECT(WritableStream, &obj, stream);
1660 if (NS_SUCCEEDED(rv)) {
1661 MOZ_ASSERT(stream);
1663 *aTag = SCTAG_DOM_WRITABLESTREAM;
1664 *aContent = nullptr;
1666 UniqueMessagePortId id;
1667 if (!stream->Transfer(aCx, id)) {
1668 return false;
1670 *aExtraData = mPortIdentifiers.Length();
1671 mPortIdentifiers.AppendElement(id.release());
1672 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1673 return true;
1678 RefPtr<TransformStream> stream;
1679 rv = UNWRAP_OBJECT(TransformStream, &obj, stream);
1680 if (NS_SUCCEEDED(rv)) {
1681 MOZ_ASSERT(stream);
1683 *aTag = SCTAG_DOM_TRANSFORMSTREAM;
1684 *aContent = nullptr;
1686 UniqueMessagePortId id1;
1687 UniqueMessagePortId id2;
1688 if (!stream->Transfer(aCx, id1, id2)) {
1689 return false;
1691 *aExtraData = mPortIdentifiers.Length();
1692 mPortIdentifiers.AppendElement(id1.release());
1693 mPortIdentifiers.AppendElement(id2.release());
1694 *aOwnership = JS::SCTAG_TMO_CUSTOM;
1695 return true;
1700 return false;
1703 void StructuredCloneHolder::CustomFreeTransferHandler(
1704 uint32_t aTag, JS::TransferableOwnership aOwnership, void* aContent,
1705 uint64_t aExtraData) {
1706 MOZ_ASSERT(mSupportsTransferring);
1708 if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
1709 MOZ_ASSERT(!aContent);
1710 #ifdef FUZZING
1711 if (aExtraData >= mPortIdentifiers.Length()) {
1712 return;
1714 #endif
1715 MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
1716 MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
1717 return;
1720 if (aTag == SCTAG_DOM_CANVAS &&
1721 CloneScope() == StructuredCloneScope::SameProcess) {
1722 MOZ_ASSERT(aContent);
1723 OffscreenCanvasCloneData* data =
1724 static_cast<OffscreenCanvasCloneData*>(aContent);
1725 delete data;
1726 return;
1729 if (aTag == SCTAG_DOM_IMAGEBITMAP &&
1730 CloneScope() == StructuredCloneScope::SameProcess) {
1731 MOZ_ASSERT(aContent);
1732 ImageBitmapCloneData* data = static_cast<ImageBitmapCloneData*>(aContent);
1733 delete data;
1734 return;
1737 if (aTag == SCTAG_DOM_READABLESTREAM || aTag == SCTAG_DOM_WRITABLESTREAM) {
1738 MOZ_ASSERT(!aContent);
1739 #ifdef FUZZING
1740 if (aExtraData >= mPortIdentifiers.Length()) {
1741 return;
1743 #endif
1744 MOZ_ASSERT(aExtraData < mPortIdentifiers.Length());
1745 MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
1746 return;
1749 if (aTag == SCTAG_DOM_TRANSFORMSTREAM) {
1750 MOZ_ASSERT(!aContent);
1751 #ifdef FUZZING
1752 if (aExtraData + 1 >= mPortIdentifiers.Length()) {
1753 return;
1755 #endif
1756 MOZ_ASSERT(aExtraData + 1 < mPortIdentifiers.Length());
1757 MessagePort::ForceClose(mPortIdentifiers[aExtraData]);
1758 MessagePort::ForceClose(mPortIdentifiers[aExtraData + 1]);
1759 return;
1762 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1763 aTag == SCTAG_DOM_VIDEOFRAME &&
1764 CloneScope() == StructuredCloneScope::SameProcess) {
1765 if (aContent) {
1766 VideoFrame::TransferredData* data =
1767 static_cast<VideoFrame::TransferredData*>(aContent);
1768 delete data;
1770 return;
1772 if (StaticPrefs::dom_media_webcodecs_enabled() &&
1773 aTag == SCTAG_DOM_AUDIODATA &&
1774 CloneScope() == StructuredCloneScope::SameProcess) {
1775 if (aContent) {
1776 AudioData::TransferredData* data =
1777 static_cast<AudioData::TransferredData*>(aContent);
1778 delete data;
1780 return;
1784 bool StructuredCloneHolder::CustomCanTransferHandler(
1785 JSContext* aCx, JS::Handle<JSObject*> aObj,
1786 bool* aSameProcessScopeRequired) {
1787 if (!mSupportsTransferring) {
1788 return false;
1791 JS::Rooted<JSObject*> obj(aCx, aObj);
1794 MessagePort* port = nullptr;
1795 nsresult rv = UNWRAP_OBJECT(MessagePort, &obj, port);
1796 if (NS_SUCCEEDED(rv)) {
1797 return true;
1802 OffscreenCanvas* canvas = nullptr;
1803 nsresult rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas);
1804 if (NS_SUCCEEDED(rv)) {
1805 SameProcessScopeRequired(aSameProcessScopeRequired);
1806 return CloneScope() == StructuredCloneScope::SameProcess;
1811 ImageBitmap* bitmap = nullptr;
1812 nsresult rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap);
1813 if (NS_SUCCEEDED(rv)) {
1814 if (bitmap->IsWriteOnly()) {
1815 return false;
1818 SameProcessScopeRequired(aSameProcessScopeRequired);
1819 return CloneScope() == StructuredCloneScope::SameProcess;
1824 ReadableStream* stream = nullptr;
1825 nsresult rv = UNWRAP_OBJECT(ReadableStream, &obj, stream);
1826 if (NS_SUCCEEDED(rv)) {
1827 // https://streams.spec.whatwg.org/#ref-for-transfer-steps
1828 // Step 1: If ! IsReadableStreamLocked(value) is true, throw a
1829 // "DataCloneError" DOMException.
1830 return !stream->Locked();
1835 WritableStream* stream = nullptr;
1836 nsresult rv = UNWRAP_OBJECT(WritableStream, &obj, stream);
1837 if (NS_SUCCEEDED(rv)) {
1838 // https://streams.spec.whatwg.org/#ref-for-transfer-stepsâ‘ 
1839 // Step 1: If ! IsWritableStreamLocked(value) is true, throw a
1840 // "DataCloneError" DOMException.
1841 return !stream->Locked();
1846 TransformStream* stream = nullptr;
1847 nsresult rv = UNWRAP_OBJECT(TransformStream, &obj, stream);
1848 if (NS_SUCCEEDED(rv)) {
1849 // https://streams.spec.whatwg.org/#ref-for-transfer-steps②
1850 // Step 3 + 4: If ! Is{Readable,Writable}StreamLocked(value) is true,
1851 // throw a "DataCloneError" DOMException.
1852 return !stream->Readable()->Locked() && !stream->Writable()->Locked();
1856 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1857 VideoFrame* videoframe = nullptr;
1858 nsresult rv = UNWRAP_OBJECT(VideoFrame, &obj, videoframe);
1859 if (NS_SUCCEEDED(rv)) {
1860 SameProcessScopeRequired(aSameProcessScopeRequired);
1861 return CloneScope() == StructuredCloneScope::SameProcess;
1865 if (StaticPrefs::dom_media_webcodecs_enabled()) {
1866 mozilla::dom::AudioData* audioData = nullptr;
1867 nsresult rv = UNWRAP_OBJECT(AudioData, &obj, audioData);
1868 if (NS_SUCCEEDED(rv)) {
1869 SameProcessScopeRequired(aSameProcessScopeRequired);
1870 return CloneScope() == StructuredCloneScope::SameProcess;
1874 return false;
1877 bool StructuredCloneHolder::TakeTransferredPortsAsSequence(
1878 Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts) {
1879 nsTArray<RefPtr<MessagePort>> ports = TakeTransferredPorts();
1881 aPorts.Clear();
1882 for (uint32_t i = 0, len = ports.Length(); i < len; ++i) {
1883 if (!aPorts.AppendElement(ports[i].forget(), fallible)) {
1884 return false;
1888 return true;
1891 void StructuredCloneHolder::SameProcessScopeRequired(
1892 bool* aSameProcessScopeRequired) {
1893 MOZ_ASSERT(aSameProcessScopeRequired);
1894 if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) {
1895 mStructuredCloneScope = StructuredCloneScope::SameProcess;
1896 *aSameProcessScopeRequired = true;
1900 } // namespace mozilla::dom