/src/mozilla-central/dom/base/StructuredCloneBlob.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "mozilla/dom/StructuredCloneBlob.h" |
8 | | |
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" |
17 | | |
18 | | namespace mozilla { |
19 | | namespace dom { |
20 | | |
21 | | StructuredCloneBlob::StructuredCloneBlob() |
22 | | : StructuredCloneHolder(CloningSupported, TransferringNotSupported, |
23 | | StructuredCloneScope::DifferentProcess) |
24 | 0 | {} |
25 | | |
26 | | StructuredCloneBlob::~StructuredCloneBlob() |
27 | 0 | { |
28 | 0 | UnregisterWeakMemoryReporter(this); |
29 | 0 | } |
30 | | |
31 | | |
32 | | /* static */ already_AddRefed<StructuredCloneBlob> |
33 | | StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue, |
34 | | JS::HandleObject aTargetGlobal, |
35 | | ErrorResult& aRv) |
36 | 0 | { |
37 | 0 | JSContext* cx = aGlobal.Context(); |
38 | 0 |
|
39 | 0 | RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create(); |
40 | 0 |
|
41 | 0 | Maybe<JSAutoRealm> ar; |
42 | 0 | JS::RootedValue value(cx, aValue); |
43 | 0 |
|
44 | 0 | if (aTargetGlobal) { |
45 | 0 | JS::RootedObject targetGlobal(cx, js::CheckedUnwrap(aTargetGlobal)); |
46 | 0 | if (!targetGlobal) { |
47 | 0 | js::ReportAccessDenied(cx); |
48 | 0 | aRv.NoteJSContextException(cx); |
49 | 0 | return nullptr; |
50 | 0 | } |
51 | 0 | |
52 | 0 | ar.emplace(cx, targetGlobal); |
53 | 0 |
|
54 | 0 | if (!JS_WrapValue(cx, &value)) { |
55 | 0 | aRv.NoteJSContextException(cx); |
56 | 0 | return nullptr; |
57 | 0 | } |
58 | 0 | } else if (value.isObject()) { |
59 | 0 | JS::RootedObject obj(cx, js::CheckedUnwrap(&value.toObject())); |
60 | 0 | if (!obj) { |
61 | 0 | js::ReportAccessDenied(cx); |
62 | 0 | aRv.NoteJSContextException(cx); |
63 | 0 | return nullptr; |
64 | 0 | } |
65 | 0 | |
66 | 0 | ar.emplace(cx, obj); |
67 | 0 | value = JS::ObjectValue(*obj); |
68 | 0 | } |
69 | 0 |
|
70 | 0 | holder->Write(cx, value, aRv); |
71 | 0 | if (aRv.Failed()) { |
72 | 0 | return nullptr; |
73 | 0 | } |
74 | 0 | |
75 | 0 | return holder.forget(); |
76 | 0 | } |
77 | | |
78 | | void |
79 | | StructuredCloneBlob::Deserialize(JSContext* aCx, JS::HandleObject aTargetScope, |
80 | | JS::MutableHandleValue aResult, ErrorResult& aRv) |
81 | 0 | { |
82 | 0 | JS::RootedObject scope(aCx, js::CheckedUnwrap(aTargetScope)); |
83 | 0 | if (!scope) { |
84 | 0 | js::ReportAccessDenied(aCx); |
85 | 0 | aRv.NoteJSContextException(aCx); |
86 | 0 | return; |
87 | 0 | } |
88 | 0 | |
89 | 0 | { |
90 | 0 | JSAutoRealm ar(aCx, scope); |
91 | 0 |
|
92 | 0 | Read(xpc::NativeGlobal(scope), aCx, aResult, aRv); |
93 | 0 | if (aRv.Failed()) { |
94 | 0 | return; |
95 | 0 | } |
96 | 0 | } |
97 | 0 | |
98 | 0 | if (!JS_WrapValue(aCx, aResult)) { |
99 | 0 | aResult.set(JS::UndefinedValue()); |
100 | 0 | aRv.NoteJSContextException(aCx); |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | | |
105 | | /* static */ JSObject* |
106 | | StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader, |
107 | | StructuredCloneHolder* aHolder) |
108 | 0 | { |
109 | 0 | JS::RootedObject obj(aCx); |
110 | 0 | { |
111 | 0 | RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create(); |
112 | 0 |
|
113 | 0 | if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) || |
114 | 0 | !holder->WrapObject(aCx, nullptr, &obj)) { |
115 | 0 | return nullptr; |
116 | 0 | } |
117 | 0 | } |
118 | 0 | return obj.get(); |
119 | 0 | } |
120 | | |
121 | | bool |
122 | | StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader, |
123 | | StructuredCloneHolder* aHolder) |
124 | 0 | { |
125 | 0 | uint32_t length; |
126 | 0 | uint32_t version; |
127 | 0 | if (!JS_ReadUint32Pair(aReader, &length, &version)) { |
128 | 0 | return false; |
129 | 0 | } |
130 | 0 | |
131 | 0 | uint32_t blobOffset; |
132 | 0 | uint32_t blobCount; |
133 | 0 | if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) { |
134 | 0 | return false; |
135 | 0 | } |
136 | 0 | if (blobCount) { |
137 | 0 | #ifdef FUZZING |
138 | 0 | if (blobOffset >= aHolder->BlobImpls().Length()) { |
139 | 0 | return false; |
140 | 0 | } |
141 | 0 | #endif |
142 | 0 | BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount); |
143 | 0 | } |
144 | 0 |
|
145 | 0 | JSStructuredCloneData data(mStructuredCloneScope); |
146 | 0 | while (length) { |
147 | 0 | size_t size; |
148 | 0 | char* buffer = data.AllocateBytes(length, &size); |
149 | 0 | if (!buffer || !JS_ReadBytes(aReader, buffer, size)) { |
150 | 0 | return false; |
151 | 0 | } |
152 | 0 | length -= size; |
153 | 0 | } |
154 | 0 |
|
155 | 0 | mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope, |
156 | 0 | &StructuredCloneHolder::sCallbacks, |
157 | 0 | this); |
158 | 0 | mBuffer->adopt(std::move(data), version, &StructuredCloneHolder::sCallbacks); |
159 | 0 |
|
160 | 0 | return true; |
161 | 0 | } |
162 | | |
163 | | bool |
164 | | StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter, |
165 | | StructuredCloneHolder* aHolder) |
166 | 0 | { |
167 | 0 | auto& data = mBuffer->data(); |
168 | 0 | if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) || |
169 | 0 | !JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) || |
170 | 0 | !JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(), BlobImpls().Length())) { |
171 | 0 | return false; |
172 | 0 | } |
173 | 0 | |
174 | 0 | aHolder->BlobImpls().AppendElements(BlobImpls()); |
175 | 0 |
|
176 | 0 | return data.ForEachDataChunk([&](const char* aData, size_t aSize) { |
177 | 0 | return JS_WriteBytes(aWriter, aData, aSize); |
178 | 0 | }); |
179 | 0 | } |
180 | | |
181 | | bool |
182 | | StructuredCloneBlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto, JS::MutableHandleObject aResult) |
183 | 0 | { |
184 | 0 | return StructuredCloneHolder_Binding::Wrap(aCx, this, aGivenProto, aResult); |
185 | 0 | } |
186 | | |
187 | | |
188 | | NS_IMETHODIMP |
189 | | StructuredCloneBlob::CollectReports(nsIHandleReportCallback* aHandleReport, |
190 | | nsISupports* aData, bool aAnonymize) |
191 | 0 | { |
192 | 0 | MOZ_COLLECT_REPORT( |
193 | 0 | "explicit/dom/structured-clone-holder", KIND_HEAP, UNITS_BYTES, |
194 | 0 | MallocSizeOf(this) + SizeOfExcludingThis(MallocSizeOf), |
195 | 0 | "Memory used by StructuredCloneHolder DOM objects."); |
196 | 0 |
|
197 | 0 | return NS_OK; |
198 | 0 | } |
199 | | |
200 | | NS_IMPL_ISUPPORTS(StructuredCloneBlob, nsIMemoryReporter) |
201 | | |
202 | | } // namespace dom |
203 | | } // namespace mozilla |