Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/indexedDB/IDBFileHandle.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 "IDBFileHandle.h"
8
9
#include "ActorsChild.h"
10
#include "BackgroundChildImpl.h"
11
#include "IDBEvents.h"
12
#include "IDBMutableFile.h"
13
#include "mozilla/Assertions.h"
14
#include "mozilla/dom/File.h"
15
#include "mozilla/dom/IDBFileHandleBinding.h"
16
#include "mozilla/dom/IPCBlobUtils.h"
17
#include "mozilla/dom/PBackgroundFileHandle.h"
18
#include "mozilla/EventDispatcher.h"
19
#include "mozilla/ipc/BackgroundChild.h"
20
#include "nsContentUtils.h"
21
#include "nsQueryObject.h"
22
#include "nsServiceManagerUtils.h"
23
#include "nsWidgetsCID.h"
24
25
namespace mozilla {
26
namespace dom {
27
28
using namespace mozilla::dom::indexedDB;
29
using namespace mozilla::ipc;
30
31
namespace {
32
33
already_AddRefed<IDBFileRequest>
34
GenerateFileRequest(IDBFileHandle* aFileHandle)
35
0
{
36
0
  MOZ_ASSERT(aFileHandle);
37
0
  aFileHandle->AssertIsOnOwningThread();
38
0
39
0
  RefPtr<IDBFileRequest> fileRequest =
40
0
    IDBFileRequest::Create(aFileHandle, /* aWrapAsDOMRequest */ false);
41
0
  MOZ_ASSERT(fileRequest);
42
0
43
0
  return fileRequest.forget();
44
0
}
45
46
} // namespace
47
48
IDBFileHandle::IDBFileHandle(IDBMutableFile* aMutableFile,
49
                             FileMode aMode)
50
  : mMutableFile(aMutableFile)
51
  , mBackgroundActor(nullptr)
52
  , mLocation(0)
53
  , mPendingRequestCount(0)
54
  , mReadyState(INITIAL)
55
  , mMode(aMode)
56
  , mAborted(false)
57
  , mCreating(false)
58
#ifdef DEBUG
59
  , mSentFinishOrAbort(false)
60
  , mFiredCompleteOrAbort(false)
61
#endif
62
0
{
63
0
  MOZ_ASSERT(aMutableFile);
64
0
  aMutableFile->AssertIsOnOwningThread();
65
0
}
66
67
IDBFileHandle::~IDBFileHandle()
68
0
{
69
0
  AssertIsOnOwningThread();
70
0
  MOZ_ASSERT(!mPendingRequestCount);
71
0
  MOZ_ASSERT(!mCreating);
72
0
  MOZ_ASSERT(mSentFinishOrAbort);
73
0
  MOZ_ASSERT_IF(mBackgroundActor, mFiredCompleteOrAbort);
74
0
75
0
  mMutableFile->UnregisterFileHandle(this);
76
0
77
0
  if (mBackgroundActor) {
78
0
    mBackgroundActor->SendDeleteMeInternal();
79
0
80
0
    MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
81
0
  }
82
0
}
83
84
// static
85
already_AddRefed<IDBFileHandle>
86
IDBFileHandle::Create(IDBMutableFile* aMutableFile,
87
                      FileMode aMode)
88
0
{
89
0
  MOZ_ASSERT(aMutableFile);
90
0
  aMutableFile->AssertIsOnOwningThread();
91
0
  MOZ_ASSERT(aMode == FileMode::Readonly || aMode == FileMode::Readwrite);
92
0
93
0
  RefPtr<IDBFileHandle> fileHandle =
94
0
    new IDBFileHandle(aMutableFile, aMode);
95
0
96
0
  fileHandle->BindToOwner(aMutableFile);
97
0
98
0
  // XXX Fix!
99
0
  MOZ_ASSERT(NS_IsMainThread(), "This won't work on non-main threads!");
100
0
101
0
  nsCOMPtr<nsIRunnable> runnable = do_QueryObject(fileHandle);
102
0
  nsContentUtils::AddPendingIDBTransaction(runnable.forget());
103
0
104
0
  fileHandle->mCreating = true;
105
0
106
0
  aMutableFile->RegisterFileHandle(fileHandle);
107
0
108
0
  return fileHandle.forget();
109
0
}
110
111
// static
112
IDBFileHandle*
113
IDBFileHandle::GetCurrent()
114
0
{
115
0
  MOZ_ASSERT(BackgroundChild::GetForCurrentThread());
116
0
117
0
  BackgroundChildImpl::ThreadLocal* threadLocal =
118
0
    BackgroundChildImpl::GetThreadLocalForCurrentThread();
119
0
  MOZ_ASSERT(threadLocal);
120
0
121
0
  return threadLocal->mCurrentFileHandle;
122
0
}
123
124
#ifdef DEBUG
125
126
void
127
IDBFileHandle::AssertIsOnOwningThread() const
128
{
129
  MOZ_ASSERT(mMutableFile);
130
  mMutableFile->AssertIsOnOwningThread();
131
}
132
133
#endif // DEBUG
134
135
void
136
IDBFileHandle::SetBackgroundActor(BackgroundFileHandleChild* aActor)
137
0
{
138
0
  AssertIsOnOwningThread();
139
0
  MOZ_ASSERT(aActor);
140
0
  MOZ_ASSERT(!mBackgroundActor);
141
0
142
0
  mBackgroundActor = aActor;
143
0
}
144
145
void
146
IDBFileHandle::StartRequest(IDBFileRequest* aFileRequest,
147
                            const FileRequestParams& aParams)
148
0
{
149
0
  AssertIsOnOwningThread();
150
0
  MOZ_ASSERT(aFileRequest);
151
0
  MOZ_ASSERT(aParams.type() != FileRequestParams::T__None);
152
0
153
0
  BackgroundFileRequestChild* actor =
154
0
    new BackgroundFileRequestChild(aFileRequest);
155
0
156
0
  mBackgroundActor->SendPBackgroundFileRequestConstructor(actor, aParams);
157
0
158
0
  // Balanced in BackgroundFileRequestChild::Recv__delete__().
159
0
  OnNewRequest();
160
0
}
161
162
void
163
IDBFileHandle::OnNewRequest()
164
0
{
165
0
  AssertIsOnOwningThread();
166
0
167
0
  if (!mPendingRequestCount) {
168
0
    MOZ_ASSERT(mReadyState == INITIAL);
169
0
    mReadyState = LOADING;
170
0
  }
171
0
172
0
  ++mPendingRequestCount;
173
0
}
174
175
void
176
IDBFileHandle::OnRequestFinished(bool aActorDestroyedNormally)
177
0
{
178
0
  AssertIsOnOwningThread();
179
0
  MOZ_ASSERT(mPendingRequestCount);
180
0
181
0
  --mPendingRequestCount;
182
0
183
0
  if (!mPendingRequestCount && !mMutableFile->IsInvalidated()) {
184
0
    mReadyState = FINISHING;
185
0
186
0
    if (aActorDestroyedNormally) {
187
0
      if (!mAborted) {
188
0
        SendFinish();
189
0
      } else {
190
0
        SendAbort();
191
0
      }
192
0
    } else {
193
0
      // Don't try to send any more messages to the parent if the request actor
194
0
      // was killed.
195
#ifdef DEBUG
196
      MOZ_ASSERT(!mSentFinishOrAbort);
197
      mSentFinishOrAbort = true;
198
#endif
199
    }
200
0
  }
201
0
}
202
203
void
204
IDBFileHandle::FireCompleteOrAbortEvents(bool aAborted)
205
0
{
206
0
  AssertIsOnOwningThread();
207
0
  MOZ_ASSERT(!mFiredCompleteOrAbort);
208
0
209
0
  mReadyState = DONE;
210
0
211
#ifdef DEBUG
212
  mFiredCompleteOrAbort = true;
213
#endif
214
215
0
  RefPtr<Event> event;
216
0
  if (aAborted) {
217
0
    event = CreateGenericEvent(this, nsDependentString(kAbortEventType),
218
0
                               eDoesBubble, eNotCancelable);
219
0
  } else {
220
0
    event = CreateGenericEvent(this, nsDependentString(kCompleteEventType),
221
0
                               eDoesNotBubble, eNotCancelable);
222
0
  }
223
0
  if (NS_WARN_IF(!event)) {
224
0
    return;
225
0
  }
226
0
227
0
  IgnoredErrorResult rv;
228
0
  DispatchEvent(*event, rv);
229
0
  if (rv.Failed()) {
230
0
    NS_WARNING("DispatchEvent failed!");
231
0
  }
232
0
}
233
234
bool
235
IDBFileHandle::IsOpen() const
236
0
{
237
0
  AssertIsOnOwningThread();
238
0
239
0
  // If we haven't started anything then we're open.
240
0
  if (mReadyState == INITIAL) {
241
0
    return true;
242
0
  }
243
0
244
0
  // If we've already started then we need to check to see if we still have the
245
0
  // mCreating flag set. If we do (i.e. we haven't returned to the event loop
246
0
  // from the time we were created) then we are open. Otherwise check the
247
0
  // currently running file handles to see if it's the same. We only allow other
248
0
  // requests to be made if this file handle is currently running.
249
0
  if (mReadyState == LOADING && (mCreating || GetCurrent() == this)) {
250
0
    return true;
251
0
  }
252
0
253
0
  return false;
254
0
}
255
256
void
257
IDBFileHandle::Abort()
258
0
{
259
0
  AssertIsOnOwningThread();
260
0
261
0
  if (IsFinishingOrDone()) {
262
0
    // Already started (and maybe finished) the finish or abort so there is
263
0
    // nothing to do here.
264
0
    return;
265
0
  }
266
0
267
0
  const bool isInvalidated = mMutableFile->IsInvalidated();
268
0
  bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
269
0
270
#ifdef DEBUG
271
  if (isInvalidated) {
272
    mSentFinishOrAbort = true;
273
  }
274
#endif
275
276
0
  mAborted = true;
277
0
  mReadyState = DONE;
278
0
279
0
  // Fire the abort event if there are no outstanding requests. Otherwise the
280
0
  // abort event will be fired when all outstanding requests finish.
281
0
  if (needToSendAbort) {
282
0
    SendAbort();
283
0
  }
284
0
}
285
286
already_AddRefed<IDBFileRequest>
287
IDBFileHandle::GetMetadata(const IDBFileMetadataParameters& aParameters,
288
                           ErrorResult& aRv)
289
0
{
290
0
  AssertIsOnOwningThread();
291
0
292
0
  // Common state checking
293
0
  if (!CheckState(aRv)) {
294
0
    return nullptr;
295
0
  }
296
0
297
0
  // Argument checking for get metadata.
298
0
  if (!aParameters.mSize && !aParameters.mLastModified) {
299
0
    aRv.ThrowTypeError<MSG_METADATA_NOT_CONFIGURED>();
300
0
    return nullptr;
301
0
  }
302
0
303
0
 // Do nothing if the window is closed
304
0
  if (!CheckWindow()) {
305
0
    return nullptr;
306
0
  }
307
0
308
0
  FileRequestGetMetadataParams params;
309
0
  params.size() = aParameters.mSize;
310
0
  params.lastModified() = aParameters.mLastModified;
311
0
312
0
  RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
313
0
314
0
  StartRequest(fileRequest, params);
315
0
316
0
  return fileRequest.forget();
317
0
}
318
319
already_AddRefed<IDBFileRequest>
320
IDBFileHandle::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
321
0
{
322
0
  AssertIsOnOwningThread();
323
0
324
0
  // State checking for write
325
0
  if (!CheckStateForWrite(aRv)) {
326
0
    return nullptr;
327
0
  }
328
0
329
0
  // Getting location and additional state checking for truncate
330
0
  uint64_t location;
331
0
  if (aSize.WasPassed()) {
332
0
    // Just in case someone calls us from C++
333
0
    MOZ_ASSERT(aSize.Value() != UINT64_MAX, "Passed wrong size!");
334
0
    location = aSize.Value();
335
0
  } else {
336
0
    if (mLocation == UINT64_MAX) {
337
0
      aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
338
0
      return nullptr;
339
0
    }
340
0
    location = mLocation;
341
0
  }
342
0
343
0
  // Do nothing if the window is closed
344
0
  if (!CheckWindow()) {
345
0
    return nullptr;
346
0
  }
347
0
348
0
  FileRequestTruncateParams params;
349
0
  params.offset() = location;
350
0
351
0
  RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
352
0
353
0
  StartRequest(fileRequest, params);
354
0
355
0
  if (aSize.WasPassed()) {
356
0
    mLocation = aSize.Value();
357
0
  }
358
0
359
0
  return fileRequest.forget();
360
0
}
361
362
already_AddRefed<IDBFileRequest>
363
IDBFileHandle::Flush(ErrorResult& aRv)
364
0
{
365
0
  AssertIsOnOwningThread();
366
0
367
0
  // State checking for write
368
0
  if (!CheckStateForWrite(aRv)) {
369
0
    return nullptr;
370
0
  }
371
0
372
0
  // Do nothing if the window is closed
373
0
  if (!CheckWindow()) {
374
0
    return nullptr;
375
0
  }
376
0
377
0
  FileRequestFlushParams params;
378
0
379
0
  RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
380
0
381
0
  StartRequest(fileRequest, params);
382
0
383
0
  return fileRequest.forget();
384
0
}
385
386
void
387
IDBFileHandle::Abort(ErrorResult& aRv)
388
0
{
389
0
  AssertIsOnOwningThread();
390
0
391
0
  // This method is special enough for not using generic state checking methods.
392
0
393
0
  if (IsFinishingOrDone()) {
394
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
395
0
    return;
396
0
  }
397
0
398
0
  Abort();
399
0
}
400
401
bool
402
IDBFileHandle::CheckState(ErrorResult& aRv)
403
0
{
404
0
  if (!IsOpen()) {
405
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
406
0
    return false;
407
0
  }
408
0
409
0
  return true;
410
0
}
411
412
bool
413
IDBFileHandle::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
414
0
{
415
0
  // Common state checking
416
0
  if (!CheckState(aRv)) {
417
0
    return false;
418
0
  }
419
0
420
0
  // Additional state checking for read
421
0
  if (mLocation == UINT64_MAX) {
422
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
423
0
    return false;
424
0
  }
425
0
426
0
  // Argument checking for read
427
0
  if (!aSize) {
428
0
    aRv.ThrowTypeError<MSG_INVALID_READ_SIZE>();
429
0
    return false;
430
0
  }
431
0
432
0
  return true;
433
0
}
434
435
bool
436
IDBFileHandle::CheckStateForWrite(ErrorResult& aRv)
437
0
{
438
0
  // Common state checking
439
0
  if (!CheckState(aRv)) {
440
0
    return false;
441
0
  }
442
0
443
0
  // Additional state checking for write
444
0
  if (mMode != FileMode::Readwrite) {
445
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
446
0
    return false;
447
0
  }
448
0
449
0
  return true;
450
0
}
451
452
bool
453
IDBFileHandle::CheckStateForWriteOrAppend(bool aAppend, ErrorResult& aRv)
454
0
{
455
0
  // State checking for write
456
0
  if (!CheckStateForWrite(aRv)) {
457
0
    return false;
458
0
  }
459
0
460
0
  // Additional state checking for write
461
0
  if (!aAppend && mLocation == UINT64_MAX) {
462
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
463
0
    return false;
464
0
  }
465
0
466
0
  return true;
467
0
}
468
469
bool
470
IDBFileHandle::CheckWindow()
471
0
{
472
0
  AssertIsOnOwningThread();
473
0
474
0
  return GetOwner();
475
0
}
476
477
already_AddRefed<IDBFileRequest>
478
IDBFileHandle::Read(uint64_t aSize, bool aHasEncoding,
479
                    const nsAString& aEncoding, ErrorResult& aRv)
480
0
{
481
0
  AssertIsOnOwningThread();
482
0
483
0
  // State and argument checking for read
484
0
  if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
485
0
    return nullptr;
486
0
  }
487
0
488
0
  // Do nothing if the window is closed
489
0
  if (!CheckWindow()) {
490
0
    return nullptr;
491
0
  }
492
0
493
0
  FileRequestReadParams params;
494
0
  params.offset() = mLocation;
495
0
  params.size() = aSize;
496
0
497
0
  RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
498
0
  if (aHasEncoding) {
499
0
    fileRequest->SetEncoding(aEncoding);
500
0
  }
501
0
502
0
  StartRequest(fileRequest, params);
503
0
504
0
  mLocation += aSize;
505
0
506
0
  return fileRequest.forget();
507
0
}
508
509
already_AddRefed<IDBFileRequest>
510
IDBFileHandle::WriteOrAppend(
511
                       const StringOrArrayBufferOrArrayBufferViewOrBlob& aValue,
512
                       bool aAppend,
513
                       ErrorResult& aRv)
514
0
{
515
0
  AssertIsOnOwningThread();
516
0
517
0
  if (aValue.IsString()) {
518
0
    return WriteOrAppend(aValue.GetAsString(), aAppend, aRv);
519
0
  }
520
0
521
0
  if (aValue.IsArrayBuffer()) {
522
0
    return WriteOrAppend(aValue.GetAsArrayBuffer(), aAppend, aRv);
523
0
  }
524
0
525
0
  if (aValue.IsArrayBufferView()) {
526
0
    return WriteOrAppend(aValue.GetAsArrayBufferView(), aAppend, aRv);
527
0
  }
528
0
529
0
  MOZ_ASSERT(aValue.IsBlob());
530
0
  return WriteOrAppend(aValue.GetAsBlob(), aAppend, aRv);
531
0
}
532
533
already_AddRefed<IDBFileRequest>
534
IDBFileHandle::WriteOrAppend(const nsAString& aValue,
535
                             bool aAppend,
536
                             ErrorResult& aRv)
537
0
{
538
0
  AssertIsOnOwningThread();
539
0
540
0
  // State checking for write or append
541
0
  if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
542
0
    return nullptr;
543
0
  }
544
0
545
0
  NS_ConvertUTF16toUTF8 cstr(aValue);
546
0
547
0
  uint64_t dataLength = cstr.Length();;
548
0
  if (!dataLength) {
549
0
    return nullptr;
550
0
  }
551
0
552
0
  FileRequestStringData stringData(cstr);
553
0
554
0
  // Do nothing if the window is closed
555
0
  if (!CheckWindow()) {
556
0
    return nullptr;
557
0
  }
558
0
559
0
  return WriteInternal(stringData, dataLength, aAppend, aRv);
560
0
}
561
562
already_AddRefed<IDBFileRequest>
563
IDBFileHandle::WriteOrAppend(const ArrayBuffer& aValue,
564
                             bool aAppend,
565
                             ErrorResult& aRv)
