Bug 1866402 - Make it possible to initialize temporary origins without ensuring origin directories; r=dom-storage-reviewers,jari

LSNG already uses some QuotaManager APIs to achieve that origin directories are
not created if they don't exist during datastore preparation, but the feature
is not easy to use and it's also not generalized enough for use in other quota
clients. Besides that, the way how it's currently done in LSNG complicates
removal of QuotaManager::EnsureTemporaryOriginIsInitializedInternal calls from
LSNG. This patch is about generalizing of the feature, making it available to
all quota clients.

Differential Revision: https://phabricator.services.mozilla.com/D195551
This commit is contained in:
Jan Varga
2024-10-12 20:58:36 +00:00
parent 14224a2551
commit 7783acd7c8
41 changed files with 790 additions and 210 deletions

14
dom/cache/Context.cpp vendored
View File

@@ -406,11 +406,15 @@ Context::QuotaInitRunnable::Run() {
QuotaManager* quotaManager = QuotaManager::Get();
MOZ_DIAGNOSTIC_ASSERT(quotaManager);
QM_TRY_UNWRAP(mDirectoryMetadata->mDir,
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
*mDirectoryMetadata)
.map([](const auto& res) { return res.first; }));
QM_TRY_UNWRAP(
mDirectoryMetadata->mDir,
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
*mDirectoryMetadata, /* aCreateIfNonExistent */ true)
.map([](const auto& res) { return res.first; }));
QM_TRY(quotaManager->EnsureTemporaryOriginDirectoryCreated(
*mDirectoryMetadata));
auto* cacheQuotaClient = CacheQuotaClient::Get();
MOZ_DIAGNOSTIC_ASSERT(cacheQuotaClient);

View File

@@ -76,8 +76,12 @@ function initPersistentOrigin(principal) {
return Services.qms.initializePersistentOrigin(principal);
}
function initTemporaryOrigin(principal) {
return Services.qms.initializeTemporaryOrigin("default", principal);
function initTemporaryOrigin(principal, createIfNonExistent = true) {
return Services.qms.initializeTemporaryOrigin(
"default",
principal,
createIfNonExistent
);
}
function clearOrigin(principal, persistence) {

View File

@@ -170,10 +170,13 @@ nsresult EnsureFileSystemDirectory(
quota::QuotaManager* quotaManager = quota::QuotaManager::Get();
MOZ_ASSERT(quotaManager);
QM_TRY_INSPECT(
const auto& fileSystemDirectory,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(aOriginMetadata)
.map([](const auto& aPair) { return aPair.first; }));
QM_TRY_INSPECT(const auto& fileSystemDirectory,
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
aOriginMetadata, /* aCreateIfNonExistent */ true)
.map([](const auto& aPair) { return aPair.first; }));
QM_TRY(quotaManager->EnsureTemporaryOriginDirectoryCreated(aOriginMetadata));
QM_TRY(QM_TO_RESULT(fileSystemDirectory->AppendRelativePath(
NS_LITERAL_STRING_FROM_CSTRING(FILESYSTEM_DIRECTORY_NAME))));

View File

@@ -36,10 +36,11 @@ void FileSystemParentTest::TearDown() {
}
// static
void FileSystemParentTest::InitializeTemporaryOrigin() {
void FileSystemParentTest::InitializeTemporaryOrigin(
bool aCreateIfNonExistent) {
ASSERT_NO_FATAL_FAILURE(
QuotaManagerDependencyFixture::InitializeTemporaryOrigin(
GetTestOriginMetadata()));
GetTestOriginMetadata(), aCreateIfNonExistent));
}
// static

View File

@@ -46,7 +46,7 @@ class FileSystemParentTest : public quota::test::QuotaManagerDependencyFixture {
void TearDown() override;
static void InitializeTemporaryOrigin();
static void InitializeTemporaryOrigin(bool aCreateIfNonExistent = true);
static void GetOriginUsage(quota::UsageInfo& aResult);

View File

@@ -131,7 +131,8 @@ TEST_F(TestFileSystemOriginInitialization, EmptyOriginDirectory) {
// Initialize origin
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin());
ASSERT_NO_FATAL_FAILURE(
InitializeTemporaryOrigin(/* aCreateIfNonExistent */ true));
// After initialization,
// * origin usage is nothing

View File

@@ -15263,8 +15263,14 @@ nsresult OpenDatabaseOp::DoDatabaseWork() {
mOriginMetadata));
}
QM_TRY_RETURN(quotaManager->EnsureTemporaryOriginIsInitializedInternal(
QM_TRY_UNWRAP(auto dbDirectory,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata, /* aCreateIfNonExistent */ true));
QM_TRY(quotaManager->EnsureTemporaryOriginDirectoryCreated(
mOriginMetadata));
return std::move(dbDirectory);
}()
.map([](const auto& res) { return res.first; })));
@@ -16849,8 +16855,14 @@ nsresult GetDatabasesOp::DoDatabaseWork() {
mOriginMetadata));
}
QM_TRY_RETURN(quotaManager->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata));
QM_TRY_UNWRAP(auto dbDirectory,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata, /* aCreateIfNonExistent */ true));
QM_TRY(
quotaManager->EnsureTemporaryOriginDirectoryCreated(mOriginMetadata));
return std::move(dbDirectory);
}()
.map([](const auto& res) { return Ok{}; })));

View File

