IDBFactory.cpp (26988B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "IDBFactory.h" 8 9 #include "BackgroundChildImpl.h" 10 #include "IDBRequest.h" 11 #include "IndexedDatabaseManager.h" 12 #include "ProfilerHelpers.h" 13 #include "ReportInternalError.h" 14 #include "ThreadLocal.h" 15 #include "mozilla/BasePrincipal.h" 16 #include "mozilla/ErrorResult.h" 17 #include "mozilla/Preferences.h" 18 #include "mozilla/StaticPrefs_dom.h" 19 #include "mozilla/StorageAccess.h" 20 #include "mozilla/dom/BindingDeclarations.h" 21 #include "mozilla/dom/BrowserChild.h" 22 #include "mozilla/dom/Document.h" 23 #include "mozilla/dom/IDBFactoryBinding.h" 24 #include "mozilla/dom/Promise.h" 25 #include "mozilla/dom/WorkerPrivate.h" 26 #include "mozilla/dom/quota/PrincipalUtils.h" 27 #include "mozilla/dom/quota/QuotaManager.h" 28 #include "mozilla/dom/quota/ResultExtensions.h" 29 #include "mozilla/ipc/BackgroundChild.h" 30 #include "mozilla/ipc/BackgroundUtils.h" 31 #include "mozilla/ipc/PBackground.h" 32 #include "mozilla/ipc/PBackgroundChild.h" 33 #include "nsAboutProtocolUtils.h" 34 #include "nsContentUtils.h" 35 #include "nsGlobalWindowInner.h" 36 #include "nsIAboutModule.h" 37 #include "nsILoadContext.h" 38 #include "nsIURI.h" 39 #include "nsIUUIDGenerator.h" 40 #include "nsIWebNavigation.h" 41 #include "nsLiteralString.h" 42 #include "nsNetUtil.h" 43 #include "nsSandboxFlags.h" 44 #include "nsServiceManagerUtils.h" 45 #include "nsStringFwd.h" 46 47 // Include this last to avoid path problems on Windows. 48 #include "ActorsChild.h" 49 50 namespace mozilla::dom { 51 52 using namespace mozilla::dom::indexedDB; 53 using namespace mozilla::dom::quota; 54 using namespace mozilla::ipc; 55 56 namespace { 57 58 constexpr nsLiteralCString kAccessError("The operation is insecure"); 59 60 } // namespace 61 62 struct IDBFactory::PendingRequestInfo { 63 RefPtr<IDBOpenDBRequest> mRequest; 64 FactoryRequestParams mParams; 65 66 PendingRequestInfo(IDBOpenDBRequest* aRequest, 67 const FactoryRequestParams& aParams) 68 : mRequest(aRequest), mParams(aParams) { 69 MOZ_ASSERT(aRequest); 70 MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None); 71 } 72 }; 73 74 IDBFactory::IDBFactory(const IDBFactoryGuard&, bool aAllowed) 75 : mBackgroundActor(nullptr), 76 mInnerWindowID(0), 77 mActiveTransactionCount(0), 78 mActiveDatabaseCount(0), 79 mAllowed(aAllowed), 80 mBackgroundActorFailed(false), 81 mPrivateBrowsingMode(false) { 82 AssertIsOnOwningThread(); 83 } 84 85 IDBFactory::~IDBFactory() { 86 MOZ_ASSERT_IF(mBackgroundActorFailed, !mBackgroundActor); 87 88 if (mBackgroundActor) { 89 mBackgroundActor->SendDeleteMeInternal(); 90 MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!"); 91 } 92 } 93 94 // static 95 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForWindow( 96 nsPIDOMWindowInner* aWindow) { 97 MOZ_ASSERT(NS_IsMainThread()); 98 MOZ_ASSERT(aWindow); 99 100 nsCOMPtr<nsIPrincipal> principal; 101 nsresult rv = AllowedForWindowInternal(aWindow, &principal); 102 103 if (NS_WARN_IF(NS_FAILED(rv))) { 104 if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) { 105 NS_WARNING("IndexedDB is not permitted in a third-party window."); 106 } 107 108 if (rv == NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR) { 109 IDB_REPORT_INTERNAL_ERR(); 110 } 111 112 auto factory = 113 MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false); 114 factory->BindToOwner(aWindow->AsGlobal()); 115 factory->mInnerWindowID = aWindow->WindowID(); 116 117 return factory; 118 } 119 120 MOZ_ASSERT(principal); 121 122 auto principalInfo = MakeUnique<PrincipalInfo>(); 123 rv = PrincipalToPrincipalInfo(principal, principalInfo.get()); 124 if (NS_WARN_IF(NS_FAILED(rv))) { 125 IDB_REPORT_INTERNAL_ERR(); 126 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 127 } 128 129 MOZ_ASSERT(principalInfo->type() == PrincipalInfo::TContentPrincipalInfo || 130 principalInfo->type() == PrincipalInfo::TSystemPrincipalInfo); 131 132 if (NS_WARN_IF(!quota::IsPrincipalInfoValid(*principalInfo))) { 133 IDB_REPORT_INTERNAL_ERR(); 134 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 135 } 136 137 nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow); 138 nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav); 139 140 auto factory = MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ true); 141 factory->mPrincipalInfo = std::move(principalInfo); 142 143 factory->BindToOwner(aWindow->AsGlobal()); 144 145 factory->mBrowserChild = BrowserChild::GetFrom(aWindow); 146 factory->mEventTarget = 147 nsGlobalWindowInner::Cast(aWindow)->SerialEventTarget(); 148 factory->mInnerWindowID = aWindow->WindowID(); 149 factory->mPrivateBrowsingMode = 150 loadContext && loadContext->UsePrivateBrowsing(); 151 152 return factory; 153 } 154 155 // static 156 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForMainThreadJS( 157 nsIGlobalObject* aGlobal) { 158 MOZ_ASSERT(NS_IsMainThread()); 159 MOZ_ASSERT(aGlobal); 160 161 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aGlobal); 162 if (NS_WARN_IF(!sop)) { 163 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 164 } 165 166 auto principalInfo = MakeUnique<PrincipalInfo>(); 167 nsIPrincipal* principal = sop->GetEffectiveStoragePrincipal(); 168 MOZ_ASSERT(principal); 169 bool isSystem; 170 if (!AllowedForPrincipal(principal, &isSystem)) { 171 auto factory = 172 MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false); 173 factory->BindToOwner(aGlobal); 174 175 return factory; 176 } 177 178 nsresult rv = PrincipalToPrincipalInfo(principal, principalInfo.get()); 179 if (NS_WARN_IF(NS_FAILED(rv))) { 180 return Err(rv); 181 } 182 183 if (NS_WARN_IF(!quota::IsPrincipalInfoValid(*principalInfo))) { 184 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 185 } 186 187 return CreateForMainThreadJSInternal(aGlobal, std::move(principalInfo)); 188 } 189 190 // static 191 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForWorker( 192 nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo>&& aPrincipalInfo, 193 uint64_t aInnerWindowID) { 194 MOZ_ASSERT(!NS_IsMainThread()); 195 MOZ_ASSERT(aGlobal); 196 197 if (!aPrincipalInfo) { 198 auto factory = 199 MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false); 200 factory->BindToOwner(aGlobal); 201 factory->mInnerWindowID = aInnerWindowID; 202 203 return factory; 204 } 205 206 MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None); 207 208 return CreateInternal(aGlobal, std::move(aPrincipalInfo), aInnerWindowID); 209 } 210 211 // static 212 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateForMainThreadJSInternal( 213 nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo> aPrincipalInfo) { 214 MOZ_ASSERT(NS_IsMainThread()); 215 MOZ_ASSERT(aGlobal); 216 MOZ_ASSERT(aPrincipalInfo); 217 218 IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate(); 219 if (NS_WARN_IF(!mgr)) { 220 IDB_REPORT_INTERNAL_ERR(); 221 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 222 } 223 224 nsresult rv = mgr->EnsureLocale(); 225 if (NS_WARN_IF(NS_FAILED(rv))) { 226 IDB_REPORT_INTERNAL_ERR(); 227 return Err(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 228 }; 229 230 return CreateInternal(aGlobal, std::move(aPrincipalInfo), 231 /* aInnerWindowID */ 0); 232 } 233 234 // static 235 Result<RefPtr<IDBFactory>, nsresult> IDBFactory::CreateInternal( 236 nsIGlobalObject* aGlobal, UniquePtr<PrincipalInfo> aPrincipalInfo, 237 uint64_t aInnerWindowID) { 238 MOZ_ASSERT(aGlobal); 239 MOZ_ASSERT(aPrincipalInfo); 240 MOZ_ASSERT(aPrincipalInfo->type() != PrincipalInfo::T__None); 241 242 if (aPrincipalInfo->type() != PrincipalInfo::TContentPrincipalInfo && 243 aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo) { 244 NS_WARNING("IndexedDB not allowed for this principal!"); 245 246 auto factory = 247 MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ false); 248 factory->BindToOwner(aGlobal); 249 factory->mInnerWindowID = aInnerWindowID; 250 251 return factory; 252 } 253 254 auto factory = MakeRefPtr<IDBFactory>(IDBFactoryGuard{}, /* aAllowed */ true); 255 factory->mPrincipalInfo = std::move(aPrincipalInfo); 256 factory->BindToOwner(aGlobal); 257 factory->mEventTarget = GetCurrentSerialEventTarget(); 258 factory->mInnerWindowID = aInnerWindowID; 259 260 return factory; 261 } 262 263 // static 264 bool IDBFactory::AllowedForWindow(nsPIDOMWindowInner* aWindow) { 265 MOZ_ASSERT(NS_IsMainThread()); 266 MOZ_ASSERT(aWindow); 267 268 return !NS_WARN_IF(NS_FAILED(AllowedForWindowInternal(aWindow, nullptr))); 269 } 270 271 // static 272 nsresult IDBFactory::AllowedForWindowInternal( 273 nsPIDOMWindowInner* aWindow, nsCOMPtr<nsIPrincipal>* aPrincipal) { 274 MOZ_ASSERT(NS_IsMainThread()); 275 MOZ_ASSERT(aWindow); 276 277 IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate(); 278 if (NS_WARN_IF(!mgr)) { 279 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 280 } 281 282 nsresult rv = mgr->EnsureLocale(); 283 if (NS_WARN_IF(NS_FAILED(rv))) { 284 IDB_REPORT_INTERNAL_ERR(); 285 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 286 }; 287 288 StorageAccess access = StorageAllowedForWindow(aWindow); 289 290 // the factory callsite records whether the browser is in private browsing. 291 // and thus we don't have to respect that setting here. IndexedDB has no 292 // concept of session-local storage, and thus ignores it. 293 if (access == StorageAccess::eDeny) { 294 return NS_ERROR_DOM_SECURITY_ERR; 295 } 296 297 if (ShouldPartitionStorage(access) && 298 !StoragePartitioningEnabled( 299 access, aWindow->GetExtantDoc()->CookieJarSettings())) { 300 return NS_ERROR_DOM_SECURITY_ERR; 301 } 302 303 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow); 304 MOZ_ASSERT(sop); 305 306 nsCOMPtr<nsIPrincipal> principal = sop->GetEffectiveStoragePrincipal(); 307 if (NS_WARN_IF(!principal)) { 308 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 309 } 310 311 if (principal->IsSystemPrincipal()) { 312 *aPrincipal = std::move(principal); 313 return NS_OK; 314 } 315 316 // About URIs shouldn't be able to access IndexedDB unless they have the 317 // nsIAboutModule::ENABLE_INDEXED_DB flag set on them. 318 319 if (principal->SchemeIs("about")) { 320 uint32_t flags; 321 if (NS_SUCCEEDED(principal->GetAboutModuleFlags(&flags))) { 322 if (!(flags & nsIAboutModule::ENABLE_INDEXED_DB)) { 323 return NS_ERROR_DOM_NOT_SUPPORTED_ERR; 324 } 325 } else { 326 return NS_ERROR_DOM_NOT_SUPPORTED_ERR; 327 } 328 } 329 330 if (aPrincipal) { 331 *aPrincipal = std::move(principal); 332 } 333 return NS_OK; 334 } 335 336 // static 337 bool IDBFactory::AllowedForPrincipal(nsIPrincipal* aPrincipal, 338 bool* aIsSystemPrincipal) { 339 MOZ_ASSERT(NS_IsMainThread()); 340 MOZ_ASSERT(aPrincipal); 341 342 IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate(); 343 if (NS_WARN_IF(!mgr)) { 344 return false; 345 } 346 347 nsresult rv = mgr->EnsureLocale(); 348 if (NS_WARN_IF(NS_FAILED(rv))) { 349 return false; 350 }; 351 352 if (aPrincipal->IsSystemPrincipal()) { 353 if (aIsSystemPrincipal) { 354 *aIsSystemPrincipal = true; 355 } 356 return true; 357 } 358 359 if (aIsSystemPrincipal) { 360 *aIsSystemPrincipal = false; 361 } 362 363 return !aPrincipal->GetIsNullPrincipal(); 364 } 365 366 // static 367 PersistenceType IDBFactory::GetPersistenceType( 368 const PrincipalInfo& aPrincipalInfo) { 369 if (aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) { 370 // Chrome privilege always gets persistent storage. 371 return PERSISTENCE_TYPE_PERSISTENT; 372 } 373 374 if (aPrincipalInfo.type() == PrincipalInfo::TContentPrincipalInfo) { 375 nsCString origin = 376 aPrincipalInfo.get_ContentPrincipalInfo().originNoSuffix(); 377 378 if (QuotaManager::IsOriginInternal(origin)) { 379 // Internal origins always get persistent storage. 380 return PERSISTENCE_TYPE_PERSISTENT; 381 } 382 383 if (aPrincipalInfo.get_ContentPrincipalInfo().attrs().IsPrivateBrowsing()) { 384 return PERSISTENCE_TYPE_PRIVATE; 385 } 386 } 387 388 return PERSISTENCE_TYPE_DEFAULT; 389 } 390 391 void IDBFactory::UpdateActiveTransactionCount(int32_t aDelta) { 392 AssertIsOnOwningThread(); 393 MOZ_ASSERT(mAllowed); 394 MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 || (mActiveTransactionCount + aDelta) < 395 mActiveTransactionCount); 396 mActiveTransactionCount += aDelta; 397 } 398 399 void IDBFactory::UpdateActiveDatabaseCount(int32_t aDelta) { 400 AssertIsOnOwningThread(); 401 MOZ_ASSERT(mAllowed); 402 MOZ_DIAGNOSTIC_ASSERT(aDelta > 0 || 403 (mActiveDatabaseCount + aDelta) < mActiveDatabaseCount); 404 mActiveDatabaseCount += aDelta; 405 406 if (nsIGlobalObject* global = GetOwnerGlobal()) { 407 global->UpdateActiveIndexedDBDatabaseCount(aDelta); 408 } 409 } 410 411 bool IDBFactory::IsChrome() const { 412 if (!mAllowed) { 413 return false; // Minimal privileges 414 } 415 416 AssertIsOnOwningThread(); 417 MOZ_ASSERT(mPrincipalInfo); 418 419 return mPrincipalInfo->type() == PrincipalInfo::TSystemPrincipalInfo; 420 } 421 422 RefPtr<IDBOpenDBRequest> IDBFactory::Open(JSContext* aCx, 423 const nsAString& aName, 424 const Optional<uint64_t>& aVersion, 425 CallerType aCallerType, 426 ErrorResult& aRv) { 427 if (!mAllowed) { 428 aRv.ThrowSecurityError(kAccessError); 429 return nullptr; 430 } 431 432 return OpenInternal(aCx, 433 /* aPrincipal */ nullptr, aName, aVersion, 434 /* aDeleting */ false, aCallerType, aRv); 435 } 436 437 RefPtr<IDBOpenDBRequest> IDBFactory::DeleteDatabase(JSContext* aCx, 438 const nsAString& aName, 439 CallerType aCallerType, 440 ErrorResult& aRv) { 441 if (!mAllowed) { 442 aRv.ThrowSecurityError(kAccessError); 443 return nullptr; 444 } 445 446 return OpenInternal(aCx, 447 /* aPrincipal */ nullptr, aName, Optional<uint64_t>(), 448 /* aDeleting */ true, aCallerType, aRv); 449 } 450 451 already_AddRefed<Promise> IDBFactory::Databases(JSContext* const aCx, 452 ErrorResult& aRv) { 453 if (NS_WARN_IF(!GetOwnerGlobal())) { 454 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 455 return nullptr; 456 } 457 458 RefPtr<Promise> promise = Promise::CreateInfallible(GetOwnerGlobal()); 459 if (!mAllowed) { 460 promise->MaybeRejectWithSecurityError(kAccessError); 461 return promise.forget(); 462 } 463 464 // Nothing can be done here if we have previously failed to create a 465 // background actor. 466 if (mBackgroundActorFailed) { 467 promise->MaybeReject(NS_ERROR_FAILURE); 468 return promise.forget(); 469 } 470 471 PersistenceType persistenceType = GetPersistenceType(*mPrincipalInfo); 472 473 QM_TRY(MOZ_TO_RESULT(EnsureBackgroundActor()), [&promise](const nsresult rv) { 474 promise->MaybeReject(rv); 475 return promise.forget(); 476 }); 477 478 mBackgroundActor->SendGetDatabases(persistenceType, *mPrincipalInfo) 479 ->Then( 480 GetCurrentSerialEventTarget(), __func__, 481 [promise](const PBackgroundIDBFactoryChild::GetDatabasesPromise:: 482 ResolveOrRejectValue& aValue) { 483 if (aValue.IsReject()) { 484 promise->MaybeReject(NS_ERROR_FAILURE); 485 return; 486 } 487 488 const GetDatabasesResponse& response = aValue.ResolveValue(); 489 490 switch (response.type()) { 491 case GetDatabasesResponse::Tnsresult: 492 promise->MaybeReject(response.get_nsresult()); 493 494 break; 495 496 case GetDatabasesResponse::TArrayOfDatabaseMetadata: { 497 const auto& array = response.get_ArrayOfDatabaseMetadata(); 498 499 Sequence<IDBDatabaseInfo> databaseInfos; 500 501 for (const auto& databaseMetadata : array) { 502 IDBDatabaseInfo databaseInfo; 503 504 databaseInfo.mName.Construct(databaseMetadata.name()); 505 databaseInfo.mVersion.Construct(databaseMetadata.version()); 506 507 if (!databaseInfos.AppendElement(std::move(databaseInfo), 508 fallible)) { 509 promise->MaybeRejectWithTypeError("Out of memory"); 510 return; 511 } 512 } 513 514 promise->MaybeResolve(databaseInfos); 515 516 break; 517 } 518 default: 519 MOZ_CRASH("Unknown response type!"); 520 } 521 }); 522 523 return promise.forget(); 524 } 525 526 int16_t IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst, 527 JS::Handle<JS::Value> aSecond, ErrorResult& aRv) { 528 Key first, second; 529 auto result = first.SetFromJSVal(aCx, aFirst); 530 if (result.isErr()) { 531 aRv = result.unwrapErr().ExtractErrorResult( 532 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>); 533 return 0; 534 } 535 536 result = second.SetFromJSVal(aCx, aSecond); 537 if (result.isErr()) { 538 aRv = result.unwrapErr().ExtractErrorResult( 539 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>); 540 return 0; 541 } 542 543 if (first.IsUnset() || second.IsUnset()) { 544 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 545 return 0; 546 } 547 548 return Key::CompareKeys(first, second); 549 } 550 551 RefPtr<IDBOpenDBRequest> IDBFactory::OpenForPrincipal( 552 JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, 553 uint64_t aVersion, SystemCallerGuarantee aGuarantee, ErrorResult& aRv) { 554 if (!mAllowed) { 555 aRv.ThrowSecurityError(kAccessError); 556 return nullptr; 557 } 558 559 MOZ_ASSERT(aPrincipal); 560 if (!NS_IsMainThread()) { 561 MOZ_CRASH( 562 "Figure out security checks for workers! What's this aPrincipal " 563 "we have on a worker thread?"); 564 } 565 566 return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(aVersion), 567 /* aDeleting */ false, aGuarantee, aRv); 568 } 569 570 RefPtr<IDBOpenDBRequest> IDBFactory::OpenForPrincipal( 571 JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, 572 const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee, 573 ErrorResult& aRv) { 574 if (!mAllowed) { 575 aRv.ThrowSecurityError(kAccessError); 576 return nullptr; 577 } 578 579 MOZ_ASSERT(aPrincipal); 580 if (!NS_IsMainThread()) { 581 MOZ_CRASH( 582 "Figure out security checks for workers! What's this aPrincipal " 583 "we have on a worker thread?"); 584 } 585 586 return OpenInternal(aCx, aPrincipal, aName, aOptions.mVersion, 587 /* aDeleting */ false, aGuarantee, aRv); 588 } 589 590 RefPtr<IDBOpenDBRequest> IDBFactory::DeleteForPrincipal( 591 JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, 592 const IDBOpenDBOptions& aOptions, SystemCallerGuarantee aGuarantee, 593 ErrorResult& aRv) { 594 if (!mAllowed) { 595 aRv.ThrowSecurityError(kAccessError); 596 return nullptr; 597 } 598 599 MOZ_ASSERT(aPrincipal); 600 if (!NS_IsMainThread()) { 601 MOZ_CRASH( 602 "Figure out security checks for workers! What's this aPrincipal " 603 "we have on a worker thread?"); 604 } 605 606 return OpenInternal(aCx, aPrincipal, aName, Optional<uint64_t>(), 607 /* aDeleting */ true, aGuarantee, aRv); 608 } 609 610 nsresult IDBFactory::EnsureBackgroundActor() { 611 MOZ_ASSERT(mAllowed); 612 613 if (mBackgroundActor) { 614 return NS_OK; 615 } 616 617 BackgroundChildImpl::ThreadLocal* threadLocal = 618 BackgroundChildImpl::GetThreadLocalForCurrentThread(); 619 620 UniquePtr<ThreadLocal> newIDBThreadLocal; 621 ThreadLocal* idbThreadLocal; 622 623 if (threadLocal && threadLocal->mIndexedDBThreadLocal) { 624 idbThreadLocal = threadLocal->mIndexedDBThreadLocal.get(); 625 } else { 626 nsCOMPtr<nsIUUIDGenerator> uuidGen = 627 do_GetService("@mozilla.org/uuid-generator;1"); 628 MOZ_ASSERT(uuidGen); 629 630 nsID id{}; 631 MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id)); 632 633 newIDBThreadLocal = WrapUnique(new ThreadLocal(id)); 634 idbThreadLocal = newIDBThreadLocal.get(); 635 } 636 637 PBackgroundChild* backgroundActor = 638 BackgroundChild::GetOrCreateForCurrentThread(); 639 if (NS_WARN_IF(!backgroundActor)) { 640 return NS_ERROR_FAILURE; 641 } 642 643 { 644 BackgroundFactoryChild* actor = new BackgroundFactoryChild(*this); 645 646 mBackgroundActor = static_cast<BackgroundFactoryChild*>( 647 backgroundActor->SendPBackgroundIDBFactoryConstructor( 648 actor, idbThreadLocal->GetLoggingInfo(), 649 IndexedDatabaseManager::GetLocale())); 650 651 if (NS_WARN_IF(!mBackgroundActor)) { 652 return NS_ERROR_FAILURE; 653 } 654 } 655 656 if (newIDBThreadLocal) { 657 if (!threadLocal) { 658 threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread(); 659 } 660 MOZ_ASSERT(threadLocal); 661 MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal); 662 663 threadLocal->mIndexedDBThreadLocal = std::move(newIDBThreadLocal); 664 } 665 666 return NS_OK; 667 } 668 669 RefPtr<IDBOpenDBRequest> IDBFactory::OpenInternal( 670 JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, 671 const Optional<uint64_t>& aVersion, bool aDeleting, CallerType aCallerType, 672 ErrorResult& aRv) { 673 MOZ_ASSERT(mAllowed); 674 675 if (NS_WARN_IF(!GetOwnerGlobal())) { 676 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 677 return nullptr; 678 } 679 680 CommonFactoryRequestParams commonParams; 681 682 PrincipalInfo& principalInfo = commonParams.principalInfo(); 683 684 if (aPrincipal) { 685 if (!NS_IsMainThread()) { 686 MOZ_CRASH( 687 "Figure out security checks for workers! What's this " 688 "aPrincipal we have on a worker thread?"); 689 } 690 MOZ_ASSERT(aCallerType == CallerType::System); 691 MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode == 692 aPrincipal->GetIsInPrivateBrowsing()); 693 694 if (NS_WARN_IF( 695 NS_FAILED(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)))) { 696 IDB_REPORT_INTERNAL_ERR(); 697 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 698 return nullptr; 699 } 700 701 if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo && 702 principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) { 703 IDB_REPORT_INTERNAL_ERR(); 704 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 705 return nullptr; 706 } 707 708 if (NS_WARN_IF(!quota::IsPrincipalInfoValid(principalInfo))) { 709 IDB_REPORT_INTERNAL_ERR(); 710 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 711 return nullptr; 712 } 713 } else { 714 if (GetOwnerGlobal()->GetStorageAccess() == 715 StorageAccess::ePrivateBrowsing) { 716 if (NS_IsMainThread()) { 717 SetUseCounter( 718 GetOwnerGlobal()->GetGlobalJSObject(), 719 aDeleting 720 ? eUseCounter_custom_PrivateBrowsingIDBFactoryOpen 721 : eUseCounter_custom_PrivateBrowsingIDBFactoryDeleteDatabase); 722 } else { 723 SetUseCounter( 724 aDeleting ? UseCounterWorker::Custom_PrivateBrowsingIDBFactoryOpen 725 : UseCounterWorker:: 726 Custom_PrivateBrowsingIDBFactoryDeleteDatabase); 727 } 728 } 729 principalInfo = *mPrincipalInfo; 730 } 731 732 uint64_t version = 0; 733 if (!aDeleting && aVersion.WasPassed()) { 734 if (aVersion.Value() < 1) { 735 aRv.ThrowTypeError("0 (Zero) is not a valid database version."); 736 return nullptr; 737 } 738 version = aVersion.Value(); 739 } 740 741 // Nothing can be done here if we have previously failed to create a 742 // background actor. 743 if (mBackgroundActorFailed) { 744 IDB_REPORT_INTERNAL_ERR(); 745 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 746 return nullptr; 747 } 748 749 PersistenceType persistenceType = GetPersistenceType(principalInfo); 750 751 DatabaseMetadata& metadata = commonParams.metadata(); 752 metadata.name() = aName; 753 metadata.persistenceType() = persistenceType; 754 755 FactoryRequestParams params; 756 if (aDeleting) { 757 metadata.version() = 0; 758 params = DeleteDatabaseRequestParams(commonParams); 759 } else { 760 metadata.version() = version; 761 params = OpenDatabaseRequestParams(commonParams); 762 } 763 764 nsresult rv = EnsureBackgroundActor(); 765 if (NS_WARN_IF(NS_FAILED(rv))) { 766 IDB_REPORT_INTERNAL_ERR(); 767 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 768 return nullptr; 769 } 770 771 RefPtr<IDBOpenDBRequest> request = IDBOpenDBRequest::Create( 772 aCx, SafeRefPtr{this, AcquireStrongRefFromRawPtr{}}, GetOwnerGlobal()); 773 if (!request) { 774 MOZ_ASSERT(!NS_IsMainThread()); 775 aRv.ThrowUncatchableException(); 776 return nullptr; 777 } 778 779 MOZ_ASSERT(request); 780 781 if (aDeleting) { 782 IDB_LOG_MARK_CHILD_REQUEST( 783 "indexedDB.deleteDatabase(\"%s\")", "IDBFactory.deleteDatabase(%.0s)", 784 request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get()); 785 } else { 786 IDB_LOG_MARK_CHILD_REQUEST( 787 "indexedDB.open(\"%s\", %s)", "IDBFactory.open(%.0s%.0s)", 788 request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get(), 789 IDB_LOG_STRINGIFY(aVersion)); 790 } 791 792 rv = InitiateRequest(WrapNotNull(request), params); 793 if (NS_WARN_IF(NS_FAILED(rv))) { 794 IDB_REPORT_INTERNAL_ERR(); 795 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 796 return nullptr; 797 } 798 799 return request; 800 } 801 802 nsresult IDBFactory::InitiateRequest( 803 const NotNull<RefPtr<IDBOpenDBRequest>>& aRequest, 804 const FactoryRequestParams& aParams) { 805 MOZ_ASSERT(mAllowed); 806 MOZ_ASSERT(mBackgroundActor); 807 MOZ_ASSERT(!mBackgroundActorFailed); 808 809 bool deleting; 810 uint64_t requestedVersion; 811 812 switch (aParams.type()) { 813 case FactoryRequestParams::TDeleteDatabaseRequestParams: { 814 const DatabaseMetadata& metadata = 815 aParams.get_DeleteDatabaseRequestParams().commonParams().metadata(); 816 deleting = true; 817 requestedVersion = metadata.version(); 818 break; 819 } 820 821 case FactoryRequestParams::TOpenDatabaseRequestParams: { 822 const DatabaseMetadata& metadata = 823 aParams.get_OpenDatabaseRequestParams().commonParams().metadata(); 824 deleting = false; 825 requestedVersion = metadata.version(); 826 break; 827 } 828 829 default: 830 MOZ_CRASH("Should never get here!"); 831 } 832 833 auto actor = new BackgroundFactoryRequestChild( 834 SafeRefPtr{this, AcquireStrongRefFromRawPtr{}}, aRequest, deleting, 835 requestedVersion); 836 837 if (!mBackgroundActor->SendPBackgroundIDBFactoryRequestConstructor(actor, 838 aParams)) { 839 aRequest->DispatchNonTransactionError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 840 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 841 } 842 843 return NS_OK; 844 } 845 846 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBFactory) 847 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBFactory) 848 849 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBFactory) 850 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 851 NS_INTERFACE_MAP_ENTRY(nsISupports) 852 NS_INTERFACE_MAP_END 853 854 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory) 855 856 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory) 857 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild) 858 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEventTarget) 859 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 860 861 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBFactory) 862 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 863 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild) 864 NS_IMPL_CYCLE_COLLECTION_UNLINK(mEventTarget) 865 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 866 867 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBFactory) 868 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 869 NS_IMPL_CYCLE_COLLECTION_TRACE_END 870 871 JSObject* IDBFactory::WrapObject(JSContext* aCx, 872 JS::Handle<JSObject*> aGivenProto) { 873 return IDBFactory_Binding::Wrap(aCx, this, aGivenProto); 874 } 875 876 } // namespace mozilla::dom