566
0
{
567
0
  AssertIsOnOwningThread();
568
0
569
0
  // State checking for write or append
570
0
  if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
571
0
    return nullptr;
572
0
  }
573
0
574
0
  aValue.ComputeLengthAndData();
575
0
576
0
  uint64_t dataLength = aValue.Length();;
577
0
  if (!dataLength) {
578
0
    return nullptr;
579
0
  }
580
0
581
0
  const char* data = reinterpret_cast<const char*>(aValue.Data());
582
0
583
0
  FileRequestStringData stringData;
584
0
  if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
585
0
                                             fallible_t()))) {
586
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
587
0
    return nullptr;
588
0
  }
589
0
590
0
  // Do nothing if the window is closed
591
0
  if (!CheckWindow()) {
592
0
    return nullptr;
593
0
  }
594
0
595
0
  return WriteInternal(stringData, dataLength, aAppend, aRv);
596
0
}
597
598
already_AddRefed<IDBFileRequest>
599
IDBFileHandle::WriteOrAppend(const ArrayBufferView& aValue,
600
                             bool aAppend,
601
                             ErrorResult& aRv)
602
0
{
603
0
  AssertIsOnOwningThread();
604
0
605
0
  // State checking for write or append
606
0
  if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
607
0
    return nullptr;
608
0
  }
