Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/indexedDB/FileSnapshot.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 file,
5
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "FileSnapshot.h"
8
9
#include "IDBDatabase.h"
10
#include "IDBFileHandle.h"
11
#include "IDBMutableFile.h"
12
#include "mozilla/Assertions.h"
13
#include "mozilla/Mutex.h"
14
#include "nsIAsyncInputStream.h"
15
#include "nsICloneableInputStream.h"
16
#include "nsIIPCSerializableInputStream.h"
17
18
namespace mozilla {
19
namespace dom {
20
namespace indexedDB {
21
22
using namespace mozilla::ipc;
23
24
namespace {
25
26
class StreamWrapper final
27
  : public nsIAsyncInputStream
28
  , public nsIInputStreamCallback
29
  , public nsICloneableInputStream
30
  , public nsIIPCSerializableInputStream
31
{
32
  class CloseRunnable;
33
34
  nsCOMPtr<nsIEventTarget> mOwningThread;
35
  nsCOMPtr<nsIInputStream> mInputStream;
36
  RefPtr<IDBFileHandle> mFileHandle;
37
  bool mFinished;
38
39
  // This is needed to call OnInputStreamReady() with the correct inputStream.
40
  // It is protected by mutex.
41
  nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
42
43
  Mutex mMutex;
44
45
public:
46
  StreamWrapper(nsIInputStream* aInputStream,
47
                IDBFileHandle* aFileHandle)
48
    : mOwningThread(aFileHandle->GetMutableFile()->Database()->EventTarget())
49
    , mInputStream(aInputStream)
50
    , mFileHandle(aFileHandle)
51
    , mFinished(false)
52
    , mMutex("StreamWrapper::mMutex")
53
0
  {
54
0
    AssertIsOnOwningThread();
55
0
    MOZ_ASSERT(aInputStream);
56
0
    MOZ_ASSERT(aFileHandle);
57
0
    aFileHandle->AssertIsOnOwningThread();
58
0
59
0
    mFileHandle->OnNewRequest();
60
0
  }
61
62
private:
63
  virtual ~StreamWrapper();
64
65
  bool
66
  IsOnOwningThread() const
67
0
  {
68
0
    MOZ_ASSERT(mOwningThread);
69
0
70
0
    bool current;
71
0
    return NS_SUCCEEDED(mOwningThread->
72
0
                        IsOnCurrentThread(&current)) && current;
73
0
  }
74
75
  void
76
  AssertIsOnOwningThread() const
77
0
  {
78
0
    MOZ_ASSERT(IsOnOwningThread());
79
0
  }
80
81
  void
82
  Finish()
83
0
  {
84
0
    AssertIsOnOwningThread();
85
0
86
0
    if (mFinished) {
87
0
      return;
88
0
    }
89
0
90
0
    mFinished = true;
91
0
92
0
    mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */ true);
93
0
  }
94
95
  void
96
  Destroy()
97
0
  {
98
0
    if (IsOnOwningThread()) {
99
0
      delete this;
100
0
      return;
101
0
    }
102
0
103
0
    RefPtr<Runnable> destroyRunnable =
104
0
      NewNonOwningRunnableMethod("StreamWrapper::Destroy",
105
0
                                 this,
106
0
                                 &StreamWrapper::Destroy);
107
0
108
0
    MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(destroyRunnable,
109
0
                                                NS_DISPATCH_NORMAL));
110
0
  }
111
112
  bool
113
  IsCloneableInputStream() const
114
0
  {
115
0
    nsCOMPtr<nsICloneableInputStream> stream =
116
0
      do_QueryInterface(mInputStream);
117
0
    return !!stream;
118
0
  }
119
120
  bool
121
  IsIPCSerializableInputStream() const
122
0
  {
123
0
    nsCOMPtr<nsIIPCSerializableInputStream> stream =
124
0
      do_QueryInterface(mInputStream);
125
0
    return !!stream;
126
0
  }
127
128
  bool
129
  IsAsyncInputStream() const
130
0
  {
131
0
    nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
132
0
    return !!stream;
133
0
  }
134
135
  NS_DECL_THREADSAFE_ISUPPORTS
136
  NS_DECL_NSIINPUTSTREAM
137
  NS_DECL_NSIASYNCINPUTSTREAM
138
  NS_DECL_NSIINPUTSTREAMCALLBACK
139
  NS_DECL_NSICLONEABLEINPUTSTREAM
140
  NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
141
};
142
143
class StreamWrapper::CloseRunnable final
144
  : public Runnable
145
{
146
  friend class StreamWrapper;
147
148
  RefPtr<StreamWrapper> mStreamWrapper;
149
150
public:
151
  NS_INLINE_DECL_REFCOUNTING_INHERITED(CloseRunnable, Runnable)
152
153
private:
154
  explicit
155
  CloseRunnable(StreamWrapper* aStreamWrapper)
156
    : Runnable("StreamWrapper::CloseRunnable")
157
    , mStreamWrapper(aStreamWrapper)
158
0
  { }
159
160
  ~CloseRunnable()
161
0
  { }
162
163
  NS_IMETHOD
164
  Run() override;
165
};
166
167
} // anonymous namespace
168
169
BlobImplSnapshot::BlobImplSnapshot(BlobImpl* aFileImpl,
170
                                   IDBFileHandle* aFileHandle)
171
  : mBlobImpl(aFileImpl)
172
0
{
173
0
  MOZ_ASSERT(aFileImpl);
174
0
  MOZ_ASSERT(aFileHandle);
175
0
176
0
  mFileHandle =
177
0
    do_GetWeakReference(NS_ISUPPORTS_CAST(EventTarget*, aFileHandle));
178
0
}
179
180
BlobImplSnapshot::BlobImplSnapshot(BlobImpl* aFileImpl,
181
                                   nsIWeakReference* aFileHandle)
182
  : mBlobImpl(aFileImpl)
183
  , mFileHandle(aFileHandle)
184
0
{
185
0
  MOZ_ASSERT(aFileImpl);
186
0
  MOZ_ASSERT(aFileHandle);
187
0
}
188
189
BlobImplSnapshot::~BlobImplSnapshot()
190
0
{
191
0
}
192
193
NS_IMPL_ISUPPORTS_INHERITED(BlobImplSnapshot, BlobImpl, PIBlobImplSnapshot)
194
195
already_AddRefed<BlobImpl>
196
BlobImplSnapshot::CreateSlice(uint64_t aStart,
197
                              uint64_t aLength,
198
                              const nsAString& aContentType,
199
                              ErrorResult& aRv)
200
0
{
201
0
  RefPtr<BlobImpl> blobImpl =
202
0
    mBlobImpl->CreateSlice(aStart, aLength, aContentType, aRv);
203
0
204
0
  if (NS_WARN_IF(aRv.Failed())) {
205
0
    return nullptr;
206
0
  }
207
0
208
0
  blobImpl = new BlobImplSnapshot(blobImpl, mFileHandle);
209
0
  return blobImpl.forget();
210
0
}
211
212
void
213
BlobImplSnapshot::CreateInputStream(nsIInputStream** aStream, ErrorResult& aRv)
214
0
{
215
0
  nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
216
0
  RefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
217
0
  if (!fileHandle || !fileHandle->IsOpen()) {
218
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
219
0
    return;
220
0
  }
221
0
222
0
  nsCOMPtr<nsIInputStream> stream;
223
0
  mBlobImpl->CreateInputStream(getter_AddRefs(stream), aRv);
224
0
  if (NS_WARN_IF(aRv.Failed())) {
225
0
    return;
226
0
  }
227
0
228
0
  RefPtr<StreamWrapper> wrapper = new StreamWrapper(stream, fileHandle);
229
0
230
0
  wrapper.forget(aStream);
231
0
}
232
233
BlobImpl*
234
BlobImplSnapshot::GetBlobImpl() const
235
0
{
236
0
  nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
237
0
  RefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
238
0
  if (!fileHandle || !fileHandle->IsOpen()) {
239
0
    return nullptr;
240
0
  }
241
0
242
0
  return mBlobImpl;
243
0
}
244
245
StreamWrapper::~StreamWrapper()
246
0
{
247
0
  AssertIsOnOwningThread();
248
0
249
0
  Finish();
250
0
}
251
252
NS_IMPL_ADDREF(StreamWrapper)
253
NS_IMPL_RELEASE_WITH_DESTROY(StreamWrapper, Destroy())
254
255
0
NS_INTERFACE_MAP_BEGIN(StreamWrapper)
256
0
  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
257
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
258
0
                                     IsAsyncInputStream())
