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"
9 #include "js/StructuredClone.h"
10 #include "js/Utility.h"
11 #include "js/Wrapper.h"
12 #include "mozilla/dom/BlobImpl.h"
13 #include "mozilla/dom/StructuredCloneTags.h"
14 #include "mozilla/Maybe.h"
15 #include "mozilla/UniquePtr.h"
16 #include "xpcpublic.h"
21 StructuredCloneBlob::StructuredCloneBlob() {
22 mHolder
.emplace(Holder::CloningSupported
, Holder::TransferringNotSupported
,
23 Holder::StructuredCloneScope::DifferentProcess
);
26 StructuredCloneBlob::~StructuredCloneBlob() {
27 UnregisterWeakMemoryReporter(this);
31 already_AddRefed
<StructuredCloneBlob
> StructuredCloneBlob::Constructor(
32 GlobalObject
& aGlobal
, JS::HandleValue aValue
,
33 JS::HandleObject aTargetGlobal
, ErrorResult
& aRv
) {
34 JSContext
* cx
= aGlobal
.Context();
36 RefPtr
<StructuredCloneBlob
> holder
= StructuredCloneBlob::Create();
38 Maybe
<JSAutoRealm
> ar
;
39 JS::RootedValue
value(cx
, aValue
);
42 // OK to unwrap if our caller (represented by cx's Realm) can do it.
43 JS::RootedObject
targetGlobal(cx
,
44 js::CheckedUnwrapDynamic(aTargetGlobal
, cx
));
46 js::ReportAccessDenied(cx
);
47 aRv
.NoteJSContextException(cx
);
51 ar
.emplace(cx
, targetGlobal
);
53 if (!JS_WrapValue(cx
, &value
)) {
54 aRv
.NoteJSContextException(cx
);
57 } else if (value
.isObject()) {
58 // OK to unwrap if our caller (represented by cx's Realm) can do it.
59 JS::RootedObject
obj(cx
, js::CheckedUnwrapDynamic(&value
.toObject(), cx
));
61 js::ReportAccessDenied(cx
);
62 aRv
.NoteJSContextException(cx
);
67 value
= JS::ObjectValue(*obj
);
70 holder
->mHolder
->Write(cx
, value
, aRv
);
75 return holder
.forget();
78 void StructuredCloneBlob::Deserialize(JSContext
* aCx
,
79 JS::HandleObject aTargetScope
,
81 JS::MutableHandleValue aResult
,
83 // OK to unwrap if our caller (represented by aCx's Realm) can do it.
84 JS::RootedObject
scope(aCx
, js::CheckedUnwrapDynamic(aTargetScope
, aCx
));
86 js::ReportAccessDenied(aCx
);
87 aRv
.NoteJSContextException(aCx
);
91 if (!mHolder
.isSome()) {
92 aRv
.Throw(NS_ERROR_NOT_INITIALIZED
);
97 JSAutoRealm
ar(aCx
, scope
);
99 mHolder
->Read(xpc::NativeGlobal(scope
), aCx
, aResult
, aRv
);
109 if (!JS_WrapValue(aCx
, aResult
)) {
110 aResult
.set(JS::UndefinedValue());
111 aRv
.NoteJSContextException(aCx
);
116 JSObject
* StructuredCloneBlob::ReadStructuredClone(
117 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
118 StructuredCloneHolder
* aHolder
) {
119 JS::RootedObject
obj(aCx
);
121 RefPtr
<StructuredCloneBlob
> holder
= StructuredCloneBlob::Create();
123 if (!holder
->mHolder
->ReadStructuredCloneInternal(aCx
, aReader
, aHolder
) ||
124 !holder
->WrapObject(aCx
, nullptr, &obj
)) {
131 bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
132 JSContext
* aCx
, JSStructuredCloneReader
* aReader
,
133 StructuredCloneHolder
* aHolder
) {
136 if (!JS_ReadUint32Pair(aReader
, &length
, &version
)) {
142 if (!JS_ReadUint32Pair(aReader
, &blobOffset
, &blobCount
)) {
147 if (blobOffset
>= aHolder
->BlobImpls().Length()) {
151 BlobImpls().AppendElements(&aHolder
->BlobImpls()[blobOffset
], blobCount
);
154 JSStructuredCloneData
data(mStructuredCloneScope
);
157 char* buffer
= data
.AllocateBytes(length
, &size
);
158 if (!buffer
|| !JS_ReadBytes(aReader
, buffer
, size
)) {
164 mBuffer
= MakeUnique
<JSAutoStructuredCloneBuffer
>(
165 mStructuredCloneScope
, &StructuredCloneHolder::sCallbacks
, this);
166 mBuffer
->adopt(std::move(data
), version
, &StructuredCloneHolder::sCallbacks
);
171 bool StructuredCloneBlob::WriteStructuredClone(JSContext
* aCx
,
172 JSStructuredCloneWriter
* aWriter
,
173 StructuredCloneHolder
* aHolder
) {
174 if (mHolder
.isNothing()) {
177 return mHolder
->WriteStructuredClone(aCx
, aWriter
, aHolder
);
180 bool StructuredCloneBlob::Holder::WriteStructuredClone(
181 JSContext
* aCx
, JSStructuredCloneWriter
* aWriter
,
182 StructuredCloneHolder
* aHolder
) {
183 auto& data
= mBuffer
->data();
184 if (!JS_WriteUint32Pair(aWriter
, SCTAG_DOM_STRUCTURED_CLONE_HOLDER
, 0) ||
185 !JS_WriteUint32Pair(aWriter
, data
.Size(), JS_STRUCTURED_CLONE_VERSION
) ||
186 !JS_WriteUint32Pair(aWriter
, aHolder
->BlobImpls().Length(),
187 BlobImpls().Length())) {
191 aHolder
->BlobImpls().AppendElements(BlobImpls());
193 return data
.ForEachDataChunk([&](const char* aData
, size_t aSize
) {
194 return JS_WriteBytes(aWriter
, aData
, aSize
);
198 bool StructuredCloneBlob::WrapObject(JSContext
* aCx
,
199 JS::HandleObject aGivenProto
,
200 JS::MutableHandleObject aResult
) {
201 return StructuredCloneHolder_Binding::Wrap(aCx
, this, aGivenProto
, aResult
);
205 StructuredCloneBlob::CollectReports(nsIHandleReportCallback
* aHandleReport
,
206 nsISupports
* aData
, bool aAnonymize
) {
207 size_t size
= MallocSizeOf(this);
208 if (mHolder
.isSome()) {
209 size
+= mHolder
->SizeOfExcludingThis(MallocSizeOf
);
212 MOZ_COLLECT_REPORT("explicit/dom/structured-clone-holder", KIND_HEAP
,
214 "Memory used by StructuredCloneHolder DOM objects.");
219 NS_IMPL_ISUPPORTS(StructuredCloneBlob
, nsIMemoryReporter
)
222 } // namespace mozilla