609
0
610
0
  aValue.ComputeLengthAndData();
611
0
612
0
  uint64_t dataLength = aValue.Length();;
613
0
  if (!dataLength) {
614
0
    return nullptr;
615
0
  }
616
0
617
0
  const char* data = reinterpret_cast<const char*>(aValue.Data());
618
0
619
0
  FileRequestStringData stringData;
620
0
  if (NS_WARN_IF(!stringData.string().Assign(data, aValue.Length(),
621
0
                                             fallible_t()))) {
622
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
623
0
    return nullptr;
624
0
  }
625
0
626
0
  // Do nothing if the window is closed
627
0
  if (!CheckWindow()) {
628
0
    return nullptr;
629
0
  }
630
0
631
0
  return WriteInternal(stringData, dataLength, aAppend, aRv);
632
0
}
633
634
already_AddRefed<IDBFileRequest>
635
IDBFileHandle::WriteOrAppend(Blob& aValue,
636
                             bool aAppend,
637
                             ErrorResult& aRv)
638
0
{
639
0
  AssertIsOnOwningThread();
640
0
641
0
  // State checking for write or append
642
0
  if (!CheckStateForWriteOrAppend(aAppend, aRv)) {
643
0
    return nullptr;
644
0
  }
645
0
646
0
  ErrorResult error;
647
0
  uint64_t dataLength = aValue.GetSize(error);
648
0
  if (NS_WARN_IF(error.Failed())) {
649
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
650
0
    return nullptr;
651
0
  }
652
0
653
0
  if (!dataLength) {
654
0
    return nullptr;
655
0
  }
656
0
657
0
  PBackgroundChild* backgroundActor = BackgroundChild::GetForCurrentThread();
658
0
  MOZ_ASSERT(backgroundActor);
659
0
660
0
  IPCBlob ipcBlob;
661
0
  nsresult rv =
662
0
    IPCBlobUtils::Serialize(aValue.Impl(), backgroundActor, ipcBlob);
663
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
664
0
    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
665
0
    return nullptr;
666
0
  }
