QuotaManagerDependencyFixture.cpp (17782B)
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 9 #include "DirectoryMetadata.h" 10 #include "QuotaManagerTestHelpers.h" 11 #include "mozIStorageService.h" 12 #include "mozStorageCID.h" 13 #include "mozilla/BasePrincipal.h" 14 #include "mozilla/dom/ScriptSettings.h" 15 #include "mozilla/dom/quota/QuotaManagerService.h" 16 #include "mozilla/dom/quota/ResultExtensions.h" 17 #include "mozilla/dom/quota/UsageInfo.h" 18 #include "mozilla/gtest/MozAssertions.h" 19 #include "mozilla/ipc/BackgroundUtils.h" 20 #include "mozilla/ipc/PBackgroundSharedTypes.h" 21 #include "nsIPrefBranch.h" 22 #include "nsIPrefService.h" 23 #include "nsIQuotaCallbacks.h" 24 #include "nsIQuotaRequests.h" 25 #include "nsIVariant.h" 26 #include "nsScriptSecurityManager.h" 27 28 namespace mozilla::dom::quota::test { 29 30 namespace { 31 32 class RequestResolver final : public nsIQuotaCallback { 33 public: 34 RequestResolver() : mDone(false) {} 35 36 bool IsDone() const { return mDone; } 37 38 NS_DECL_ISUPPORTS 39 40 NS_IMETHOD OnComplete(nsIQuotaRequest* aRequest) override { 41 mDone = true; 42 43 return NS_OK; 44 } 45 46 private: 47 ~RequestResolver() = default; 48 49 bool mDone; 50 }; 51 52 void CreateContentPrincipalInfo(const nsACString& aOrigin, 53 mozilla::ipc::PrincipalInfo& aPrincipalInfo) { 54 nsCOMPtr<nsIPrincipal> principal = 55 BasePrincipal::CreateContentPrincipal(aOrigin); 56 QM_TRY(MOZ_TO_RESULT(principal), QM_TEST_FAIL); 57 58 mozilla::ipc::PrincipalInfo principalInfo; 59 QM_TRY(MOZ_TO_RESULT(PrincipalToPrincipalInfo(principal, &aPrincipalInfo)), 60 QM_TEST_FAIL); 61 } 62 63 } // namespace 64 65 NS_IMPL_ISUPPORTS(RequestResolver, nsIQuotaCallback) 66 67 // static 68 void QuotaManagerDependencyFixture::InitializeFixture() { 69 // Some QuotaManagerService methods fail if the testing pref is not set. 70 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 71 72 prefs->SetBoolPref("dom.quotaManager.testing", true); 73 74 // The first initialization of storage service must be done on the main 75 // thread. 76 nsCOMPtr<mozIStorageService> storageService = 77 do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); 78 ASSERT_TRUE(storageService); 79 80 nsIObserver* observer = QuotaManager::GetObserver(); 81 ASSERT_TRUE(observer); 82 83 nsresult rv = observer->Observe(nullptr, "profile-do-change", nullptr); 84 ASSERT_NS_SUCCEEDED(rv); 85 86 rv = observer->Observe(nullptr, "contextual-identity-service-load-finished", 87 nullptr); 88 ASSERT_NS_SUCCEEDED(rv); 89 90 // Force creation of the quota manager. 91 ASSERT_NO_FATAL_FAILURE(EnsureQuotaManager()); 92 93 QuotaManager* quotaManager = QuotaManager::Get(); 94 ASSERT_TRUE(quotaManager); 95 96 ASSERT_TRUE(quotaManager->OwningThread()); 97 98 sBackgroundTarget = quotaManager->OwningThread(); 99 } 100 101 // static 102 void QuotaManagerDependencyFixture::ShutdownFixture() { 103 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 104 105 prefs->SetBoolPref("dom.quotaManager.testing", false); 106 107 nsIObserver* observer = QuotaManager::GetObserver(); 108 ASSERT_TRUE(observer); 109 110 nsresult rv = observer->Observe(nullptr, "profile-before-change-qm", nullptr); 111 ASSERT_NS_SUCCEEDED(rv); 112 113 PerformOnBackgroundThread([]() { QuotaManager::Reset(); }); 114 115 sBackgroundTarget = nullptr; 116 } 117 118 // static 119 void QuotaManagerDependencyFixture::InitializeStorage() { 120 PerformOnBackgroundThread([]() { 121 QuotaManager* quotaManager = QuotaManager::Get(); 122 ASSERT_TRUE(quotaManager); 123 124 Await(quotaManager->InitializeStorage()); 125 }); 126 } 127 128 // static 129 void QuotaManagerDependencyFixture::StorageInitialized(bool* aResult) { 130 ASSERT_TRUE(aResult); 131 132 PerformOnBackgroundThread([aResult]() { 133 QuotaManager* quotaManager = QuotaManager::Get(); 134 ASSERT_TRUE(quotaManager); 135 136 auto value = Await(quotaManager->StorageInitialized()); 137 if (value.IsResolve()) { 138 *aResult = value.ResolveValue(); 139 } else { 140 *aResult = false; 141 } 142 }); 143 } 144 145 // static 146 void QuotaManagerDependencyFixture::AssertStorageInitialized() { 147 bool result; 148 ASSERT_NO_FATAL_FAILURE(StorageInitialized(&result)); 149 ASSERT_TRUE(result); 150 } 151 152 // static 153 void QuotaManagerDependencyFixture::AssertStorageNotInitialized() { 154 bool result; 155 ASSERT_NO_FATAL_FAILURE(StorageInitialized(&result)); 156 ASSERT_FALSE(result); 157 } 158 159 // static 160 void QuotaManagerDependencyFixture::ClearStorage() { 161 PerformOnBackgroundThread([]() { 162 QuotaManager* quotaManager = QuotaManager::Get(); 163 ASSERT_TRUE(quotaManager); 164 165 Await(quotaManager->ClearStorage()); 166 }); 167 } 168 169 // static 170 void QuotaManagerDependencyFixture::ShutdownStorage() { 171 PerformOnBackgroundThread([]() { 172 QuotaManager* quotaManager = QuotaManager::Get(); 173 ASSERT_TRUE(quotaManager); 174 175 Await(quotaManager->ShutdownStorage()); 176 }); 177 } 178 179 // static 180 void QuotaManagerDependencyFixture::InitializeTemporaryStorage() { 181 PerformOnBackgroundThread([]() { 182 QuotaManager* quotaManager = QuotaManager::Get(); 183 ASSERT_TRUE(quotaManager); 184 185 Await(quotaManager->InitializeTemporaryStorage()); 186 }); 187 } 188 189 // static 190 void QuotaManagerDependencyFixture::TemporaryStorageInitialized(bool* aResult) { 191 ASSERT_TRUE(aResult); 192 193 PerformOnBackgroundThread([aResult]() { 194 QuotaManager* quotaManager = QuotaManager::Get(); 195 ASSERT_TRUE(quotaManager); 196 197 auto value = Await(quotaManager->TemporaryStorageInitialized()); 198 if (value.IsResolve()) { 199 *aResult = value.ResolveValue(); 200 } else { 201 *aResult = false; 202 } 203 }); 204 } 205 206 // static 207 void QuotaManagerDependencyFixture::AssertTemporaryStorageInitialized() { 208 bool result; 209 ASSERT_NO_FATAL_FAILURE(TemporaryStorageInitialized(&result)); 210 ASSERT_TRUE(result); 211 } 212 213 // static 214 void QuotaManagerDependencyFixture::AssertTemporaryStorageNotInitialized() { 215 bool result; 216 ASSERT_NO_FATAL_FAILURE(TemporaryStorageInitialized(&result)); 217 ASSERT_FALSE(result); 218 } 219 220 // static 221 void QuotaManagerDependencyFixture::ShutdownTemporaryStorage() { 222 // TODO: It would be nice to have a dedicated operation for shutting down 223 // temporary storage. 224 ASSERT_NO_FATAL_FAILURE(ShutdownStorage()); 225 ASSERT_NO_FATAL_FAILURE(InitializeStorage()); 226 } 227 228 // static 229 void QuotaManagerDependencyFixture::InitializeTemporaryOrigin( 230 const OriginMetadata& aOriginMetadata, bool aCreateIfNonExistent) { 231 PerformOnBackgroundThread([aOriginMetadata, aCreateIfNonExistent]() { 232 QuotaManager* quotaManager = QuotaManager::Get(); 233 ASSERT_TRUE(quotaManager); 234 235 Await(quotaManager->InitializeTemporaryOrigin(aOriginMetadata, 236 aCreateIfNonExistent)); 237 }); 238 } 239 240 // static 241 void QuotaManagerDependencyFixture::TemporaryOriginInitialized( 242 const OriginMetadata& aOriginMetadata, bool* aResult) { 243 ASSERT_TRUE(aResult); 244 245 PerformOnBackgroundThread([aOriginMetadata, aResult]() { 246 QuotaManager* quotaManager = QuotaManager::Get(); 247 ASSERT_TRUE(quotaManager); 248 249 auto value = 250 Await(quotaManager->TemporaryOriginInitialized(aOriginMetadata)); 251 if (value.IsResolve()) { 252 *aResult = value.ResolveValue(); 253 } else { 254 *aResult = false; 255 } 256 }); 257 } 258 259 // static 260 void QuotaManagerDependencyFixture::AssertTemporaryOriginInitialized( 261 const OriginMetadata& aOriginMetadata) { 262 bool result; 263 ASSERT_NO_FATAL_FAILURE(TemporaryOriginInitialized(aOriginMetadata, &result)); 264 ASSERT_TRUE(result); 265 } 266 267 // static 268 void QuotaManagerDependencyFixture::AssertTemporaryOriginNotInitialized( 269 const OriginMetadata& aOriginMetadata) { 270 bool result; 271 ASSERT_NO_FATAL_FAILURE(TemporaryOriginInitialized(aOriginMetadata, &result)); 272 ASSERT_FALSE(result); 273 } 274 275 // static 276 void QuotaManagerDependencyFixture::SaveOriginAccessTime( 277 const OriginMetadata& aOriginMetadata) { 278 PerformOnBackgroundThread([aOriginMetadata]() { 279 QuotaManager* quotaManager = QuotaManager::Get(); 280 MOZ_RELEASE_ASSERT(quotaManager); 281 282 auto value = Await(quotaManager->SaveOriginAccessTime(aOriginMetadata)); 283 MOZ_RELEASE_ASSERT(value.IsResolve()); 284 }); 285 } 286 287 // static 288 void QuotaManagerDependencyFixture::GetOriginUsage( 289 const OriginMetadata& aOriginMetadata, UsageInfo* aResult) { 290 ASSERT_TRUE(aResult); 291 292 mozilla::ipc::PrincipalInfo principalInfo; 293 ASSERT_NO_FATAL_FAILURE( 294 CreateContentPrincipalInfo(aOriginMetadata.mOrigin, principalInfo)); 295 296 PerformOnBackgroundThread( 297 [aResult, principalInfo = std::move(principalInfo)]() { 298 QuotaManager* quotaManager = QuotaManager::Get(); 299 ASSERT_TRUE(quotaManager); 300 301 auto value = Await(quotaManager->GetOriginUsage(principalInfo)); 302 if (value.IsResolve()) { 303 *aResult = value.ResolveValue(); 304 } else { 305 *aResult = UsageInfo(); 306 } 307 }); 308 } 309 310 // static 311 void QuotaManagerDependencyFixture::GetCachedOriginUsage( 312 const OriginMetadata& aOriginMetadata, UsageInfo* aResult) { 313 ASSERT_TRUE(aResult); 314 315 mozilla::ipc::PrincipalInfo principalInfo; 316 ASSERT_NO_FATAL_FAILURE( 317 CreateContentPrincipalInfo(aOriginMetadata.mOrigin, principalInfo)); 318 319 PerformOnBackgroundThread( 320 [aResult, principalInfo = std::move(principalInfo)]() { 321 QuotaManager* quotaManager = QuotaManager::Get(); 322 ASSERT_TRUE(quotaManager); 323 324 auto value = Await(quotaManager->GetCachedOriginUsage(principalInfo)); 325 if (value.IsResolve()) { 326 *aResult = UsageInfo(DatabaseUsageType(Some(value.ResolveValue()))); 327 } else { 328 *aResult = UsageInfo(); 329 } 330 }); 331 } 332 333 // static 334 void QuotaManagerDependencyFixture::ClearStoragesForOrigin( 335 const OriginMetadata& aOriginMetadata) { 336 mozilla::ipc::PrincipalInfo principalInfo; 337 ASSERT_NO_FATAL_FAILURE( 338 CreateContentPrincipalInfo(aOriginMetadata.mOrigin, principalInfo)); 339 340 PerformOnBackgroundThread([principalInfo = std::move(principalInfo)]() { 341 QuotaManager* quotaManager = QuotaManager::Get(); 342 ASSERT_TRUE(quotaManager); 343 344 Await(quotaManager->ClearStoragesForOrigin(/* aPersistenceType */ Nothing(), 345 principalInfo)); 346 }); 347 } 348 349 // static 350 void QuotaManagerDependencyFixture::InitializePersistentClient( 351 const ClientMetadata& aClientMetadata) { 352 PerformOnBackgroundThread([aClientMetadata]() { 353 QuotaManager* quotaManager = QuotaManager::Get(); 354 ASSERT_TRUE(quotaManager); 355 356 Await(quotaManager->InitializePersistentClient(aClientMetadata)); 357 }); 358 } 359 360 // static 361 void QuotaManagerDependencyFixture::InitializeTemporaryClient( 362 const ClientMetadata& aClientMetadata, bool aCreateIfNonExistent) { 363 PerformOnBackgroundThread([aClientMetadata, aCreateIfNonExistent]() { 364 QuotaManager* quotaManager = QuotaManager::Get(); 365 ASSERT_TRUE(quotaManager); 366 367 Await(quotaManager->InitializeTemporaryClient(aClientMetadata, 368 aCreateIfNonExistent)); 369 }); 370 } 371 372 // static 373 CStringArray QuotaManagerDependencyFixture::ListOrigins() { 374 auto result = PerformOnBackgroundThread([]() { 375 QuotaManager* quotaManager = QuotaManager::Get(); 376 MOZ_RELEASE_ASSERT(quotaManager); 377 378 auto value = Await(quotaManager->ListOrigins()); 379 MOZ_RELEASE_ASSERT(value.IsResolve()); 380 381 return std::move(value.ResolveValue()); 382 }); 383 384 return result; 385 } 386 387 // static 388 CStringArray QuotaManagerDependencyFixture::ListCachedOrigins() { 389 auto result = PerformOnBackgroundThread([]() { 390 QuotaManager* quotaManager = QuotaManager::Get(); 391 MOZ_RELEASE_ASSERT(quotaManager); 392 393 auto value = Await(quotaManager->ListCachedOrigins()); 394 MOZ_RELEASE_ASSERT(value.IsResolve()); 395 396 return std::move(value.ResolveValue()); 397 }); 398 399 return result; 400 } 401 402 // static 403 void QuotaManagerDependencyFixture::ClearStoragesForOriginAttributesPattern( 404 const nsAString& aPattern) { 405 OriginAttributesPattern pattern; 406 MOZ_ALWAYS_TRUE(pattern.Init(aPattern)); 407 408 PerformOnBackgroundThread([&pattern]() { 409 QuotaManager* quotaManager = QuotaManager::Get(); 410 MOZ_RELEASE_ASSERT(quotaManager); 411 412 auto value = 413 Await(quotaManager->ClearStoragesForOriginAttributesPattern(pattern)); 414 MOZ_RELEASE_ASSERT(value.IsResolve()); 415 }); 416 } 417 418 // static 419 void QuotaManagerDependencyFixture::ProcessPendingNormalOriginOperations() { 420 PerformOnBackgroundThread([]() { 421 QuotaManager* quotaManager = QuotaManager::Get(); 422 MOZ_RELEASE_ASSERT(quotaManager); 423 424 quotaManager->ProcessPendingNormalOriginOperations(); 425 }); 426 } 427 428 // static 429 Maybe<OriginStateMetadata> 430 QuotaManagerDependencyFixture::GetOriginStateMetadata( 431 const OriginMetadata& aOriginMetadata) { 432 const auto result = 433 PerformOnIOThread([aOriginMetadata]() -> Maybe<OriginStateMetadata> { 434 QuotaManager* quotaManager = QuotaManager::Get(); 435 MOZ_RELEASE_ASSERT(quotaManager); 436 437 return quotaManager->GetOriginStateMetadata(aOriginMetadata); 438 }); 439 440 return result; 441 } 442 443 // static 444 Maybe<OriginStateMetadata> 445 QuotaManagerDependencyFixture::LoadDirectoryMetadataHeader( 446 const OriginMetadata& aOriginMetadata) { 447 auto result = 448 PerformOnIOThread([aOriginMetadata]() -> Maybe<OriginStateMetadata> { 449 QuotaManager* quotaManager = QuotaManager::Get(); 450 MOZ_RELEASE_ASSERT(quotaManager); 451 452 auto directoryRes = quotaManager->GetOriginDirectory(aOriginMetadata); 453 MOZ_RELEASE_ASSERT(directoryRes.isOk()); 454 455 auto directory = directoryRes.unwrap(); 456 457 bool exists; 458 nsresult rv = directory->Exists(&exists); 459 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 460 461 if (!exists) { 462 return Nothing(); 463 } 464 465 auto originStateMetadataRes = 466 quota::LoadDirectoryMetadataHeader(*directory); 467 MOZ_RELEASE_ASSERT(originStateMetadataRes.isOk()); 468 469 auto originStateMetadata = originStateMetadataRes.unwrap(); 470 471 return Some(originStateMetadata); 472 }); 473 474 return result; 475 } 476 477 // static 478 uint64_t QuotaManagerDependencyFixture::TotalDirectoryIterations() { 479 const auto result = PerformOnIOThread([]() -> uint64_t { 480 QuotaManager* quotaManager = QuotaManager::Get(); 481 MOZ_RELEASE_ASSERT(quotaManager); 482 483 return quotaManager->TotalDirectoryIterations(); 484 }); 485 486 return result; 487 } 488 489 // static 490 uint64_t QuotaManagerDependencyFixture::SaveOriginAccessTimeCount() { 491 const auto result = PerformOnBackgroundThread([]() -> uint64_t { 492 QuotaManager* quotaManager = QuotaManager::Get(); 493 MOZ_RELEASE_ASSERT(quotaManager); 494 495 return quotaManager->SaveOriginAccessTimeCount(); 496 }); 497 498 return result; 499 } 500 501 // static 502 uint64_t QuotaManagerDependencyFixture::SaveOriginAccessTimeCountInternal() { 503 const auto result = PerformOnIOThread([]() -> uint64_t { 504 QuotaManager* quotaManager = QuotaManager::Get(); 505 MOZ_RELEASE_ASSERT(quotaManager); 506 507 return quotaManager->SaveOriginAccessTimeCountInternal(); 508 }); 509 510 return result; 511 } 512 513 // static 514 PrincipalMetadata QuotaManagerDependencyFixture::GetTestPrincipalMetadata() { 515 return GetPrincipalMetadata("example.com"_ns, "http://example.com"_ns); 516 } 517 518 // static 519 OriginMetadata 520 QuotaManagerDependencyFixture::GetTestPersistentOriginMetadata() { 521 return {GetTestPrincipalMetadata(), PERSISTENCE_TYPE_PERSISTENT}; 522 } 523 524 // static 525 ClientMetadata 526 QuotaManagerDependencyFixture::GetTestPersistentClientMetadata() { 527 return {GetTestPersistentOriginMetadata(), Client::SDB}; 528 } 529 530 // static 531 OriginMetadata QuotaManagerDependencyFixture::GetTestOriginMetadata() { 532 return {GetTestPrincipalMetadata(), PERSISTENCE_TYPE_DEFAULT}; 533 } 534 535 // static 536 ClientMetadata QuotaManagerDependencyFixture::GetTestClientMetadata() { 537 return {GetTestOriginMetadata(), Client::SDB}; 538 } 539 540 // static 541 OriginMetadata QuotaManagerDependencyFixture::GetTestPrivateOriginMetadata() { 542 return {GetTestPrincipalMetadata(), PERSISTENCE_TYPE_PRIVATE}; 543 } 544 545 // static 546 ClientMetadata QuotaManagerDependencyFixture::GetTestPrivateClientMetadata() { 547 return {GetTestPrivateOriginMetadata(), Client::SDB}; 548 } 549 550 // static 551 PrincipalMetadata 552 QuotaManagerDependencyFixture::GetOtherTestPrincipalMetadata() { 553 return GetPrincipalMetadata("other-example.com"_ns, 554 "http://other-example.com"_ns); 555 } 556 557 // static 558 OriginMetadata QuotaManagerDependencyFixture::GetOtherTestOriginMetadata() { 559 return {GetOtherTestPrincipalMetadata(), PERSISTENCE_TYPE_DEFAULT}; 560 } 561 562 // static 563 ClientMetadata QuotaManagerDependencyFixture::GetOtherTestClientMetadata() { 564 return {GetOtherTestOriginMetadata(), Client::SDB}; 565 } 566 567 // static 568 void QuotaManagerDependencyFixture::EnsureQuotaManager() { 569 // This is needed to satisfy the IsCallerChrome check in 570 // QuotaManagerService::StorageName. In more detail, accessing the Subject 571 // Principal without an AutoJSAPI on the stack is forbidden. 572 AutoJSAPI jsapi; 573 574 bool ok = jsapi.Init(xpc::PrivilegedJunkScope()); 575 ASSERT_TRUE(ok); 576 577 nsCOMPtr<nsIQuotaManagerService> qms = QuotaManagerService::GetOrCreate(); 578 ASSERT_TRUE(qms); 579 580 // In theory, any nsIQuotaManagerService method which ensures quota manager 581 // on the PBackground thread, could be called here. `StorageName` was chosen 582 // because it doesn't need to do any directory locking or IO. 583 // XXX Consider adding a dedicated nsIQuotaManagerService method for this. 584 nsCOMPtr<nsIQuotaRequest> request; 585 nsresult rv = qms->StorageName(getter_AddRefs(request)); 586 ASSERT_NS_SUCCEEDED(rv); 587 588 RefPtr<RequestResolver> resolver = new RequestResolver(); 589 590 rv = request->SetCallback(resolver); 591 ASSERT_NS_SUCCEEDED(rv); 592 593 SpinEventLoopUntil("Promise is fulfilled"_ns, 594 [&resolver]() { return resolver->IsDone(); }); 595 } 596 597 constinit nsCOMPtr<nsISerialEventTarget> 598 QuotaManagerDependencyFixture::sBackgroundTarget; 599 600 } // namespace mozilla::dom::quota::test