Line data Source code
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 "jswrapper.h"
12 :
13 : #include "xpcpublic.h"
14 :
15 : #include "mozilla/Maybe.h"
16 : #include "mozilla/UniquePtr.h"
17 : #include "mozilla/dom/StructuredCloneTags.h"
18 :
19 : namespace mozilla {
20 : namespace dom {
21 :
22 0 : StructuredCloneBlob::StructuredCloneBlob()
23 : : StructuredCloneHolder(CloningSupported, TransferringNotSupported,
24 0 : StructuredCloneScope::DifferentProcess)
25 0 : {};
26 :
27 :
28 : /* static */ already_AddRefed<StructuredCloneBlob>
29 0 : StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue,
30 : JS::HandleObject aTargetGlobal,
31 : ErrorResult& aRv)
32 : {
33 0 : JSContext* cx = aGlobal.Context();
34 :
35 0 : RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
36 :
37 0 : Maybe<JSAutoCompartment> ac;
38 0 : JS::RootedValue value(cx, aValue);
39 :
40 0 : if (aTargetGlobal) {
41 0 : JS::RootedObject targetGlobal(cx, js::CheckedUnwrap(aTargetGlobal));
42 0 : if (!targetGlobal) {
43 0 : js::ReportAccessDenied(cx);
44 0 : aRv.NoteJSContextException(cx);
45 0 : return nullptr;
46 : }
47 :
48 0 : ac.emplace(cx, targetGlobal);
49 :
50 0 : if (!JS_WrapValue(cx, &value)) {
51 0 : aRv.NoteJSContextException(cx);
52 0 : return nullptr;
53 : }
54 0 : } else if (value.isObject()) {
55 0 : JS::RootedObject obj(cx, js::CheckedUnwrap(&value.toObject()));
56 0 : if (!obj) {
57 0 : js::ReportAccessDenied(cx);
58 0 : aRv.NoteJSContextException(cx);
59 0 : return nullptr;
60 : }
61 :
62 0 : ac.emplace(cx, obj);
63 0 : value = JS::ObjectValue(*obj);
64 : }
65 :
66 0 : holder->Write(cx, value, aRv);
67 0 : if (aRv.Failed()) {
68 0 : return nullptr;
69 : }
70 :
71 0 : return holder.forget();
72 : }
73 :
74 : void
75 0 : StructuredCloneBlob::Deserialize(JSContext* aCx, JS::HandleObject aTargetScope,
76 : JS::MutableHandleValue aResult, ErrorResult& aRv)
77 : {
78 0 : JS::RootedObject scope(aCx, js::CheckedUnwrap(aTargetScope));
79 0 : if (!scope) {
80 0 : js::ReportAccessDenied(aCx);
81 0 : aRv.NoteJSContextException(aCx);
82 0 : return;
83 : }
84 :
85 : {
86 0 : JSAutoCompartment ac(aCx, scope);
87 :
88 0 : Read(xpc::NativeGlobal(scope), aCx, aResult, aRv);
89 0 : if (aRv.Failed()) {
90 0 : return;
91 : }
92 : }
93 :
94 0 : if (!JS_WrapValue(aCx, aResult)) {
95 0 : aResult.set(JS::UndefinedValue());
96 0 : aRv.NoteJSContextException(aCx);
97 : }
98 : }
99 :
100 :
101 : /* static */ JSObject*
102 0 : StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
103 : StructuredCloneHolder* aHolder)
104 : {
105 0 : JS::RootedObject obj(aCx);
106 : {
107 0 : RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
108 :
109 0 : if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
110 0 : !holder->WrapObject(aCx, nullptr, &obj)) {
111 0 : return nullptr;
112 : }
113 : }
114 0 : return obj.get();
115 : }
116 :
117 : bool
118 0 : StructuredCloneBlob::ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
119 : StructuredCloneHolder* aHolder)
120 : {
121 : uint32_t length;
122 : uint32_t version;
123 0 : if (!JS_ReadUint32Pair(aReader, &length, &version)) {
124 0 : return false;
125 : }
126 :
127 : uint32_t blobOffset;
128 : uint32_t blobCount;
129 0 : if (!JS_ReadUint32Pair(aReader, &blobOffset, &blobCount)) {
130 0 : return false;
131 : }
132 0 : if (blobCount) {
133 0 : BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
134 : }
135 :
136 0 : JSStructuredCloneData data;
137 0 : while (length) {
138 : size_t size;
139 0 : char* buffer = data.AllocateBytes(length, &size);
140 0 : if (!buffer || !JS_ReadBytes(aReader, buffer, size)) {
141 0 : return false;
142 : }
143 0 : length -= size;
144 : }
145 :
146 0 : mBuffer = MakeUnique<JSAutoStructuredCloneBuffer>(mStructuredCloneScope,
147 0 : &StructuredCloneHolder::sCallbacks,
148 0 : this);
149 0 : mBuffer->adopt(Move(data), version, &StructuredCloneHolder::sCallbacks);
150 :
151 0 : return true;
152 : }
153 :
154 : bool
155 0 : StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWriter* aWriter,
156 : StructuredCloneHolder* aHolder)
157 : {
158 0 : auto& data = mBuffer->data();
159 0 : if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_HOLDER, 0) ||
160 0 : !JS_WriteUint32Pair(aWriter, data.Size(), JS_STRUCTURED_CLONE_VERSION) ||
161 0 : !JS_WriteUint32Pair(aWriter, aHolder->BlobImpls().Length(), BlobImpls().Length())) {
162 0 : return false;
163 : }
164 :
165 0 : aHolder->BlobImpls().AppendElements(BlobImpls());
166 :
167 0 : auto iter = data.Iter();
168 0 : while (!iter.Done()) {
169 0 : if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
170 0 : return false;
171 : }
172 0 : iter.Advance(data, iter.RemainingInSegment());
173 : }
174 :
175 0 : return true;
176 : }
177 :
178 : bool
179 0 : StructuredCloneBlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto, JS::MutableHandleObject aResult)
180 : {
181 0 : return StructuredCloneHolderBinding::Wrap(aCx, this, aGivenProto, aResult);
182 : }
183 :
184 : } // namespace dom
185 : } // namespace mozilla
|