Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/StructuredCloneHolder.h
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
#ifndef mozilla_dom_StructuredCloneHolder_h
8
#define mozilla_dom_StructuredCloneHolder_h
9
10
#include "jsapi.h"
11
#include "js/StructuredClone.h"
12
#include "mozilla/MemoryReporting.h"
13
#include "mozilla/Move.h"
14
#include "mozilla/UniquePtr.h"
15
#include "mozilla/dom/BindingDeclarations.h"
16
#include "nsISupports.h"
17
#include "nsTArray.h"
18
19
#ifdef DEBUG
20
#include "nsIThread.h"
21
#endif
22
23
class nsIInputStream;
24
25
namespace mozilla {
26
class ErrorResult;
27
namespace layers {
28
class Image;
29
}
30
31
namespace gfx {
32
class DataSourceSurface;
33
}
34
35
namespace dom {
36
37
class StructuredCloneHolderBase
38
{
39
public:
40
  typedef JS::StructuredCloneScope StructuredCloneScope;
41
42
  StructuredCloneHolderBase(StructuredCloneScope aScope = StructuredCloneScope::SameProcessSameThread);
43
  virtual ~StructuredCloneHolderBase();
44
45
  // Note, it is unsafe to std::move() a StructuredCloneHolderBase since a raw
46
  // this pointer is passed to mBuffer as a callback closure.  That must
47
  // be fixed if you want to implement a move constructor here.
48
  StructuredCloneHolderBase(StructuredCloneHolderBase&& aOther) = delete;
49
50
  // These methods should be implemented in order to clone data.
51
  // Read more documentation in js/public/StructuredClone.h.
52
53
  virtual JSObject* CustomReadHandler(JSContext* aCx,
54
                                      JSStructuredCloneReader* aReader,
55
                                      uint32_t aTag,
56
                                      uint32_t aIndex) = 0;
57
58
  virtual bool CustomWriteHandler(JSContext* aCx,
59
                                  JSStructuredCloneWriter* aWriter,
60
                                  JS::Handle<JSObject*> aObj) = 0;
61
62
  // This method has to be called when this object is not needed anymore.
63
  // It will free memory and the buffer. This has to be called because
64
  // otherwise the buffer will be freed in the DTOR of this class and at that
65
  // point we cannot use the overridden methods.
66
  void Clear();
67
68
  // If these 3 methods are not implement, transfering objects will not be
69
  // allowed. Otherwise only arrayBuffers will be transferred.
70
71
  virtual bool
72
  CustomReadTransferHandler(JSContext* aCx,
73
                            JSStructuredCloneReader* aReader,
74
                            uint32_t aTag,
75
                            void* aContent,
76
                            uint64_t aExtraData,
77
                            JS::MutableHandleObject aReturnObject);
78
79
  virtual bool
80
  CustomWriteTransferHandler(JSContext* aCx,
81
                             JS::Handle<JSObject*> aObj,
82
                             // Output:
83
                             uint32_t* aTag,
84
                             JS::TransferableOwnership* aOwnership,
85
                             void** aContent,
86
                             uint64_t* aExtraData);
87
88
  virtual void
89
  CustomFreeTransferHandler(uint32_t aTag,
90
                            JS::TransferableOwnership aOwnership,
91
                            void* aContent,
92
                            uint64_t aExtraData);
93
94
  virtual bool
95
  CustomCanTransferHandler(JSContext* aCx,
96
                           JS::Handle<JSObject*> aObj);
97
98
  // These methods are what you should use to read/write data.
99
100
  // Execute the serialization of aValue using the Structured Clone Algorithm.
101
  // The data can read back using Read().
102
  bool Write(JSContext* aCx,
103
             JS::Handle<JS::Value> aValue);
104
105
  // Like Write() but it supports the transferring of objects and handling
106
  // of cloning policy.
107
  bool Write(JSContext* aCx,
108
             JS::Handle<JS::Value> aValue,
109
             JS::Handle<JS::Value> aTransfer,
110
             JS::CloneDataPolicy cloneDataPolicy);
111
112
  // If Write() has been called, this method retrieves data and stores it into
113
  // aValue.
114
  bool Read(JSContext* aCx,
115
            JS::MutableHandle<JS::Value> aValue);
116
117
  bool HasData() const
118
0
  {
119
0
    return !!mBuffer;
120
0
  }
121
122
  JSStructuredCloneData& BufferData() const
123
  {
124
    MOZ_ASSERT(mBuffer, "Write() has never been called.");
125
    return mBuffer->data();
126
  }
127
128
  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
129
0
  {
130
0
    size_t size = 0;
131
0
    if (HasData()) {
132
0
      size += mBuffer->sizeOfIncludingThis(aMallocSizeOf);
133
0
    }
134
0
    return size;
135
0
  }
136
137
protected:
138
  UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
139
140
  StructuredCloneScope mStructuredCloneScope;
141
142
#ifdef DEBUG
143
  bool mClearCalled;
144
#endif
145
};
146
147
class BlobImpl;
148
class MessagePort;
149
class MessagePortIdentifier;
150
151
class StructuredCloneHolder : public StructuredCloneHolderBase
152
{
153
public:
154
  enum CloningSupport
155
  {
156
    CloningSupported,
157
    CloningNotSupported
158
  };
159
160
  enum TransferringSupport
161
  {
162
    TransferringSupported,
163
    TransferringNotSupported
164
  };
165
166
  // If cloning is supported, this object will clone objects such as Blobs,
167
  // FileList, ImageData, etc.
168
  // If transferring is supported, we will transfer MessagePorts and in the
169
  // future other transferrable objects.
170
  // The StructuredCloneScope is useful to know where the cloned/transferred
171
  // data can be read and written. Additional checks about the nature of the
172
  // objects will be done based on this scope value because not all the
173
  // objects can be sent between threads or processes.
174
  explicit StructuredCloneHolder(CloningSupport aSupportsCloning,
175
                                 TransferringSupport aSupportsTransferring,
176
                                 StructuredCloneScope aStructuredCloneScope);
177
  virtual ~StructuredCloneHolder();
178
179
  StructuredCloneHolder(StructuredCloneHolder&& aOther) = delete;
180
181
  // Normally you should just use Write() and Read().
182
183
  void Write(JSContext* aCx,
184
             JS::Handle<JS::Value> aValue,
185
             ErrorResult &aRv);
186
187
  void Write(JSContext* aCx,
188
             JS::Handle<JS::Value> aValue,
189
             JS::Handle<JS::Value> aTransfer,
190
             JS::CloneDataPolicy cloneDataPolicy,
191
             ErrorResult &aRv);
192
193
  void Read(nsISupports* aParent,
194
            JSContext* aCx,
195
            JS::MutableHandle<JS::Value> aValue,
196
            ErrorResult &aRv);
197
198
  // Call this method to know if this object is keeping some DOM object alive.
199
  bool HasClonedDOMObjects() const
200
  {
201
    return !mBlobImplArray.IsEmpty() ||
202
           !mWasmModuleArray.IsEmpty() ||
203
           !mClonedSurfaces.IsEmpty() ||
204
           !mInputStreamArray.IsEmpty();
205
  }
206
207
  nsTArray<RefPtr<BlobImpl>>& BlobImpls()
208
0
  {
209
0
    MOZ_ASSERT(mSupportsCloning, "Blobs cannot be taken/set if cloning is not supported.");
210
0
    return mBlobImplArray;
211
0
  }
212
213
  nsTArray<RefPtr<JS::WasmModule>>& WasmModules()
214
0
  {
215
0
    MOZ_ASSERT(mSupportsCloning, "WasmModules cannot be taken/set if cloning is not supported.");
216
0
    return mWasmModuleArray;
217
0
  }
218
219
  nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams()
220
0
  {
221
0
    MOZ_ASSERT(mSupportsCloning, "InputStreams cannot be taken/set if cloning is not supported.");
222
0
    return mInputStreamArray;
223
0
  }
224
225
  StructuredCloneScope CloneScope() const
226
  {
227
    return mStructuredCloneScope;
228
  }
229
230
  // The parent object is set internally just during the Read(). This method
231
  // can be used by read functions to retrieve it.
232
  nsISupports* ParentDuringRead() const
233
0
  {
234
0
    return mParent;
235
0
  }
236
237
  // This must be called if the transferring has ports generated by Read().
238
  // MessagePorts are not thread-safe and they must be retrieved in the thread
239
  // where they are created.
240
  nsTArray<RefPtr<MessagePort>>&& TakeTransferredPorts()
241
0
  {
242
0
    MOZ_ASSERT(mSupportsTransferring);
243
0
    return std::move(mTransferredPorts);
244
0
  }
245
246
  // This method uses TakeTransferredPorts() to populate a sequence of
247
  // MessagePorts for WebIDL binding classes.
248
  bool
249
  TakeTransferredPortsAsSequence(Sequence<OwningNonNull<mozilla::dom::MessagePort>>& aPorts);
250
251
  nsTArray<MessagePortIdentifier>& PortIdentifiers() const
252
  {
253
    MOZ_ASSERT(mSupportsTransferring);
254
    return mPortIdentifiers;
255
  }
256
257
  nsTArray<RefPtr<gfx::DataSourceSurface>>& GetSurfaces()
258
0
  {
259
0
    return mClonedSurfaces;
260
0
  }
261
262
  // Implementations of the virtual methods to allow cloning of objects which
263
  // JS engine itself doesn't clone.
264
265
  virtual JSObject* CustomReadHandler(JSContext* aCx,
266
                                      JSStructuredCloneReader* aReader,
267
                                      uint32_t aTag,
268
                                      uint32_t aIndex) override;
269
270
  virtual bool CustomWriteHandler(JSContext* aCx,
271
                                  JSStructuredCloneWriter* aWriter,
272
                                  JS::Handle<JSObject*> aObj) override;
273
274
  virtual bool CustomReadTransferHandler(JSContext* aCx,
275
                                         JSStructuredCloneReader* aReader,
276
                                         uint32_t aTag,
277
                                         void* aContent,
278
                                         uint64_t aExtraData,
279
                                         JS::MutableHandleObject aReturnObject) override;
280
281
  virtual bool CustomWriteTransferHandler(JSContext* aCx,
282
                                          JS::Handle<JSObject*> aObj,
283
                                          uint32_t* aTag,
284
                                          JS::TransferableOwnership* aOwnership,
285
                                          void** aContent,
286
                                          uint64_t* aExtraData) override;
287
288
  virtual void CustomFreeTransferHandler(uint32_t aTag,
289
                                         JS::TransferableOwnership aOwnership,
290
                                         void* aContent,
291
                                         uint64_t aExtraData) override;
292
293
  virtual bool CustomCanTransferHandler(JSContext* aCx,
294
                                        JS::Handle<JSObject*> aObj) override;
295
296
  // These 2 static methods are useful to read/write fully serializable objects.
297
  // They can be used by custom StructuredCloneHolderBase classes to
298
  // serialize objects such as ImageData, CryptoKey, RTCCertificate, etc.
299
300
  static JSObject* ReadFullySerializableObjects(JSContext* aCx,
301
                                                JSStructuredCloneReader* aReader,
302
                                                uint32_t aTag);
303
304
  static bool  WriteFullySerializableObjects(JSContext* aCx,
305
                                             JSStructuredCloneWriter* aWriter,
306
                                             JS::Handle<JSObject*> aObj);
307
308
  static const JSStructuredCloneCallbacks sCallbacks;
309
310
protected:
311
  // If you receive a buffer from IPC, you can use this method to retrieve a
312
  // JS::Value. It can happen that you want to pre-populate the array of Blobs
313
  // and/or the PortIdentifiers.
314
  void ReadFromBuffer(nsISupports* aParent,
315
                      JSContext* aCx,
316
                      JSStructuredCloneData& aBuffer,
317
                      JS::MutableHandle<JS::Value> aValue,
318
                      ErrorResult &aRv);
319
320
  void ReadFromBuffer(nsISupports* aParent,
321
                      JSContext* aCx,
322
                      JSStructuredCloneData& aBuffer,
323
                      uint32_t aAlgorithmVersion,
324
                      JS::MutableHandle<JS::Value> aValue,
325
                      ErrorResult &aRv);
326
327
  bool mSupportsCloning;
328
  bool mSupportsTransferring;
329
330
  // SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
331
  // account for objects in the following arrays because a) they're not expected
332
  // to be stored in long-lived StructuredCloneHolder objects, and b) in the
333
  // case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
334
  // and the other types do not hold significant amounts of memory alive.
335
336
  // Used for cloning blobs in the structured cloning algorithm.
337
  nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
338
339
  // Used for cloning JS::WasmModules in the structured cloning algorithm.
340
  nsTArray<RefPtr<JS::WasmModule>> mWasmModuleArray;
341
342
  // Used for cloning InputStream in the structured cloning algorithm.
343
  nsTArray<nsCOMPtr<nsIInputStream>> mInputStreamArray;
344
345
  // This is used for sharing the backend of ImageBitmaps.
346
  // The DataSourceSurface object must be thread-safely reference-counted.
347
  // The DataSourceSurface object will not be written ever via any ImageBitmap
348
  // instance, so no race condition will occur.
349
  nsTArray<RefPtr<gfx::DataSourceSurface>> mClonedSurfaces;
350
351
  // This raw pointer is only set within ::Read() and is unset by the end.
352
  nsISupports* MOZ_NON_OWNING_REF mParent;
353
354
  // This array contains the ports once we've finished the reading. It's
355
  // generated from the mPortIdentifiers array.
356
  nsTArray<RefPtr<MessagePort>> mTransferredPorts;
357
358
  // This array contains the identifiers of the MessagePorts. Based on these we
359
  // are able to reconnect the new transferred ports with the other
360
  // MessageChannel ports.
361
  mutable nsTArray<MessagePortIdentifier> mPortIdentifiers;
362
363
#ifdef DEBUG
364
  nsCOMPtr<nsIEventTarget> mCreationEventTarget;
365
#endif
366
};
367
368
} // dom namespace
369
} // mozilla namespace
370
371
#endif // mozilla_dom_StructuredCloneHolder_h