667
0
668
0
  FileRequestBlobData blobData;
669
0
  blobData.blob() = ipcBlob;
670
0
671
0
  // Do nothing if the window is closed
672
0
  if (!CheckWindow()) {
673
0
    return nullptr;
674
0
  }
675
0
676
0
  return WriteInternal(blobData, dataLength, aAppend, aRv);
677
0
}
678
679
already_AddRefed<IDBFileRequest>
680
IDBFileHandle::WriteInternal(const FileRequestData& aData,
681
                             uint64_t aDataLength,
682
                             bool aAppend,
683
                             ErrorResult& aRv)
684
0
{
685
0
  AssertIsOnOwningThread();
686
0
687
0
  DebugOnly<ErrorResult> error;
688
0
  MOZ_ASSERT(CheckStateForWrite(error));
689
0
  MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
690
0
  MOZ_ASSERT(aDataLength);
691
0
  MOZ_ASSERT(CheckWindow());
692
0
693
0
  FileRequestWriteParams params;
694
0
  params.offset() = aAppend ? UINT64_MAX : mLocation;
695
0
  params.data() = aData;
696
0
  params.dataLength() = aDataLength;
697
0
698
0
  RefPtr<IDBFileRequest> fileRequest = GenerateFileRequest(this);
699
0
  MOZ_ASSERT(fileRequest);
700
0
701
0
  StartRequest(fileRequest, params);
702
0
703
0
  if (aAppend) {
704
0
    mLocation = UINT64_MAX;
705
0
  }
706
0
  else {
707
0
    mLocation += aDataLength;
708
0
  }
709
0
710
0
  return fileRequest.forget();
711
0
}
712
713
void
714
IDBFileHandle::SendFinish()
715
0
{
716
0
  AssertIsOnOwningThread();
717
0
  MOZ_ASSERT(!mAborted);
718
0
  MOZ_ASSERT(IsFinishingOrDone());
719
0
  MOZ_ASSERT(!mSentFinishOrAbort);
720
0
  MOZ_ASSERT(!mPendingRequestCount);
721
0
722
0
  MOZ_ASSERT(mBackgroundActor);
723
0
  mBackgroundActor->SendFinish();
724
0
725
#ifdef DEBUG
726
  mSentFinishOrAbort = true;
727
#endif
728
}
729
730
void
731
IDBFileHandle::SendAbort()
732
0
{
733
0
  AssertIsOnOwningThread();
734
0
  MOZ_ASSERT(mAborted);
735
0
  MOZ_ASSERT(IsFinishingOrDone());
736
0
  MOZ_ASSERT(!mSentFinishOrAbort);
737
0
738
0
  MOZ_ASSERT(mBackgroundActor);
739
0
  mBackgroundActor->SendAbort();
740
0
741
#ifdef DEBUG
742
  mSentFinishOrAbort = true;
743
#endif
744
}
745
746
NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
747
NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
748
749
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFileHandle)
750
0
  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
