Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / base / StructuredCloneBlob.cpp
blob9c0f76432335fb1ee1cf73cb152962c8ef7cb7d2
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 <cstddef>
10 #include <cstdint>
11 #include <new>
12 #include <utility>
13 #include "js/StructuredClone.h"
14 #include "js/Value.h"
15 #include "js/Wrapper.h"
16 #include "jsapi.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);
39 /* static */
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);
54 if (aTargetGlobal) {
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));
58 if (!targetGlobal) {
59 js::ReportAccessDenied(cx);
60 aRv.NoteJSContextException(cx);
61 return nullptr;
64 ar.emplace(cx, targetGlobal);
66 if (!JS_WrapValue(cx, &value)) {
67 aRv.NoteJSContextException(cx);
68 return nullptr;
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));
74 if (!obj) {
75 js::ReportAccessDenied(cx);
76 aRv.NoteJSContextException(cx);
77 return nullptr;
80 ar.emplace(cx, obj);
81 value = JS::ObjectValue(*obj);
84 holder->mHolder->Write(cx, value, aRv);
85 if (aRv.Failed()) {
86 return nullptr;
89 return holder.forget();
92 void StructuredCloneBlob::Deserialize(JSContext* aCx,
93 JS::Handle<JSObject*> aTargetScope,
94 bool aKeepData,
95 JS::MutableHandle<JS::Value> aResult,
96 ErrorResult& aRv) {
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));
99 if (!scope) {
100 js::ReportAccessDenied(aCx);
101 aRv.NoteJSContextException(aCx);
102 return;
105 if (!mHolder.isSome()) {
106 aRv.Throw(NS_ERROR_NOT_INITIALIZED);
107 return;
111 JSAutoRealm ar(aCx, scope);
113 mHolder->Read(xpc::NativeGlobal(scope), aCx, aResult, aRv);
114 if (aRv.Failed()) {
115 return;
119 if (!aKeepData) {
120 mHolder.reset();
123 if (!JS_WrapValue(aCx, aResult)) {
124 aResult.set(JS::UndefinedValue());
125 aRv.NoteJSContextException(aCx);
129 /* static */
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)) {
138 return nullptr;
141 if (!StructuredCloneHolder::ReadCString(aReader, holder->mAnonymizedName)) {
142 return nullptr;
145 if (!holder->mHolder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
146 !holder->WrapObject(aCx, nullptr, &obj)) {
147 return nullptr;
150 return obj.get();
153 bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
154 JSContext* aCx, JSStructuredCloneReader* aReader,
155 StructuredCloneHolder* aHolder) {
156 uint32_t length;
157 uint32_t version;
158 if (!JS_ReadUint32Pair(aReader, &length, &version)) {
159 return false;
161 if (length % 8 != 0) {
162 return false;
165 uint32_t blobOffset;
166 uint32_t blobCount;
167 if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) {
168 return false;
170 if (blobCount) {
171 #ifdef FUZZING
172 if (blobOffset >= aHolder->BlobImpls().Length()) {
173 return false;
175 #endif
176 BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
179 JSStructuredCloneData data(mStructuredCloneScope);
180 while (length) {
181 size_t size;
182 char* buffer = data.AllocateBytes(length, &size);
183 if (!buffer || !JS_ReadBytes(aReader, buffer, size)) {
184 return false;
186 length -= size;
189 mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(
190 mStructuredCloneScope, &StructuredCloneHolder::sCallbacks, this);
191 mBuffer->adopt(std::move(data), version, &StructuredCloneHolder::sCallbacks);
193 return true;
196 bool StructuredCloneBlob::WriteStructuredClone(JSContext* aCx,
197 JSStructuredCloneWriter* aWriter,
198 StructuredCloneHolder* aHolder) {
199 if (mHolder.isNothing()) {
200 return false;
203 if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
204 !StructuredCloneHolder::WriteCString(aWriter, mName) ||
205 !StructuredCloneHolder::WriteCString(aWriter, mAnonymizedName)) {
206 return false;
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())) {
219 return false;
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);
235 NS_IMETHODIMP
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(
244 ""_ns,
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);
250 return NS_OK;
253 NS_IMPL_ISUPPORTS(StructuredCloneBlob, nsIMemoryReporter)
255 } // namespace mozilla::dom