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
, override
)
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
{
307 // Just created on the PBackground thread, dispatched to the main thread.
308 // Next step is FinishOpen.
311 // Ensuring quota manager is created and opening directory on the
312 // PBackground thread. Next step is either SendingResults if quota manager
313 // is not available or DirectoryOpenPending if quota manager is available.
316 // Waiting for directory open allowed on the PBackground thread. The next
317 // step is either SendingResults if directory lock failed to acquire, or
318 // DatabaseWorkOpen if directory lock is acquired.
319 DirectoryOpenPending
,
321 // Waiting to do/doing work on the QuotaManager IO thread. Its next step is
325 // Waiting to send/sending results on the PBackground thread. Next step is
333 const SDBRequestOpenParams mParams
;
334 RefPtr
<DirectoryLock
> mDirectoryLock
;
335 nsCOMPtr
<nsIFileRandomAccessStream
> mFileRandomAccessStream
;
336 // XXX Consider changing this to ClientMetadata.
337 quota::OriginMetadata mOriginMetadata
;
339 bool mFileRandomAccessStreamOpen
;
342 OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
344 nsresult
Dispatch() override
;
351 nsresult
FinishOpen();
353 nsresult
SendToIOThread();
355 nsresult
DatabaseWork();
357 void StreamClosedCallback();
359 // ConnectionOperationBase overrides
360 nsresult
DoDatabaseWork(
361 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
363 void GetResponse(SDBRequestResponse
& aResponse
) override
;
365 void OnSuccess() override
;
367 void Cleanup() override
;
372 void DirectoryLockAcquired(DirectoryLock
* aLock
);
374 void DirectoryLockFailed();
377 class SeekOp final
: public ConnectionOperationBase
{
378 const SDBRequestSeekParams mParams
;
381 SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
384 ~SeekOp() override
= default;
386 nsresult
DoDatabaseWork(
387 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
389 void GetResponse(SDBRequestResponse
& aResponse
) override
;
392 class ReadOp final
: public ConnectionOperationBase
{
393 const SDBRequestReadParams mParams
;
395 RefPtr
<FixedBufferOutputStream
> mOutputStream
;
398 ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
400 bool Init() override
;
403 ~ReadOp() override
= default;
405 nsresult
DoDatabaseWork(
406 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
408 void GetResponse(SDBRequestResponse
& aResponse
) override
;
411 class WriteOp final
: public ConnectionOperationBase
{
412 const SDBRequestWriteParams mParams
;
414 nsCOMPtr
<nsIInputStream
> mInputStream
;
419 WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
421 bool Init() override
;
424 ~WriteOp() override
= default;
426 nsresult
DoDatabaseWork(
427 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
429 void GetResponse(SDBRequestResponse
& aResponse
) override
;
432 class CloseOp final
: public ConnectionOperationBase
{
434 explicit CloseOp(Connection
* aConnection
);
437 ~CloseOp() override
= default;
439 nsresult
DoDatabaseWork(
440 nsIFileRandomAccessStream
* aFileRandomAccessStream
) override
;
442 void GetResponse(SDBRequestResponse
& aResponse
) override
;
444 void OnSuccess() override
;
447 /*******************************************************************************
448 * Other class declarations
449 ******************************************************************************/
451 class QuotaClient final
: public mozilla::dom::quota::Client
{
452 static QuotaClient
* sInstance
;
457 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient
, override
)
459 Type
GetType() override
;
461 Result
<UsageInfo
, nsresult
> InitOrigin(PersistenceType aPersistenceType
,
462 const OriginMetadata
& aOriginMetadata
,
463 const AtomicBool
& aCanceled
) override
;
465 nsresult
InitOriginWithoutTracking(PersistenceType aPersistenceType
,
466 const OriginMetadata
& aOriginMetadata
,
467 const AtomicBool
& aCanceled
) override
;
469 Result
<UsageInfo
, nsresult
> GetUsageForOrigin(
470 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
471 const AtomicBool
& aCanceled
) override
;
473 void OnOriginClearCompleted(PersistenceType aPersistenceType
,
474 const nsACString
& aOrigin
) override
;
476 void OnRepositoryClearCompleted(PersistenceType aPersistenceType
) override
;
478 void ReleaseIOThreadObjects() override
;
480 void AbortOperationsForLocks(
481 const DirectoryLockIdTable
& aDirectoryLockIds
) override
;
483 void AbortOperationsForProcess(ContentParentId aContentParentId
) override
;
485 void AbortAllOperations() override
;
487 void StartIdleMaintenance() override
;
489 void StopIdleMaintenance() override
;
492 ~QuotaClient() override
;
494 void InitiateShutdown() override
;
495 bool IsShutdownCompleted() const override
;
496 nsCString
GetShutdownStatus() const override
;
497 void ForceKillActors() override
;
498 void FinalizeShutdown() override
;
501 /*******************************************************************************
503 ******************************************************************************/
505 using ConnectionArray
= nsTArray
<NotNull
<RefPtr
<Connection
>>>;
507 StaticAutoPtr
<ConnectionArray
> gOpenConnections
;
509 template <typename Condition
>
510 void AllowToCloseConnectionsMatching(const Condition
& aCondition
) {
511 AssertIsOnBackgroundThread();
513 if (gOpenConnections
) {
514 for (const auto& connection
: *gOpenConnections
) {
515 if (aCondition(*connection
)) {
516 connection
->AllowToClose();
524 /*******************************************************************************
526 ******************************************************************************/
528 already_AddRefed
<PBackgroundSDBConnectionParent
>
529 AllocPBackgroundSDBConnectionParent(const PersistenceType
& aPersistenceType
,
530 const PrincipalInfo
& aPrincipalInfo
) {
531 AssertIsOnBackgroundThread();
533 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
537 if (NS_WARN_IF(!IsValidPersistenceType(aPersistenceType
))) {
538 MOZ_CRASH_UNLESS_FUZZING();
542 if (NS_WARN_IF(aPrincipalInfo
.type() == PrincipalInfo::TNullPrincipalInfo
)) {
543 MOZ_CRASH_UNLESS_FUZZING();
547 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo
))) {
548 MOZ_CRASH_UNLESS_FUZZING();
552 RefPtr
<Connection
> actor
= new Connection(aPersistenceType
, aPrincipalInfo
);
554 return actor
.forget();
557 bool RecvPBackgroundSDBConnectionConstructor(
558 PBackgroundSDBConnectionParent
* aActor
,
559 const PersistenceType
& aPersistenceType
,
560 const PrincipalInfo
& aPrincipalInfo
) {
561 AssertIsOnBackgroundThread();
563 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
570 already_AddRefed
<mozilla::dom::quota::Client
> CreateQuotaClient() {
571 AssertIsOnBackgroundThread();
573 RefPtr
<QuotaClient
> client
= new QuotaClient();
574 return client
.forget();
577 } // namespace simpledb
579 /*******************************************************************************
581 ******************************************************************************/
583 StreamHelper::StreamHelper(nsIFileRandomAccessStream
* aFileRandomAccessStream
,
584 nsIRunnable
* aCallback
)
585 : Runnable("dom::StreamHelper"),
586 mOwningEventTarget(GetCurrentSerialEventTarget()),
587 mFileRandomAccessStream(aFileRandomAccessStream
),
588 mCallback(aCallback
) {
589 AssertIsOnBackgroundThread();
590 MOZ_ASSERT(aFileRandomAccessStream
);
591 MOZ_ASSERT(aCallback
);
594 StreamHelper::~StreamHelper() {
595 MOZ_ASSERT(!mFileRandomAccessStream
);
596 MOZ_ASSERT(!mCallback
);
599 void StreamHelper::AsyncClose() {
600 AssertIsOnBackgroundThread();
602 QuotaManager
* quotaManager
= QuotaManager::Get();
603 MOZ_ASSERT(quotaManager
);
606 quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
));
609 void StreamHelper::RunOnBackgroundThread() {
610 AssertIsOnBackgroundThread();
612 nsCOMPtr
<nsIFileRandomAccessStream
> fileRandomAccessStream
;
613 mFileRandomAccessStream
.swap(fileRandomAccessStream
);
615 nsCOMPtr
<nsIRunnable
> callback
;
616 mCallback
.swap(callback
);
621 void StreamHelper::RunOnIOThread() {
622 AssertIsOnIOThread();
623 MOZ_ASSERT(mFileRandomAccessStream
);
625 nsCOMPtr
<nsIInputStream
> inputStream
=
626 do_QueryInterface(mFileRandomAccessStream
);
627 MOZ_ASSERT(inputStream
);
629 nsresult rv
= inputStream
->Close();
630 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
632 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
636 StreamHelper::Run() {
637 MOZ_ASSERT(mCallback
);
639 if (IsOnBackgroundThread()) {
640 RunOnBackgroundThread();
648 /*******************************************************************************
650 ******************************************************************************/
652 Connection::Connection(PersistenceType aPersistenceType
,
653 const PrincipalInfo
& aPrincipalInfo
)
654 : mPrincipalInfo(aPrincipalInfo
),
655 mPersistenceType(aPersistenceType
),
656 mRunningRequest(false),
658 mAllowedToClose(false),
659 mActorDestroyed(false) {
660 AssertIsOnBackgroundThread();
661 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
664 Connection::~Connection() {
665 MOZ_ASSERT(!mRunningRequest
);
667 MOZ_ASSERT(mActorDestroyed
);
670 void Connection::OnNewRequest() {
671 AssertIsOnBackgroundThread();
672 MOZ_ASSERT(!mRunningRequest
);
674 mRunningRequest
= true;
677 void Connection::OnRequestFinished() {
678 AssertIsOnBackgroundThread();
679 MOZ_ASSERT(mRunningRequest
);
681 mRunningRequest
= false;
686 void Connection::OnOpen(
687 const nsACString
& aOrigin
, const nsAString
& aName
,
688 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
689 already_AddRefed
<nsIFileRandomAccessStream
> aFileRandomAccessStream
) {
690 AssertIsOnBackgroundThread();
691 MOZ_ASSERT(!aOrigin
.IsEmpty());
692 MOZ_ASSERT(!aName
.IsEmpty());
693 MOZ_ASSERT(mOrigin
.IsEmpty());
694 MOZ_ASSERT(mName
.IsEmpty());
695 MOZ_ASSERT(!mDirectoryLock
);
696 MOZ_ASSERT(!mFileRandomAccessStream
);
701 mDirectoryLock
= aDirectoryLock
;
702 mFileRandomAccessStream
= aFileRandomAccessStream
;
705 if (!gOpenConnections
) {
706 gOpenConnections
= new ConnectionArray();
709 gOpenConnections
->AppendElement(WrapNotNullUnchecked(this));
712 void Connection::OnClose() {
713 AssertIsOnBackgroundThread();
714 MOZ_ASSERT(!mOrigin
.IsEmpty());
715 MOZ_ASSERT(mDirectoryLock
);
716 MOZ_ASSERT(mFileRandomAccessStream
);
721 mDirectoryLock
= nullptr;
722 mFileRandomAccessStream
= nullptr;
725 MOZ_ASSERT(gOpenConnections
);
726 gOpenConnections
->RemoveElement(this);
728 if (gOpenConnections
->IsEmpty()) {
729 gOpenConnections
= nullptr;
732 if (mAllowedToClose
&& !mActorDestroyed
) {
733 Unused
<< SendClosed();
737 void Connection::AllowToClose() {
738 AssertIsOnBackgroundThread();
740 if (mAllowedToClose
) {
744 mAllowedToClose
= true;
746 if (!mActorDestroyed
) {
747 Unused
<< SendAllowToClose();
753 void Connection::MaybeCloseStream() {
754 AssertIsOnBackgroundThread();
756 if (!mRunningRequest
&& mOpen
&& mAllowedToClose
) {
757 nsCOMPtr
<nsIRunnable
> callback
= NewRunnableMethod(
758 "dom::Connection::OnClose", this, &Connection::OnClose
);
760 RefPtr
<StreamHelper
> helper
=
761 new StreamHelper(mFileRandomAccessStream
, callback
);
762 helper
->AsyncClose();
766 bool Connection::VerifyRequestParams(const SDBRequestParams
& aParams
) const {
767 AssertIsOnBackgroundThread();
768 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
770 switch (aParams
.type()) {
771 case SDBRequestParams::TSDBRequestOpenParams
: {
772 if (NS_WARN_IF(mOpen
)) {
773 MOZ_CRASH_UNLESS_FUZZING();
780 case SDBRequestParams::TSDBRequestSeekParams
:
781 case SDBRequestParams::TSDBRequestReadParams
:
782 case SDBRequestParams::TSDBRequestWriteParams
:
783 case SDBRequestParams::TSDBRequestCloseParams
: {
784 if (NS_WARN_IF(!mOpen
)) {
785 MOZ_CRASH_UNLESS_FUZZING();
793 MOZ_CRASH("Should never get here!");
799 void Connection::ActorDestroy(ActorDestroyReason aWhy
) {
800 AssertIsOnBackgroundThread();
801 MOZ_ASSERT(!mActorDestroyed
);
803 mActorDestroyed
= true;
808 mozilla::ipc::IPCResult
Connection::RecvDeleteMe() {
809 AssertIsOnBackgroundThread();
810 MOZ_ASSERT(!mActorDestroyed
);
812 IProtocol
* mgr
= Manager();
813 if (!PBackgroundSDBConnectionParent::Send__delete__(this)) {
814 return IPC_FAIL_NO_REASON(mgr
);
820 PBackgroundSDBRequestParent
* Connection::AllocPBackgroundSDBRequestParent(
821 const SDBRequestParams
& aParams
) {
822 AssertIsOnBackgroundThread();
823 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
825 if (aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
&&
826 NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
830 if (mAllowedToClose
) {
835 // Always verify parameters in DEBUG builds!
836 bool trustParams
= false;
838 PBackgroundParent
* backgroundActor
= Manager();
839 MOZ_ASSERT(backgroundActor
);
841 bool trustParams
= !BackgroundParent::IsOtherProcessActor(backgroundActor
);
844 if (NS_WARN_IF(!trustParams
&& !VerifyRequestParams(aParams
))) {
845 MOZ_CRASH_UNLESS_FUZZING();
849 if (NS_WARN_IF(mRunningRequest
)) {
850 MOZ_CRASH_UNLESS_FUZZING();
854 QM_TRY(QuotaManager::EnsureCreated(), nullptr);
856 RefPtr
<ConnectionOperationBase
> actor
;
858 switch (aParams
.type()) {
859 case SDBRequestParams::TSDBRequestOpenParams
:
860 actor
= new OpenOp(this, aParams
);
863 case SDBRequestParams::TSDBRequestSeekParams
:
864 actor
= new SeekOp(this, aParams
);
867 case SDBRequestParams::TSDBRequestReadParams
:
868 actor
= new ReadOp(this, aParams
);
871 case SDBRequestParams::TSDBRequestWriteParams
:
872 actor
= new WriteOp(this, aParams
);
875 case SDBRequestParams::TSDBRequestCloseParams
:
876 actor
= new CloseOp(this);
880 MOZ_CRASH("Should never get here!");
883 // Transfer ownership to IPDL.
884 return actor
.forget().take();
887 mozilla::ipc::IPCResult
Connection::RecvPBackgroundSDBRequestConstructor(
888 PBackgroundSDBRequestParent
* aActor
, const SDBRequestParams
& aParams
) {
889 AssertIsOnBackgroundThread();
891 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
892 MOZ_ASSERT_IF(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
,
893 !QuotaClient::IsShuttingDownOnBackgroundThread());
894 MOZ_ASSERT(!mAllowedToClose
);
895 MOZ_ASSERT(!mRunningRequest
);
897 auto* op
= static_cast<ConnectionOperationBase
*>(aActor
);
899 if (NS_WARN_IF(!op
->Init())) {
901 return IPC_FAIL_NO_REASON(this);
904 if (NS_WARN_IF(NS_FAILED(op
->Dispatch()))) {
906 return IPC_FAIL_NO_REASON(this);
912 bool Connection::DeallocPBackgroundSDBRequestParent(
913 PBackgroundSDBRequestParent
* aActor
) {
914 AssertIsOnBackgroundThread();
917 // Transfer ownership back from IPDL.
918 RefPtr
<ConnectionOperationBase
> actor
=
919 dont_AddRef(static_cast<ConnectionOperationBase
*>(aActor
));
923 /*******************************************************************************
924 * ConnectionOperationBase
925 ******************************************************************************/
927 ConnectionOperationBase::~ConnectionOperationBase() {
930 "ConnectionOperationBase::Cleanup() was not called by a subclass!");
931 MOZ_ASSERT(mActorDestroyed
);
934 bool ConnectionOperationBase::Init() {
935 AssertIsOnBackgroundThread();
936 MOZ_ASSERT(mConnection
);
938 mConnection
->OnNewRequest();
943 nsresult
ConnectionOperationBase::Dispatch() {
944 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
945 IsActorDestroyed()) {
946 return NS_ERROR_ABORT
;
949 QuotaManager
* quotaManager
= QuotaManager::Get();
950 MOZ_ASSERT(quotaManager
);
952 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
953 if (NS_WARN_IF(NS_FAILED(rv
))) {
960 void ConnectionOperationBase::Cleanup() {
961 AssertIsOnOwningThread();
962 MOZ_ASSERT(mConnection
);
964 mConnection
->OnRequestFinished();
966 mConnection
= nullptr;
969 void ConnectionOperationBase::SendResults() {
970 AssertIsOnOwningThread();
972 if (IsActorDestroyed()) {
973 MaybeSetFailureCode(NS_ERROR_FAILURE
);
975 SDBRequestResponse response
;
977 if (NS_SUCCEEDED(mResultCode
)) {
978 GetResponse(response
);
980 MOZ_ASSERT(response
.type() != SDBRequestResponse::T__None
);
981 MOZ_ASSERT(response
.type() != SDBRequestResponse::Tnsresult
);
983 response
= mResultCode
;
986 Unused
<< PBackgroundSDBRequestParent::Send__delete__(this, response
);
988 if (NS_SUCCEEDED(mResultCode
)) {
996 void ConnectionOperationBase::DatabaseWork() {
997 AssertIsOnIOThread();
998 MOZ_ASSERT(NS_SUCCEEDED(mResultCode
));
1000 if (!OperationMayProceed()) {
1001 // The operation was canceled in some way, likely because the child process
1003 mResultCode
= NS_ERROR_ABORT
;
1005 nsIFileRandomAccessStream
* fileRandomAccessStream
=
1006 mConnection
->GetFileRandomAccessStream();
1007 MOZ_ASSERT(fileRandomAccessStream
);
1009 nsresult rv
= DoDatabaseWork(fileRandomAccessStream
);
1010 if (NS_FAILED(rv
)) {
1015 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1018 void ConnectionOperationBase::OnSuccess() { AssertIsOnOwningThread(); }
1021 ConnectionOperationBase::Run() {
1022 if (IsOnBackgroundThread()) {
1031 void ConnectionOperationBase::ActorDestroy(ActorDestroyReason aWhy
) {
1032 AssertIsOnBackgroundThread();
1034 mOperationMayProceed
= false;
1035 mActorDestroyed
= true;
1038 OpenOp::OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1039 : ConnectionOperationBase(aConnection
),
1040 mParams(aParams
.get_SDBRequestOpenParams()),
1041 mState(State::Initial
),
1042 mFileRandomAccessStreamOpen(false) {
1043 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
);
1047 MOZ_ASSERT(!mDirectoryLock
);
1048 MOZ_ASSERT(!mFileRandomAccessStream
);
1049 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1050 MOZ_ASSERT_IF(OperationMayProceed(),
1051 mState
== State::Initial
|| mState
== State::Completed
);
1054 nsresult
OpenOp::Dispatch() {
1055 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1060 nsresult
OpenOp::Open() {
1061 MOZ_ASSERT(NS_IsMainThread());
1062 MOZ_ASSERT(mState
== State::Initial
);
1064 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1065 !OperationMayProceed()) {
1066 return NS_ERROR_ABORT
;
1069 if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled
, false))) {
1070 return NS_ERROR_UNEXPECTED
;
1073 mState
= State::FinishOpen
;
1074 MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1079 nsresult
OpenOp::FinishOpen() {
1080 AssertIsOnOwningThread();
1081 MOZ_ASSERT(mOriginMetadata
.mOrigin
.IsEmpty());
1082 MOZ_ASSERT(!mDirectoryLock
);
1083 MOZ_ASSERT(mState
== State::FinishOpen
);
1085 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1086 IsActorDestroyed()) {
1087 return NS_ERROR_ABORT
;
1090 QuotaManager
* quotaManager
= QuotaManager::Get();
1091 MOZ_ASSERT(quotaManager
);
1093 const PrincipalInfo
& principalInfo
= GetConnection()->GetPrincipalInfo();
1095 PersistenceType persistenceType
= GetConnection()->GetPersistenceType();
1097 if (principalInfo
.type() == PrincipalInfo::TSystemPrincipalInfo
) {
1098 mOriginMetadata
= {QuotaManager::GetInfoForChrome(), persistenceType
};
1100 MOZ_ASSERT(principalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
);
1103 auto principalMetadata
,
1104 quotaManager
->GetInfoFromValidatedPrincipalInfo(principalInfo
));
1106 mOriginMetadata
= {std::move(principalMetadata
), persistenceType
};
1109 if (gOpenConnections
) {
1110 for (const auto& connection
: *gOpenConnections
) {
1111 if (connection
->Origin() == mOriginMetadata
.mOrigin
&&
1112 connection
->Name() == mParams
.name()) {
1113 return NS_ERROR_STORAGE_BUSY
;
1118 // Open the directory
1120 mState
= State::DirectoryOpenPending
;
1123 ->OpenClientDirectory({mOriginMetadata
, mozilla::dom::quota::Client::SDB
})
1125 GetCurrentSerialEventTarget(), __func__
,
1126 [self
= RefPtr(this)](
1127 const ClientDirectoryLockPromise::ResolveOrRejectValue
& aValue
) {
1128 if (aValue
.IsResolve()) {
1129 self
->DirectoryLockAcquired(aValue
.ResolveValue());
1131 self
->DirectoryLockFailed();
1138 nsresult
OpenOp::SendToIOThread() {
1139 AssertIsOnOwningThread();
1140 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1142 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1143 IsActorDestroyed()) {
1144 return NS_ERROR_ABORT
;
1147 mFileRandomAccessStream
= new FileRandomAccessStream(
1148 GetConnection()->GetPersistenceType(), mOriginMetadata
,
1149 mozilla::dom::quota::Client::SDB
);
1151 QuotaManager
* quotaManager
= QuotaManager::Get();
1152 MOZ_ASSERT(quotaManager
);
1154 // Must set this before dispatching otherwise we will race with the IO thread.
1155 mState
= State::DatabaseWorkOpen
;
1157 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
1158 if (NS_WARN_IF(NS_FAILED(rv
))) {
1165 nsresult
OpenOp::DatabaseWork() {
1166 AssertIsOnIOThread();
1167 MOZ_ASSERT(mState
== State::DatabaseWorkOpen
);
1168 MOZ_ASSERT(mFileRandomAccessStream
);
1169 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1171 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1172 !OperationMayProceed()) {
1173 return NS_ERROR_ABORT
;
1176 QuotaManager
* quotaManager
= QuotaManager::Get();
1177 MOZ_ASSERT(quotaManager
);
1180 const auto& dbDirectory
,
1181 ([persistenceType
= GetConnection()->GetPersistenceType(), "aManager
,
1183 -> mozilla::Result
<std::pair
<nsCOMPtr
<nsIFile
>, bool>, nsresult
> {
1184 if (persistenceType
== PERSISTENCE_TYPE_PERSISTENT
) {
1185 QM_TRY_RETURN(quotaManager
->EnsurePersistentOriginIsInitialized(
1189 QM_TRY(MOZ_TO_RESULT(
1190 quotaManager
->EnsureTemporaryStorageIsInitializedInternal()));
1191 QM_TRY_RETURN(quotaManager
->EnsureTemporaryOriginIsInitialized(
1192 persistenceType
, mOriginMetadata
));
1194 .map([](const auto& res
) { return res
.first
; })));
1197 dbDirectory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1198 if (NS_WARN_IF(NS_FAILED(rv
))) {
1203 rv
= dbDirectory
->Exists(&exists
);
1204 if (NS_WARN_IF(NS_FAILED(rv
))) {
1209 rv
= dbDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
1210 if (NS_WARN_IF(NS_FAILED(rv
))) {
1217 MOZ_ASSERT(NS_SUCCEEDED(dbDirectory
->IsDirectory(&isDirectory
)));
1218 MOZ_ASSERT(isDirectory
);
1222 nsCOMPtr
<nsIFile
> dbFile
;
1223 rv
= dbDirectory
->Clone(getter_AddRefs(dbFile
));
1224 if (NS_WARN_IF(NS_FAILED(rv
))) {
1228 rv
= dbFile
->Append(mParams
.name() + kSDBSuffix
);
1229 if (NS_WARN_IF(NS_FAILED(rv
))) {
1233 nsString databaseFilePath
;
1234 rv
= dbFile
->GetPath(databaseFilePath
);
1235 if (NS_WARN_IF(NS_FAILED(rv
))) {
1239 rv
= mFileRandomAccessStream
->Init(dbFile
, PR_RDWR
| PR_CREATE_FILE
, 0644, 0);
1240 if (NS_WARN_IF(NS_FAILED(rv
))) {
1244 mFileRandomAccessStreamOpen
= true;
1246 rv
= DoDatabaseWork(mFileRandomAccessStream
);
1247 if (NS_WARN_IF(NS_FAILED(rv
))) {
1251 // Must set mState before dispatching otherwise we will race with the owning
1253 mState
= State::SendingResults
;
1255 rv
= OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
);
1256 if (NS_WARN_IF(NS_FAILED(rv
))) {
1263 void OpenOp::StreamClosedCallback() {
1264 AssertIsOnOwningThread();
1265 MOZ_ASSERT(NS_FAILED(ResultCode()));
1266 MOZ_ASSERT(mDirectoryLock
);
1267 MOZ_ASSERT(mFileRandomAccessStream
);
1268 MOZ_ASSERT(mFileRandomAccessStreamOpen
);
1270 mDirectoryLock
= nullptr;
1271 mFileRandomAccessStream
= nullptr;
1272 mFileRandomAccessStreamOpen
= false;
1275 nsresult
OpenOp::DoDatabaseWork(
1276 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1277 AssertIsOnIOThread();
1282 void OpenOp::GetResponse(SDBRequestResponse
& aResponse
) {
1283 AssertIsOnOwningThread();
1285 aResponse
= SDBRequestOpenResponse();
1288 void OpenOp::OnSuccess() {
1289 AssertIsOnOwningThread();
1290 MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
1291 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1292 MOZ_ASSERT(mDirectoryLock
);
1293 MOZ_ASSERT(mFileRandomAccessStream
);
1294 MOZ_ASSERT(mFileRandomAccessStreamOpen
);
1296 RefPtr
<DirectoryLock
> directoryLock
;
1297 nsCOMPtr
<nsIFileRandomAccessStream
> fileRandomAccessStream
;
1299 mDirectoryLock
.swap(directoryLock
);
1300 mFileRandomAccessStream
.swap(fileRandomAccessStream
);
1301 mFileRandomAccessStreamOpen
= false;
1303 GetConnection()->OnOpen(mOriginMetadata
.mOrigin
, mParams
.name(),
1304 directoryLock
.forget(),
1305 fileRandomAccessStream
.forget());
1308 void OpenOp::Cleanup() {
1309 AssertIsOnOwningThread();
1310 MOZ_ASSERT_IF(mFileRandomAccessStreamOpen
, mFileRandomAccessStream
);
1312 if (mFileRandomAccessStream
&& mFileRandomAccessStreamOpen
) {
1313 // If we have an initialized file stream then the operation must have failed
1314 // and there must be a directory lock too.
1315 MOZ_ASSERT(NS_FAILED(ResultCode()));
1316 MOZ_ASSERT(mDirectoryLock
);
1318 // We must close the stream on the I/O thread before releasing it on this
1319 // thread. The directory lock can't be released either.
1320 nsCOMPtr
<nsIRunnable
> callback
=
1321 NewRunnableMethod("dom::OpenOp::StreamClosedCallback", this,
1322 &OpenOp::StreamClosedCallback
);
1324 RefPtr
<StreamHelper
> helper
=
1325 new StreamHelper(mFileRandomAccessStream
, callback
);
1326 helper
->AsyncClose();
1328 MOZ_ASSERT(!mFileRandomAccessStreamOpen
);
1330 mDirectoryLock
= nullptr;
1331 mFileRandomAccessStream
= nullptr;
1334 ConnectionOperationBase::Cleanup();
1342 case State::Initial
:
1346 case State::FinishOpen
:
1350 case State::DatabaseWorkOpen
:
1351 rv
= DatabaseWork();
1354 case State::SendingResults
:
1359 MOZ_CRASH("Bad state!");
1362 if (NS_WARN_IF(NS_FAILED(rv
)) && mState
!= State::SendingResults
) {
1363 MaybeSetFailureCode(rv
);
1365 // Must set mState before dispatching otherwise we will race with the owning
1367 mState
= State::SendingResults
;
1369 if (IsOnOwningThread()) {
1372 MOZ_ALWAYS_SUCCEEDS(
1373 OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1380 void OpenOp::DirectoryLockAcquired(DirectoryLock
* aLock
) {
1381 AssertIsOnOwningThread();
1382 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1383 MOZ_ASSERT(!mDirectoryLock
);
1385 mDirectoryLock
= aLock
;
1387 nsresult rv
= SendToIOThread();
1388 if (NS_WARN_IF(NS_FAILED(rv
))) {
1389 MaybeSetFailureCode(rv
);
1391 // The caller holds a strong reference to us, no need for a self reference
1392 // before calling Run().
1394 mState
= State::SendingResults
;
1395 MOZ_ALWAYS_SUCCEEDS(Run());
1401 void OpenOp::DirectoryLockFailed() {
1402 AssertIsOnOwningThread();
1403 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1404 MOZ_ASSERT(!mDirectoryLock
);
1406 MaybeSetFailureCode(NS_ERROR_FAILURE
);
1408 // The caller holds a strong reference to us, no need for a self reference
1409 // before calling Run().
1411 mState
= State::SendingResults
;
1412 MOZ_ALWAYS_SUCCEEDS(Run());
1415 SeekOp::SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1416 : ConnectionOperationBase(aConnection
),
1417 mParams(aParams
.get_SDBRequestSeekParams()) {
1418 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestSeekParams
);
1421 nsresult
SeekOp::DoDatabaseWork(
1422 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1423 AssertIsOnIOThread();
1424 MOZ_ASSERT(aFileRandomAccessStream
);
1426 nsresult rv
= aFileRandomAccessStream
->Seek(nsISeekableStream::NS_SEEK_SET
,
1429 if (NS_WARN_IF(NS_FAILED(rv
))) {
1436 void SeekOp::GetResponse(SDBRequestResponse
& aResponse
) {
1437 aResponse
= SDBRequestSeekResponse();
1440 ReadOp::ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1441 : ConnectionOperationBase(aConnection
),
1442 mParams(aParams
.get_SDBRequestReadParams()) {
1443 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestReadParams
);
1446 bool ReadOp::Init() {
1447 AssertIsOnOwningThread();
1449 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1453 if (NS_WARN_IF(mParams
.size() > std::numeric_limits
<std::size_t>::max())) {
1457 mOutputStream
= FixedBufferOutputStream::Create(mParams
.size(), fallible
);
1458 if (NS_WARN_IF(!mOutputStream
)) {
1465 nsresult
ReadOp::DoDatabaseWork(
1466 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1467 AssertIsOnIOThread();
1468 MOZ_ASSERT(aFileRandomAccessStream
);
1470 nsCOMPtr
<nsIInputStream
> inputStream
=
1471 do_QueryInterface(aFileRandomAccessStream
);
1472 MOZ_ASSERT(inputStream
);
1476 uint64_t offset
= 0;
1479 char copyBuffer
[kCopyBufferSize
];
1481 uint64_t max
= mParams
.size() - offset
;
1486 uint32_t count
= sizeof(copyBuffer
);
1492 rv
= inputStream
->Read(copyBuffer
, count
, &numRead
);
1493 if (NS_WARN_IF(NS_FAILED(rv
))) {
1502 rv
= mOutputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1503 if (NS_WARN_IF(NS_FAILED(rv
))) {
1507 if (NS_WARN_IF(numWrite
!= numRead
)) {
1508 return NS_ERROR_FAILURE
;
1514 MOZ_ASSERT(offset
== mParams
.size());
1516 MOZ_ALWAYS_SUCCEEDS(mOutputStream
->Close());
1521 void ReadOp::GetResponse(SDBRequestResponse
& aResponse
) {
1522 aResponse
= SDBRequestReadResponse(nsCString(mOutputStream
->WrittenData()));
1525 WriteOp::WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1526 : ConnectionOperationBase(aConnection
),
1527 mParams(aParams
.get_SDBRequestWriteParams()),
1529 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestWriteParams
);
1532 bool WriteOp::Init() {
1533 AssertIsOnOwningThread();
1535 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1539 const nsCString
& string
= mParams
.data();
1541 nsCOMPtr
<nsIInputStream
> inputStream
;
1542 nsresult rv
= NS_NewCStringInputStream(getter_AddRefs(inputStream
), string
);
1543 if (NS_WARN_IF(NS_FAILED(rv
))) {
1547 mInputStream
= std::move(inputStream
);
1548 mSize
= string
.Length();
1553 nsresult
WriteOp::DoDatabaseWork(
1554 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1555 AssertIsOnIOThread();
1556 MOZ_ASSERT(aFileRandomAccessStream
);
1558 nsCOMPtr
<nsIOutputStream
> outputStream
=
1559 do_QueryInterface(aFileRandomAccessStream
);
1560 MOZ_ASSERT(outputStream
);
1565 char copyBuffer
[kCopyBufferSize
];
1568 rv
= mInputStream
->Read(copyBuffer
, sizeof(copyBuffer
), &numRead
);
1569 if (NS_WARN_IF(NS_FAILED(rv
))) {
1578 rv
= outputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1579 if (NS_WARN_IF(NS_FAILED(rv
))) {
1583 if (NS_WARN_IF(numWrite
!= numRead
)) {
1584 return NS_ERROR_FAILURE
;
1588 MOZ_ALWAYS_SUCCEEDS(mInputStream
->Close());
1593 void WriteOp::GetResponse(SDBRequestResponse
& aResponse
) {
1594 aResponse
= SDBRequestWriteResponse();
1597 CloseOp::CloseOp(Connection
* aConnection
)
1598 : ConnectionOperationBase(aConnection
) {}
1600 nsresult
CloseOp::DoDatabaseWork(
1601 nsIFileRandomAccessStream
* aFileRandomAccessStream
) {
1602 AssertIsOnIOThread();
1603 MOZ_ASSERT(aFileRandomAccessStream
);
1605 nsCOMPtr
<nsIInputStream
> inputStream
=
1606 do_QueryInterface(aFileRandomAccessStream
);
1607 MOZ_ASSERT(inputStream
);
1609 nsresult rv
= inputStream
->Close();
1610 if (NS_WARN_IF(NS_FAILED(rv
))) {
1617 void CloseOp::GetResponse(SDBRequestResponse
& aResponse
) {
1618 aResponse
= SDBRequestCloseResponse();
1621 void CloseOp::OnSuccess() {
1622 AssertIsOnOwningThread();
1624 GetConnection()->OnClose();
1627 /*******************************************************************************
1629 ******************************************************************************/
1631 QuotaClient
* QuotaClient::sInstance
= nullptr;
1633 QuotaClient::QuotaClient() {
1634 AssertIsOnBackgroundThread();
1635 MOZ_ASSERT(!sInstance
, "We expect this to be a singleton!");
1640 QuotaClient::~QuotaClient() {
1641 AssertIsOnBackgroundThread();
1642 MOZ_ASSERT(sInstance
== this, "We expect this to be a singleton!");
1644 sInstance
= nullptr;
1647 mozilla::dom::quota::Client::Type
QuotaClient::GetType() {
1648 return QuotaClient::SDB
;
1651 Result
<UsageInfo
, nsresult
> QuotaClient::InitOrigin(
1652 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1653 const AtomicBool
& aCanceled
) {
1654 AssertIsOnIOThread();
1656 return GetUsageForOrigin(aPersistenceType
, aOriginMetadata
, aCanceled
);
1659 nsresult
QuotaClient::InitOriginWithoutTracking(
1660 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1661 const AtomicBool
& aCanceled
) {
1662 AssertIsOnIOThread();
1667 Result
<UsageInfo
, nsresult
> QuotaClient::GetUsageForOrigin(
1668 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1669 const AtomicBool
& aCanceled
) {
1670 AssertIsOnIOThread();
1671 MOZ_ASSERT(aOriginMetadata
.mPersistenceType
== aPersistenceType
);
1673 QuotaManager
* quotaManager
= QuotaManager::Get();
1674 MOZ_ASSERT(quotaManager
);
1676 QM_TRY_UNWRAP(auto directory
,
1677 quotaManager
->GetOriginDirectory(aOriginMetadata
));
1679 MOZ_ASSERT(directory
);
1682 directory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1683 if (NS_WARN_IF(NS_FAILED(rv
))) {
1687 DebugOnly
<bool> exists
;
1688 MOZ_ASSERT(NS_SUCCEEDED(directory
->Exists(&exists
)) && exists
);
1690 QM_TRY_RETURN(ReduceEachFileAtomicCancelable(
1691 *directory
, aCanceled
, UsageInfo
{},
1692 [](UsageInfo usageInfo
,
1693 const nsCOMPtr
<nsIFile
>& file
) -> Result
<UsageInfo
, nsresult
> {
1694 QM_TRY_INSPECT(const bool& isDirectory
,
1695 MOZ_TO_RESULT_INVOKE_MEMBER(file
, IsDirectory
));
1698 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1703 QM_TRY(MOZ_TO_RESULT(file
->GetLeafName(leafName
)));
1705 if (StringEndsWith(leafName
, kSDBSuffix
)) {
1706 QM_TRY_INSPECT(const int64_t& fileSize
,
1707 MOZ_TO_RESULT_INVOKE_MEMBER(file
, GetFileSize
));
1709 MOZ_ASSERT(fileSize
>= 0);
1712 UsageInfo
{DatabaseUsageType(Some(uint64_t(fileSize
)))};
1715 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1721 void QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType
,
1722 const nsACString
& aOrigin
) {
1723 AssertIsOnIOThread();
1726 void QuotaClient::OnRepositoryClearCompleted(PersistenceType aPersistenceType
) {
1727 AssertIsOnIOThread();
1730 void QuotaClient::ReleaseIOThreadObjects() { AssertIsOnIOThread(); }
1732 void QuotaClient::AbortOperationsForLocks(
1733 const DirectoryLockIdTable
& aDirectoryLockIds
) {
1734 AssertIsOnBackgroundThread();
1736 AllowToCloseConnectionsMatching([&aDirectoryLockIds
](const auto& connection
) {
1737 // If the connections is registered in gOpenConnections then it must have
1738 // a directory lock.
1739 return IsLockForObjectContainedInLockTable(connection
, aDirectoryLockIds
);
1743 void QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId
) {
1744 AssertIsOnBackgroundThread();
1747 void QuotaClient::AbortAllOperations() {
1748 AssertIsOnBackgroundThread();
1750 AllowToCloseConnectionsMatching([](const auto&) { return true; });
1753 void QuotaClient::StartIdleMaintenance() { AssertIsOnBackgroundThread(); }
1755 void QuotaClient::StopIdleMaintenance() { AssertIsOnBackgroundThread(); }
1757 void QuotaClient::InitiateShutdown() {
1758 AssertIsOnBackgroundThread();
1760 if (gOpenConnections
) {
1761 for (const auto& connection
: *gOpenConnections
) {
1762 connection
->AllowToClose();
1767 bool QuotaClient::IsShutdownCompleted() const { return !gOpenConnections
; }
1769 void QuotaClient::ForceKillActors() {
1770 // Currently we don't implement killing actors (are there any to kill here?).
1773 nsCString
QuotaClient::GetShutdownStatus() const {
1774 // XXX Gather information here.
1775 return "To be implemented"_ns
;
1778 void QuotaClient::FinalizeShutdown() {
1779 // Nothing to do here.
1782 } // namespace mozilla::dom