@@ -1245,7 +1245,7 @@ class ConnectionDatastoreOperationBase : public DatastoreOperationBase {
class Connection final : public CachingDatabaseConnection {
friend class ConnectionThread;
class InitTemporaryOriginHelper;
class GetOrCreateTemporaryOriginDirectoryHelper;
class FlushOp;
class CloseOp;
@@ -1360,16 +1360,17 @@ class Connection final : public CachingDatabaseConnection {
};
/**
* Helper to invoke EnsureTemporaryOriginIsInitializedInternal on the
* QuotaManager IO thread from the LocalStorage connection thread when creating
* a database connection on demand. This is necessary because we attempt to
* defer the creation of the origin directory and the database until absolutely
* needed, but the directory creation and origin initialization must happen on
* the QM IO thread for invariant reasons. (We can't just use a mutex because
* there could be logic on the IO thread that also wants to deal with the same
* origin, so we need to queue a runnable and wait our turn.)
* Helper to invoke GetOrCreateTemporaryOriginDirectory on the QuotaManager IO
* thread from the LocalStorage connection thread when creating a database
* connection on demand. This is necessary because we attempt to defer the
* creation of the origin directory and the database until absolutely needed,
* but the directory creation must happen on the QM IO thread for invariant
* reasons. (We can't just use a mutex because there could be logic on the IO
* thread that also wants to deal with the same origin, so we need to queue a
* runnable and wait our turn.)
*/
class Connection::InitTemporaryOriginHelper final : public Runnable {
class Connection::GetOrCreateTemporaryOriginDirectoryHelper final
: public Runnable {
mozilla::Monitor mMonitor MOZ_UNANNOTATED;
const OriginMetadata mOriginMetadata;
nsString mOriginDirectoryPath;
@@ -1377,9 +1378,12 @@ class Connection::InitTemporaryOriginHelper final : public Runnable {
bool mWaiting;
public:
explicit InitTemporaryOriginHelper(const OriginMetadata& aOriginMetadata)
: Runnable("dom::localstorage::Connection::InitTemporaryOriginHelper"),
mMonitor("InitTemporaryOriginHelper::mMonitor"),
explicit GetOrCreateTemporaryOriginDirectoryHelper(
const OriginMetadata& aOriginMetadata)
: Runnable(
"dom::localstorage::Connection::"
"GetOrCreateTemporaryOriginDirectoryHelper"),
mMonitor("GetOrCreateTemporaryOriginDirectoryHelper::mMonitor"),
mOriginMetadata(aOriginMetadata),
mIOThreadResultCode(NS_OK),
mWaiting(true) {
@@ -1389,7 +1393,7 @@ class Connection::InitTemporaryOriginHelper final : public Runnable {
Result<nsString, nsresult> BlockAndReturnOriginDirectoryPath();
private:
~InitTemporaryOriginHelper() = default;
~GetOrCreateTemporaryOriginDirectoryHelper() = default;
nsresult RunOnIOThread();
@@ -4069,8 +4073,8 @@ nsresult Connection::EnsureStorageConnection() {
return NS_OK;
}
RefPtr<InitTemporaryOriginHelper> helper =
new InitTemporaryOriginHelper(mOriginMetadata);
auto helper =
MakeRefPtr<GetOrCreateTemporaryOriginDirectoryHelper>(mOriginMetadata);
QM_TRY_INSPECT(const auto& originDirectoryPath,
helper->BlockAndReturnOriginDirectoryPath());
@@ -4223,7 +4227,8 @@ void Connection::FlushTimerCallback(nsITimer* aTimer, void* aClosure) {
}
Result<nsString, nsresult>
Connection::InitTemporaryOriginHelper::BlockAndReturnOriginDirectoryPath() {
Connection::GetOrCreateTemporaryOriginDirectoryHelper::
BlockAndReturnOriginDirectoryPath() {
AssertIsOnGlobalConnectionThread();
QuotaManager* quotaManager = QuotaManager::Get();
@@ -4242,7 +4247,8 @@ Connection::InitTemporaryOriginHelper::BlockAndReturnOriginDirectoryPath() {
return mOriginDirectoryPath;
}
nsresult Connection::InitTemporaryOriginHelper::RunOnIOThread() {
nsresult
Connection::GetOrCreateTemporaryOriginDirectoryHelper::RunOnIOThread() {
AssertIsOnIOThread();
QuotaManager* quotaManager = QuotaManager::Get();
@@ -4250,8 +4256,7 @@ nsresult Connection::InitTemporaryOriginHelper::RunOnIOThread() {
QM_TRY_INSPECT(
const auto& directoryEntry,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(mOriginMetadata)
.map([](const auto& res) { return res.first; }));
quotaManager->GetOrCreateTemporaryOriginDirectory(mOriginMetadata));
QM_TRY(MOZ_TO_RESULT(directoryEntry->GetPath(mOriginDirectoryPath)));
@@ -4259,7 +4264,7 @@ nsresult Connection::InitTemporaryOriginHelper::RunOnIOThread() {
}
NS_IMETHODIMP
Connection::InitTemporaryOriginHelper::Run() {
Connection::GetOrCreateTemporaryOriginDirectoryHelper::Run() {
AssertIsOnIOThread();
nsresult rv = RunOnIOThread();
@@ -7010,21 +7015,21 @@ nsresult PrepareDatastoreOp::DatabaseWork() {
([hasDataForMigration, &quotaManager,
this]() -> mozilla::Result<nsCOMPtr<nsIFile>, nsresult> {
if (hasDataForMigration) {
QM_TRY_RETURN(quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata)
.map([](const auto& res) { return res.first; }));
QM_TRY_RETURN(
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata, /* aCreateIfNonExistent*/ true)
.map([](const auto& res) { return res.first; }));
}
MOZ_ASSERT(mOriginMetadata.mPersistenceType ==
PERSISTENCE_TYPE_DEFAULT);
QM_TRY_UNWRAP(auto directoryEntry,
quotaManager->GetOriginDirectory(mOriginMetadata));
quotaManager->EnsureQuotaForOrigin(mOriginMetadata);
return directoryEntry;
QM_TRY_RETURN(
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata, /* aCreateIfNonExistent*/ false)
.map([](const auto& res) { return res.first; }));
}()));
QM_TRY(MOZ_TO_RESULT(directoryEntry->Append(

View File

@@ -102,8 +102,16 @@ function initPersistentOrigin(principal) {
return Services.qms.initializePersistentOrigin(principal);
}
function initTemporaryOrigin(persistence, principal) {
return Services.qms.initializeTemporaryOrigin(persistence, principal);
function initTemporaryOrigin(
persistence,
principal,
createIfNonExistent = true
) {
return Services.qms.initializeTemporaryOrigin(
persistence,
principal,
createIfNonExistent
);
}
function getOriginUsage(principal) {

View File

@@ -98,6 +98,7 @@
#include "mozilla/dom/quota/FileUtils.h"
#include "mozilla/dom/quota/MozPromiseUtils.h"
#include "mozilla/dom/quota/PersistenceType.h"
#include "mozilla/dom/quota/QuotaManagerImpl.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/quota/ResultExtensions.h"
#include "mozilla/dom/quota/ScopedLogExtraInfo.h"
@@ -2434,7 +2435,8 @@ void QuotaManager::Shutdown() {
void QuotaManager::InitQuotaForOrigin(
const FullOriginMetadata& aFullOriginMetadata,
const ClientUsageArray& aClientUsages, uint64_t aUsageBytes) {
const ClientUsageArray& aClientUsages, uint64_t aUsageBytes,
bool aDirectoryExists) {
AssertIsOnIOThread();
MOZ_ASSERT(IsBestEffortPersistenceType(aFullOriginMetadata.mPersistenceType));
@@ -2448,61 +2450,7 @@ void QuotaManager::InitQuotaForOrigin(
groupInfo, aFullOriginMetadata.mOrigin,
aFullOriginMetadata.mStorageOrigin, aFullOriginMetadata.mIsPrivate,
aClientUsages, aUsageBytes, aFullOriginMetadata.mLastAccessTime,
aFullOriginMetadata.mPersisted,
/* aDirectoryExists */ true));
}
void QuotaManager::EnsureQuotaForOrigin(const OriginMetadata& aOriginMetadata) {
AssertIsOnIOThread();
MOZ_ASSERT(IsBestEffortPersistenceType(aOriginMetadata.mPersistenceType));
MutexAutoLock lock(mQuotaMutex);
RefPtr<GroupInfo> groupInfo = LockedGetOrCreateGroupInfo(
aOriginMetadata.mPersistenceType, aOriginMetadata.mSuffix,
aOriginMetadata.mGroup);
RefPtr<OriginInfo> originInfo =
groupInfo->LockedGetOriginInfo(aOriginMetadata.mOrigin);
if (!originInfo) {
groupInfo->LockedAddOriginInfo(MakeNotNull<RefPtr<OriginInfo>>(
groupInfo, aOriginMetadata.mOrigin, aOriginMetadata.mStorageOrigin,
aOriginMetadata.mIsPrivate, ClientUsageArray(),
/* aUsageBytes */ 0,
/* aAccessTime */ PR_Now(), /* aPersisted */ false,
/* aDirectoryExists */ false));
}
}
int64_t QuotaManager::NoteOriginDirectoryCreated(
const OriginMetadata& aOriginMetadata) {
AssertIsOnIOThread();
MOZ_ASSERT(IsBestEffortPersistenceType(aOriginMetadata.mPersistenceType));
int64_t timestamp;
MutexAutoLock lock(mQuotaMutex);
RefPtr<GroupInfo> groupInfo = LockedGetOrCreateGroupInfo(
aOriginMetadata.mPersistenceType, aOriginMetadata.mSuffix,
aOriginMetadata.mGroup);
RefPtr<OriginInfo> originInfo =
groupInfo->LockedGetOriginInfo(aOriginMetadata.mOrigin);
if (originInfo) {
timestamp = originInfo->LockedAccessTime();
originInfo->mDirectoryExists = true;
} else {
timestamp = PR_Now();
groupInfo->LockedAddOriginInfo(MakeNotNull<RefPtr<OriginInfo>>(
groupInfo, aOriginMetadata.mOrigin, aOriginMetadata.mStorageOrigin,
aOriginMetadata.mIsPrivate, ClientUsageArray(),
/* aUsageBytes */ 0, /* aAccessTime */ timestamp,
/* aPersisted */ false,
/* aDirectoryExists */ true));
}
return timestamp;
aFullOriginMetadata.mPersisted, aDirectoryExists));
}
void QuotaManager::DecreaseUsageForClient(const ClientMetadata& aClientMetadata,
@@ -2954,7 +2902,7 @@ void QuotaManager::UnloadQuota() {
for (const auto& originInfo : groupInfo->mOriginInfos) {
MOZ_ASSERT(!originInfo->mCanonicalQuotaObjects.Count());
if (!originInfo->mDirectoryExists) {
if (!originInfo->LockedDirectoryExists()) {
continue;
}
@@ -3006,6 +2954,43 @@ void QuotaManager::UnloadQuota() {
QM_TRY(MOZ_TO_RESULT(transaction.Commit()), QM_VOID);
}
void QuotaManager::RemoveOriginFromCache(
const OriginMetadata& aOriginMetadata) {
AssertIsOnIOThread();
MOZ_ASSERT(mStorageConnection);
MOZ_ASSERT(!mTemporaryStorageInitializedInternal);
if (!mCacheUsable) {
return;
}
mozStorageTransaction transaction(
mStorageConnection, false, mozIStorageConnection::TRANSACTION_IMMEDIATE);
QM_TRY_INSPECT(
const auto& stmt,
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
nsCOMPtr<mozIStorageStatement>, mStorageConnection, CreateStatement,
"DELETE FROM origin WHERE repository_id = :repository_id AND suffix = :suffix AND group_ = :group AND origin = :origin;"_ns),
QM_VOID);
QM_TRY(MOZ_TO_RESULT(stmt->BindInt32ByName("repository_id"_ns,
aOriginMetadata.mPersistenceType)),
QM_VOID);
QM_TRY(MOZ_TO_RESULT(
stmt->BindUTF8StringByName("suffix"_ns, aOriginMetadata.mSuffix)),
QM_VOID);
QM_TRY(MOZ_TO_RESULT(
stmt->BindUTF8StringByName("group"_ns, aOriginMetadata.mGroup)),
QM_VOID);
QM_TRY(MOZ_TO_RESULT(
stmt->BindUTF8StringByName("origin"_ns, aOriginMetadata.mOrigin)),
QM_VOID);
QM_TRY(MOZ_TO_RESULT(stmt->Execute()), QM_VOID);
QM_TRY(MOZ_TO_RESULT(transaction.Commit()), QM_VOID);
}
already_AddRefed<QuotaObject> QuotaManager::GetQuotaObject(
PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
Client::Type aClientType, nsIFile* aFile, int64_t aFileSize,
@@ -3220,6 +3205,49 @@ Result<bool, nsresult> QuotaManager::DoesOriginDirectoryExist(
QM_TRY_RETURN(MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
}
Result<nsCOMPtr<nsIFile>, nsresult>
QuotaManager::GetOrCreateTemporaryOriginDirectory(
const OriginMetadata& aOriginMetadata) {
AssertIsOnIOThread();
MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
MOZ_DIAGNOSTIC_ASSERT(IsStorageInitializedInternal());
MOZ_DIAGNOSTIC_ASSERT(IsTemporaryStorageInitializedInternal());
MOZ_DIAGNOSTIC_ASSERT(IsTemporaryOriginInitializedInternal(aOriginMetadata));
QM_TRY_UNWRAP(auto directory, GetOriginDirectory(aOriginMetadata));
QM_TRY_INSPECT(const bool& created, EnsureOriginDirectory(*directory));
if (created) {
// A new origin directory has been created.
// We have a temporary origin which has been initialized without ensuring
// respective origin directory. So OriginInfo already exists and it needs
// to be updated because the origin directory has been just created.
auto [timestamp, persisted] =
WithOriginInfo(aOriginMetadata, [](const auto& originInfo) {
const int64_t timestamp = originInfo->LockedAccessTime();
const bool persisted = originInfo->LockedPersisted();
originInfo->LockedDirectoryCreated();
return std::make_pair(timestamp, persisted);
});
QM_TRY(MOZ_TO_RESULT(CreateDirectoryMetadata2(*directory, timestamp,
persisted, aOriginMetadata)));
}
return std::move(directory);
}
Result<Ok, nsresult> QuotaManager::EnsureTemporaryOriginDirectoryCreated(
const OriginMetadata& aOriginMetadata) {
QM_TRY_RETURN(GetOrCreateTemporaryOriginDirectory(aOriginMetadata)
.map([](const auto& res) { return Ok{}; }));
}
// static
nsresult QuotaManager::CreateDirectoryMetadata(
nsIFile& aDirectory, int64_t aTimestamp,
@@ -5373,6 +5401,16 @@ RefPtr<UniversalDirectoryLock> QuotaManager::CreateDirectoryLockInternal(
aClientType, aExclusive, aCategory);
}
bool QuotaManager::IsPendingOrigin(
const OriginMetadata& aOriginMetadata) const {
MutexAutoLock lock(mQuotaMutex);
RefPtr<OriginInfo> originInfo =
LockedGetOriginInfo(aOriginMetadata.mPersistenceType, aOriginMetadata);
return originInfo && !originInfo->LockedDirectoryExists();
}
RefPtr<BoolPromise> QuotaManager::InitializePersistentOrigin(
const PrincipalInfo& aPrincipalInfo) {
AssertIsOnOwningThread();
@@ -5544,7 +5582,8 @@ QuotaManager::EnsurePersistentOriginIsInitializedInternal(
}
RefPtr<BoolPromise> QuotaManager::InitializeTemporaryOrigin(
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo) {
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
bool aCreateIfNonExistent) {
AssertIsOnOwningThread();
QM_TRY_UNWRAP(PrincipalMetadata principalMetadata,
@@ -5571,19 +5610,21 @@ RefPtr<BoolPromise> QuotaManager::InitializeTemporaryOrigin(
return directoryLock->Acquire()->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr(this), aPersistenceType, aPrincipalInfo,
aCreateIfNonExistent,
directoryLock](const BoolPromise::ResolveOrRejectValue& aValue) mutable {
if (aValue.IsReject()) {
return BoolPromise::CreateAndReject(aValue.RejectValue(), __func__);
}
return self->InitializeTemporaryOrigin(aPersistenceType, aPrincipalInfo,
aCreateIfNonExistent,
std::move(directoryLock));
});
}
RefPtr<BoolPromise> QuotaManager::InitializeTemporaryOrigin(
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock) {
AssertIsOnOwningThread();
MOZ_ASSERT(aDirectoryLock);
MOZ_ASSERT(aDirectoryLock->Acquired());
@@ -5603,7 +5644,7 @@ RefPtr<BoolPromise> QuotaManager::InitializeTemporaryOrigin(
auto initializeTemporaryOriginOp = CreateInitializeTemporaryOriginOp(
WrapMovingNotNullUnchecked(this), aPersistenceType, aPrincipalInfo,
std::move(aDirectoryLock));
aCreateIfNonExistent, std::move(aDirectoryLock));
RegisterNormalOriginOp(*initializeTemporaryOriginOp);
@@ -5658,26 +5699,47 @@ bool QuotaManager::IsTemporaryOriginInitializedInternal(
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
QuotaManager::EnsureTemporaryOriginIsInitializedInternal(
const OriginMetadata& aOriginMetadata) {
const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent) {
AssertIsOnIOThread();
MOZ_ASSERT(aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
MOZ_DIAGNOSTIC_ASSERT(mStorageConnection);
MOZ_DIAGNOSTIC_ASSERT(mTemporaryStorageInitializedInternal);
const auto innerFunc = [&aOriginMetadata, this](const auto&)
const auto innerFunc = [&aOriginMetadata, aCreateIfNonExistent,
this](const auto&)
-> mozilla::Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult> {
// Get directory for this origin and persistence type.
QM_TRY_UNWRAP(auto directory, GetOriginDirectory(aOriginMetadata));
if (IsTemporaryOriginInitializedInternal(aOriginMetadata)) {
return std::pair(std::move(directory), false);
}
if (!aCreateIfNonExistent) {
const int64_t timestamp = PR_Now();
InitQuotaForOrigin(FullOriginMetadata{aOriginMetadata,
/* aPersisted */ false, timestamp},
ClientUsageArray(), /* aUsageBytes */ 0,
/* aDirectoryExists */ false);
return std::pair(std::move(directory), false);
}
QM_TRY_INSPECT(const bool& created, EnsureOriginDirectory(*directory));
if (created) {
const int64_t timestamp = NoteOriginDirectoryCreated(aOriginMetadata);
const int64_t timestamp = PR_Now();
// Only creating .metadata-v2 to reduce IO.
QM_TRY(MOZ_TO_RESULT(CreateDirectoryMetadata2(*directory, timestamp,
/* aPersisted */ false,
aOriginMetadata)));
// Don't need to traverse the directory, since it's empty.
InitQuotaForOrigin(FullOriginMetadata{aOriginMetadata,
/* aPersisted */ false, timestamp},
ClientUsageArray(), /* aUsageBytes */ 0);
}
// TODO: If the metadata file exists and we didn't call
@@ -5758,7 +5820,8 @@ QuotaManager::EnsureTemporaryClientIsInitialized(
MOZ_DIAGNOSTIC_ASSERT(IsTemporaryStorageInitializedInternal());
MOZ_DIAGNOSTIC_ASSERT(IsTemporaryOriginInitializedInternal(aClientMetadata));
QM_TRY_UNWRAP(auto directory, GetOriginDirectory(aClientMetadata));
QM_TRY_UNWRAP(auto directory,
GetOrCreateTemporaryOriginDirectory(aClientMetadata));
QM_TRY(MOZ_TO_RESULT(
directory->Append(Client::TypeToString(aClientMetadata.mClientType))));

View File

@@ -173,4 +173,11 @@ void OriginInfo::LockedPersist() {
mGroupInfo->mUsage -= mUsage;
}
void OriginInfo::LockedDirectoryCreated() {
AssertCurrentThreadOwnsQuotaMutex();
MOZ_ASSERT(!mDirectoryExists);
mDirectoryExists = true;
}
} // namespace mozilla::dom::quota

View File

@@ -19,6 +19,7 @@ class GroupInfo;
class OriginInfo final {
friend class CanonicalQuotaObject;
friend class GroupInfo;
friend class PersistOp;
friend class QuotaManager;
public:
@@ -65,6 +66,12 @@ class OriginInfo final {
bool IsExtensionOrigin() const { return mIsExtension; }
bool LockedDirectoryExists() const {
AssertCurrentThreadOwnsQuotaMutex();
return mDirectoryExists;
}
OriginMetadata FlattenToOriginMetadata() const;
FullOriginMetadata LockedFlattenToFullOriginMetadata() const;
@@ -96,6 +103,8 @@ class OriginInfo final {
void LockedPersist();
void LockedDirectoryCreated();
nsTHashMap<nsStringHashKey, NotNull<CanonicalQuotaObject*>>
mCanonicalQuotaObjects;
ClientUsageArray mClientUsages;
@@ -114,7 +123,7 @@ class OriginInfo final {
* want to be able to track quota for an origin without creating its origin
* directory or the per-client files until they are actually needed to store
* data. In those cases, the OriginInfo will be created by
* EnsureQuotaForOrigin and the resulting mDirectoryExists will be false until
* InitQuotaForOrigin and the resulting mDirectoryExists will be false until
* the origin actually needs to be created. It is possible for mUsage to be
* greater than zero while mDirectoryExists is false, representing a state
* where a client like LocalStorage has reserved quota for disk writes, but

View File

@@ -476,11 +476,13 @@ class InitializePersistentOriginOp final : public InitializeOriginRequestBase {
class InitializeTemporaryOriginOp final : public InitializeOriginRequestBase {
const PersistenceType mPersistenceType;
const bool mCreateIfNonExistent;
public:
InitializeTemporaryOriginOp(MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
PersistenceType aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
bool aCreateIfNonExistent,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
private:
@@ -984,10 +986,10 @@ RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentOriginOp(
RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock) {
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock) {
return MakeRefPtr<InitializeTemporaryOriginOp>(
std::move(aQuotaManager), aPersistenceType, aPrincipalInfo,
std::move(aDirectoryLock));
aCreateIfNonExistent, std::move(aDirectoryLock));
}
RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
@@ -1986,11 +1988,12 @@ bool InitializePersistentOriginOp::GetResolveValue() {
InitializeTemporaryOriginOp::InitializeTemporaryOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock)
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock)
: InitializeOriginRequestBase(std::move(aQuotaManager),
"dom::quota::InitializeTemporaryOriginOp",
aPrincipalInfo, std::move(aDirectoryLock)),
mPersistenceType(aPersistenceType) {
mPersistenceType(aPersistenceType),
mCreateIfNonExistent(aCreateIfNonExistent) {
AssertIsOnOwningThread();
}
@@ -2009,7 +2012,8 @@ nsresult InitializeTemporaryOriginOp::DoDirectoryWork(
QM_TRY_UNWRAP(mCreated,
(aQuotaManager
.EnsureTemporaryOriginIsInitializedInternal(
OriginMetadata{mPrincipalMetadata, mPersistenceType})
OriginMetadata{mPrincipalMetadata, mPersistenceType},
mCreateIfNonExistent)
.map([](const auto& res) { return res.second; })));
return NS_OK;
@@ -2371,17 +2375,14 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
aQuotaManager, aOriginMetadata.mPersistenceType,
OriginScope::FromOrigin(aOriginMetadata.mOrigin),
[&aQuotaManager, &aOriginMetadata](
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
-> Result<Ok, nsresult> {
QM_TRY_UNWRAP(auto directory,
aQuotaManager.GetOriginDirectory(aOriginMetadata));
QM_TRY_INSPECT(const bool& exists,
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists));
if (!exists) {
return Ok{};
}
// We're not checking if the origin directory actualy exists because
// it can be a pending origin (OriginInfo does exist but the origin
// directory hasn't been created yet).
QM_TRY_RETURN(aBody(std::move(directory)));
});
@@ -2395,7 +2396,7 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
DeleteFilesInternal(
aQuotaManager, aPersistenceType, aOriginScope,
[&aQuotaManager, &aPersistenceType](
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>&&)>& aBody)
const std::function<Result<Ok, nsresult>(nsCOMPtr<nsIFile>)>& aBody)
-> Result<Ok, nsresult> {
QM_TRY_INSPECT(
const auto& directory,
@@ -2408,7 +2409,38 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
return Ok{};
}
QM_TRY_RETURN(CollectEachFile(*directory, aBody));
QM_TRY(CollectEachFile(*directory, aBody));
// CollectEachFile above only consulted the file-system to get a list of
// known origins, but we also need to include origins that have pending
// quota usage.
nsTArray<OriginMetadata> originMetadataArray;
aQuotaManager.CollectPendingOriginsForListing(
[aPersistenceType, &originMetadataArray](const auto& originInfo) {
if (originInfo->GetGroupInfo()->GetPersistenceType() !=
aPersistenceType) {
return;
}
originMetadataArray.AppendElement(
originInfo->FlattenToOriginMetadata());
});
if (originMetadataArray.IsEmpty()) {
return Ok{};
}
nsTArray<nsCOMPtr<nsIFile>> originDirectories;
QM_TRY(TransformAbortOnErr(
originMetadataArray, MakeBackInserter(originDirectories),
[&aQuotaManager](const auto& originMetadata)
-> Result<nsCOMPtr<nsIFile>, nsresult> {
QM_TRY_UNWRAP(auto originDirectory,
aQuotaManager.GetOriginDirectory(originMetadata));
return originDirectory;
}));
QM_TRY_RETURN(CollectEachInRange(originDirectories, aBody));
});
}
@@ -2431,7 +2463,7 @@ void ClearRequestBase::DeleteFilesInternal(
QM_TRY(
aFileCollector([&originScope = aOriginScope, aPersistenceType,
&aQuotaManager, &directoriesForRemovalRetry,
this](nsCOMPtr<nsIFile>&& file)
this](nsCOMPtr<nsIFile> file)
-> mozilla::Result<Ok, nsresult> {
QM_TRY_INSPECT(const auto& dirEntryKind, GetDirEntryKind(*file));
@@ -2486,8 +2518,10 @@ void ClearRequestBase::DeleteFilesInternal(
: aQuotaManager.IsTemporaryStorageInitializedInternal();
// If it hasn't been initialized, we don't need to update the
// quota and notify the removing client.
// quota and notify the removing client, but we do need to remove
// it from quota info cache.
if (!initialized) {
aQuotaManager.RemoveOriginFromCache(metadata);
break;
}
@@ -2511,9 +2545,34 @@ void ClearRequestBase::DeleteFilesInternal(
break;
}
case nsIFileKind::DoesNotExist:
// Ignore files that got removed externally while iterating.
case nsIFileKind::DoesNotExist: {
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
break;
}
QM_TRY_UNWRAP(auto metadata, aQuotaManager.GetOriginMetadata(file));
MOZ_ASSERT(metadata.mPersistenceType == aPersistenceType);
// Skip the origin directory if it doesn't match the pattern.
if (!originScope.Matches(
OriginScope::FromOrigin(metadata.mOrigin))) {
break;
}
if (!aQuotaManager.IsPendingOrigin(metadata)) {
break;
}
mOriginMetadataArray.AppendElement(metadata);
aQuotaManager.RemoveQuotaForOrigin(aPersistenceType, metadata);
aQuotaManager.OriginClearCompleted(
aPersistenceType, metadata.mOrigin, Nullable<Client::Type>());
break;
}
}
mIterations++;
@@ -2885,6 +2944,11 @@ void ShutdownOriginOp::CollectOriginMetadata(
QM_TRY_INSPECT(const bool& exists,
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_VOID);
if (!exists) {
if (aOriginMetadata.mPersistenceType != PERSISTENCE_TYPE_PERSISTENT &&
mQuotaManager->IsPendingOrigin(aOriginMetadata)) {
mOriginMetadataArray.AppendElement(aOriginMetadata);
}
return;
}
@@ -3094,6 +3158,7 @@ nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
// Update directory metadata on disk first. Then, create/update the
// originInfo if needed.
QM_TRY_INSPECT(const auto& directory,
aQuotaManager.GetOriginDirectory(originMetadata));
@@ -3101,22 +3166,58 @@ nsresult PersistOp::DoDirectoryWork(QuotaManager& aQuotaManager) {
aQuotaManager.EnsureOriginDirectory(*directory));
if (created) {
// A new origin directory has been created.
// XXX The code below could be converted to a function which returns the
// timestamp.
int64_t timestamp;
// Origin directory has been successfully created.
// Create OriginInfo too if temporary storage was already initialized.
// Update OriginInfo too if temporary origin was already initialized.
if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
timestamp = aQuotaManager.NoteOriginDirectoryCreated(originMetadata);
if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
// We have a temporary origin which has been initialized without
// ensuring respective origin directory. So OriginInfo already exists
// and it needs to be updated because the origin directory has been
// just created.
timestamp = aQuotaManager.WithOriginInfo(
originMetadata, [](const auto& originInfo) {
const int64_t timestamp = originInfo->LockedAccessTime();
originInfo->LockedDirectoryCreated();
return timestamp;
});
} else {
timestamp = PR_Now();
}
} else {
timestamp = PR_Now();
}
QM_TRY(MOZ_TO_RESULT(QuotaManager::CreateDirectoryMetadata2(
*directory, timestamp,
/* aPersisted */ true, originMetadata)));
*directory, timestamp, /* aPersisted */ true, originMetadata)));
// Update or create OriginInfo too if temporary storage was already
// initialized.
if (aQuotaManager.IsTemporaryStorageInitializedInternal()) {
aQuotaManager.PersistOrigin(originMetadata);
if (aQuotaManager.IsTemporaryOriginInitializedInternal(originMetadata)) {
// In this case, we have a temporary origin which has been initialized
// without ensuring respective origin directory. So OriginInfo already
// exists and it needs to be updated because the origin directory has
// been just created.
aQuotaManager.PersistOrigin(originMetadata);
} else {
// In this case, we have a temporary origin which hasn't been
// initialized yet. So OriginInfo needs to be created because the
// origin directory has been just created.
aQuotaManager.InitQuotaForOrigin(
FullOriginMetadata{originMetadata, /* aPersisted */ true,
timestamp},
ClientUsageArray(), /* aUsageBytes */ 0);
}
}
} else {
QM_TRY_INSPECT(

View File

@@ -98,7 +98,7 @@ RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializeTemporaryOriginOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,
const PersistenceType aPersistenceType,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock);
RefPtr<ResolvableNormalOriginOp<bool>> CreateInitializePersistentClientOp(
MovingNotNull<RefPtr<QuotaManager>> aQuotaManager,

View File

@@ -142,7 +142,8 @@ parent:
returns(BoolResponse response);
async InitializeTemporaryOrigin(PersistenceType persistenceType,
PrincipalInfo principalInfo)
PrincipalInfo principalInfo,
bool createIfNonExistent)
returns(BoolResponse response);
async InitializePersistentClient(PrincipalInfo principalInfo,

View File

@@ -158,36 +158,19 @@ class QuotaManager final : public BackgroundThreadObject {
}
/**
* For initialization of an origin where the directory already exists. This is
* used by EnsureTemporaryStorageIsInitializedInternal/InitializeRepository
* once it has tallied origin usage by calling each of the QuotaClient
* InitOrigin methods.
* For initialization of an origin where the directory either exists or it
* does not. The directory exists case is used by InitializeOrigin once it
* has tallied origin usage by calling each of the QuotaClient InitOrigin
* methods. It's also used by LoadQuota when quota information is available
* from the cache. EnsureTemporaryStorageIsInitializedInternal calls this
* either if the directory exists or it does not depending on requirements
* of a particular quota client. The special case when origin directory is
* not created during origin initialization is currently utilized only by
* LSNG.
*/
void InitQuotaForOrigin(const FullOriginMetadata& aFullOriginMetadata,
const ClientUsageArray& aClientUsages,
uint64_t aUsageBytes);
/**
* For use in special-cases like LSNG where we need to be able to know that
* there is no data stored for an origin. LSNG knows that there is 0 usage for
* its storage of an origin and wants to make sure there is a QuotaObject
* tracking this. This method will create a non-persisted, 0-usage,
* mDirectoryExists=false OriginInfo if there isn't already an OriginInfo. If
* an OriginInfo already exists, it will be left as-is, because that implies a
* different client has usages for the origin (and there's no need to add
* LSNG's 0 usage to the QuotaObject).
*/
void EnsureQuotaForOrigin(const OriginMetadata& aOriginMetadata);
/**
* For use when creating an origin directory. It's possible that origin usage
* is already being tracked due to a call to EnsureQuotaForOrigin, and in that
* case we need to update the existing OriginInfo rather than create a new
* one.
*
* @return last access time of the origin.
*/
int64_t NoteOriginDirectoryCreated(const OriginMetadata& aOriginMetadata);
uint64_t aUsageBytes, bool aDirectoryExists = true);
// XXX clients can use QuotaObject instead of calling this method directly.
void DecreaseUsageForClient(const ClientMetadata& aClientMetadata,
@@ -219,6 +202,8 @@ class QuotaManager final : public BackgroundThreadObject {
void UnloadQuota();
void RemoveOriginFromCache(const OriginMetadata& aOriginMetadata);
already_AddRefed<QuotaObject> GetQuotaObject(
PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
Client::Type aClientType, nsIFile* aFile, int64_t aFileSize = -1,
@@ -236,6 +221,10 @@ class QuotaManager final : public BackgroundThreadObject {
void PersistOrigin(const OriginMetadata& aOriginMetadata);
template <typename F>
auto WithOriginInfo(const OriginMetadata& aOriginMetadata, F aFunction)
-> std::invoke_result_t<F, const RefPtr<OriginInfo>&>;
using DirectoryLockIdTableArray =
AutoTArray<Client::DirectoryLockIdTable, Client::TYPE_MAX>;
void AbortOperationsForLocks(const DirectoryLockIdTableArray& aLockIds);
@@ -250,6 +239,12 @@ class QuotaManager final : public BackgroundThreadObject {
Result<bool, nsresult> DoesOriginDirectoryExist(
const OriginMetadata& aOriginMetadata) const;
Result<nsCOMPtr<nsIFile>, nsresult> GetOrCreateTemporaryOriginDirectory(
const OriginMetadata& aOriginMetadata);
Result<Ok, nsresult> EnsureTemporaryOriginDirectoryCreated(
const OriginMetadata& aOriginMetadata);
static nsresult CreateDirectoryMetadata(
nsIFile& aDirectory, int64_t aTimestamp,
const OriginMetadata& aOriginMetadata);
@@ -334,6 +329,8 @@ class QuotaManager final : public BackgroundThreadObject {
template <typename P>
void CollectPendingOriginsForListing(P aPredicate);
bool IsPendingOrigin(const OriginMetadata& aOriginMetadata) const;
RefPtr<BoolPromise> InitializeStorage();
RefPtr<BoolPromise> InitializeStorage(
@@ -388,11 +385,12 @@ class QuotaManager final : public BackgroundThreadObject {
const OriginMetadata& aOriginMetadata);
RefPtr<BoolPromise> InitializeTemporaryOrigin(
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo);
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
bool aCreateIfNonExistent);
RefPtr<BoolPromise> InitializeTemporaryOrigin(
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo,
RefPtr<UniversalDirectoryLock> aDirectoryLock);
bool aCreateIfNonExistent, RefPtr<UniversalDirectoryLock> aDirectoryLock);
RefPtr<BoolPromise> TemporaryOriginInitialized(
PersistenceType aPersistenceType, const PrincipalInfo& aPrincipalInfo);
@@ -407,7 +405,7 @@ class QuotaManager final : public BackgroundThreadObject {
// indicating whether the directory was newly created.
Result<std::pair<nsCOMPtr<nsIFile>, bool>, nsresult>
EnsureTemporaryOriginIsInitializedInternal(
const OriginMetadata& aOriginMetadata);
const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent);
RefPtr<BoolPromise> InitializePersistentClient(
const PrincipalInfo& aPrincipalInfo, Client::Type aClientType);

View File

@@ -14,6 +14,19 @@
namespace mozilla::dom::quota {
template <typename F>
auto QuotaManager::WithOriginInfo(const OriginMetadata& aOriginMetadata,
F aFunction)
-> std::invoke_result_t<F, const RefPtr<OriginInfo>&> {
MutexAutoLock lock(mQuotaMutex);
RefPtr<OriginInfo> originInfo =
LockedGetOriginInfo(aOriginMetadata.mPersistenceType, aOriginMetadata);
MOZ_ASSERT(originInfo);
return aFunction(originInfo);
}
template <typename P>
void QuotaManager::CollectPendingOriginsForListing(P aPredicate) {
MutexAutoLock lock(mQuotaMutex);
@@ -28,7 +41,7 @@ void QuotaManager::CollectPendingOriginsForListing(P aPredicate) {
pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
if (groupInfo) {
for (const auto& originInfo : groupInfo->mOriginInfos) {
if (!originInfo->mDirectoryExists) {
if (!originInfo->LockedDirectoryExists()) {
aPredicate(originInfo);
}
}

View File

@@ -711,7 +711,7 @@ QuotaManagerService::InitializePersistentOrigin(nsIPrincipal* aPrincipal,
NS_IMETHODIMP
QuotaManagerService::InitializeTemporaryOrigin(
const nsACString& aPersistenceType, nsIPrincipal* aPrincipal,
nsIQuotaRequest** _retval) {
bool aCreateIfNonExistent, nsIQuotaRequest** _retval) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPrincipal);
MOZ_ASSERT(nsContentUtils::IsCallerChrome());
@@ -752,7 +752,8 @@ QuotaManagerService::InitializeTemporaryOrigin(
auto request = MakeRefPtr<Request>();
mBackgroundActor
->SendInitializeTemporaryOrigin(persistenceType, principalInfo)
->SendInitializeTemporaryOrigin(persistenceType, principalInfo,
aCreateIfNonExistent)
->Then(GetCurrentSerialEventTarget(), __func__,
BoolResponsePromiseResolveOrRejectCallback(request));

View File

@@ -440,7 +440,7 @@ mozilla::ipc::IPCResult Quota::RecvInitializePersistentOrigin(
mozilla::ipc::IPCResult Quota::RecvInitializeTemporaryOrigin(
const PersistenceType& aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
const PrincipalInfo& aPrincipalInfo, const bool& aCreateIfNonExistent,
InitializeTemporaryOriginResolver&& aResolve) {
AssertIsOnBackgroundThread();
@@ -459,7 +459,9 @@ mozilla::ipc::IPCResult Quota::RecvInitializeTemporaryOrigin(
QuotaManager::GetOrCreate(),
ResolveBoolResponseAndReturn(aResolve));
quotaManager->InitializeTemporaryOrigin(aPersistenceType, aPrincipalInfo)
quotaManager
->InitializeTemporaryOrigin(aPersistenceType, aPrincipalInfo,
aCreateIfNonExistent)
->Then(GetCurrentSerialEventTarget(), __func__,
BoolPromiseResolveOrRejectCallback(this, std::move(aResolve)));

View File

@@ -64,7 +64,7 @@ class Quota final : public PQuotaParent {
virtual mozilla::ipc::IPCResult RecvInitializeTemporaryOrigin(
const PersistenceType& aPersistenceType,
const PrincipalInfo& aPrincipalInfo,
const PrincipalInfo& aPrincipalInfo, const bool& aCreateIfNonExistent,
InitializeTemporaryOriginResolver&& aResolve) override;
virtual mozilla::ipc::IPCResult RecvInitializePersistentClient(

View File

@@ -116,10 +116,15 @@ interface nsIQuotaManagerService : nsISupports
*
* @param aPrincipal
* A principal for the origin whose directory is to be initialized.
*
* @param aCreateIfNonExistent
* An optional boolean to indicate creation of origin directory if it
* doesn't exist yet.
*/
[must_use] nsIQuotaRequest
initializeTemporaryOrigin(in ACString aPersistenceType,
in nsIPrincipal aPrincipal);
in nsIPrincipal aPrincipal,
[optional] in boolean aCreateIfNonExistent);
/**
* Initializes persistent client directory for the given origin and client.

View File

@@ -221,18 +221,19 @@ void QuotaManagerDependencyFixture::ShutdownTemporaryStorage() {
// static
void QuotaManagerDependencyFixture::InitializeTemporaryOrigin(
const OriginMetadata& aOriginMetadata) {
const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent) {
mozilla::ipc::PrincipalInfo principalInfo;
ASSERT_NO_FATAL_FAILURE(
CreateContentPrincipalInfo(aOriginMetadata.mOrigin, principalInfo));
PerformOnBackgroundThread([persistenceType = aOriginMetadata.mPersistenceType,
principalInfo = std::move(principalInfo)]() {
principalInfo = std::move(principalInfo),
aCreateIfNonExistent]() {
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
Await(quotaManager->InitializeTemporaryOrigin(persistenceType,
principalInfo));
Await(quotaManager->InitializeTemporaryOrigin(
persistenceType, principalInfo, aCreateIfNonExistent));
});
}

View File

@@ -45,7 +45,8 @@ class QuotaManagerDependencyFixture : public testing::Test {
static void AssertTemporaryStorageNotInitialized();
static void ShutdownTemporaryStorage();
static void InitializeTemporaryOrigin(const OriginMetadata& aOriginMetadata);
static void InitializeTemporaryOrigin(const OriginMetadata& aOriginMetadata,
bool aCreateIfNonExistent = true);
static void TemporaryOriginInitialized(const OriginMetadata& aOriginMetadata,
bool* aResult);
static void AssertTemporaryOriginInitialized(

View File

@@ -59,7 +59,7 @@ TEST_F(TestFileOutputStream, extendFileStreamWithSetEOF) {
{
auto res = quotaManager->EnsureTemporaryOriginIsInitializedInternal(
originMetadata);
originMetadata, /* aCreateIfNonExistent */ true);
ASSERT_TRUE(res.isOk());
}
@@ -80,7 +80,8 @@ TEST_F(TestFileOutputStream, extendFileStreamWithSetEOF) {
quota::Client::Type::SDB);
{
auto testPathRes = quotaManager->GetOriginDirectory(originMetadata);
auto testPathRes =
quotaManager->GetOrCreateTemporaryOriginDirectory(originMetadata);
ASSERT_TRUE(testPathRes.isOk());

View File

@@ -23,6 +23,10 @@ class TestQuotaManager : public QuotaManagerDependencyFixture {
static void SetUpTestCase() { ASSERT_NO_FATAL_FAILURE(InitializeFixture()); }
static void TearDownTestCase() { ASSERT_NO_FATAL_FAILURE(ShutdownFixture()); }
void TearDown() override {
ASSERT_NO_FATAL_FAILURE(ClearStoragesForOrigin(GetTestOriginMetadata()));
}
};
// Test OpenStorageDirectory when an opening of the storage directory is
@@ -1417,7 +1421,8 @@ TEST_F(TestQuotaManager,
promises.AppendElement(quotaManager->InitializeStorage());
promises.AppendElement(quotaManager->InitializeTemporaryStorage());
promises.AppendElement(quotaManager->InitializeTemporaryOrigin(
testOriginMetadata.mPersistenceType, principalInfo));
testOriginMetadata.mPersistenceType, principalInfo,
/* aCreateIfNonExistent */ false));
{
auto value =
@@ -1436,7 +1441,8 @@ TEST_F(TestQuotaManager,
promises.AppendElement(quotaManager->InitializeStorage());
promises.AppendElement(quotaManager->InitializeTemporaryStorage());
promises.AppendElement(quotaManager->InitializeTemporaryOrigin(
testOriginMetadata.mPersistenceType, principalInfo));
testOriginMetadata.mPersistenceType, principalInfo,
/* aCreateIfNonExistent */ true));
{
auto value =
@@ -1466,7 +1472,58 @@ TEST_F(TestQuotaManager, ClearStoragesForOrigin_Simple) {
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(
InitializeTemporaryOrigin(GetTestOriginMetadata(),
/* aCreateIfNonExistent */ true));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginInitialized(GetTestOriginMetadata()));
PerformOnBackgroundThread([]() {
auto testOriginMetadata = GetTestOriginMetadata();
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateContentPrincipal(testOriginMetadata.mOrigin);
QM_TRY(MOZ_TO_RESULT(principal), QM_TEST_FAIL);
mozilla::ipc::PrincipalInfo principalInfo;
QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo)),
QM_TEST_FAIL);
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
{
auto value = Await(quotaManager->ClearStoragesForOrigin(
/* aPersistenceType */ Nothing(), principalInfo));
ASSERT_TRUE(value.IsResolve());
ASSERT_TRUE(quotaManager->IsStorageInitialized());
ASSERT_TRUE(quotaManager->IsTemporaryStorageInitialized());
ASSERT_FALSE(quotaManager->IsTemporaryOriginInitialized(
testOriginMetadata.mPersistenceType, principalInfo));
}
});
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
}
TEST_F(TestQuotaManager, ClearStoragesForOrigin_NonExistentOriginDirectory) {
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
ASSERT_NO_FATAL_FAILURE(AssertStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginNotInitialized(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ false));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
@@ -1515,7 +1572,58 @@ TEST_F(TestQuotaManager, ClearStoragesForOriginPrefix_Simple) {
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ true));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginInitialized(GetTestOriginMetadata()));
PerformOnBackgroundThread([]() {
auto testOriginMetadata = GetTestOriginMetadata();
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateContentPrincipal(testOriginMetadata.mOrigin);
QM_TRY(MOZ_TO_RESULT(principal), QM_TEST_FAIL);
mozilla::ipc::PrincipalInfo principalInfo;
QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo)),
QM_TEST_FAIL);
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
{
auto value = Await(quotaManager->ClearStoragesForOriginPrefix(
/* aPersistenceType */ Nothing(), principalInfo));
ASSERT_TRUE(value.IsResolve());
ASSERT_TRUE(quotaManager->IsStorageInitialized());
ASSERT_TRUE(quotaManager->IsTemporaryStorageInitialized());
ASSERT_FALSE(quotaManager->IsTemporaryOriginInitialized(
testOriginMetadata.mPersistenceType, principalInfo));
}
});
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
}
TEST_F(TestQuotaManager,
ClearStoragesForOriginPrefix_NonExistentOriginDirectory) {
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
ASSERT_NO_FATAL_FAILURE(AssertStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginNotInitialized(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ false));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
@@ -1564,7 +1672,58 @@ TEST_F(TestQuotaManager, ClearStoragesForOriginAttributesPattern_Simple) {
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ true));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginInitialized(GetTestOriginMetadata()));
PerformOnBackgroundThread([]() {
auto testOriginMetadata = GetTestOriginMetadata();
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateContentPrincipal(testOriginMetadata.mOrigin);
QM_TRY(MOZ_TO_RESULT(principal), QM_TEST_FAIL);
mozilla::ipc::PrincipalInfo principalInfo;
QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo)),
QM_TEST_FAIL);
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
{
auto value = Await(quotaManager->ClearStoragesForOriginAttributesPattern(
OriginAttributesPattern()));
ASSERT_TRUE(value.IsResolve());
ASSERT_TRUE(quotaManager->IsStorageInitialized());
ASSERT_TRUE(quotaManager->IsTemporaryStorageInitialized());
ASSERT_FALSE(quotaManager->IsTemporaryOriginInitialized(
testOriginMetadata.mPersistenceType, principalInfo));
}
});
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
}
TEST_F(TestQuotaManager,
ClearStoragesForOriginAttributesPattern_NonExistentOriginDirectory) {
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
ASSERT_NO_FATAL_FAILURE(AssertStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginNotInitialized(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ false));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
@@ -1613,7 +1772,57 @@ TEST_F(TestQuotaManager, ShutdownStoragesForOrigin_Simple) {
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ true));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginInitialized(GetTestOriginMetadata()));
PerformOnBackgroundThread([]() {
auto testOriginMetadata = GetTestOriginMetadata();
nsCOMPtr<nsIPrincipal> principal =
BasePrincipal::CreateContentPrincipal(testOriginMetadata.mOrigin);
QM_TRY(MOZ_TO_RESULT(principal), QM_TEST_FAIL);
mozilla::ipc::PrincipalInfo principalInfo;
QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &principalInfo)),
QM_TEST_FAIL);
QuotaManager* quotaManager = QuotaManager::Get();
ASSERT_TRUE(quotaManager);
{
auto value = Await(quotaManager->ShutdownStoragesForOrigin(
/* aPersistenceType */ Nothing(), principalInfo));
ASSERT_TRUE(value.IsResolve());
ASSERT_TRUE(quotaManager->IsStorageInitialized());
ASSERT_TRUE(quotaManager->IsTemporaryStorageInitialized());
ASSERT_FALSE(quotaManager->IsTemporaryOriginInitialized(
testOriginMetadata.mPersistenceType, principalInfo));
}
});
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
}
TEST_F(TestQuotaManager, ShutdownStoragesForOrigin_NonExistentOriginDirectory) {
ASSERT_NO_FATAL_FAILURE(ShutdownStorage());
ASSERT_NO_FATAL_FAILURE(AssertStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageNotInitialized());
ASSERT_NO_FATAL_FAILURE(
AssertTemporaryOriginNotInitialized(GetTestOriginMetadata()));
ASSERT_NO_FATAL_FAILURE(InitializeStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryStorage());
ASSERT_NO_FATAL_FAILURE(InitializeTemporaryOrigin(
GetTestOriginMetadata(), /* aCreateIfNonExistent */ false));
ASSERT_NO_FATAL_FAILURE(AssertStorageInitialized());
ASSERT_NO_FATAL_FAILURE(AssertTemporaryStorageInitialized());

View File

@@ -32,11 +32,15 @@ namespace {
void InitializeClientDirectory(const ClientMetadata& aClientMetadata) {
QuotaManager* quotaManager = QuotaManager::Get();
QM_TRY_INSPECT(
const auto& directory,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(aClientMetadata)
.map([](const auto& aPair) { return aPair.first; }),
QM_TEST_FAIL);
QM_TRY_INSPECT(const auto& directory,
quotaManager
->EnsureTemporaryOriginIsInitializedInternal(
aClientMetadata, /* aCreateIfNonExistent */ true)
.map([](const auto& aPair) { return aPair.first; }),
QM_TEST_FAIL);
QM_TRY(quotaManager->EnsureTemporaryOriginDirectoryCreated(aClientMetadata),
QM_TEST_FAIL);
QM_TRY(MOZ_TO_RESULT(directory->Append(
Client::TypeToString(aClientMetadata.mClientType))),

View File

@@ -121,16 +121,16 @@ class QuotaTestCase(MarionetteTestCase):
script_args=(),
)
def initTemporaryOrigin(self, persistenceType, origin):
def initTemporaryOrigin(self, persistenceType, origin, createIfNonExistent=True):
with self.marionette.using_context(self.marionette.CONTEXT_CHROME):
return self.executeAsyncScript(
"""
const [persistenceType, origin] = arguments;
const [persistenceType, origin, createIfNonExistent] = arguments;
async function main() {
const principal = Services.scriptSecurityManager.
createContentPrincipalFromOrigin(origin);
let req = Services.qms.initializeTemporaryOrigin(persistenceType, principal);
let req = Services.qms.initializeTemporaryOrigin(persistenceType, principal, createIfNonExistent);
await requestFinished(req)
return true;
@@ -139,6 +139,7 @@ class QuotaTestCase(MarionetteTestCase):
script_args=(
persistenceType,
origin,
createIfNonExistent,
),
)

View File

@@ -178,10 +178,16 @@ function initPersistentOrigin(principal, callback) {
return request;
}
function initTemporaryOrigin(persistence, principal, callback) {
function initTemporaryOrigin(
persistence,
principal,
createIfNonExistent = true,
callback
) {
let request = SpecialPowers._getQuotaManager().initializeTemporaryOrigin(
persistence,
principal
principal,
createIfNonExistent
);
request.callback = callback;

View File

@@ -594,7 +594,11 @@ const testcases = [
},
{
name: initTemporaryOrigin,
args: ["default", getPrincipal("https://example2.com")],
args: [
"default",
getPrincipal("https://example2.com"),
/* createIfNonExistent */ true,
],
},
],
expectedSnapshots: {
@@ -668,15 +672,27 @@ const testcases = [
initFunctions: [
{
name: initTemporaryOrigin,
args: ["temporary", getPrincipal("https://example.com")],
args: [
"temporary",
getPrincipal("https://example.com"),
/* createIfNonExistent */ true,
],
},
{
name: initTemporaryOrigin,
args: ["default", getPrincipal("https://example.com")],
args: [
"default",
getPrincipal("https://example.com"),
/* createIfNonExistent */ true,
],
},
{
name: initTemporaryOrigin,
args: ["default", getPrincipal("https://example1.com")],
args: [
"default",
getPrincipal("https://example1.com"),
/* createIfNonExistent */ true,
],
},
{
name: initPersistentOrigin,

View File

@@ -75,7 +75,12 @@ function* testSteps() {
initTemporaryStorage(continueToNextStepSync);
yield undefined;
initTemporaryOrigin(origin.persistence, principal, continueToNextStepSync);
initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
yield undefined;
info("Reading out contents of metadata file");

View File

@@ -0,0 +1,76 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const { IndexedDBUtils } = ChromeUtils.importESModule(
"resource://testing-common/dom/indexedDB/test/modules/IndexedDBUtils.sys.mjs"
);
const { LocalStorageUtils } = ChromeUtils.importESModule(
"resource://testing-common/dom/localstorage/test/modules/LocalStorageUtils.sys.mjs"
);
const { PrincipalUtils } = ChromeUtils.importESModule(
"resource://testing-common/dom/quota/test/modules/PrincipalUtils.sys.mjs"
);
const { QuotaUtils } = ChromeUtils.importESModule(
"resource://testing-common/dom/quota/test/modules/QuotaUtils.sys.mjs"
);
async function testNonExistentOriginDirectory() {
const principal = PrincipalUtils.createPrincipal("https://example.com");
const name = "test_quotaClientInteractions.js";
const objectStoreName = "foo";
info("Opening LocalStorage database");
{
const storage = LocalStorageUtils.createStorage(principal);
storage.open();
}
info("Opening IndexedDB database");
{
const request = indexedDB.openForPrincipal(principal, name);
request.onupgradeneeded = function (event) {
const database = event.target.result;
database.createObjectStore(objectStoreName);
};
const database = await IndexedDBUtils.requestFinished(request);
database.close();
}
info("Resetting storage");
{
const request = Services.qms.reset();
await QuotaUtils.requestFinished(request);
}
info("Opening LocalStorage database");
{
const storage = LocalStorageUtils.createStorage(principal);
storage.open();
}
info("Deleting IndexedDB database");
{
const request = indexedDB.deleteForPrincipal(principal, name);
await IndexedDBUtils.requestFinished(request);
}
}
/* exported testSteps */
async function testSteps() {
add_task(
{
pref_set: [
["dom.storage.testing", true],
["dom.storage.client_validation", false],
],
},
testNonExistentOriginDirectory
);
}

View File

@@ -85,7 +85,11 @@ async function testSteps() {
info("Initializing origins");
for (let index = 0; index < 30; index++) {
request = initTemporaryOrigin("default", getPrincipal(getOrigin(index)));
request = initTemporaryOrigin(
"default",
getPrincipal(getOrigin(index)),
/* createIfNonExistent */ true
);
await requestFinished(request);
}

View File

@@ -78,7 +78,11 @@ async function testSteps() {
info(`Testing ${origin.url}`);
try {
request = initTemporaryOrigin("default", getPrincipal(origin.url));
request = initTemporaryOrigin(
"default",
getPrincipal(origin.url),
/* createIfNonExistent */ true
);
await requestFinished(request);
ok(true, "Should not have thrown");

View File

@@ -172,6 +172,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
yield undefined;

View File

@@ -107,6 +107,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
yield undefined;

View File

@@ -363,6 +363,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
}

View File

@@ -148,6 +148,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
yield undefined;

View File

@@ -144,6 +144,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
yield undefined;

View File

@@ -165,6 +165,7 @@ function* testSteps() {
request = initTemporaryOrigin(
origin.persistence,
principal,
/* createIfNonExistent */ true,
continueToNextStepSync
);
}

View File

@@ -103,6 +103,8 @@ skip-if = ["condprof"] # frequent perma fail, then goes away.
["test_persist_groupLimit.js"]
["test_quotaClientInteractions.js"]
["test_removeLocalStorage.js"]
["test_simpledb.js"]

View File

@@ -1196,8 +1196,14 @@ nsresult OpenOp::DatabaseWork() {
mOriginMetadata));
}
QM_TRY_RETURN(quotaManager->EnsureTemporaryOriginIsInitializedInternal(
QM_TRY_UNWRAP(auto dbDirectory,
quotaManager->EnsureTemporaryOriginIsInitializedInternal(
mOriginMetadata, /* aCreateIfNonExistent */ true));
QM_TRY(quotaManager->EnsureTemporaryOriginDirectoryCreated(
mOriginMetadata));
return std::move(dbDirectory);
}()
.map([](const auto& res) { return res.first; })));