278 lines
9.6 KiB
C++
278 lines
9.6 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "QuotaManagerDependencyFixture.h"
|
|
#include "mozIStorageConnection.h"
|
|
#include "mozIStorageService.h"
|
|
#include "mozStorageCID.h"
|
|
#include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
|
|
#include "mozilla/dom/quota/QuotaCommon.h"
|
|
#include "mozilla/dom/quota/QuotaManager.h"
|
|
#include "mozilla/dom/quota/QuotaObject.h"
|
|
#include "mozilla/dom/quota/ResultExtensions.h"
|
|
#include "nsIFile.h"
|
|
#include "nsIFileProtocolHandler.h"
|
|
#include "nsIFileURL.h"
|
|
#include "nsIURIMutator.h"
|
|
#include "nss.h"
|
|
|
|
namespace mozilla {
|
|
|
|
struct NSSInitContextDeleter {
|
|
void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
|
|
};
|
|
|
|
namespace dom::quota::test {
|
|
|
|
namespace {
|
|
|
|
void InitializeClientDirectory(const ClientMetadata& aClientMetadata) {
|
|
QuotaManager* quotaManager = QuotaManager::Get();
|
|
|
|
QM_TRY_INSPECT(
|
|
const auto& directory,
|
|
quotaManager->GetOrCreateTemporaryOriginDirectory(aClientMetadata),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(directory->Append(
|
|
Client::TypeToString(aClientMetadata.mClientType))),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_INSPECT(const bool& exists,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_TEST_FAIL);
|
|
|
|
if (!exists) {
|
|
QM_TRY(MOZ_TO_RESULT(directory->Create(nsIFile::DIRECTORY_TYPE, 0755)),
|
|
QM_TEST_FAIL);
|
|
}
|
|
}
|
|
|
|
void CreateStorageConnection(
|
|
const ClientMetadata& aClientMetadata,
|
|
const Maybe<int64_t>& aMaybeDirectoryLockId,
|
|
const Maybe<IPCStreamCipherStrategy::KeyType>& aMaybeKey,
|
|
nsCOMPtr<mozIStorageConnection>& aConnection) {
|
|
QuotaManager* quotaManager = QuotaManager::Get();
|
|
|
|
QM_TRY_UNWRAP(auto databaseFile,
|
|
quotaManager->GetOriginDirectory(aClientMetadata),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(databaseFile->Append(
|
|
Client::TypeToString(aClientMetadata.mClientType))),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(databaseFile->Append(u"testdatabase.sqlite"_ns)),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_INSPECT(
|
|
const auto& protocolHandler,
|
|
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIProtocolHandler>,
|
|
MOZ_SELECT_OVERLOAD(do_GetService),
|
|
NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file"),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_INSPECT(const auto& fileHandler,
|
|
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIFileProtocolHandler>,
|
|
MOZ_SELECT_OVERLOAD(do_QueryInterface),
|
|
protocolHandler),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_INSPECT(
|
|
const auto& mutator,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsCOMPtr<nsIURIMutator>, fileHandler,
|
|
NewFileURIMutator, databaseFile),
|
|
QM_TEST_FAIL);
|
|
|
|
const auto directoryLockIdClause = [&aMaybeDirectoryLockId] {
|
|
nsAutoCString directoryLockIdClause;
|
|
if (aMaybeDirectoryLockId) {
|
|
directoryLockIdClause =
|
|
"&directoryLockId="_ns + IntToCString(*aMaybeDirectoryLockId);
|
|
}
|
|
return directoryLockIdClause;
|
|
}();
|
|
|
|
const auto keyClause = [&aMaybeKey] {
|
|
nsAutoCString keyClause;
|
|
if (aMaybeKey) {
|
|
keyClause.AssignLiteral("&key=");
|
|
for (uint8_t byte : IPCStreamCipherStrategy::SerializeKey(*aMaybeKey)) {
|
|
keyClause.AppendPrintf("%02x", byte);
|
|
}
|
|
}
|
|
return keyClause;
|
|
}();
|
|
|
|
QM_TRY_INSPECT(
|
|
const auto& fileURL,
|
|
([&mutator, &directoryLockIdClause,
|
|
&keyClause]() -> Result<nsCOMPtr<nsIFileURL>, nsresult> {
|
|
nsCOMPtr<nsIFileURL> result;
|
|
QM_TRY(MOZ_TO_RESULT(NS_MutateURI(mutator)
|
|
.SetQuery("cache=private"_ns +
|
|
directoryLockIdClause + keyClause)
|
|
.Finalize(result)));
|
|
return result;
|
|
}()),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_INSPECT(const auto& storageService,
|
|
MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>,
|
|
MOZ_SELECT_OVERLOAD(do_GetService),
|
|
MOZ_STORAGE_SERVICE_CONTRACTID),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY_UNWRAP(auto connection,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
|
|
nsCOMPtr<mozIStorageConnection>, storageService,
|
|
OpenDatabaseWithFileURL, fileURL, EmptyCString(),
|
|
mozIStorageService::CONNECTION_DEFAULT),
|
|
QM_TEST_FAIL);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(
|
|
connection->ExecuteSimpleSQL("PRAGMA journal_mode = wal;"_ns)),
|
|
QM_TEST_FAIL);
|
|
|
|
// The connection needs to be re-created, otherwise GetQuotaObjects is not
|
|
// able to get the quota object for the journal file.
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
|
|
|
|
QM_TRY_UNWRAP(connection,
|
|
MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(
|
|
nsCOMPtr<mozIStorageConnection>, storageService,
|
|
OpenDatabaseWithFileURL, fileURL, EmptyCString(),
|
|
mozIStorageService::CONNECTION_DEFAULT),
|
|
QM_TEST_FAIL);
|
|
|
|
aConnection = std::move(connection);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class TestStorageConnection : public QuotaManagerDependencyFixture {
|
|
public:
|
|
static void SetUpTestCase() {
|
|
// Do this only once, do not tear it down per test case.
|
|
if (!sNssContext) {
|
|
sNssContext.reset(
|
|
NSS_InitContext("", "", "", "", nullptr,
|
|
NSS_INIT_READONLY | NSS_INIT_NOCERTDB |
|
|
NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN |
|
|
NSS_INIT_OPTIMIZESPACE | NSS_INIT_NOROOTINIT));
|
|
}
|
|
|
|
ASSERT_NO_FATAL_FAILURE(InitializeFixture());
|
|
}
|
|
|
|
static void TearDownTestCase() {
|
|
ASSERT_NO_FATAL_FAILURE(ShutdownFixture());
|
|
|
|
sNssContext = nullptr;
|
|
}
|
|
|
|
void TearDown() override {
|
|
ASSERT_NO_FATAL_FAILURE(ClearStoragesForOrigin(GetTestOriginMetadata()));
|
|
}
|
|
|
|
private:
|
|
struct NSSInitContextDeleter {
|
|
void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); }
|
|
};
|
|
MOZ_RUNINIT inline static std::unique_ptr<NSSInitContext,
|
|
NSSInitContextDeleter>
|
|
sNssContext;
|
|
};
|
|
|
|
TEST_F(TestStorageConnection, BaseVFS) {
|
|
// XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
|
|
// base-toolchains builds fail with: error: duplicate label
|
|
// 'gtest_label_testnofatal_214'
|
|
PerformClientDirectoryTest(GetTestClientMetadata(), [](int64_t) {
|
|
ASSERT_NO_FATAL_FAILURE(InitializeClientDirectory(GetTestClientMetadata()));
|
|
|
|
nsCOMPtr<mozIStorageConnection> connection;
|
|
ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(
|
|
GetTestClientMetadata(), Nothing(), Nothing(), connection));
|
|
|
|
RefPtr<QuotaObject> quotaObject;
|
|
RefPtr<QuotaObject> journalQuotaObject;
|
|
|
|
nsresult rv = connection->GetQuotaObjects(
|
|
getter_AddRefs(quotaObject), getter_AddRefs(journalQuotaObject));
|
|
ASSERT_EQ(rv, NS_ERROR_FAILURE);
|
|
|
|
ASSERT_FALSE(quotaObject);
|
|
ASSERT_FALSE(journalQuotaObject);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
|
|
});
|
|
}
|
|
|
|
TEST_F(TestStorageConnection, QuotaVFS) {
|
|
// XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
|
|
// base-toolchains builds fail with: error: duplicate label
|
|
// 'gtest_label_testnofatal_214'
|
|
PerformClientDirectoryTest(
|
|
GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
InitializeClientDirectory(GetTestClientMetadata()));
|
|
|
|
nsCOMPtr<mozIStorageConnection> connection;
|
|
ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
|
|
Some(aDirectoryLockId),
|
|
Nothing(), connection));
|
|
|
|
RefPtr<QuotaObject> quotaObject;
|
|
RefPtr<QuotaObject> journalQuotaObject;
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
|
|
getter_AddRefs(quotaObject),
|
|
getter_AddRefs(journalQuotaObject))),
|
|
QM_TEST_FAIL);
|
|
|
|
ASSERT_TRUE(quotaObject);
|
|
ASSERT_TRUE(journalQuotaObject);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
|
|
});
|
|
}
|
|
|
|
TEST_F(TestStorageConnection, ObfuscatingVFS) {
|
|
// XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because
|
|
// base-toolchains builds fail with: error: duplicate label
|
|
// 'gtest_label_testnofatal_214'
|
|
PerformClientDirectoryTest(
|
|
GetTestClientMetadata(), [](int64_t aDirectoryLockId) {
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
InitializeClientDirectory(GetTestClientMetadata()));
|
|
|
|
QM_TRY_INSPECT(const auto& key, IPCStreamCipherStrategy::GenerateKey(),
|
|
QM_TEST_FAIL);
|
|
|
|
nsCOMPtr<mozIStorageConnection> connection;
|
|
ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(),
|
|
Some(aDirectoryLockId),
|
|
Some(key), connection));
|
|
|
|
RefPtr<QuotaObject> quotaObject;
|
|
RefPtr<QuotaObject> journalQuotaObject;
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects(
|
|
getter_AddRefs(quotaObject),
|
|
getter_AddRefs(journalQuotaObject))),
|
|
QM_TEST_FAIL);
|
|
|
|
ASSERT_TRUE(quotaObject);
|
|
ASSERT_TRUE(journalQuotaObject);
|
|
|
|
QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL);
|
|
});
|
|
}
|
|
|
|
} // namespace dom::quota::test
|
|
} // namespace mozilla
|