751
0
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
752
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
753
754
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFileHandle)
755
756
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBFileHandle,
757
0
                                                  DOMEventTargetHelper)
758
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMutableFile)
759
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
760
761
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBFileHandle,
762
0
                                                DOMEventTargetHelper)
763
0
  // Don't unlink mMutableFile!
764
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
765
766
NS_IMETHODIMP
767
IDBFileHandle::Run()
768
0
{
769
0
  AssertIsOnOwningThread();
770
0
771
0
  // We're back at the event loop, no longer newborn.
772
0
  mCreating = false;
773
0
774
0
  // Maybe finish if there were no requests generated.
775
0
  if (mReadyState == INITIAL) {
776
0
    mReadyState = DONE;
777
0
778
0
    SendFinish();
779
0
  }
780
0
781
0
  return NS_OK;
782
0
}
783
784
void
785
IDBFileHandle::GetEventTargetParent(EventChainPreVisitor& aVisitor)
786
0
{
787
0
  AssertIsOnOwningThread();
788
0
789
0
  aVisitor.mCanHandle = true;
790
0
  aVisitor.SetParentTarget(mMutableFile, false);
791
0
}
792
793
// virtual
794
JSObject*
795
IDBFileHandle::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
796
0
{
797
0
  AssertIsOnOwningThread();
798
0
799
0
  return IDBFileHandle_Binding::Wrap(aCx, this, aGivenProto);
800
0
}
801
802
} // namespace dom
803
} // namespace mozilla