259
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
260
0
                                     IsAsyncInputStream())
261
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
262
0
                                     IsCloneableInputStream())
263
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
264
0
                                     IsIPCSerializableInputStream())
265
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
266
0
NS_INTERFACE_MAP_END
267
268
NS_IMETHODIMP
269
StreamWrapper::Close()
270
0
{
271
0
  RefPtr<CloseRunnable> closeRunnable = new CloseRunnable(this);
272
0
273
0
  MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(closeRunnable,
274
0
                                              NS_DISPATCH_NORMAL));
275
0
276
0
  return NS_OK;
277
0
}
278
279
NS_IMETHODIMP
280
StreamWrapper::Available(uint64_t* _retval)
281
0
{
282
0
  return mInputStream->Available(_retval);
283
0
}
284
285
NS_IMETHODIMP
286
StreamWrapper::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
287
0
{
288
0
  return mInputStream->Read(aBuf, aCount, _retval);
289
0
}
290
291
NS_IMETHODIMP
292
StreamWrapper::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
293
                            uint32_t aCount, uint32_t* _retval)
294
0
{
295
0
  return mInputStream->ReadSegments(aWriter, aClosure, aCount, _retval);
296
0
}
297
298
NS_IMETHODIMP
299
StreamWrapper::IsNonBlocking(bool* _retval)
300
0
{
301
0
  return mInputStream->IsNonBlocking(_retval);
302
0
}
303
304
void
305
StreamWrapper::Serialize(InputStreamParams& aParams,
306
                         FileDescriptorArray& aFileDescriptors)
