TestStorageConnection.cpp (9960B)
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/. */ 6 7 #include "QuotaManagerDependencyFixture.h" 8 #include "mozIStorageConnection.h" 9 #include "mozIStorageService.h" 10 #include "mozStorageCID.h" 11 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h" 12 #include "mozilla/dom/quota/QuotaCommon.h" 13 #include "mozilla/dom/quota/QuotaManager.h" 14 #include "mozilla/dom/quota/QuotaObject.h" 15 #include "mozilla/dom/quota/ResultExtensions.h" 16 #include "nsIFile.h" 17 #include "nsIFileProtocolHandler.h" 18 #include "nsIFileURL.h" 19 #include "nsIURIMutator.h" 20 #include "nss.h" 21 22 namespace mozilla { 23 24 struct NSSInitContextDeleter { 25 void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); } 26 }; 27 28 namespace dom::quota::test { 29 30 namespace { 31 32 void InitializeClientDirectory(const ClientMetadata& aClientMetadata) { 33 QuotaManager* quotaManager = QuotaManager::Get(); 34 35 QM_TRY_INSPECT( 36 const auto& directory, 37 quotaManager->GetOrCreateTemporaryOriginDirectory(aClientMetadata), 38 QM_TEST_FAIL); 39 40 QM_TRY(MOZ_TO_RESULT(directory->Append( 41 Client::TypeToString(aClientMetadata.mClientType))), 42 QM_TEST_FAIL); 43 44 QM_TRY_INSPECT(const bool& exists, 45 MOZ_TO_RESULT_INVOKE_MEMBER(directory, Exists), QM_TEST_FAIL); 46 47 if (!exists) { 48 QM_TRY(MOZ_TO_RESULT(directory->Create(nsIFile::DIRECTORY_TYPE, 0755)), 49 QM_TEST_FAIL); 50 } 51 } 52 53 void CreateStorageConnection( 54 const ClientMetadata& aClientMetadata, 55 const Maybe<int64_t>& aMaybeDirectoryLockId, 56 const Maybe<IPCStreamCipherStrategy::KeyType>& aMaybeKey, 57 nsCOMPtr<mozIStorageConnection>& aConnection) { 58 QuotaManager* quotaManager = QuotaManager::Get(); 59 60 QM_TRY_UNWRAP(auto databaseFile, 61 quotaManager->GetOriginDirectory(aClientMetadata), 62 QM_TEST_FAIL); 63 64 QM_TRY(MOZ_TO_RESULT(databaseFile->Append( 65 Client::TypeToString(aClientMetadata.mClientType))), 66 QM_TEST_FAIL); 67 68 QM_TRY(MOZ_TO_RESULT(databaseFile->Append(u"testdatabase.sqlite"_ns)), 69 QM_TEST_FAIL); 70 71 QM_TRY_INSPECT( 72 const auto& protocolHandler, 73 MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIProtocolHandler>, 74 MOZ_SELECT_OVERLOAD(do_GetService), 75 NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file"), 76 QM_TEST_FAIL); 77 78 QM_TRY_INSPECT(const auto& fileHandler, 79 MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<nsIFileProtocolHandler>, 80 MOZ_SELECT_OVERLOAD(do_QueryInterface), 81 protocolHandler), 82 QM_TEST_FAIL); 83 84 QM_TRY_INSPECT( 85 const auto& mutator, 86 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED(nsCOMPtr<nsIURIMutator>, fileHandler, 87 NewFileURIMutator, databaseFile), 88 QM_TEST_FAIL); 89 90 const auto directoryLockIdClause = [&aMaybeDirectoryLockId] { 91 nsAutoCString directoryLockIdClause; 92 if (aMaybeDirectoryLockId) { 93 directoryLockIdClause = 94 "&directoryLockId="_ns + IntToCString(*aMaybeDirectoryLockId); 95 } 96 return directoryLockIdClause; 97 }(); 98 99 const auto keyClause = [&aMaybeKey] { 100 nsAutoCString keyClause; 101 if (aMaybeKey) { 102 keyClause.AssignLiteral("&key="); 103 for (uint8_t byte : IPCStreamCipherStrategy::SerializeKey(*aMaybeKey)) { 104 keyClause.AppendPrintf("%02x", byte); 105 } 106 } 107 return keyClause; 108 }(); 109 110 QM_TRY_INSPECT( 111 const auto& fileURL, 112 ([&mutator, &directoryLockIdClause, 113 &keyClause]() -> Result<nsCOMPtr<nsIFileURL>, nsresult> { 114 nsCOMPtr<nsIFileURL> result; 115 QM_TRY(MOZ_TO_RESULT(NS_MutateURI(mutator) 116 .SetQuery("cache=private"_ns + 117 directoryLockIdClause + keyClause) 118 .Finalize(result))); 119 return result; 120 }()), 121 QM_TEST_FAIL); 122 123 QM_TRY_INSPECT(const auto& storageService, 124 MOZ_TO_RESULT_GET_TYPED(nsCOMPtr<mozIStorageService>, 125 MOZ_SELECT_OVERLOAD(do_GetService), 126 MOZ_STORAGE_SERVICE_CONTRACTID), 127 QM_TEST_FAIL); 128 129 QM_TRY_UNWRAP(auto connection, 130 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( 131 nsCOMPtr<mozIStorageConnection>, storageService, 132 OpenDatabaseWithFileURL, fileURL, EmptyCString(), 133 mozIStorageService::CONNECTION_DEFAULT), 134 QM_TEST_FAIL); 135 136 QM_TRY(MOZ_TO_RESULT( 137 connection->ExecuteSimpleSQL("PRAGMA journal_mode = wal;"_ns)), 138 QM_TEST_FAIL); 139 140 // The connection needs to be re-created, otherwise GetQuotaObjects is not 141 // able to get the quota object for the journal file. 142 143 QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL); 144 145 QM_TRY_UNWRAP(connection, 146 MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( 147 nsCOMPtr<mozIStorageConnection>, storageService, 148 OpenDatabaseWithFileURL, fileURL, EmptyCString(), 149 mozIStorageService::CONNECTION_DEFAULT), 150 QM_TEST_FAIL); 151 152 aConnection = std::move(connection); 153 } 154 155 } // namespace 156 157 class TestStorageConnection : public QuotaManagerDependencyFixture { 158 public: 159 static void SetUpTestCase() { 160 // Do this only once, do not tear it down per test case. 161 if (!sNssContext) { 162 sNssContext.reset( 163 NSS_InitContext("", "", "", "", nullptr, 164 NSS_INIT_READONLY | NSS_INIT_NOCERTDB | 165 NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN | 166 NSS_INIT_OPTIMIZESPACE | NSS_INIT_NOROOTINIT)); 167 } 168 169 ASSERT_NO_FATAL_FAILURE(InitializeFixture()); 170 } 171 172 static void TearDownTestCase() { 173 ASSERT_NO_FATAL_FAILURE(ShutdownFixture()); 174 175 sNssContext = nullptr; 176 } 177 178 void TearDown() override { 179 ASSERT_NO_FATAL_FAILURE(ClearStoragesForOrigin(GetTestOriginMetadata())); 180 } 181 182 private: 183 struct NSSInitContextDeleter { 184 void operator()(NSSInitContext* p) { NSS_ShutdownContext(p); } 185 }; 186 static std::unique_ptr<NSSInitContext, NSSInitContextDeleter> sNssContext; 187 }; 188 constinit std::unique_ptr<NSSInitContext, 189 TestStorageConnection::NSSInitContextDeleter> 190 TestStorageConnection::sNssContext; 191 192 TEST_F(TestStorageConnection, BaseVFS) { 193 // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because 194 // base-toolchains builds fail with: error: duplicate label 195 // 'gtest_label_testnofatal_214' 196 PerformClientDirectoryTest(GetTestClientMetadata(), [](int64_t) { 197 ASSERT_NO_FATAL_FAILURE(InitializeClientDirectory(GetTestClientMetadata())); 198 199 nsCOMPtr<mozIStorageConnection> connection; 200 ASSERT_NO_FATAL_FAILURE(CreateStorageConnection( 201 GetTestClientMetadata(), Nothing(), Nothing(), connection)); 202 203 RefPtr<QuotaObject> quotaObject; 204 RefPtr<QuotaObject> journalQuotaObject; 205 206 nsresult rv = connection->GetQuotaObjects( 207 getter_AddRefs(quotaObject), getter_AddRefs(journalQuotaObject)); 208 ASSERT_EQ(rv, NS_ERROR_FAILURE); 209 210 ASSERT_FALSE(quotaObject); 211 ASSERT_FALSE(journalQuotaObject); 212 213 QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL); 214 }); 215 } 216 217 TEST_F(TestStorageConnection, QuotaVFS) { 218 // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because 219 // base-toolchains builds fail with: error: duplicate label 220 // 'gtest_label_testnofatal_214' 221 PerformClientDirectoryTest( 222 GetTestClientMetadata(), [](int64_t aDirectoryLockId) { 223 ASSERT_NO_FATAL_FAILURE( 224 InitializeClientDirectory(GetTestClientMetadata())); 225 226 nsCOMPtr<mozIStorageConnection> connection; 227 ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(), 228 Some(aDirectoryLockId), 229 Nothing(), connection)); 230 231 RefPtr<QuotaObject> quotaObject; 232 RefPtr<QuotaObject> journalQuotaObject; 233 234 QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects( 235 getter_AddRefs(quotaObject), 236 getter_AddRefs(journalQuotaObject))), 237 QM_TEST_FAIL); 238 239 ASSERT_TRUE(quotaObject); 240 ASSERT_TRUE(journalQuotaObject); 241 242 QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL); 243 }); 244 } 245 246 TEST_F(TestStorageConnection, ObfuscatingVFS) { 247 // XXX This call can't be wrapped with ASSERT_NO_FATAL_FAILURE because 248 // base-toolchains builds fail with: error: duplicate label 249 // 'gtest_label_testnofatal_214' 250 PerformClientDirectoryTest( 251 GetTestClientMetadata(), [](int64_t aDirectoryLockId) { 252 ASSERT_NO_FATAL_FAILURE( 253 InitializeClientDirectory(GetTestClientMetadata())); 254 255 QM_TRY_INSPECT(const auto& key, IPCStreamCipherStrategy::GenerateKey(), 256 QM_TEST_FAIL); 257 258 nsCOMPtr<mozIStorageConnection> connection; 259 ASSERT_NO_FATAL_FAILURE(CreateStorageConnection(GetTestClientMetadata(), 260 Some(aDirectoryLockId), 261 Some(key), connection)); 262 263 RefPtr<QuotaObject> quotaObject; 264 RefPtr<QuotaObject> journalQuotaObject; 265 266 QM_TRY(MOZ_TO_RESULT(connection->GetQuotaObjects( 267 getter_AddRefs(quotaObject), 268 getter_AddRefs(journalQuotaObject))), 269 QM_TEST_FAIL); 270 271 ASSERT_TRUE(quotaObject); 272 ASSERT_TRUE(journalQuotaObject); 273 274 QM_TRY(MOZ_TO_RESULT(connection->Close()), QM_TEST_FAIL); 275 }); 276 } 277 278 } // namespace dom::quota::test 279 } // namespace mozilla