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/. */
7 #include "ActorsParent.h"
10 #include "SimpleDBCommon.h"
17 #include "ErrorList.h"
18 #include "MainThreadUtils.h"
19 #include "mozilla/AlreadyAddRefed.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/Atomics.h"
22 #include "mozilla/DebugOnly.h"
23 #include "mozilla/FixedBufferOutputStream.h"
24 #include "mozilla/Maybe.h"
25 #include "mozilla/Preferences.h"
26 #include "mozilla/RefPtr.h"
27 #include "mozilla/Result.h"
28 #include "mozilla/ResultExtensions.h"
29 #include "mozilla/SpinEventLoopUntil.h"
30 #include "mozilla/StaticPtr.h"
31 #include "mozilla/Unused.h"
32 #include "mozilla/Variant.h"
33 #include "mozilla/dom/PBackgroundSDBConnection.h"
34 #include "mozilla/dom/PBackgroundSDBConnectionParent.h"
35 #include "mozilla/dom/PBackgroundSDBRequestParent.h"
36 #include "mozilla/dom/ipc/IdType.h"
37 #include "mozilla/dom/quota/Client.h"
38 #include "mozilla/dom/quota/ClientImpl.h"
39 #include "mozilla/dom/quota/DirectoryLock.h"
40 #include "mozilla/dom/quota/FileStreams.h"
41 #include "mozilla/dom/quota/QuotaCommon.h"
42 #include "mozilla/dom/quota/QuotaManager.h"
43 #include "mozilla/dom/quota/ResultExtensions.h"
44 #include "mozilla/dom/quota/UsageInfo.h"
45 #include "mozilla/ipc/BackgroundParent.h"
46 #include "mozilla/ipc/BackgroundUtils.h"
47 #include "mozilla/ipc/PBackgroundParent.h"
48 #include "mozilla/ipc/PBackgroundSharedTypes.h"
49 #include "mozilla/ipc/ProtocolUtils.h"
53 #include "nsIDirectoryEnumerator.h"
54 #include "nsIEventTarget.h"
56 #include "nsIFileStreams.h"
57 #include "nsIInputStream.h"
58 #include "nsIOutputStream.h"
59 #include "nsIRunnable.h"
60 #include "nsISeekableStream.h"
61 #include "nsISupports.h"
62 #include "nsIThread.h"
63 #include "nsLiteralString.h"
65 #include "nsStringFwd.h"
66 #include "nsStringStream.h"
68 #include "nsTLiteralString.h"
69 #include "nsTStringRepr.h"
70 #include "nsThreadUtils.h"
74 namespace mozilla::dom
{
76 using namespace mozilla::dom::quota
;
77 using namespace mozilla::ipc
;
81 /*******************************************************************************
83 ******************************************************************************/
85 const uint32_t kCopyBufferSize
= 32768;
87 constexpr auto kSDBSuffix
= u
".sdb"_ns
;
89 /*******************************************************************************
90 * Actor class declarations
91 ******************************************************************************/
93 class StreamHelper final
: public Runnable
{
94 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
95 nsCOMPtr
<nsIFileRandomAccessStream
> mFileRandomAccessStream
;
96 nsCOMPtr
<nsIRunnable
> mCallback
;
99 StreamHelper(nsIFileRandomAccessStream
* aFileRandomAccessStream
,
100 nsIRunnable
* aCallback
);
105 ~StreamHelper() override
;
107 void RunOnBackgroundThread();
109 void RunOnIOThread();
114 class Connection final
: public PBackgroundSDBConnectionParent
{
115 RefPtr
<DirectoryLock
> mDirectoryLock
;
116 nsCOMPtr
<nsIFileRandomAccessStream
> mFileRandomAccessStream
;
117 const PrincipalInfo mPrincipalInfo
;
121 PersistenceType mPersistenceType
;
122 bool mRunningRequest
;
124 bool mAllowedToClose
;
125 bool mActorDestroyed
;
128 Connection(PersistenceType aPersistenceType
,
129 const PrincipalInfo
& aPrincipalInfo
);
131 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::Connection
)
133 Maybe
<DirectoryLock
&> MaybeDirectoryLockRef() const {
134 AssertIsOnBackgroundThread();
136 return ToMaybeRef(mDirectoryLock
.get());
139 nsIFileRandomAccessStream
* GetFileRandomAccessStream() const {
140 AssertIsOnIOThread();
142 return mFileRandomAccessStream
;
145 PersistenceType
GetPersistenceType() const { return mPersistenceType
; }
147 const PrincipalInfo
& GetPrincipalInfo() const {
148 AssertIsOnBackgroundThread();
150 return mPrincipalInfo
;
153 const nsCString
& Origin() const {
154 AssertIsOnBackgroundThread();
155 MOZ_ASSERT(!mOrigin
.IsEmpty());
160 const nsString
& Name() const {
161 AssertIsOnBackgroundThread();
162 MOZ_ASSERT(!mName
.IsEmpty());
169 void OnRequestFinished();
172 const nsACString
& aOrigin
, const nsAString
& aName
,
173 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
174 already_AddRefed
<nsIFileRandomAccessStream
> aFileRandomAccessStream
);
183 void MaybeCloseStream();
185 bool VerifyRequestParams(const SDBRequestParams
& aParams
) const;
188 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
190 mozilla::ipc::IPCResult
RecvDeleteMe() override
;
192 virtual PBackgroundSDBRequestParent
* AllocPBackgroundSDBRequestParent(
193 const SDBRequestParams
& aParams
) override
;
195 virtual mozilla::ipc::IPCResult
RecvPBackgroundSDBRequestConstructor(
196 PBackgroundSDBRequestParent
* aActor
,
197 const SDBRequestParams
& aParams
) override
;
199 virtual bool DeallocPBackgroundSDBRequestParent(
200 PBackgroundSDBRequestParent
* aActor
) override
;
203 class ConnectionOperationBase
: public Runnable
,
204 public PBackgroundSDBRequestParent
{
205 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
206 RefPtr
<Connection
> mConnection
;
207 nsresult mResultCode
;
208 Atomic
<bool> mOperationMayProceed
;
209 bool mActorDestroyed
;
212 nsIEventTarget
* OwningEventTarget() const {
213 MOZ_ASSERT(mOwningEventTarget
);
215 return mOwningEventTarget
;
218 bool IsOnOwningThread() const {
219 MOZ_ASSERT(mOwningEventTarget
);
222 return NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)) &&
226 void AssertIsOnOwningThread() const {
227 MOZ_ASSERT(IsOnBackgroundThread());
228 MOZ_ASSERT(IsOnOwningThread());
231 Connection
* GetConnection() const {
232 MOZ_ASSERT(mConnection
);
237 nsresult
ResultCode() const { return mResultCode
; }
239 void MaybeSetFailureCode(nsresult aErrorCode
) {
240 MOZ_ASSERT(NS_FAILED(aErrorCode
));
242 if (NS_SUCCEEDED(mResultCode
)) {
243 mResultCode
= aErrorCode
;
247 // May be called on any thread, but you should call IsActorDestroyed() if
248 // you know you're on the background thread because it is slightly faster.
249 bool OperationMayProceed() const { return mOperationMayProceed
; }
251 bool IsActorDestroyed() const {
252 AssertIsOnOwningThread();
254 return mActorDestroyed
;
257 // May be overridden by subclasses if they need to perform work on the
258 // background thread before being dispatched but must always call the base
259 // class implementation. Returning false will kill the child actors and
263 virtual nsresult
Dispatch();
265 // This callback will be called on the background thread before releasing the
266 // final reference to this request object. Subclasses may perform any
267 // additional cleanup here but must always call the base class implementation.
268 virtual void Cleanup();
271 ConnectionOperationBase(Connection
* aConnection
)
272 : Runnable("dom::ConnectionOperationBase"),
273 mOwningEventTarget(GetCurrentSerialEventTarget()),
274 mConnection(aConnection
),
276 mOperationMayProceed(true),
277 mActorDestroyed(false) {
278 AssertIsOnOwningThread();
281 ~ConnectionOperationBase() override
;
287 // Methods that subclasses must implement.
288 virtual nsresult
DoDatabaseWork(
289 nsIFileRandomAccessStream
* aFileRandomAccessStream
) = 0;
291 // Subclasses use this override to set the IPDL response value.
292 virtual void GetResponse(SDBRequestResponse
& aResponse
) = 0;
294 // A method that subclasses may implement.
295 virtual void OnSuccess();
302 void ActorDestroy(ActorDestroyReason aWhy
) override
;
305 class OpenOp final
: public ConnectionOperationBase
,
306 public OpenDirectoryListener
{
308 // Just created on the PBackground thread, dispatched to the main thread.
309 // Next step is FinishOpen.
312 // Ensuring quota manager is created and opening directory on the
313 // PBackground thread. Next step is either SendingResults if quota manager
314 // is not available or DirectoryOpenPending if quota manager is available.
317 // Waiting for directory open allowed on the PBackground thread. The next
318 // step is either SendingResults if directory lock failed to acquire, or
319 // DatabaseWorkOpen if directory lock is acquired.
320 DirectoryOpenPending
,
322 // Waiting to do/doing work on the QuotaManager IO thread. Its next step is
326 // Waiting to send/sending results on the PBackground thread. Next step is
334 const SDBRequestOpenParams mParams
;
335 RefPtr
<DirectoryLock
> mDirectoryLock
;
336 nsCOMPtr
<nsIFileRandomAccessStream
> mFileRandomAccessStream
;
337 // XXX Consider changing this to ClientMetadata.
338 quota::OriginMetadata mOriginMetadata
;
340 bool mFileRandomAccessStreamOpen
;
343 OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
345 nsresult
Dispatch() override
;
352 nsresult
FinishOpen();
354 nsresult
SendToIOThread();
356 nsresult
DatabaseWork();
358 void StreamClosedCallback();
360 // ConnectionOperationBase overrides
361 nsresult
DoDatabaseWork(
362 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
364 void GetResponse(SDBRequestResponse
& aResponse
) override
;
366 void OnSuccess() override
;
368 void Cleanup() override
;
370 NS_DECL_ISUPPORTS_INHERITED
375 // OpenDirectoryListener overrides.
376 void DirectoryLockAcquired(DirectoryLock
* aLock
) override
;
378 void DirectoryLockFailed() override
;
381 class SeekOp final
: public ConnectionOperationBase
{
382 const SDBRequestSeekParams mParams
;
385 SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
388 ~SeekOp() override
= default;
390 nsresult
DoDatabaseWork(
391 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
393 void GetResponse(SDBRequestResponse
& aResponse
) override
;
396 class ReadOp final
: public ConnectionOperationBase
{
397 const SDBRequestReadParams mParams
;
399 RefPtr
<FixedBufferOutputStream
> mOutputStream
;
402 ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
404 bool Init() override
;
407 ~ReadOp() override
= default;
409 nsresult
DoDatabaseWork(
410 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
412 void GetResponse(SDBRequestResponse
& aResponse
) override
;
415 class WriteOp final
: public ConnectionOperationBase
{
416 const SDBRequestWriteParams mParams
;
418 nsCOMPtr
<nsIInputStream
> mInputStream
;
423 WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
425 bool Init() override
;
428 ~WriteOp() override
= default;
430 nsresult
DoDatabaseWork(
431 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
433 void GetResponse(SDBRequestResponse
& aResponse
) override
;
436 class CloseOp final
: public ConnectionOperationBase
{
438 explicit CloseOp(Connection
* aConnection
);
441 ~CloseOp() override
= default;
443 nsresult
DoDatabaseWork(
444 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
446 void GetResponse(SDBRequestResponse
& aResponse
) override
;
448 void OnSuccess() override
;
451 /*******************************************************************************
452 * Other class declarations
453 ******************************************************************************/
455 class QuotaClient final
: public mozilla::dom::quota::Client
{
456 static QuotaClient
* sInstance
;
461 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient
, override
)
463 Type
GetType() override
;
465 Result
<UsageInfo
, nsresult
> InitOrigin(PersistenceType aPersistenceType
,
466 const OriginMetadata
& aOriginMetadata
,
467 const AtomicBool
& aCanceled
) override
;
469 nsresult
InitOriginWithoutTracking(PersistenceType aPersistenceType
,
470 const OriginMetadata
& aOriginMetadata
,
471 const AtomicBool
& aCanceled
) override
;
473 Result
<UsageInfo
, nsresult
> GetUsageForOrigin(
474 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
475 const AtomicBool
& aCanceled
) override
;
477 void OnOriginClearCompleted(PersistenceType aPersistenceType
,
478 const nsACString
& aOrigin
) override
;
480 void OnRepositoryClearCompleted(PersistenceType aPersistenceType
) override
;
482 void ReleaseIOThreadObjects() override
;
484 void AbortOperationsForLocks(
485 const DirectoryLockIdTable
& aDirectoryLockIds
) override
;
487 void AbortOperationsForProcess(ContentParentId aContentParentId
) override
;
489 void AbortAllOperations() override
;
491 void StartIdleMaintenance() override
;
493 void StopIdleMaintenance() override
;
496 ~QuotaClient() override
;
498 void InitiateShutdown() override
;
499 bool IsShutdownCompleted() const override
;
500 nsCString
GetShutdownStatus() const override
;
501 void ForceKillActors() override
;
502 void FinalizeShutdown() override
;
505 /*******************************************************************************
507 ******************************************************************************/
509 using ConnectionArray
= nsTArray
<NotNull
<RefPtr
<Connection
>>>;
511 StaticAutoPtr
<ConnectionArray
> gOpenConnections
;
513 template <typename Condition
>
514 void AllowToCloseConnectionsMatching(const Condition
& aCondition
) {
515 AssertIsOnBackgroundThread();
517 if (gOpenConnections
) {
518 for (const auto& connection
: *gOpenConnections
) {
519 if (aCondition(*connection
)) {
520 connection
->AllowToClose();
528 /*******************************************************************************
530 ******************************************************************************/
532 PBackgroundSDBConnectionParent
* AllocPBackgroundSDBConnectionParent(
533 const PersistenceType
& aPersistenceType
,
534 const PrincipalInfo
& aPrincipalInfo
) {
535 AssertIsOnBackgroundThread();
537 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
541 if (NS_WARN_IF(!IsValidPersistenceType(aPersistenceType
))) {
542 MOZ_CRASH_UNLESS_FUZZING();
546 if (NS_WARN_IF(aPrincipalInfo
.type() == PrincipalInfo::TNullPrincipalInfo
)) {
547 MOZ_CRASH_UNLESS_FUZZING();
551 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo
))) {
552 MOZ_CRASH_UNLESS_FUZZING();
556 RefPtr
<Connection
> actor
= new Connection(aPersistenceType
, aPrincipalInfo
);
558 return actor
.forget().take();
561 bool RecvPBackgroundSDBConnectionConstructor(
562 PBackgroundSDBConnectionParent
* aActor
,
563 const PersistenceType
& aPersistenceType
,
564 const PrincipalInfo
& aPrincipalInfo
) {
565 AssertIsOnBackgroundThread();
567 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
572 bool DeallocPBackgroundSDBConnectionParent(
573 PBackgroundSDBConnectionParent
* aActor
) {
574 AssertIsOnBackgroundThread();
577 RefPtr
<Connection
> actor
= dont_AddRef(static_cast<Connection
*>(aActor
));
583 already_AddRefed
<mozilla::dom::quota::Client
> CreateQuotaClient() {
584 AssertIsOnBackgroundThread();
586 RefPtr
<QuotaClient
> client
= new QuotaClient();
587 return client
.forget();
590 } // namespace simpledb
592 /*******************************************************************************
594 ******************************************************************************/
596 StreamHelper::StreamHelper(nsIFileRandomAccessStream
* aFileRandomAccessStream
,
597 nsIRunnable
* aCallback
)
598 : Runnable("dom::StreamHelper"),
599 mOwningEventTarget(GetCurrentSerialEventTarget()),
600 mFileRandomAccessStream(aFileRandomAccessStream
),
601 mCallback(aCallback
) {
602 AssertIsOnBackgroundThread();
603 MOZ_ASSERT(aFileRandomAccessStream
);
604 MOZ_ASSERT(aCallback
);
607 StreamHelper::~StreamHelper() {
608 MOZ_ASSERT(!mFileRandomAccessStream
);
609 MOZ_ASSERT(!mCallback
);
612 void StreamHelper::AsyncClose() {
613 AssertIsOnBackgroundThread();
615 QuotaManager
* quotaManager
= QuotaManager::Get();
616 MOZ_ASSERT(quotaManager
);
619 quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
));
622 void StreamHelper::RunOnBackgroundThread() {
623 AssertIsOnBackgroundThread();
625 nsCOMPtr
<nsIFileRandomAccessStream
> fileRandomAccessStream
;
626 mFileRandomAccessStream
.swap(fileRandomAccessStream
);
628 nsCOMPtr
<nsIRunnable
> callback
;
629 mCallback
.swap(callback
);
634 void StreamHelper::RunOnIOThread() {
635 AssertIsOnIOThread();
636 MOZ_ASSERT(mFileRandomAccessStream
);
638 nsCOMPtr
<nsIInputStream
> inputStream
=
639 do_QueryInterface(mFileRandomAccessStream
);
640 MOZ_ASSERT(inputStream
);
642 nsresult rv
= inputStream
->Close();
643 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
645 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
649 StreamHelper::Run() {
650 MOZ_ASSERT(mCallback
);
652 if (IsOnBackgroundThread()) {
653 RunOnBackgroundThread();
661 /*******************************************************************************
663 ******************************************************************************/
665 Connection::Connection(PersistenceType aPersistenceType
,
666 const PrincipalInfo
& aPrincipalInfo
)
667 : mPrincipalInfo(aPrincipalInfo
),
668 mPersistenceType(aPersistenceType
),
669 mRunningRequest(false),
671 mAllowedToClose(false),
672 mActorDestroyed(false) {
673 AssertIsOnBackgroundThread();
674 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
677 Connection::~Connection() {
678 MOZ_ASSERT(!mRunningRequest
);
680 MOZ_ASSERT(mActorDestroyed
);
683 void Connection::OnNewRequest() {
684 AssertIsOnBackgroundThread();
685 MOZ_ASSERT(!mRunningRequest
);
687 mRunningRequest
= true;
690 void Connection::OnRequestFinished() {
691 AssertIsOnBackgroundThread();
692 MOZ_ASSERT(mRunningRequest
);
694 mRunningRequest
= false;
699 void Connection::OnOpen(
700 const nsACString
& aOrigin
, const nsAString
& aName
,
701 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
702 already_AddRefed
<nsIFileRandomAccessStream
> aFileRandomAccessStream
) {
703 AssertIsOnBackgroundThread();
704 MOZ_ASSERT(!aOrigin
.IsEmpty());
705 MOZ_ASSERT(!aName
.IsEmpty());
706 MOZ_ASSERT(mOrigin
.IsEmpty());
707 MOZ_ASSERT(mName
.IsEmpty());
708 MOZ_ASSERT(!mDirectoryLock
);
709 MOZ_ASSERT(!mFileRandomAccessStream
);
714 mDirectoryLock
= aDirectoryLock
;
715 mFileRandomAccessStream
= aFileRandomAccessStream
;
718 if (!gOpenConnections
) {
719 gOpenConnections
= new ConnectionArray();
722 gOpenConnections
->AppendElement(WrapNotNullUnchecked(this));
725 void Connection::OnClose() {
726 AssertIsOnBackgroundThread();
727 MOZ_ASSERT(!mOrigin
.IsEmpty());
728 MOZ_ASSERT(mDirectoryLock
);
729 MOZ_ASSERT(mFileRandomAccessStream
);
734 mDirectoryLock
= nullptr;
735 mFileRandomAccessStream
= nullptr;
738 MOZ_ASSERT(gOpenConnections
);
739 gOpenConnections
->RemoveElement(this);
741 if (gOpenConnections
->IsEmpty()) {
742 gOpenConnections
= nullptr;
745 if (mAllowedToClose
&& !mActorDestroyed
) {
746 Unused
<< SendClosed();
750 void Connection::AllowToClose() {
751 AssertIsOnBackgroundThread();
753 if (mAllowedToClose
) {
757 mAllowedToClose
= true;
759 if (!mActorDestroyed
) {
760 Unused
<< SendAllowToClose();
766 void Connection::MaybeCloseStream() {
767 AssertIsOnBackgroundThread();
769 if (!mRunningRequest
&& mOpen
&& mAllowedToClose
) {
770 nsCOMPtr
<nsIRunnable
> callback
= NewRunnableMethod(
771 "dom::Connection::OnClose", this, &Connection::OnClose
);
773 RefPtr
<StreamHelper
> helper
=
774 new StreamHelper(mFileRandomAccessStream
, callback
);
775 helper
->AsyncClose();
779 bool Connection::VerifyRequestParams(const SDBRequestParams
& aParams
) const {
780 AssertIsOnBackgroundThread();
781 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
783 switch (aParams
.type()) {
784 case SDBRequestParams::TSDBRequestOpenParams
: {
785 if (NS_WARN_IF(mOpen
)) {
786 MOZ_CRASH_UNLESS_FUZZING();
793 case SDBRequestParams::TSDBRequestSeekParams
:
794 case SDBRequestParams::TSDBRequestReadParams
:
795 case SDBRequestParams::TSDBRequestWriteParams
:
796 case SDBRequestParams::TSDBRequestCloseParams
: {
797 if (NS_WARN_IF(!mOpen
)) {
798 MOZ_CRASH_UNLESS_FUZZING();
806 MOZ_CRASH("Should never get here!");
812 void Connection::ActorDestroy(ActorDestroyReason aWhy
) {
813 AssertIsOnBackgroundThread();
814 MOZ_ASSERT(!mActorDestroyed
);
816 mActorDestroyed
= true;
821 mozilla::ipc::IPCResult
Connection::RecvDeleteMe() {
822 AssertIsOnBackgroundThread();
823 MOZ_ASSERT(!mActorDestroyed
);
825 IProtocol
* mgr
= Manager();
826 if (!PBackgroundSDBConnectionParent::Send__delete__(this)) {
827 return IPC_FAIL_NO_REASON(mgr
);
833 PBackgroundSDBRequestParent
* Connection::AllocPBackgroundSDBRequestParent(
834 const SDBRequestParams
& aParams
) {
835 AssertIsOnBackgroundThread();
836 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
838 if (aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
&&
839 NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
843 if (mAllowedToClose
) {
848 // Always verify parameters in DEBUG builds!
849 bool trustParams
= false;
851 PBackgroundParent
* backgroundActor
= Manager();
852 MOZ_ASSERT(backgroundActor
);
854 bool trustParams
= !BackgroundParent::IsOtherProcessActor(backgroundActor
);
857 if (NS_WARN_IF(!trustParams
&& !VerifyRequestParams(aParams
))) {
858 MOZ_CRASH_UNLESS_FUZZING();
862 if (NS_WARN_IF(mRunningRequest
)) {
863 MOZ_CRASH_UNLESS_FUZZING();
867 QM_TRY(QuotaManager::EnsureCreated(), nullptr);
869 RefPtr
<ConnectionOperationBase
> actor
;
871 switch (aParams
.type()) {
872 case SDBRequestParams::TSDBRequestOpenParams
:
873 actor
= new OpenOp(this, aParams
);
876 case SDBRequestParams::TSDBRequestSeekParams
:
877 actor
= new SeekOp(this, aParams
);
880 case SDBRequestParams::TSDBRequestReadParams
:
881 actor
= new ReadOp(this, aParams
);
884 case SDBRequestParams::TSDBRequestWriteParams
:
885 actor
= new WriteOp(this, aParams
);
888 case SDBRequestParams::TSDBRequestCloseParams
:
889 actor
= new CloseOp(this);
893 MOZ_CRASH("Should never get here!");
896 // Transfer ownership to IPDL.
897 return actor
.forget().take();
900 mozilla::ipc::IPCResult
Connection::RecvPBackgroundSDBRequestConstructor(
901 PBackgroundSDBRequestParent
* aActor
, const SDBRequestParams
& aParams
) {
902 AssertIsOnBackgroundThread();
904 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
905 MOZ_ASSERT_IF(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
,
906 !QuotaClient::IsShuttingDownOnBackgroundThread());
907 MOZ_ASSERT(!mAllowedToClose
);
908 MOZ_ASSERT(!mRunningRequest
);
910 auto* op
= static_cast<ConnectionOperationBase
*>(aActor
);
912 if (NS_WARN_IF(!op
->Init())) {
914 return IPC_FAIL_NO_REASON(this);
917 if (NS_WARN_IF(NS_FAILED(op
->Dispatch()))) {
919 return IPC_FAIL_NO_REASON(this);
925 bool Connection::DeallocPBackgroundSDBRequestParent(
926 PBackgroundSDBRequestParent
* aActor
) {
927 AssertIsOnBackgroundThread();
930 // Transfer ownership back from IPDL.
931 RefPtr
<ConnectionOperationBase
> actor
=
932 dont_AddRef(static_cast<ConnectionOperationBase
*>(aActor
));
936 /*******************************************************************************
937 * ConnectionOperationBase
938 ******************************************************************************/
940 ConnectionOperationBase::~ConnectionOperationBase() {
943 "ConnectionOperationBase::Cleanup() was not called by a subclass!");
944 MOZ_ASSERT(mActorDestroyed
);
947 bool ConnectionOperationBase::Init() {
948 AssertIsOnBackgroundThread();
949 MOZ_ASSERT(mConnection
);
951 mConnection
->OnNewRequest();
956 nsresult
ConnectionOperationBase::Dispatch() {
957 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
958 IsActorDestroyed()) {
959 return NS_ERROR_ABORT
;
962 QuotaManager
* quotaManager
= QuotaManager::Get();
963 MOZ_ASSERT(quotaManager
);
965 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
966 if (NS_WARN_IF(NS_FAILED(rv
))) {
973 void ConnectionOperationBase::Cleanup() {
974 AssertIsOnOwningThread();
975 MOZ_ASSERT(mConnection
);
977 mConnection
->OnRequestFinished();
979 mConnection
= nullptr;
982 void ConnectionOperationBase::SendResults() {
983 AssertIsOnOwningThread();
985 if (IsActorDestroyed()) {
986 MaybeSetFailureCode(NS_ERROR_FAILURE
);
988 SDBRequestResponse response
;
990 if (NS_SUCCEEDED(mResultCode
)) {
991 GetResponse(response
);
993 MOZ_ASSERT(response
.type() != SDBRequestResponse::T__None
);
994 MOZ_ASSERT(response
.type() != SDBRequestResponse::Tnsresult
);
996 response
= mResultCode
;
999 Unused
<< PBackgroundSDBRequestParent::Send__delete__(this, response
);
1001 if (NS_SUCCEEDED(mResultCode
)) {
1009 void ConnectionOperationBase::DatabaseWork() {
1010 AssertIsOnIOThread();
1011 MOZ_ASSERT(NS_SUCCEEDED(mResultCode
));
1013 if (!OperationMayProceed()) {
1014 // The operation was canceled in some way, likely because the child process
1016 mResultCode
= NS_ERROR_ABORT
;
1018 nsIFileRandomAccessStream
* fileRandomAccessStream
=
1019 mConnection
->GetFileRandomAccessStream();
1020 MOZ_ASSERT(fileRandomAccessStream
);
1022 nsresult rv
= DoDatabaseWork(fileRandomAccessStream
);
1023 if (NS_FAILED(rv
)) {
1028 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1031 void ConnectionOperationBase::OnSuccess() { AssertIsOnOwningThread(); }
1034 ConnectionOperationBase::Run() {
1035 if (IsOnBackgroundThread()) {
1044 void ConnectionOperationBase::ActorDestroy(ActorDestroyReason aWhy
) {
1045 AssertIsOnBackgroundThread();
1047 mOperationMayProceed
= false;
1048 mActorDestroyed
= true;
1051 OpenOp::OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1052 : ConnectionOperationBase(aConnection
),
1053 mParams(aParams
.get_SDBRequestOpenParams()),
1054 mState(State::Initial
),
1055 mFileRandomAccessStreamOpen(false) {
1056 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
);
1060 MOZ_ASSERT(!mDirectoryLock
);
1061 MOZ_ASSERT(!mFileRandomAccessStream
);
1062 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1063 MOZ_ASSERT_IF(OperationMayProceed(),
1064 mState
== State::Initial
|| mState
== State::Completed
);
1067 nsresult
OpenOp::Dispatch() {
1068 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1073 nsresult
OpenOp::Open() {
1074 MOZ_ASSERT(NS_IsMainThread());
1075 MOZ_ASSERT(mState
== State::Initial
);
1077 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1078 !OperationMayProceed()) {
1079 return NS_ERROR_ABORT
;
1082 if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled
, false))) {
1083 return NS_ERROR_UNEXPECTED
;
1086 mState
= State::FinishOpen
;
1087 MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1092 nsresult
OpenOp::FinishOpen() {
1093 AssertIsOnOwningThread();
1094 MOZ_ASSERT(mOriginMetadata
.mOrigin
.IsEmpty());
1095 MOZ_ASSERT(!mDirectoryLock
);
1096 MOZ_ASSERT(mState
== State::FinishOpen
);
1098 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1099 IsActorDestroyed()) {
1100 return NS_ERROR_ABORT
;
1103 QuotaManager
* quotaManager
= QuotaManager::Get();
1104 MOZ_ASSERT(quotaManager
);
1106 const PrincipalInfo
& principalInfo
= GetConnection()->GetPrincipalInfo();
1108 PersistenceType persistenceType
= GetConnection()->GetPersistenceType();
1110 if (principalInfo
.type() == PrincipalInfo::TSystemPrincipalInfo
) {
1111 mOriginMetadata
= {QuotaManager::GetInfoForChrome(), persistenceType
};
1113 MOZ_ASSERT(principalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
);
1116 auto principalMetadata
,
1117 quotaManager
->GetInfoFromValidatedPrincipalInfo(principalInfo
));
1119 mOriginMetadata
= {std::move(principalMetadata
), persistenceType
};
1122 if (gOpenConnections
) {
1123 for (const auto& connection
: *gOpenConnections
) {
1124 if (connection
->Origin() == mOriginMetadata
.mOrigin
&&
1125 connection
->Name() == mParams
.name()) {
1126 return NS_ERROR_STORAGE_BUSY
;
1131 // Open the directory
1133 RefPtr
<DirectoryLock
> directoryLock
= quotaManager
->CreateDirectoryLock(
1134 GetConnection()->GetPersistenceType(), mOriginMetadata
,
1135 mozilla::dom::quota::Client::SDB
,
1136 /* aExclusive */ false);
1138 mState
= State::DirectoryOpenPending
;
1139 directoryLock
->Acquire(this);
1144 nsresult
OpenOp::SendToIOThread() {
1145 AssertIsOnOwningThread();
1146 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1148 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1149 IsActorDestroyed()) {
1150 return NS_ERROR_ABORT
;
1153 mFileRandomAccessStream
= new FileRandomAccessStream(
1154 GetConnection()->GetPersistenceType(), mOriginMetadata
,
1155 mozilla::dom::quota::Client::SDB
);
1157 QuotaManager
* quotaManager
= QuotaManager::Get();
1158 MOZ_ASSERT(quotaManager
);
1160 // Must set this before dispatching otherwise we will race with the IO thread.
1161 mState
= State::DatabaseWorkOpen
;
1163 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
1164 if (NS_WARN_IF(NS_FAILED(rv
))) {
1171 nsresult
OpenOp::DatabaseWork() {
1172 AssertIsOnIOThread();
1173 MOZ_ASSERT(mState
== State::DatabaseWorkOpen
);
1174 MOZ_ASSERT(mFileRandomAccessStream
);
1175 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1177 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1178 !OperationMayProceed()) {
1179 return NS_ERROR_ABORT
;
1182 QuotaManager
* quotaManager
= QuotaManager::Get();
1183 MOZ_ASSERT(quotaManager
);
1185 QM_TRY(MOZ_TO_RESULT(quotaManager
->EnsureStorageIsInitialized()));
1188 const auto& dbDirectory
,
1189 ([persistenceType
= GetConnection()->GetPersistenceType(), "aManager
,
1191 -> mozilla::Result
<std::pair
<nsCOMPtr
<nsIFile
>, bool>, nsresult
> {
1192 if (persistenceType
== PERSISTENCE_TYPE_PERSISTENT
) {
1193 QM_TRY_RETURN(quotaManager
->EnsurePersistentOriginIsInitialized(
1198 MOZ_TO_RESULT(quotaManager
->EnsureTemporaryStorageIsInitialized()));
1199 QM_TRY_RETURN(quotaManager
->EnsureTemporaryOriginIsInitialized(
1200 persistenceType
, mOriginMetadata
));
1202 .map([](const auto& res
) { return res
.first
; })));
1205 dbDirectory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1206 if (NS_WARN_IF(NS_FAILED(rv
))) {
1211 rv
= dbDirectory
->Exists(&exists
);
1212 if (NS_WARN_IF(NS_FAILED(rv
))) {
1217 rv
= dbDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
1218 if (NS_WARN_IF(NS_FAILED(rv
))) {
1225 MOZ_ASSERT(NS_SUCCEEDED(dbDirectory
->IsDirectory(&isDirectory
)));
1226 MOZ_ASSERT(isDirectory
);
1230 nsCOMPtr
<nsIFile
> dbFile
;
1231 rv
= dbDirectory
->Clone(getter_AddRefs(dbFile
));
1232 if (NS_WARN_IF(NS_FAILED(rv
))) {
1236 rv
= dbFile
->Append(mParams
.name() + kSDBSuffix
);
1237 if (NS_WARN_IF(NS_FAILED(rv
))) {
1241 nsString databaseFilePath
;
1242 rv
= dbFile
->GetPath(databaseFilePath
);
1243 if (NS_WARN_IF(NS_FAILED(rv
))) {
1247 rv
= mFileRandomAccessStream
->Init(dbFile
, PR_RDWR
| PR_CREATE_FILE
, 0644, 0);
1248 if (NS_WARN_IF(NS_FAILED(rv
))) {
1252 mFileRandomAccessStreamOpen
= true;
1254 rv
= DoDatabaseWork(mFileRandomAccessStream
);
1255 if (NS_WARN_IF(NS_FAILED(rv
))) {
1259 // Must set mState before dispatching otherwise we will race with the owning
1261 mState
= State::SendingResults
;
1263 rv
= OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
);
1264 if (NS_WARN_IF(NS_FAILED(rv
))) {
1271 void OpenOp::StreamClosedCallback() {
1272 AssertIsOnOwningThread();
1273 MOZ_ASSERT(NS_FAILED(ResultCode()));
1274 MOZ_ASSERT(mDirectoryLock
);
1275 MOZ_ASSERT(mFileRandomAccessStream
);
1276 MOZ_ASSERT(mFileRandomAccessStreamOpen
);
1278 mDirectoryLock
= nullptr;
1279 mFileRandomAccessStream
= nullptr;
1280 mFileRandomAccessStreamOpen
= false;
1283 nsresult
OpenOp::DoDatabaseWork(
1284 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1285 AssertIsOnIOThread();
1290 void OpenOp::GetResponse(SDBRequestResponse
& aResponse
) {
1291 AssertIsOnOwningThread();
1293 aResponse
= SDBRequestOpenResponse();
1296 void OpenOp::OnSuccess() {
1297 AssertIsOnOwningThread();
1298 MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
1299 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1300 MOZ_ASSERT(mDirectoryLock
);
1301 MOZ_ASSERT(mFileRandomAccessStream
);
1302 MOZ_ASSERT(mFileRandomAccessStreamOpen
);
1304 RefPtr
<DirectoryLock
> directoryLock
;
1305 nsCOMPtr
<nsIFileRandomAccessStream
> fileRandomAccessStream
;
1307 mDirectoryLock
.swap(directoryLock
);
1308 mFileRandomAccessStream
.swap(fileRandomAccessStream
);
1309 mFileRandomAccessStreamOpen
= false;
1311 GetConnection()->OnOpen(mOriginMetadata
.mOrigin
, mParams
.name(),
1312 directoryLock
.forget(),
1313 fileRandomAccessStream
.forget());
1316 void OpenOp::Cleanup() {
1317 AssertIsOnOwningThread();
1318 MOZ_ASSERT_IF(mFileRandomAccessStreamOpen
, mFileRandomAccessStream
);
1320 if (mFileRandomAccessStream
&& mFileRandomAccessStreamOpen
) {
1321 // If we have an initialized file stream then the operation must have failed
1322 // and there must be a directory lock too.
1323 MOZ_ASSERT(NS_FAILED(ResultCode()));
1324 MOZ_ASSERT(mDirectoryLock
);
1326 // We must close the stream on the I/O thread before releasing it on this
1327 // thread. The directory lock can't be released either.
1328 nsCOMPtr
<nsIRunnable
> callback
=
1329 NewRunnableMethod("dom::OpenOp::StreamClosedCallback", this,
1330 &OpenOp::StreamClosedCallback
);
1332 RefPtr
<StreamHelper
> helper
=
1333 new StreamHelper(mFileRandomAccessStream
, callback
);
1334 helper
->AsyncClose();
1336 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1338 mDirectoryLock
= nullptr;
1339 mFileRandomAccessStream
= nullptr;
1342 ConnectionOperationBase::Cleanup();
1345 NS_IMPL_ISUPPORTS_INHERITED0(OpenOp
, ConnectionOperationBase
)
1352 case State::Initial
:
1356 case State::FinishOpen
:
1360 case State::DatabaseWorkOpen
:
1361 rv
= DatabaseWork();
1364 case State::SendingResults
:
1369 MOZ_CRASH("Bad state!");
1372 if (NS_WARN_IF(NS_FAILED(rv
)) && mState
!= State::SendingResults
) {
1373 MaybeSetFailureCode(rv
);
1375 // Must set mState before dispatching otherwise we will race with the owning
1377 mState
= State::SendingResults
;
1379 if (IsOnOwningThread()) {
1382 MOZ_ALWAYS_SUCCEEDS(
1383 OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1390 void OpenOp::DirectoryLockAcquired(DirectoryLock
* aLock
) {
1391 AssertIsOnOwningThread();
1392 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1393 MOZ_ASSERT(!mDirectoryLock
);
1395 mDirectoryLock
= aLock
;
1397 nsresult rv
= SendToIOThread();
1398 if (NS_WARN_IF(NS_FAILED(rv
))) {
1399 MaybeSetFailureCode(rv
);
1401 // The caller holds a strong reference to us, no need for a self reference
1402 // before calling Run().
1404 mState
= State::SendingResults
;
1405 MOZ_ALWAYS_SUCCEEDS(Run());
1411 void OpenOp::DirectoryLockFailed() {
1412 AssertIsOnOwningThread();
1413 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1414 MOZ_ASSERT(!mDirectoryLock
);
1416 MaybeSetFailureCode(NS_ERROR_FAILURE
);
1418 // The caller holds a strong reference to us, no need for a self reference
1419 // before calling Run().
1421 mState
= State::SendingResults
;
1422 MOZ_ALWAYS_SUCCEEDS(Run());
1425 SeekOp::SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1426 : ConnectionOperationBase(aConnection
),
1427 mParams(aParams
.get_SDBRequestSeekParams()) {
1428 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestSeekParams
);
1431 nsresult
SeekOp::DoDatabaseWork(
1432 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1433 AssertIsOnIOThread();
1434 MOZ_ASSERT(aFileRandomAccessStream
);
1436 nsresult rv
= aFileRandomAccessStream
->Seek(nsISeekableStream::NS_SEEK_SET
,
1439 if (NS_WARN_IF(NS_FAILED(rv
))) {
1446 void SeekOp::GetResponse(SDBRequestResponse
& aResponse
) {
1447 aResponse
= SDBRequestSeekResponse();
1450 ReadOp::ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1451 : ConnectionOperationBase(aConnection
),
1452 mParams(aParams
.get_SDBRequestReadParams()) {
1453 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestReadParams
);
1456 bool ReadOp::Init() {
1457 AssertIsOnOwningThread();
1459 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1463 if (NS_WARN_IF(mParams
.size() > std::numeric_limits
<std::size_t>::max())) {
1467 mOutputStream
= FixedBufferOutputStream::Create(mParams
.size(), fallible
);
1468 if (NS_WARN_IF(!mOutputStream
)) {
1475 nsresult
ReadOp::DoDatabaseWork(
1476 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1477 AssertIsOnIOThread();
1478 MOZ_ASSERT(aFileRandomAccessStream
);
1480 nsCOMPtr
<nsIInputStream
> inputStream
=
1481 do_QueryInterface(aFileRandomAccessStream
);
1482 MOZ_ASSERT(inputStream
);
1486 uint64_t offset
= 0;
1489 char copyBuffer
[kCopyBufferSize
];
1491 uint64_t max
= mParams
.size() - offset
;
1496 uint32_t count
= sizeof(copyBuffer
);
1502 rv
= inputStream
->Read(copyBuffer
, count
, &numRead
);
1503 if (NS_WARN_IF(NS_FAILED(rv
))) {
1512 rv
= mOutputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1513 if (NS_WARN_IF(NS_FAILED(rv
))) {
1517 if (NS_WARN_IF(numWrite
!= numRead
)) {
1518 return NS_ERROR_FAILURE
;
1524 MOZ_ASSERT(offset
== mParams
.size());
1526 MOZ_ALWAYS_SUCCEEDS(mOutputStream
->Close());
1531 void ReadOp::GetResponse(SDBRequestResponse
& aResponse
) {
1532 aResponse
= SDBRequestReadResponse(nsCString(mOutputStream
->WrittenData()));
1535 WriteOp::WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1536 : ConnectionOperationBase(aConnection
),
1537 mParams(aParams
.get_SDBRequestWriteParams()),
1539 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestWriteParams
);
1542 bool WriteOp::Init() {
1543 AssertIsOnOwningThread();
1545 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1549 const nsCString
& string
= mParams
.data();
1551 nsCOMPtr
<nsIInputStream
> inputStream
;
1552 nsresult rv
= NS_NewCStringInputStream(getter_AddRefs(inputStream
), string
);
1553 if (NS_WARN_IF(NS_FAILED(rv
))) {
1557 mInputStream
= std::move(inputStream
);
1558 mSize
= string
.Length();
1563 nsresult
WriteOp::DoDatabaseWork(
1564 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1565 AssertIsOnIOThread();
1566 MOZ_ASSERT(aFileRandomAccessStream
);
1568 nsCOMPtr
<nsIOutputStream
> outputStream
=
1569 do_QueryInterface(aFileRandomAccessStream
);
1570 MOZ_ASSERT(outputStream
);
1575 char copyBuffer
[kCopyBufferSize
];
1578 rv
= mInputStream
->Read(copyBuffer
, sizeof(copyBuffer
), &numRead
);
1579 if (NS_WARN_IF(NS_FAILED(rv
))) {
1588 rv
= outputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1589 if (NS_WARN_IF(NS_FAILED(rv
))) {
1593 if (NS_WARN_IF(numWrite
!= numRead
)) {
1594 return NS_ERROR_FAILURE
;
1598 MOZ_ALWAYS_SUCCEEDS(mInputStream
->Close());
1603 void WriteOp::GetResponse(SDBRequestResponse
& aResponse
) {
1604 aResponse
= SDBRequestWriteResponse();
1607 CloseOp::CloseOp(Connection
* aConnection
)
1608 : ConnectionOperationBase(aConnection
) {}
1610 nsresult
CloseOp::DoDatabaseWork(
1611 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1612 AssertIsOnIOThread();
1613 MOZ_ASSERT(aFileRandomAccessStream
);
1615 nsCOMPtr
<nsIInputStream
> inputStream
=
1616 do_QueryInterface(aFileRandomAccessStream
);
1617 MOZ_ASSERT(inputStream
);
1619 nsresult rv
= inputStream
->Close();
1620 if (NS_WARN_IF(NS_FAILED(rv
))) {
1627 void CloseOp::GetResponse(SDBRequestResponse
& aResponse
) {
1628 aResponse
= SDBRequestCloseResponse();
1631 void CloseOp::OnSuccess() {
1632 AssertIsOnOwningThread();
1634 GetConnection()->OnClose();
1637 /*******************************************************************************
1639 ******************************************************************************/
1641 QuotaClient
* QuotaClient::sInstance
= nullptr;
1643 QuotaClient::QuotaClient() {
1644 AssertIsOnBackgroundThread();
1645 MOZ_ASSERT(!sInstance
, "We expect this to be a singleton!");
1650 QuotaClient::~QuotaClient() {
1651 AssertIsOnBackgroundThread();
1652 MOZ_ASSERT(sInstance
== this, "We expect this to be a singleton!");
1654 sInstance
= nullptr;
1657 mozilla::dom::quota::Client::Type
QuotaClient::GetType() {
1658 return QuotaClient::SDB
;
1661 Result
<UsageInfo
, nsresult
> QuotaClient::InitOrigin(
1662 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1663 const AtomicBool
& aCanceled
) {
1664 AssertIsOnIOThread();
1666 return GetUsageForOrigin(aPersistenceType
, aOriginMetadata
, aCanceled
);
1669 nsresult
QuotaClient::InitOriginWithoutTracking(
1670 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1671 const AtomicBool
& aCanceled
) {
1672 AssertIsOnIOThread();
1677 Result
<UsageInfo
, nsresult
> QuotaClient::GetUsageForOrigin(
1678 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1679 const AtomicBool
& aCanceled
) {
1680 AssertIsOnIOThread();
1681 MOZ_ASSERT(aOriginMetadata
.mPersistenceType
== aPersistenceType
);
1683 QuotaManager
* quotaManager
= QuotaManager::Get();
1684 MOZ_ASSERT(quotaManager
);
1686 QM_TRY_UNWRAP(auto directory
,
1687 quotaManager
->GetOriginDirectory(aOriginMetadata
));
1689 MOZ_ASSERT(directory
);
1692 directory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1693 if (NS_WARN_IF(NS_FAILED(rv
))) {
1697 DebugOnly
<bool> exists
;
1698 MOZ_ASSERT(NS_SUCCEEDED(directory
->Exists(&exists
)) && exists
);
1700 QM_TRY_RETURN(ReduceEachFileAtomicCancelable(
1701 *directory
, aCanceled
, UsageInfo
{},
1702 [](UsageInfo usageInfo
,
1703 const nsCOMPtr
<nsIFile
>& file
) -> Result
<UsageInfo
, nsresult
> {
1704 QM_TRY_INSPECT(const bool& isDirectory
,
1705 MOZ_TO_RESULT_INVOKE_MEMBER(file
, IsDirectory
));
1708 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1713 QM_TRY(MOZ_TO_RESULT(file
->GetLeafName(leafName
)));
1715 if (StringEndsWith(leafName
, kSDBSuffix
)) {
1716 QM_TRY_INSPECT(const int64_t& fileSize
,
1717 MOZ_TO_RESULT_INVOKE_MEMBER(file
, GetFileSize
));
1719 MOZ_ASSERT(fileSize
>= 0);
1722 UsageInfo
{DatabaseUsageType(Some(uint64_t(fileSize
)))};
1725 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1731 void QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType
,
1732 const nsACString
& aOrigin
) {
1733 AssertIsOnIOThread();
1736 void QuotaClient::OnRepositoryClearCompleted(PersistenceType aPersistenceType
) {
1737 AssertIsOnIOThread();
1740 void QuotaClient::ReleaseIOThreadObjects() { AssertIsOnIOThread(); }
1742 void QuotaClient::AbortOperationsForLocks(
1743 const DirectoryLockIdTable
& aDirectoryLockIds
) {
1744 AssertIsOnBackgroundThread();
1746 AllowToCloseConnectionsMatching([&aDirectoryLockIds
](const auto& connection
) {
1747 // If the connections is registered in gOpenConnections then it must have
1748 // a directory lock.
1749 return IsLockForObjectContainedInLockTable(connection
, aDirectoryLockIds
);
1753 void QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId
) {
1754 AssertIsOnBackgroundThread();
1757 void QuotaClient::AbortAllOperations() {
1758 AssertIsOnBackgroundThread();
1760 AllowToCloseConnectionsMatching([](const auto&) { return true; });
1763 void QuotaClient::StartIdleMaintenance() { AssertIsOnBackgroundThread(); }
1765 void QuotaClient::StopIdleMaintenance() { AssertIsOnBackgroundThread(); }
1767 void QuotaClient::InitiateShutdown() {
1768 AssertIsOnBackgroundThread();
1770 if (gOpenConnections
) {
1771 for (const auto& connection
: *gOpenConnections
) {
1772 connection
->AllowToClose();
1777 bool QuotaClient::IsShutdownCompleted() const { return !gOpenConnections
; }
1779 void QuotaClient::ForceKillActors() {
1780 // Currently we don't implement killing actors (are there any to kill here?).
1783 nsCString
QuotaClient::GetShutdownStatus() const {
1784 // XXX Gather information here.
1785 return "To be implemented"_ns
;
1788 void QuotaClient::FinalizeShutdown() {
1789 // Nothing to do here.
1792 } // namespace mozilla::dom