307
0
{
308
0
  nsCOMPtr<nsIIPCSerializableInputStream> stream =
309
0
    do_QueryInterface(mInputStream);
310
0
311
0
  if (stream) {
312
0
    stream->Serialize(aParams, aFileDescriptors);
313
0
  }
314
0
}
315
316
bool
317
StreamWrapper::Deserialize(const InputStreamParams& aParams,
318
                           const FileDescriptorArray& aFileDescriptors)
319
0
{
320
0
  MOZ_CRASH("This method should never be called");
321
0
  return false;
322
0
}
323
324
Maybe<uint64_t>
325
StreamWrapper::ExpectedSerializedLength()
326
0
{
327
0
  nsCOMPtr<nsIIPCSerializableInputStream> stream =
328
0
    do_QueryInterface(mInputStream);
329
0
330
0
  if (stream) {
331
0
    return stream->ExpectedSerializedLength();
332
0
  }
333
0
  return Nothing();
334
0
}
335
336
NS_IMETHODIMP
337
StreamWrapper::CloseWithStatus(nsresult aStatus)
338
0
{
339
0
  nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
340
0
  if (!stream) {
341
0
    return NS_ERROR_NO_INTERFACE;
342
0
  }
343
0
344
0
  nsresult rv = stream->CloseWithStatus(aStatus);
345
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
346
0
    return rv;
347
0
  }
348
0
349
0
  return Close();
350
0
}
351
352
NS_IMETHODIMP
353
StreamWrapper::AsyncWait(nsIInputStreamCallback* aCallback,
354
                         uint32_t aFlags,
355
                         uint32_t aRequestedCount,
356
                         nsIEventTarget* aEventTarget)
357
0
{
358
0
  nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
359
0
  if (!stream) {
360
0
    return NS_ERROR_NO_INTERFACE;
361
0
  }
362
0
363
0
  nsCOMPtr<nsIInputStreamCallback> callback = aCallback ? this : nullptr;
364
0
  {
365
0
    MutexAutoLock lock(mMutex);
366
0
367
0
    if (mAsyncWaitCallback && aCallback) {
368
0
      return NS_ERROR_FAILURE;
369
0
    }
370
0
371
0
    mAsyncWaitCallback = aCallback;
372
0
  }
373
0
374
0
  return stream->AsyncWait(callback, aFlags, aRequestedCount, aEventTarget);
375
0
}
376
377
// nsIInputStreamCallback
378
379
NS_IMETHODIMP
380
StreamWrapper::OnInputStreamReady(nsIAsyncInputStream* aStream)
381
0
{
382
0
  nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
383
0
  if (!stream) {
384
0
    return NS_ERROR_NO_INTERFACE;
385
0
  }
386
0
387
0
  nsCOMPtr<nsIInputStreamCallback> callback;
388
0
  {
389
0
    MutexAutoLock lock(mMutex);
390
0
391
0
    // We have been canceled in the meanwhile.
392
0
    if (!mAsyncWaitCallback) {
393
0
      return NS_OK;
394
0
    }
395
0
396
0
    callback.swap(mAsyncWaitCallback);
397
0
  }
398
0
399
0
  MOZ_ASSERT(callback);
400
0
  return callback->OnInputStreamReady(this);
401
0
}
402
403
// nsICloneableInputStream
404
405
NS_IMETHODIMP
406
StreamWrapper::GetCloneable(bool* aCloneable)
407
0
{
408
0
  nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mInputStream);
409
0
  if (!stream) {
410
0
    *aCloneable = false;
411
0
    return NS_ERROR_NO_INTERFACE;
412
0
  }
413
0
414
0
  return stream->GetCloneable(aCloneable);
415
0
}
416
417
NS_IMETHODIMP
418
StreamWrapper::Clone(nsIInputStream** aResult)
419
0
{
420
0
  nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mInputStream);
421
0
  if (!stream) {
422
0
    return NS_ERROR_NO_INTERFACE;
423
0
  }
424
0
425
0
  return stream->Clone(aResult);
426
0
}
427
428
NS_IMETHODIMP
429
StreamWrapper::
430
CloseRunnable::Run()
431
0
{
432
0
  mStreamWrapper->Finish();
433
0
434
0
  return NS_OK;
435
0
}
436
437
} // namespace indexedDB
438
} // namespace dom
439
} // namespace mozilla