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