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/Maybe.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/RefPtr.h"
26 #include "mozilla/Result.h"
27 #include "mozilla/ResultExtensions.h"
28 #include "mozilla/SpinEventLoopUntil.h"
29 #include "mozilla/StaticPtr.h"
30 #include "mozilla/Unused.h"
31 #include "mozilla/Variant.h"
32 #include "mozilla/dom/PBackgroundSDBConnection.h"
33 #include "mozilla/dom/PBackgroundSDBConnectionParent.h"
34 #include "mozilla/dom/PBackgroundSDBRequestParent.h"
35 #include "mozilla/dom/ipc/IdType.h"
36 #include "mozilla/dom/quota/Client.h"
37 #include "mozilla/dom/quota/ClientImpl.h"
38 #include "mozilla/dom/quota/DirectoryLock.h"
39 #include "mozilla/dom/quota/FileStreams.h"
40 #include "mozilla/dom/quota/MemoryOutputStream.h"
41 #include "mozilla/dom/quota/QuotaCommon.h"
42 #include "mozilla/dom/quota/QuotaManager.h"
43 #include "mozilla/dom/quota/UsageInfo.h"
44 #include "mozilla/ipc/BackgroundParent.h"
45 #include "mozilla/ipc/BackgroundUtils.h"
46 #include "mozilla/ipc/PBackgroundParent.h"
47 #include "mozilla/ipc/PBackgroundSharedTypes.h"
48 #include "mozilla/ipc/ProtocolUtils.h"
52 #include "nsIDirectoryEnumerator.h"
53 #include "nsIEventTarget.h"
55 #include "nsIFileStreams.h"
56 #include "nsIInputStream.h"
57 #include "nsIOutputStream.h"
58 #include "nsIRunnable.h"
59 #include "nsISeekableStream.h"
60 #include "nsISupports.h"
61 #include "nsIThread.h"
62 #include "nsLiteralString.h"
64 #include "nsStringFwd.h"
65 #include "nsStringStream.h"
67 #include "nsTLiteralString.h"
68 #include "nsTStringRepr.h"
69 #include "nsThreadUtils.h"
73 #define DISABLE_ASSERTS_FOR_FUZZING 0
75 #if DISABLE_ASSERTS_FOR_FUZZING
76 # define ASSERT_UNLESS_FUZZING(...) \
80 # define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
83 namespace mozilla::dom
{
85 using namespace mozilla::dom::quota
;
86 using namespace mozilla::ipc
;
90 /*******************************************************************************
92 ******************************************************************************/
94 const uint32_t kCopyBufferSize
= 32768;
96 constexpr auto kSDBSuffix
= u
".sdb"_ns
;
98 /*******************************************************************************
99 * Actor class declarations
100 ******************************************************************************/
102 class StreamHelper final
: public Runnable
{
103 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
104 nsCOMPtr
<nsIFileStream
> mFileStream
;
105 nsCOMPtr
<nsIRunnable
> mCallback
;
108 StreamHelper(nsIFileStream
* aFileStream
, nsIRunnable
* aCallback
);
113 ~StreamHelper() override
;
115 void RunOnBackgroundThread();
117 void RunOnIOThread();
122 class Connection final
: public PBackgroundSDBConnectionParent
{
123 RefPtr
<DirectoryLock
> mDirectoryLock
;
124 nsCOMPtr
<nsIFileStream
> mFileStream
;
125 const PrincipalInfo mPrincipalInfo
;
129 PersistenceType mPersistenceType
;
130 bool mRunningRequest
;
132 bool mAllowedToClose
;
133 bool mActorDestroyed
;
136 Connection(PersistenceType aPersistenceType
,
137 const PrincipalInfo
& aPrincipalInfo
);
139 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::Connection
)
141 Maybe
<DirectoryLock
&> MaybeDirectoryLockRef() const {
142 AssertIsOnBackgroundThread();
144 return ToMaybeRef(mDirectoryLock
.get());
147 nsIFileStream
* GetFileStream() const {
148 AssertIsOnIOThread();
153 PersistenceType
GetPersistenceType() const { return mPersistenceType
; }
155 const PrincipalInfo
& GetPrincipalInfo() const {
156 MOZ_ASSERT(NS_IsMainThread());
158 return mPrincipalInfo
;
161 const nsCString
& Origin() const {
162 AssertIsOnBackgroundThread();
163 MOZ_ASSERT(!mOrigin
.IsEmpty());
168 const nsString
& Name() const {
169 AssertIsOnBackgroundThread();
170 MOZ_ASSERT(!mName
.IsEmpty());
177 void OnRequestFinished();
179 void OnOpen(const nsACString
& aOrigin
, const nsAString
& aName
,
180 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
181 already_AddRefed
<nsIFileStream
> aFileStream
);
190 void MaybeCloseStream();
192 bool VerifyRequestParams(const SDBRequestParams
& aParams
) const;
195 virtual void ActorDestroy(ActorDestroyReason aWhy
) override
;
197 mozilla::ipc::IPCResult
RecvDeleteMe() override
;
199 virtual PBackgroundSDBRequestParent
* AllocPBackgroundSDBRequestParent(
200 const SDBRequestParams
& aParams
) override
;
202 virtual mozilla::ipc::IPCResult
RecvPBackgroundSDBRequestConstructor(
203 PBackgroundSDBRequestParent
* aActor
,
204 const SDBRequestParams
& aParams
) override
;
206 virtual bool DeallocPBackgroundSDBRequestParent(
207 PBackgroundSDBRequestParent
* aActor
) override
;
210 class ConnectionOperationBase
: public Runnable
,
211 public PBackgroundSDBRequestParent
{
212 nsCOMPtr
<nsIEventTarget
> mOwningEventTarget
;
213 RefPtr
<Connection
> mConnection
;
214 nsresult mResultCode
;
215 Atomic
<bool> mOperationMayProceed
;
216 bool mActorDestroyed
;
219 nsIEventTarget
* OwningEventTarget() const {
220 MOZ_ASSERT(mOwningEventTarget
);
222 return mOwningEventTarget
;
225 bool IsOnOwningThread() const {
226 MOZ_ASSERT(mOwningEventTarget
);
229 return NS_SUCCEEDED(mOwningEventTarget
->IsOnCurrentThread(¤t
)) &&
233 void AssertIsOnOwningThread() const {
234 MOZ_ASSERT(IsOnBackgroundThread());
235 MOZ_ASSERT(IsOnOwningThread());
238 Connection
* GetConnection() const {
239 MOZ_ASSERT(mConnection
);
244 nsresult
ResultCode() const { return mResultCode
; }
246 void MaybeSetFailureCode(nsresult aErrorCode
) {
247 MOZ_ASSERT(NS_FAILED(aErrorCode
));
249 if (NS_SUCCEEDED(mResultCode
)) {
250 mResultCode
= aErrorCode
;
254 // May be called on any thread, but you should call IsActorDestroyed() if
255 // you know you're on the background thread because it is slightly faster.
256 bool OperationMayProceed() const { return mOperationMayProceed
; }
258 bool IsActorDestroyed() const {
259 AssertIsOnOwningThread();
261 return mActorDestroyed
;
264 // May be overridden by subclasses if they need to perform work on the
265 // background thread before being dispatched but must always call the base
266 // class implementation. Returning false will kill the child actors and
270 virtual nsresult
Dispatch();
272 // This callback will be called on the background thread before releasing the
273 // final reference to this request object. Subclasses may perform any
274 // additional cleanup here but must always call the base class implementation.
275 virtual void Cleanup();
278 ConnectionOperationBase(Connection
* aConnection
)
279 : Runnable("dom::ConnectionOperationBase"),
280 mOwningEventTarget(GetCurrentEventTarget()),
281 mConnection(aConnection
),
283 mOperationMayProceed(true),
284 mActorDestroyed(false) {
285 AssertIsOnOwningThread();
288 ~ConnectionOperationBase() override
;
294 // Methods that subclasses must implement.
295 virtual nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) = 0;
297 // Subclasses use this override to set the IPDL response value.
298 virtual void GetResponse(SDBRequestResponse
& aResponse
) = 0;
300 // A method that subclasses may implement.
301 virtual void OnSuccess();
308 void ActorDestroy(ActorDestroyReason aWhy
) override
;
311 class OpenOp final
: public ConnectionOperationBase
,
312 public OpenDirectoryListener
{
314 // Just created on the PBackground thread, dispatched to the main thread.
315 // Next step is FinishOpen.
318 // Opening directory or initializing quota manager on the PBackground
319 // thread. Next step is either DirectoryOpenPending if quota manager is
320 // already initialized or QuotaManagerPending if quota manager needs to be
324 // Waiting for quota manager initialization to complete on the PBackground
325 // thread. Next step is either SendingResults if initialization failed or
326 // DirectoryOpenPending if initialization succeeded.
329 // Waiting for directory open allowed on the PBackground thread. The next
330 // step is either SendingResults if directory lock failed to acquire, or
331 // DatabaseWorkOpen if directory lock is acquired.
332 DirectoryOpenPending
,
334 // Waiting to do/doing work on the QuotaManager IO thread. Its next step is
338 // Waiting to send/sending results on the PBackground thread. Next step is
346 const SDBRequestOpenParams mParams
;
347 RefPtr
<DirectoryLock
> mDirectoryLock
;
348 nsCOMPtr
<nsIFileStream
> mFileStream
;
349 // XXX Consider changing this to ClientMetadata.
350 quota::OriginMetadata mOriginMetadata
;
352 bool mFileStreamOpen
;
355 OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
357 nsresult
Dispatch() override
;
364 nsresult
FinishOpen();
366 nsresult
QuotaManagerOpen();
368 nsresult
OpenDirectory();
370 nsresult
SendToIOThread();
372 nsresult
DatabaseWork();
374 void StreamClosedCallback();
376 // ConnectionOperationBase overrides
377 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
379 void GetResponse(SDBRequestResponse
& aResponse
) override
;
381 void OnSuccess() override
;
383 void Cleanup() override
;
385 NS_DECL_ISUPPORTS_INHERITED
390 // OpenDirectoryListener overrides.
391 void DirectoryLockAcquired(DirectoryLock
* aLock
) override
;
393 void DirectoryLockFailed() override
;
396 class SeekOp final
: public ConnectionOperationBase
{
397 const SDBRequestSeekParams mParams
;
400 SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
403 ~SeekOp() override
= default;
405 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
407 void GetResponse(SDBRequestResponse
& aResponse
) override
;
410 class ReadOp final
: public ConnectionOperationBase
{
411 const SDBRequestReadParams mParams
;
413 RefPtr
<MemoryOutputStream
> mOutputStream
;
416 ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
418 bool Init() override
;
421 ~ReadOp() override
= default;
423 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
425 void GetResponse(SDBRequestResponse
& aResponse
) override
;
428 class WriteOp final
: public ConnectionOperationBase
{
429 const SDBRequestWriteParams mParams
;
431 nsCOMPtr
<nsIInputStream
> mInputStream
;
436 WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
);
438 bool Init() override
;
441 ~WriteOp() override
= default;
443 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
445 void GetResponse(SDBRequestResponse
& aResponse
) override
;
448 class CloseOp final
: public ConnectionOperationBase
{
450 explicit CloseOp(Connection
* aConnection
);
453 ~CloseOp() override
= default;
455 nsresult
DoDatabaseWork(nsIFileStream
* aFileStream
) override
;
457 void GetResponse(SDBRequestResponse
& aResponse
) override
;
459 void OnSuccess() override
;
462 /*******************************************************************************
463 * Other class declarations
464 ******************************************************************************/
466 class QuotaClient final
: public mozilla::dom::quota::Client
{
467 static QuotaClient
* sInstance
;
469 bool mShutdownRequested
;
474 static bool IsShuttingDownOnBackgroundThread() {
475 AssertIsOnBackgroundThread();
478 return sInstance
->IsShuttingDown();
481 return QuotaManager::IsShuttingDown();
484 static bool IsShuttingDownOnNonBackgroundThread() {
485 MOZ_ASSERT(!IsOnBackgroundThread());
487 return QuotaManager::IsShuttingDown();
490 bool IsShuttingDown() const {
491 AssertIsOnBackgroundThread();
493 return mShutdownRequested
;
496 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient
, override
)
498 Type
GetType() override
;
500 Result
<UsageInfo
, nsresult
> InitOrigin(PersistenceType aPersistenceType
,
501 const OriginMetadata
& aOriginMetadata
,
502 const AtomicBool
& aCanceled
) override
;
504 nsresult
InitOriginWithoutTracking(PersistenceType aPersistenceType
,
505 const OriginMetadata
& aOriginMetadata
,
506 const AtomicBool
& aCanceled
) override
;
508 Result
<UsageInfo
, nsresult
> GetUsageForOrigin(
509 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
510 const AtomicBool
& aCanceled
) override
;
512 void OnOriginClearCompleted(PersistenceType aPersistenceType
,
513 const nsACString
& aOrigin
) override
;
515 void ReleaseIOThreadObjects() override
;
517 void AbortOperationsForLocks(
518 const DirectoryLockIdTable
& aDirectoryLockIds
) override
;
520 void AbortOperationsForProcess(ContentParentId aContentParentId
) override
;
522 void AbortAllOperations() override
;
524 void StartIdleMaintenance() override
;
526 void StopIdleMaintenance() override
;
529 ~QuotaClient() override
;
531 void InitiateShutdown() override
;
532 bool IsShutdownCompleted() const override
;
533 nsCString
GetShutdownStatus() const override
;
534 void ForceKillActors() override
;
535 void FinalizeShutdown() override
;
538 /*******************************************************************************
540 ******************************************************************************/
542 using ConnectionArray
= nsTArray
<NotNull
<RefPtr
<Connection
>>>;
544 StaticAutoPtr
<ConnectionArray
> gOpenConnections
;
546 template <typename Condition
>
547 void AllowToCloseConnectionsMatching(const Condition
& aCondition
) {
548 AssertIsOnBackgroundThread();
550 if (gOpenConnections
) {
551 for (const auto& connection
: *gOpenConnections
) {
552 if (aCondition(*connection
)) {
553 connection
->AllowToClose();
561 /*******************************************************************************
563 ******************************************************************************/
565 PBackgroundSDBConnectionParent
* AllocPBackgroundSDBConnectionParent(
566 const PersistenceType
& aPersistenceType
,
567 const PrincipalInfo
& aPrincipalInfo
) {
568 AssertIsOnBackgroundThread();
570 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
574 if (NS_WARN_IF(!IsValidPersistenceType(aPersistenceType
))) {
575 ASSERT_UNLESS_FUZZING();
579 if (NS_WARN_IF(aPrincipalInfo
.type() == PrincipalInfo::TNullPrincipalInfo
)) {
580 ASSERT_UNLESS_FUZZING();
584 if (NS_WARN_IF(!QuotaManager::IsPrincipalInfoValid(aPrincipalInfo
))) {
585 ASSERT_UNLESS_FUZZING();
589 RefPtr
<Connection
> actor
= new Connection(aPersistenceType
, aPrincipalInfo
);
591 return actor
.forget().take();
594 bool RecvPBackgroundSDBConnectionConstructor(
595 PBackgroundSDBConnectionParent
* aActor
,
596 const PersistenceType
& aPersistenceType
,
597 const PrincipalInfo
& aPrincipalInfo
) {
598 AssertIsOnBackgroundThread();
600 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
605 bool DeallocPBackgroundSDBConnectionParent(
606 PBackgroundSDBConnectionParent
* aActor
) {
607 AssertIsOnBackgroundThread();
610 RefPtr
<Connection
> actor
= dont_AddRef(static_cast<Connection
*>(aActor
));
616 already_AddRefed
<mozilla::dom::quota::Client
> CreateQuotaClient() {
617 AssertIsOnBackgroundThread();
619 RefPtr
<QuotaClient
> client
= new QuotaClient();
620 return client
.forget();
623 } // namespace simpledb
625 /*******************************************************************************
627 ******************************************************************************/
629 StreamHelper::StreamHelper(nsIFileStream
* aFileStream
, nsIRunnable
* aCallback
)
630 : Runnable("dom::StreamHelper"),
631 mOwningEventTarget(GetCurrentEventTarget()),
632 mFileStream(aFileStream
),
633 mCallback(aCallback
) {
634 AssertIsOnBackgroundThread();
635 MOZ_ASSERT(aFileStream
);
636 MOZ_ASSERT(aCallback
);
639 StreamHelper::~StreamHelper() {
640 MOZ_ASSERT(!mFileStream
);
641 MOZ_ASSERT(!mCallback
);
644 void StreamHelper::AsyncClose() {
645 AssertIsOnBackgroundThread();
647 QuotaManager
* quotaManager
= QuotaManager::Get();
648 MOZ_ASSERT(quotaManager
);
651 quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
));
654 void StreamHelper::RunOnBackgroundThread() {
655 AssertIsOnBackgroundThread();
657 nsCOMPtr
<nsIFileStream
> fileStream
;
658 mFileStream
.swap(fileStream
);
660 nsCOMPtr
<nsIRunnable
> callback
;
661 mCallback
.swap(callback
);
666 void StreamHelper::RunOnIOThread() {
667 AssertIsOnIOThread();
668 MOZ_ASSERT(mFileStream
);
670 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(mFileStream
);
671 MOZ_ASSERT(inputStream
);
673 nsresult rv
= inputStream
->Close();
674 Unused
<< NS_WARN_IF(NS_FAILED(rv
));
676 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
680 StreamHelper::Run() {
681 MOZ_ASSERT(mCallback
);
683 if (IsOnBackgroundThread()) {
684 RunOnBackgroundThread();
692 /*******************************************************************************
694 ******************************************************************************/
696 Connection::Connection(PersistenceType aPersistenceType
,
697 const PrincipalInfo
& aPrincipalInfo
)
698 : mPrincipalInfo(aPrincipalInfo
),
699 mPersistenceType(aPersistenceType
),
700 mRunningRequest(false),
702 mAllowedToClose(false),
703 mActorDestroyed(false) {
704 AssertIsOnBackgroundThread();
705 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
708 Connection::~Connection() {
709 MOZ_ASSERT(!mRunningRequest
);
711 MOZ_ASSERT(mActorDestroyed
);
714 void Connection::OnNewRequest() {
715 AssertIsOnBackgroundThread();
716 MOZ_ASSERT(!mRunningRequest
);
718 mRunningRequest
= true;
721 void Connection::OnRequestFinished() {
722 AssertIsOnBackgroundThread();
723 MOZ_ASSERT(mRunningRequest
);
725 mRunningRequest
= false;
730 void Connection::OnOpen(const nsACString
& aOrigin
, const nsAString
& aName
,
731 already_AddRefed
<DirectoryLock
> aDirectoryLock
,
732 already_AddRefed
<nsIFileStream
> aFileStream
) {
733 AssertIsOnBackgroundThread();
734 MOZ_ASSERT(!aOrigin
.IsEmpty());
735 MOZ_ASSERT(!aName
.IsEmpty());
736 MOZ_ASSERT(mOrigin
.IsEmpty());
737 MOZ_ASSERT(mName
.IsEmpty());
738 MOZ_ASSERT(!mDirectoryLock
);
739 MOZ_ASSERT(!mFileStream
);
744 mDirectoryLock
= aDirectoryLock
;
745 mFileStream
= aFileStream
;
748 if (!gOpenConnections
) {
749 gOpenConnections
= new ConnectionArray();
752 gOpenConnections
->AppendElement(WrapNotNullUnchecked(this));
755 void Connection::OnClose() {
756 AssertIsOnBackgroundThread();
757 MOZ_ASSERT(!mOrigin
.IsEmpty());
758 MOZ_ASSERT(mDirectoryLock
);
759 MOZ_ASSERT(mFileStream
);
764 mDirectoryLock
= nullptr;
765 mFileStream
= nullptr;
768 MOZ_ASSERT(gOpenConnections
);
769 gOpenConnections
->RemoveElement(this);
771 if (gOpenConnections
->IsEmpty()) {
772 gOpenConnections
= nullptr;
775 if (mAllowedToClose
&& !mActorDestroyed
) {
776 Unused
<< SendClosed();
780 void Connection::AllowToClose() {
781 AssertIsOnBackgroundThread();
783 if (mAllowedToClose
) {
787 mAllowedToClose
= true;
789 if (!mActorDestroyed
) {
790 Unused
<< SendAllowToClose();
796 void Connection::MaybeCloseStream() {
797 AssertIsOnBackgroundThread();
799 if (!mRunningRequest
&& mOpen
&& mAllowedToClose
) {
800 nsCOMPtr
<nsIRunnable
> callback
= NewRunnableMethod(
801 "dom::Connection::OnClose", this, &Connection::OnClose
);
803 RefPtr
<StreamHelper
> helper
= new StreamHelper(mFileStream
, callback
);
804 helper
->AsyncClose();
808 bool Connection::VerifyRequestParams(const SDBRequestParams
& aParams
) const {
809 AssertIsOnBackgroundThread();
810 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
812 switch (aParams
.type()) {
813 case SDBRequestParams::TSDBRequestOpenParams
: {
814 if (NS_WARN_IF(mOpen
)) {
815 ASSERT_UNLESS_FUZZING();
822 case SDBRequestParams::TSDBRequestSeekParams
:
823 case SDBRequestParams::TSDBRequestReadParams
:
824 case SDBRequestParams::TSDBRequestWriteParams
:
825 case SDBRequestParams::TSDBRequestCloseParams
: {
826 if (NS_WARN_IF(!mOpen
)) {
827 ASSERT_UNLESS_FUZZING();
835 MOZ_CRASH("Should never get here!");
841 void Connection::ActorDestroy(ActorDestroyReason aWhy
) {
842 AssertIsOnBackgroundThread();
843 MOZ_ASSERT(!mActorDestroyed
);
845 mActorDestroyed
= true;
850 mozilla::ipc::IPCResult
Connection::RecvDeleteMe() {
851 AssertIsOnBackgroundThread();
852 MOZ_ASSERT(!mActorDestroyed
);
854 IProtocol
* mgr
= Manager();
855 if (!PBackgroundSDBConnectionParent::Send__delete__(this)) {
856 return IPC_FAIL_NO_REASON(mgr
);
862 PBackgroundSDBRequestParent
* Connection::AllocPBackgroundSDBRequestParent(
863 const SDBRequestParams
& aParams
) {
864 AssertIsOnBackgroundThread();
865 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
867 if (aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
&&
868 NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
872 if (mAllowedToClose
) {
877 // Always verify parameters in DEBUG builds!
878 bool trustParams
= false;
880 PBackgroundParent
* backgroundActor
= Manager();
881 MOZ_ASSERT(backgroundActor
);
883 bool trustParams
= !BackgroundParent::IsOtherProcessActor(backgroundActor
);
886 if (NS_WARN_IF(!trustParams
&& !VerifyRequestParams(aParams
))) {
887 ASSERT_UNLESS_FUZZING();
891 if (NS_WARN_IF(mRunningRequest
)) {
892 ASSERT_UNLESS_FUZZING();
896 RefPtr
<ConnectionOperationBase
> actor
;
898 switch (aParams
.type()) {
899 case SDBRequestParams::TSDBRequestOpenParams
:
900 actor
= new OpenOp(this, aParams
);
903 case SDBRequestParams::TSDBRequestSeekParams
:
904 actor
= new SeekOp(this, aParams
);
907 case SDBRequestParams::TSDBRequestReadParams
:
908 actor
= new ReadOp(this, aParams
);
911 case SDBRequestParams::TSDBRequestWriteParams
:
912 actor
= new WriteOp(this, aParams
);
915 case SDBRequestParams::TSDBRequestCloseParams
:
916 actor
= new CloseOp(this);
920 MOZ_CRASH("Should never get here!");
923 // Transfer ownership to IPDL.
924 return actor
.forget().take();
927 mozilla::ipc::IPCResult
Connection::RecvPBackgroundSDBRequestConstructor(
928 PBackgroundSDBRequestParent
* aActor
, const SDBRequestParams
& aParams
) {
929 AssertIsOnBackgroundThread();
931 MOZ_ASSERT(aParams
.type() != SDBRequestParams::T__None
);
932 MOZ_ASSERT_IF(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
,
933 !QuotaClient::IsShuttingDownOnBackgroundThread());
934 MOZ_ASSERT(!mAllowedToClose
);
935 MOZ_ASSERT(!mRunningRequest
);
937 auto* op
= static_cast<ConnectionOperationBase
*>(aActor
);
939 if (NS_WARN_IF(!op
->Init())) {
941 return IPC_FAIL_NO_REASON(this);
944 if (NS_WARN_IF(NS_FAILED(op
->Dispatch()))) {
946 return IPC_FAIL_NO_REASON(this);
952 bool Connection::DeallocPBackgroundSDBRequestParent(
953 PBackgroundSDBRequestParent
* aActor
) {
954 AssertIsOnBackgroundThread();
957 // Transfer ownership back from IPDL.
958 RefPtr
<ConnectionOperationBase
> actor
=
959 dont_AddRef(static_cast<ConnectionOperationBase
*>(aActor
));
963 /*******************************************************************************
964 * ConnectionOperationBase
965 ******************************************************************************/
967 ConnectionOperationBase::~ConnectionOperationBase() {
970 "ConnectionOperationBase::Cleanup() was not called by a subclass!");
971 MOZ_ASSERT(mActorDestroyed
);
974 bool ConnectionOperationBase::Init() {
975 AssertIsOnBackgroundThread();
976 MOZ_ASSERT(mConnection
);
978 mConnection
->OnNewRequest();
983 nsresult
ConnectionOperationBase::Dispatch() {
984 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
985 IsActorDestroyed()) {
986 return NS_ERROR_ABORT
;
989 QuotaManager
* quotaManager
= QuotaManager::Get();
990 MOZ_ASSERT(quotaManager
);
992 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
993 if (NS_WARN_IF(NS_FAILED(rv
))) {
1000 void ConnectionOperationBase::Cleanup() {
1001 AssertIsOnOwningThread();
1002 MOZ_ASSERT(mConnection
);
1004 mConnection
->OnRequestFinished();
1006 mConnection
= nullptr;
1009 void ConnectionOperationBase::SendResults() {
1010 AssertIsOnOwningThread();
1012 if (IsActorDestroyed()) {
1013 MaybeSetFailureCode(NS_ERROR_FAILURE
);
1015 SDBRequestResponse response
;
1017 if (NS_SUCCEEDED(mResultCode
)) {
1018 GetResponse(response
);
1020 MOZ_ASSERT(response
.type() != SDBRequestResponse::T__None
);
1021 MOZ_ASSERT(response
.type() != SDBRequestResponse::Tnsresult
);
1023 response
= mResultCode
;
1026 Unused
<< PBackgroundSDBRequestParent::Send__delete__(this, response
);
1028 if (NS_SUCCEEDED(mResultCode
)) {
1036 void ConnectionOperationBase::DatabaseWork() {
1037 AssertIsOnIOThread();
1038 MOZ_ASSERT(NS_SUCCEEDED(mResultCode
));
1040 if (!OperationMayProceed()) {
1041 // The operation was canceled in some way, likely because the child process
1043 mResultCode
= NS_ERROR_ABORT
;
1045 nsIFileStream
* fileStream
= mConnection
->GetFileStream();
1046 MOZ_ASSERT(fileStream
);
1048 nsresult rv
= DoDatabaseWork(fileStream
);
1049 if (NS_FAILED(rv
)) {
1054 MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget
->Dispatch(this, NS_DISPATCH_NORMAL
));
1057 void ConnectionOperationBase::OnSuccess() { AssertIsOnOwningThread(); }
1060 ConnectionOperationBase::Run() {
1061 if (IsOnBackgroundThread()) {
1070 void ConnectionOperationBase::ActorDestroy(ActorDestroyReason aWhy
) {
1071 AssertIsOnBackgroundThread();
1073 mOperationMayProceed
= false;
1074 mActorDestroyed
= true;
1077 OpenOp::OpenOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1078 : ConnectionOperationBase(aConnection
),
1079 mParams(aParams
.get_SDBRequestOpenParams()),
1080 mState(State::Initial
),
1081 mFileStreamOpen(false) {
1082 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestOpenParams
);
1086 MOZ_ASSERT(!mDirectoryLock
);
1087 MOZ_ASSERT(!mFileStream
);
1088 MOZ_ASSERT(!mFileStreamOpen
);
1089 MOZ_ASSERT_IF(OperationMayProceed(),
1090 mState
== State::Initial
|| mState
== State::Completed
);
1093 nsresult
OpenOp::Dispatch() {
1094 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
1099 nsresult
OpenOp::Open() {
1100 MOZ_ASSERT(NS_IsMainThread());
1101 MOZ_ASSERT(mState
== State::Initial
);
1103 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1104 !OperationMayProceed()) {
1105 return NS_ERROR_ABORT
;
1108 if (NS_WARN_IF(!Preferences::GetBool(kPrefSimpleDBEnabled
, false))) {
1109 return NS_ERROR_UNEXPECTED
;
1112 PersistenceType persistenceType
= GetConnection()->GetPersistenceType();
1114 const PrincipalInfo
& principalInfo
= GetConnection()->GetPrincipalInfo();
1116 if (principalInfo
.type() == PrincipalInfo::TSystemPrincipalInfo
) {
1117 mOriginMetadata
= {QuotaManager::GetInfoForChrome(), persistenceType
};
1119 MOZ_ASSERT(principalInfo
.type() == PrincipalInfo::TContentPrincipalInfo
);
1121 QM_TRY_INSPECT(const auto& principal
,
1122 PrincipalInfoToPrincipal(principalInfo
));
1124 QM_TRY_UNWRAP(auto principalMetadata
,
1125 QuotaManager::GetInfoFromPrincipal(principal
));
1127 mOriginMetadata
= {std::move(principalMetadata
), persistenceType
};
1130 mState
= State::FinishOpen
;
1131 MOZ_ALWAYS_SUCCEEDS(OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1136 nsresult
OpenOp::FinishOpen() {
1137 AssertIsOnOwningThread();
1138 MOZ_ASSERT(mState
== State::FinishOpen
);
1140 if (gOpenConnections
) {
1141 for (const auto& connection
: *gOpenConnections
) {
1142 if (connection
->Origin() == mOriginMetadata
.mOrigin
&&
1143 connection
->Name() == mParams
.name()) {
1144 return NS_ERROR_STORAGE_BUSY
;
1149 if (QuotaManager::Get()) {
1150 nsresult rv
= OpenDirectory();
1151 if (NS_WARN_IF(NS_FAILED(rv
))) {
1158 mState
= State::QuotaManagerPending
;
1159 QuotaManager::GetOrCreate(this);
1164 nsresult
OpenOp::QuotaManagerOpen() {
1165 AssertIsOnOwningThread();
1166 MOZ_ASSERT(mState
== State::QuotaManagerPending
);
1168 if (NS_WARN_IF(!QuotaManager::Get())) {
1169 return NS_ERROR_FAILURE
;
1172 nsresult rv
= OpenDirectory();
1173 if (NS_WARN_IF(NS_FAILED(rv
))) {
1180 nsresult
OpenOp::OpenDirectory() {
1181 AssertIsOnOwningThread();
1182 MOZ_ASSERT(mState
== State::FinishOpen
||
1183 mState
== State::QuotaManagerPending
);
1184 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1185 MOZ_ASSERT(!mDirectoryLock
);
1186 MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
1187 MOZ_ASSERT(QuotaManager::Get());
1189 RefPtr
<DirectoryLock
> directoryLock
=
1190 QuotaManager::Get()->CreateDirectoryLock(
1191 GetConnection()->GetPersistenceType(), mOriginMetadata
,
1192 mozilla::dom::quota::Client::SDB
,
1193 /* aExclusive */ false);
1195 mState
= State::DirectoryOpenPending
;
1196 directoryLock
->Acquire(this);
1201 nsresult
OpenOp::SendToIOThread() {
1202 AssertIsOnOwningThread();
1203 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1205 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
1206 IsActorDestroyed()) {
1207 return NS_ERROR_ABORT
;
1211 new FileStream(GetConnection()->GetPersistenceType(), mOriginMetadata
,
1212 mozilla::dom::quota::Client::SDB
);
1214 QuotaManager
* quotaManager
= QuotaManager::Get();
1215 MOZ_ASSERT(quotaManager
);
1217 // Must set this before dispatching otherwise we will race with the IO thread.
1218 mState
= State::DatabaseWorkOpen
;
1220 nsresult rv
= quotaManager
->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL
);
1221 if (NS_WARN_IF(NS_FAILED(rv
))) {
1228 nsresult
OpenOp::DatabaseWork() {
1229 AssertIsOnIOThread();
1230 MOZ_ASSERT(mState
== State::DatabaseWorkOpen
);
1231 MOZ_ASSERT(mFileStream
);
1232 MOZ_ASSERT(!mFileStreamOpen
);
1234 if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
1235 !OperationMayProceed()) {
1236 return NS_ERROR_ABORT
;
1239 QuotaManager
* quotaManager
= QuotaManager::Get();
1240 MOZ_ASSERT(quotaManager
);
1242 QM_TRY(MOZ_TO_RESULT(quotaManager
->EnsureStorageIsInitialized()));
1245 const auto& dbDirectory
,
1246 ([persistenceType
= GetConnection()->GetPersistenceType(), "aManager
,
1248 -> mozilla::Result
<std::pair
<nsCOMPtr
<nsIFile
>, bool>, nsresult
> {
1249 if (persistenceType
== PERSISTENCE_TYPE_PERSISTENT
) {
1250 QM_TRY_RETURN(quotaManager
->EnsurePersistentOriginIsInitialized(
1255 MOZ_TO_RESULT(quotaManager
->EnsureTemporaryStorageIsInitialized()));
1256 QM_TRY_RETURN(quotaManager
->EnsureTemporaryOriginIsInitialized(
1257 persistenceType
, mOriginMetadata
));
1259 .map([](const auto& res
) { return res
.first
; })));
1262 dbDirectory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1263 if (NS_WARN_IF(NS_FAILED(rv
))) {
1268 rv
= dbDirectory
->Exists(&exists
);
1269 if (NS_WARN_IF(NS_FAILED(rv
))) {
1274 rv
= dbDirectory
->Create(nsIFile::DIRECTORY_TYPE
, 0755);
1275 if (NS_WARN_IF(NS_FAILED(rv
))) {
1282 MOZ_ASSERT(NS_SUCCEEDED(dbDirectory
->IsDirectory(&isDirectory
)));
1283 MOZ_ASSERT(isDirectory
);
1287 nsCOMPtr
<nsIFile
> dbFile
;
1288 rv
= dbDirectory
->Clone(getter_AddRefs(dbFile
));
1289 if (NS_WARN_IF(NS_FAILED(rv
))) {
1293 rv
= dbFile
->Append(mParams
.name() + kSDBSuffix
);
1294 if (NS_WARN_IF(NS_FAILED(rv
))) {
1298 nsString databaseFilePath
;
1299 rv
= dbFile
->GetPath(databaseFilePath
);
1300 if (NS_WARN_IF(NS_FAILED(rv
))) {
1304 rv
= mFileStream
->Init(dbFile
, PR_RDWR
| PR_CREATE_FILE
, 0644, 0);
1305 if (NS_WARN_IF(NS_FAILED(rv
))) {
1309 mFileStreamOpen
= true;
1311 rv
= DoDatabaseWork(mFileStream
);
1312 if (NS_WARN_IF(NS_FAILED(rv
))) {
1316 // Must set mState before dispatching otherwise we will race with the owning
1318 mState
= State::SendingResults
;
1320 rv
= OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
);
1321 if (NS_WARN_IF(NS_FAILED(rv
))) {
1328 void OpenOp::StreamClosedCallback() {
1329 AssertIsOnOwningThread();
1330 MOZ_ASSERT(NS_FAILED(ResultCode()));
1331 MOZ_ASSERT(mDirectoryLock
);
1332 MOZ_ASSERT(mFileStream
);
1333 MOZ_ASSERT(mFileStreamOpen
);
1335 mDirectoryLock
= nullptr;
1336 mFileStream
= nullptr;
1337 mFileStreamOpen
= false;
1340 nsresult
OpenOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1341 AssertIsOnIOThread();
1346 void OpenOp::GetResponse(SDBRequestResponse
& aResponse
) {
1347 AssertIsOnOwningThread();
1349 aResponse
= SDBRequestOpenResponse();
1352 void OpenOp::OnSuccess() {
1353 AssertIsOnOwningThread();
1354 MOZ_ASSERT(NS_SUCCEEDED(ResultCode()));
1355 MOZ_ASSERT(!mOriginMetadata
.mOrigin
.IsEmpty());
1356 MOZ_ASSERT(mDirectoryLock
);
1357 MOZ_ASSERT(mFileStream
);
1358 MOZ_ASSERT(mFileStreamOpen
);
1360 RefPtr
<DirectoryLock
> directoryLock
;
1361 nsCOMPtr
<nsIFileStream
> fileStream
;
1363 mDirectoryLock
.swap(directoryLock
);
1364 mFileStream
.swap(fileStream
);
1365 mFileStreamOpen
= false;
1367 GetConnection()->OnOpen(mOriginMetadata
.mOrigin
, mParams
.name(),
1368 directoryLock
.forget(), fileStream
.forget());
1371 void OpenOp::Cleanup() {
1372 AssertIsOnOwningThread();
1373 MOZ_ASSERT_IF(mFileStreamOpen
, mFileStream
);
1375 if (mFileStream
&& mFileStreamOpen
) {
1376 // If we have an initialized file stream then the operation must have failed
1377 // and there must be a directory lock too.
1378 MOZ_ASSERT(NS_FAILED(ResultCode()));
1379 MOZ_ASSERT(mDirectoryLock
);
1381 // We must close the stream on the I/O thread before releasing it on this
1382 // thread. The directory lock can't be released either.
1383 nsCOMPtr
<nsIRunnable
> callback
=
1384 NewRunnableMethod("dom::OpenOp::StreamClosedCallback", this,
1385 &OpenOp::StreamClosedCallback
);
1387 RefPtr
<StreamHelper
> helper
= new StreamHelper(mFileStream
, callback
);
1388 helper
->AsyncClose();
1390 MOZ_ASSERT(!mFileStreamOpen
);
1392 mDirectoryLock
= nullptr;
1393 mFileStream
= nullptr;
1396 ConnectionOperationBase::Cleanup();
1399 NS_IMPL_ISUPPORTS_INHERITED0(OpenOp
, ConnectionOperationBase
)
1406 case State::Initial
:
1410 case State::FinishOpen
:
1414 case State::QuotaManagerPending
:
1415 rv
= QuotaManagerOpen();
1418 case State::DatabaseWorkOpen
:
1419 rv
= DatabaseWork();
1422 case State::SendingResults
:
1427 MOZ_CRASH("Bad state!");
1430 if (NS_WARN_IF(NS_FAILED(rv
)) && mState
!= State::SendingResults
) {
1431 MaybeSetFailureCode(rv
);
1433 // Must set mState before dispatching otherwise we will race with the owning
1435 mState
= State::SendingResults
;
1437 if (IsOnOwningThread()) {
1440 MOZ_ALWAYS_SUCCEEDS(
1441 OwningEventTarget()->Dispatch(this, NS_DISPATCH_NORMAL
));
1448 void OpenOp::DirectoryLockAcquired(DirectoryLock
* aLock
) {
1449 AssertIsOnOwningThread();
1450 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1451 MOZ_ASSERT(!mDirectoryLock
);
1453 mDirectoryLock
= aLock
;
1455 nsresult rv
= SendToIOThread();
1456 if (NS_WARN_IF(NS_FAILED(rv
))) {
1457 MaybeSetFailureCode(rv
);
1459 // The caller holds a strong reference to us, no need for a self reference
1460 // before calling Run().
1462 mState
= State::SendingResults
;
1463 MOZ_ALWAYS_SUCCEEDS(Run());
1469 void OpenOp::DirectoryLockFailed() {
1470 AssertIsOnOwningThread();
1471 MOZ_ASSERT(mState
== State::DirectoryOpenPending
);
1472 MOZ_ASSERT(!mDirectoryLock
);
1474 MaybeSetFailureCode(NS_ERROR_FAILURE
);
1476 // The caller holds a strong reference to us, no need for a self reference
1477 // before calling Run().
1479 mState
= State::SendingResults
;
1480 MOZ_ALWAYS_SUCCEEDS(Run());
1483 SeekOp::SeekOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1484 : ConnectionOperationBase(aConnection
),
1485 mParams(aParams
.get_SDBRequestSeekParams()) {
1486 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestSeekParams
);
1489 nsresult
SeekOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1490 AssertIsOnIOThread();
1491 MOZ_ASSERT(aFileStream
);
1493 nsCOMPtr
<nsISeekableStream
> seekableStream
= do_QueryInterface(aFileStream
);
1494 MOZ_ASSERT(seekableStream
);
1497 seekableStream
->Seek(nsISeekableStream::NS_SEEK_SET
, mParams
.offset());
1499 if (NS_WARN_IF(NS_FAILED(rv
))) {
1506 void SeekOp::GetResponse(SDBRequestResponse
& aResponse
) {
1507 aResponse
= SDBRequestSeekResponse();
1510 ReadOp::ReadOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1511 : ConnectionOperationBase(aConnection
),
1512 mParams(aParams
.get_SDBRequestReadParams()) {
1513 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestReadParams
);
1516 bool ReadOp::Init() {
1517 AssertIsOnOwningThread();
1519 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1523 mOutputStream
= MemoryOutputStream::Create(mParams
.size());
1524 if (NS_WARN_IF(!mOutputStream
)) {
1531 nsresult
ReadOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1532 AssertIsOnIOThread();
1533 MOZ_ASSERT(aFileStream
);
1535 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(aFileStream
);
1536 MOZ_ASSERT(inputStream
);
1540 uint64_t offset
= 0;
1543 char copyBuffer
[kCopyBufferSize
];
1545 uint64_t max
= mParams
.size() - offset
;
1550 uint32_t count
= sizeof(copyBuffer
);
1556 rv
= inputStream
->Read(copyBuffer
, count
, &numRead
);
1557 if (NS_WARN_IF(NS_FAILED(rv
))) {
1566 rv
= mOutputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1567 if (NS_WARN_IF(NS_FAILED(rv
))) {
1571 if (NS_WARN_IF(numWrite
!= numRead
)) {
1572 return NS_ERROR_FAILURE
;
1578 MOZ_ASSERT(offset
== mParams
.size());
1580 MOZ_ALWAYS_SUCCEEDS(mOutputStream
->Close());
1585 void ReadOp::GetResponse(SDBRequestResponse
& aResponse
) {
1586 aResponse
= SDBRequestReadResponse(mOutputStream
->Data());
1589 WriteOp::WriteOp(Connection
* aConnection
, const SDBRequestParams
& aParams
)
1590 : ConnectionOperationBase(aConnection
),
1591 mParams(aParams
.get_SDBRequestWriteParams()),
1593 MOZ_ASSERT(aParams
.type() == SDBRequestParams::TSDBRequestWriteParams
);
1596 bool WriteOp::Init() {
1597 AssertIsOnOwningThread();
1599 if (NS_WARN_IF(!ConnectionOperationBase::Init())) {
1603 const nsCString
& string
= mParams
.data();
1605 nsCOMPtr
<nsIInputStream
> inputStream
;
1606 nsresult rv
= NS_NewCStringInputStream(getter_AddRefs(inputStream
), string
);
1607 if (NS_WARN_IF(NS_FAILED(rv
))) {
1611 mInputStream
= std::move(inputStream
);
1612 mSize
= string
.Length();
1617 nsresult
WriteOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1618 AssertIsOnIOThread();
1619 MOZ_ASSERT(aFileStream
);
1621 nsCOMPtr
<nsIOutputStream
> outputStream
= do_QueryInterface(aFileStream
);
1622 MOZ_ASSERT(outputStream
);
1627 char copyBuffer
[kCopyBufferSize
];
1630 rv
= mInputStream
->Read(copyBuffer
, sizeof(copyBuffer
), &numRead
);
1631 if (NS_WARN_IF(NS_FAILED(rv
))) {
1640 rv
= outputStream
->Write(copyBuffer
, numRead
, &numWrite
);
1641 if (NS_WARN_IF(NS_FAILED(rv
))) {
1645 if (NS_WARN_IF(numWrite
!= numRead
)) {
1646 return NS_ERROR_FAILURE
;
1650 MOZ_ALWAYS_SUCCEEDS(mInputStream
->Close());
1655 void WriteOp::GetResponse(SDBRequestResponse
& aResponse
) {
1656 aResponse
= SDBRequestWriteResponse();
1659 CloseOp::CloseOp(Connection
* aConnection
)
1660 : ConnectionOperationBase(aConnection
) {}
1662 nsresult
CloseOp::DoDatabaseWork(nsIFileStream
* aFileStream
) {
1663 AssertIsOnIOThread();
1664 MOZ_ASSERT(aFileStream
);
1666 nsCOMPtr
<nsIInputStream
> inputStream
= do_QueryInterface(aFileStream
);
1667 MOZ_ASSERT(inputStream
);
1669 nsresult rv
= inputStream
->Close();
1670 if (NS_WARN_IF(NS_FAILED(rv
))) {
1677 void CloseOp::GetResponse(SDBRequestResponse
& aResponse
) {
1678 aResponse
= SDBRequestCloseResponse();
1681 void CloseOp::OnSuccess() {
1682 AssertIsOnOwningThread();
1684 GetConnection()->OnClose();
1687 /*******************************************************************************
1689 ******************************************************************************/
1691 QuotaClient
* QuotaClient::sInstance
= nullptr;
1693 QuotaClient::QuotaClient() : mShutdownRequested(false) {
1694 AssertIsOnBackgroundThread();
1695 MOZ_ASSERT(!sInstance
, "We expect this to be a singleton!");
1700 QuotaClient::~QuotaClient() {
1701 AssertIsOnBackgroundThread();
1702 MOZ_ASSERT(sInstance
== this, "We expect this to be a singleton!");
1704 sInstance
= nullptr;
1707 mozilla::dom::quota::Client::Type
QuotaClient::GetType() {
1708 return QuotaClient::SDB
;
1711 Result
<UsageInfo
, nsresult
> QuotaClient::InitOrigin(
1712 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1713 const AtomicBool
& aCanceled
) {
1714 AssertIsOnIOThread();
1716 return GetUsageForOrigin(aPersistenceType
, aOriginMetadata
, aCanceled
);
1719 nsresult
QuotaClient::InitOriginWithoutTracking(
1720 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1721 const AtomicBool
& aCanceled
) {
1722 AssertIsOnIOThread();
1727 Result
<UsageInfo
, nsresult
> QuotaClient::GetUsageForOrigin(
1728 PersistenceType aPersistenceType
, const OriginMetadata
& aOriginMetadata
,
1729 const AtomicBool
& aCanceled
) {
1730 AssertIsOnIOThread();
1732 QuotaManager
* quotaManager
= QuotaManager::Get();
1733 MOZ_ASSERT(quotaManager
);
1735 QM_TRY_UNWRAP(auto directory
, quotaManager
->GetDirectoryForOrigin(
1736 aPersistenceType
, aOriginMetadata
.mOrigin
));
1738 MOZ_ASSERT(directory
);
1741 directory
->Append(NS_LITERAL_STRING_FROM_CSTRING(SDB_DIRECTORY_NAME
));
1742 if (NS_WARN_IF(NS_FAILED(rv
))) {
1746 DebugOnly
<bool> exists
;
1747 MOZ_ASSERT(NS_SUCCEEDED(directory
->Exists(&exists
)) && exists
);
1749 QM_TRY_RETURN(ReduceEachFileAtomicCancelable(
1750 *directory
, aCanceled
, UsageInfo
{},
1751 [](UsageInfo usageInfo
,
1752 const nsCOMPtr
<nsIFile
>& file
) -> Result
<UsageInfo
, nsresult
> {
1753 QM_TRY_INSPECT(const bool& isDirectory
,
1754 MOZ_TO_RESULT_INVOKE(file
, IsDirectory
));
1757 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1762 QM_TRY(MOZ_TO_RESULT(file
->GetLeafName(leafName
)));
1764 if (StringEndsWith(leafName
, kSDBSuffix
)) {
1765 QM_TRY_INSPECT(const int64_t& fileSize
,
1766 MOZ_TO_RESULT_INVOKE(file
, GetFileSize
));
1768 MOZ_ASSERT(fileSize
>= 0);
1771 UsageInfo
{DatabaseUsageType(Some(uint64_t(fileSize
)))};
1774 Unused
<< WARN_IF_FILE_IS_UNKNOWN(*file
);
1780 void QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType
,
1781 const nsACString
& aOrigin
) {
1782 AssertIsOnIOThread();
1785 void QuotaClient::ReleaseIOThreadObjects() { AssertIsOnIOThread(); }
1787 void QuotaClient::AbortOperationsForLocks(
1788 const DirectoryLockIdTable
& aDirectoryLockIds
) {
1789 AssertIsOnBackgroundThread();
1791 AllowToCloseConnectionsMatching([&aDirectoryLockIds
](const auto& connection
) {
1792 // If the connections is registered in gOpenConnections then it must have
1793 // a directory lock.
1794 return IsLockForObjectContainedInLockTable(connection
, aDirectoryLockIds
);
1798 void QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId
) {
1799 AssertIsOnBackgroundThread();
1802 void QuotaClient::AbortAllOperations() {
1803 AssertIsOnBackgroundThread();
1805 AllowToCloseConnectionsMatching([](const auto&) { return true; });
1808 void QuotaClient::StartIdleMaintenance() { AssertIsOnBackgroundThread(); }
1810 void QuotaClient::StopIdleMaintenance() { AssertIsOnBackgroundThread(); }
1812 void QuotaClient::InitiateShutdown() {
1813 AssertIsOnBackgroundThread();
1814 MOZ_ASSERT(!mShutdownRequested
);
1816 mShutdownRequested
= true;
1818 if (gOpenConnections
) {
1819 for (const auto& connection
: *gOpenConnections
) {
1820 connection
->AllowToClose();
1825 bool QuotaClient::IsShutdownCompleted() const { return !gOpenConnections
; }
1827 void QuotaClient::ForceKillActors() {
1828 // Currently we don't implement killing actors (are there any to kill here?).
1831 nsCString
QuotaClient::GetShutdownStatus() const {
1832 // XXX Gather information here.
1833 return "To be implemented"_ns
;
1836 void QuotaClient::FinalizeShutdown() {
1837 // Nothing to do here.
1840 } // namespace mozilla::dom