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/StructuredCloneBlob.h"
13 #include "js/StructuredClone.h"
15 #include "js/Wrapper.h"
17 #include "mozilla/Assertions.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/UniquePtr.h"
21 #include "mozilla/dom/BindingDeclarations.h"
22 #include "mozilla/dom/BlobImpl.h"
23 #include "mozilla/dom/StructuredCloneHolderBinding.h"
24 #include "mozilla/dom/StructuredCloneTags.h"
25 #include "nsPrintfCString.h"
26 #include "xpcpublic.h"
28 namespace mozilla::dom
{
30 StructuredCloneBlob::StructuredCloneBlob() {
31 mHolder
.emplace(Holder::CloningSupported
, Holder::TransferringNotSupported
,
32 Holder::StructuredCloneScope::DifferentProcess
);
35 StructuredCloneBlob::~StructuredCloneBlob() {
36 UnregisterWeakMemoryReporter(this);
40 already_AddRefed
<StructuredCloneBlob
> StructuredCloneBlob::Constructor(
41 GlobalObject
& aGlobal
, const nsACString
& aName
,
42 const nsACString
& aAnonymizedName
, JS::Handle
<JS::Value
> aValue
,
43 JS::Handle
<JSObject
*> aTargetGlobal
, ErrorResult
& aRv
) {
44 JSContext
* cx
= aGlobal
.Context();
46 RefPtr
<StructuredCloneBlob
> holder
= StructuredCloneBlob::Create();
48 holder
->mName
= aName
;
49 holder
->mAnonymizedName
= aAnonymizedName
.IsVoid() ? aName
: aAnonymizedName
;
51 Maybe
<JSAutoRealm
> ar
;
52 JS::Rooted
<JS::Value
> value(cx
, aValue
);
55 // OK to unwrap if our caller (represented by cx's Realm) can do it.
56 JS::Rooted
<JSObject
*> targetGlobal(
57 cx
, js::CheckedUnwrapDynamic(aTargetGlobal
, cx
));
59 js::ReportAccessDenied(cx
);
60 aRv
.NoteJSContextException(cx
);
64 ar
.emplace(cx
, targetGlobal
);
66 if (!JS_WrapValue(cx
, &value
)) {
67 aRv
.NoteJSContextException(cx
);
70 } else if (value
.isObject()) {
71 // OK to unwrap if our caller (represented by cx's Realm) can do it.
72 JS::Rooted
<JSObject
*> obj(cx
,
73 js::CheckedUnwrapDynamic(&value
.toObject(), cx
));
75 js::ReportAccessDenied(cx
);
76 aRv
.NoteJSContextException(cx
);
81 value
= JS::ObjectValue(*obj
);
84 holder
->mHolder
->Write(cx
, value
, aRv
);
89 return holder
.forget();
92 void StructuredCloneBlob::Deserialize(JSContext
* aCx
,
93 JS::Handle
<JSObject
*> aTargetScope
,
95 JS::MutableHandle
<JS::Value
> aResult
,
97 // OK to unwrap if our caller (represented by aCx's Realm) can do it.
98 JS::Rooted
<JSObject
*> scope(aCx
, js::CheckedUnwrapDynamic(aTargetScope
, aCx
));
100 js::ReportAccessDenied(aCx
);
101 aRv
.NoteJSContextException(aCx
);
105 if (!mHolder
.isSome()) {
106 aRv
.Throw(NS_ERROR_NOT_INITIALIZED
);
111 JSAutoRealm
ar(aCx
, scope
);
113 mHolder
->Read(xpc::NativeGlobal(scope
), aCx
, aResult
, aRv
);
123 if (!JS_WrapValue(aCx
, aResult
)) {
124 aResult
.set(JS::UndefinedValue());
125 aRv
.NoteJSContextException(aCx
);
130 JSObject
* StructuredCloneBlob::ReadStructuredClone(
131 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
132 StructuredCloneHolder
* aHolder
) {
133 JS::Rooted
<JSObject
*> obj(aCx
);
135 RefPtr
<StructuredCloneBlob
> holder
= StructuredCloneBlob::Create();
137 if (!StructuredCloneHolder::ReadCString(aReader
, holder
->mName
)) {
141 if (!StructuredCloneHolder::ReadCString(aReader
, holder
->mAnonymizedName
)) {
145 if (!holder
->mHolder
->ReadStructuredCloneInternal(aCx
, aReader
, aHolder
) ||
146 !holder
->WrapObject(aCx
, nullptr, &obj
)) {
153 bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
154 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
155 StructuredCloneHolder
* aHolder
) {
158 if (!JS_ReadUint32Pair(aReader
, &length
, &version
)) {
161 if (length
% 8 != 0) {
167 if (!JS_ReadUint32Pair(aReader
, &blobOffset
, &blobCount
)) {
172 if (blobOffset
>= aHolder
->BlobImpls().Length()) {
176 BlobImpls().AppendElements(&aHolder
->BlobImpls()[blobOffset
], blobCount
);
179 JSStructuredCloneData
data(mStructuredCloneScope
);
182 char* buffer
= data
.AllocateBytes(length
, &size
);
183 if (!buffer
|| !JS_ReadBytes(aReader
, buffer
, size
)) {
189 mBuffer
= MakeUnique
<JSAutoStructuredCloneBuffer
>(
190 mStructuredCloneScope
, &StructuredCloneHolder::sCallbacks
, this);
191 mBuffer
->adopt(std::move(data
), version
, &StructuredCloneHolder::sCallbacks
);
196 bool StructuredCloneBlob::WriteStructuredClone(JSContext
* aCx
,
197 JSStructuredCloneWriter
* aWriter
,
198 StructuredCloneHolder
* aHolder
) {
199 if (mHolder
.isNothing()) {
203 if (!JS_WriteUint32Pair(aWriter
, SCTAG_DOM_STRUCTURED_CLONE_HOLDER
, 0) ||
204 !StructuredCloneHolder::WriteCString(aWriter
, mName
) ||
205 !StructuredCloneHolder::WriteCString(aWriter
, mAnonymizedName
)) {
209 return mHolder
->WriteStructuredClone(aCx
, aWriter
, aHolder
);
212 bool StructuredCloneBlob::Holder::WriteStructuredClone(
213 JSContext
* aCx
, JSStructuredCloneWriter
* aWriter
,
214 StructuredCloneHolder
* aHolder
) {
215 auto& data
= mBuffer
->data();
216 if (!JS_WriteUint32Pair(aWriter
, data
.Size(), JS_STRUCTURED_CLONE_VERSION
) ||
217 !JS_WriteUint32Pair(aWriter
, aHolder
->BlobImpls().Length(),
218 BlobImpls().Length())) {
222 aHolder
->BlobImpls().AppendElements(BlobImpls());
224 return data
.ForEachDataChunk([&](const char* aData
, size_t aSize
) {
225 return JS_WriteBytes(aWriter
, aData
, aSize
);
229 bool StructuredCloneBlob::WrapObject(JSContext
* aCx
,
230 JS::Handle
<JSObject
*> aGivenProto
,
231 JS::MutableHandle
<JSObject
*> aResult
) {
232 return StructuredCloneHolder_Binding::Wrap(aCx
, this, aGivenProto
, aResult
);
236 StructuredCloneBlob::CollectReports(nsIHandleReportCallback
* aHandleReport
,
237 nsISupports
* aData
, bool aAnonymize
) {
238 size_t size
= MallocSizeOf(this);
239 if (mHolder
.isSome()) {
240 size
+= mHolder
->SizeOfExcludingThis(MallocSizeOf
);
243 aHandleReport
->Callback(
245 nsPrintfCString("explicit/dom/structured-clone-holder/%s",
246 aAnonymize
? mAnonymizedName
.get() : mName
.get()),
247 KIND_HEAP
, UNITS_BYTES
, size
,
248 "Memory used by StructuredCloneHolder DOM objects."_ns
, aData
);
253 NS_IMPL_ISUPPORTS(StructuredCloneBlob
, nsIMemoryReporter
)
255 } // namespace mozilla::dom