diff options
Diffstat (limited to 'dom/indexedDB')
24 files changed, 221 insertions, 1202 deletions
diff --git a/dom/indexedDB/ActorsChild.cpp b/dom/indexedDB/ActorsChild.cpp index 3e8f97348..30dc9b6da 100644 --- a/dom/indexedDB/ActorsChild.cpp +++ b/dom/indexedDB/ActorsChild.cpp @@ -2385,9 +2385,14 @@ BackgroundVersionChangeTransactionChild::RecvComplete(const nsresult& aResult) database->Close(); } + RefPtr<IDBOpenDBRequest> request = mOpenDBRequest; + MOZ_ASSERT(request); + mTransaction->FireCompleteOrAbortEvents(aResult); - mOpenDBRequest->SetTransaction(nullptr); + request->SetTransaction(nullptr); + request = nullptr; + mOpenDBRequest = nullptr; NoteComplete(); @@ -3456,6 +3461,8 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) RefPtr<IDBCursor> cursor; mStrongCursor.swap(cursor); + + RefPtr<IDBTransaction> transaction = mTransaction; switch (aResponse.type()) { case CursorResponse::Tnsresult: @@ -3486,7 +3493,7 @@ BackgroundCursorChild::RecvResponse(const CursorResponse& aResponse) MOZ_CRASH("Should never get here!"); } - mTransaction->OnRequestFinished(/* aActorDestroyedNormally */ true); + transaction->OnRequestFinished(/* aActorDestroyedNormally */ true); return true; } diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index e6fe9e2a8..74afef452 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -23,6 +23,7 @@ #include "mozilla/AppProcessChecker.h" #include "mozilla/AutoRestore.h" #include "mozilla/Casting.h" +#include "mozilla/CheckedInt.h" #include "mozilla/EndianUtils.h" #include "mozilla/ErrorNames.h" #include "mozilla/LazyIdleThread.h" @@ -249,8 +250,6 @@ const char kSQLiteJournalSuffix[] = ".sqlite-journal"; const char kSQLiteSHMSuffix[] = ".sqlite-shm"; const char kSQLiteWALSuffix[] = ".sqlite-wal"; -const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled"; - const char kPrefFileHandleEnabled[] = "dom.fileHandle.enabled"; #define IDB_PREFIX "indexedDB" @@ -784,29 +783,25 @@ MakeCompressedIndexDataValues( MOZ_ASSERT(!keyBuffer.IsEmpty()); - // Don't let |infoLength| overflow. - if (NS_WARN_IF(UINT32_MAX - keyBuffer.Length() < - CompressedByteCountForIndexId(info.mIndexId) + - CompressedByteCountForNumber(keyBufferLength) + - CompressedByteCountForNumber(sortKeyBufferLength))) { - IDB_REPORT_INTERNAL_ERR(); - return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; - } - - const uint32_t infoLength = - CompressedByteCountForIndexId(info.mIndexId) + + const CheckedUint32 infoLength = + CheckedUint32(CompressedByteCountForIndexId(info.mIndexId)) + CompressedByteCountForNumber(keyBufferLength) + CompressedByteCountForNumber(sortKeyBufferLength) + keyBufferLength + sortKeyBufferLength; + // Don't let |infoLength| overflow. + if (NS_WARN_IF(!infoLength.isValid())) { + IDB_REPORT_INTERNAL_ERR(); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; + } // Don't let |blobDataLength| overflow. - if (NS_WARN_IF(UINT32_MAX - infoLength < blobDataLength)) { + if (NS_WARN_IF(UINT32_MAX - infoLength.value() < blobDataLength)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - blobDataLength += infoLength; + blobDataLength += infoLength.value(); } UniqueFreePtr<uint8_t> blobData( @@ -4134,7 +4129,6 @@ GetDatabaseFileURL(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, nsIFileURL** aResult) { MOZ_ASSERT(aDatabaseFile); @@ -4166,18 +4160,10 @@ GetDatabaseFileURL(nsIFile* aDatabaseFile, nsAutoCString type; PersistenceTypeToText(aPersistenceType, type); - nsAutoCString telemetryFilenameClause; - if (aTelemetryId) { - telemetryFilenameClause.AssignLiteral("&telemetryFilename=indexedDB-"); - telemetryFilenameClause.AppendInt(aTelemetryId); - telemetryFilenameClause.AppendLiteral(".sqlite"); - } - rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type + NS_LITERAL_CSTRING("&group=") + aGroup + NS_LITERAL_CSTRING("&origin=") + aOrigin + - NS_LITERAL_CSTRING("&cache=private") + - telemetryFilenameClause); + NS_LITERAL_CSTRING("&cache=private")); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -4427,7 +4413,6 @@ CreateStorageConnection(nsIFile* aDBFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { AssertIsOnIOThread(); @@ -4442,24 +4427,11 @@ CreateStorageConnection(nsIFile* aDBFile, nsresult rv; bool exists; - if (IndexedDatabaseManager::InLowDiskSpaceMode()) { - rv = aDBFile->Exists(&exists); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (!exists) { - NS_WARNING("Refusing to create database because disk space is low!"); - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - } - nsCOMPtr<nsIFileURL> dbFileUrl; rv = GetDatabaseFileURL(aDBFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4895,7 +4867,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4923,7 +4894,6 @@ GetStorageConnection(nsIFile* aDatabaseFile, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(dbFileUrl)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -4960,7 +4930,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, mozIStorageConnection** aConnection) { MOZ_ASSERT(!NS_IsMainThread()); @@ -4979,7 +4948,6 @@ GetStorageConnection(const nsAString& aDatabaseFilePath, aPersistenceType, aGroup, aOrigin, - aTelemetryId, aConnection); } @@ -6301,7 +6269,6 @@ private: const nsCString mId; const nsString mFilePath; uint32_t mActiveMutableFileCount; - const uint32_t mTelemetryId; const PersistenceType mPersistenceType; const bool mFileHandleDisabled; const bool mChromeWriteAccessAllowed; @@ -6318,7 +6285,6 @@ public: const Maybe<ContentParentId>& aOptionalContentParentId, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, FullDatabaseMetadata* aMetadata, FileManager* aFileManager, already_AddRefed<DirectoryLock> aDirectoryLock, @@ -6377,12 +6343,6 @@ public: return mId; } - uint32_t - TelemetryId() const - { - return mTelemetryId; - } - PersistenceType Type() const { @@ -7678,8 +7638,6 @@ class OpenDatabaseOp final // cycles. VersionChangeOp* mVersionChangeOp; - uint32_t mTelemetryId; - public: OpenDatabaseOp(Factory* aFactory, already_AddRefed<ContentParent> aContentParent, @@ -10307,13 +10265,6 @@ typedef nsDataHashtable<nsIDHashKey, DatabaseLoggingInfo*> StaticAutoPtr<DatabaseLoggingInfoHashtable> gLoggingInfoHashtable; -typedef nsDataHashtable<nsUint32HashKey, uint32_t> TelemetryIdHashtable; - -StaticAutoPtr<TelemetryIdHashtable> gTelemetryIdHashtable; - -// Protects all reads and writes to gTelemetryIdHashtable. -StaticAutoPtr<Mutex> gTelemetryIdMutex; - #ifdef DEBUG StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower; @@ -10409,88 +10360,6 @@ DecreaseBusyCount() } } -uint32_t -TelemetryIdForFile(nsIFile* aFile) -{ - // May be called on any thread! - - MOZ_ASSERT(aFile); - MOZ_ASSERT(gTelemetryIdMutex); - - // The storage directory is structured like this: - // - // <profile>/storage/<persistence>/<origin>/idb/<filename>.sqlite - // - // For the purposes of this function we're only concerned with the - // <persistence>, <origin>, and <filename> pieces. - - nsString filename; - MOZ_ALWAYS_SUCCEEDS(aFile->GetLeafName(filename)); - - // Make sure we were given a database file. - NS_NAMED_LITERAL_STRING(sqliteExtension, ".sqlite"); - - MOZ_ASSERT(StringEndsWith(filename, sqliteExtension)); - - filename.Truncate(filename.Length() - sqliteExtension.Length()); - - // Get the "idb" directory. - nsCOMPtr<nsIFile> idbDirectory; - MOZ_ALWAYS_SUCCEEDS(aFile->GetParent(getter_AddRefs(idbDirectory))); - - DebugOnly<nsString> idbLeafName; - MOZ_ASSERT(NS_SUCCEEDED(idbDirectory->GetLeafName(idbLeafName))); - MOZ_ASSERT(static_cast<nsString&>(idbLeafName).EqualsLiteral("idb")); - - // Get the <origin> directory. - nsCOMPtr<nsIFile> originDirectory; - MOZ_ALWAYS_SUCCEEDS( - idbDirectory->GetParent(getter_AddRefs(originDirectory))); - - nsString origin; - MOZ_ALWAYS_SUCCEEDS(originDirectory->GetLeafName(origin)); - - // Any databases in these directories are owned by the application and should - // not have their filenames masked. Hopefully they also appear in the - // Telemetry.cpp whitelist. - if (origin.EqualsLiteral("chrome") || - origin.EqualsLiteral("moz-safe-about+home")) { - return 0; - } - - // Get the <persistence> directory. - nsCOMPtr<nsIFile> persistenceDirectory; - MOZ_ALWAYS_SUCCEEDS( - originDirectory->GetParent(getter_AddRefs(persistenceDirectory))); - - nsString persistence; - MOZ_ALWAYS_SUCCEEDS(persistenceDirectory->GetLeafName(persistence)); - - NS_NAMED_LITERAL_STRING(separator, "*"); - - uint32_t hashValue = HashString(persistence + separator + - origin + separator + - filename); - - MutexAutoLock lock(*gTelemetryIdMutex); - - if (!gTelemetryIdHashtable) { - gTelemetryIdHashtable = new TelemetryIdHashtable(); - } - - uint32_t id; - if (!gTelemetryIdHashtable->Get(hashValue, &id)) { - static uint32_t sNextId = 1; - - // We're locked, no need for atomics. - id = sNextId++; - - gTelemetryIdHashtable->Put(hashValue, id); - } - - return id; -} - } // namespace /******************************************************************************* @@ -12270,7 +12139,6 @@ ConnectionPool::GetOrCreateConnection(const Database* aDatabase, aDatabase->Type(), aDatabase->Group(), aDatabase->Origin(), - aDatabase->TelemetryId(), getter_AddRefs(storageConnection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -14139,7 +14007,6 @@ Database::Database(Factory* aFactory, const Maybe<ContentParentId>& aOptionalContentParentId, const nsACString& aGroup, const nsACString& aOrigin, - uint32_t aTelemetryId, FullDatabaseMetadata* aMetadata, FileManager* aFileManager, already_AddRefed<DirectoryLock> aDirectoryLock, @@ -14156,7 +14023,6 @@ Database::Database(Factory* aFactory, , mId(aMetadata->mDatabaseId) , mFilePath(aMetadata->mFilePath) , mActiveMutableFileCount(0) - , mTelemetryId(aTelemetryId) , mPersistenceType(aMetadata->mCommonMetadata.persistenceType()) , mFileHandleDisabled(aFileHandleDisabled) , mChromeWriteAccessAllowed(aChromeWriteAccessAllowed) @@ -17396,8 +17262,7 @@ FileManager::InitDirectory(nsIFile* aDirectory, nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, - uint32_t aTelemetryId) + const nsACString& aOrigin) { AssertIsOnIOThread(); MOZ_ASSERT(aDirectory); @@ -17469,7 +17334,6 @@ FileManager::InitDirectory(nsIFile* aDirectory, aPersistenceType, aGroup, aOrigin, - aTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -17653,11 +17517,6 @@ QuotaClient::QuotaClient() { AssertIsOnBackgroundThread(); MOZ_ASSERT(!sInstance, "We expect this to be a singleton!"); - MOZ_ASSERT(!gTelemetryIdMutex); - - // Always create this so that later access to gTelemetryIdHashtable can be - // properly synchronized. - gTelemetryIdMutex = new Mutex("IndexedDB gTelemetryIdMutex"); sInstance = this; } @@ -17666,14 +17525,8 @@ QuotaClient::~QuotaClient() { AssertIsOnBackgroundThread(); MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!"); - MOZ_ASSERT(gTelemetryIdMutex); MOZ_ASSERT(!mMaintenanceThreadPool); - // No one else should be able to touch gTelemetryIdHashtable now that the - // QuotaClient has gone away. - gTelemetryIdHashtable = nullptr; - gTelemetryIdMutex = nullptr; - sInstance = nullptr; } @@ -17947,8 +17800,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, initInfo.mDatabaseFile, aPersistenceType, aGroup, - aOrigin, - TelemetryIdForFile(initInfo.mDatabaseFile)); + aOrigin); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -19041,7 +18893,6 @@ DatabaseMaintenance::PerformMaintenanceOnDatabase() mPersistenceType, mGroup, mOrigin, - TelemetryIdForFile(databaseFile), getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return; @@ -19240,23 +19091,6 @@ DatabaseMaintenance::DetermineMaintenanceAction( return NS_OK; } - bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode(); - - if (QuotaManager::IsRunningXPCShellTests()) { - // If we're running XPCShell then we want to test both the low disk space - // and normal disk space code paths so pick semi-randomly based on the - // current time. - lowDiskSpace = ((PR_Now() / PR_USEC_PER_MSEC) % 2) == 0; - } - - // If we're low on disk space then the best we can hope for is that an - // incremental vacuum might free some space. That is a journaled operation so - // it may not be possible even then. - if (lowDiskSpace) { - *aMaintenanceAction = MaintenanceAction::IncrementalVacuum; - return NS_OK; - } - // This method shouldn't make any permanent changes to the database, so make // sure everything gets rolled back when we leave. mozStorageTransaction transaction(aConnection, @@ -21172,16 +21006,6 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } - if (NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - if (aContentParent) { - // The DOM in the other process should have kept us from receiving any - // indexedDB messages so assume that the child is misbehaving. - aContentParent->KillHard("IndexedDB CheckPermission 1"); - } - - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - const ContentPrincipalInfo& contentPrincipalInfo = principalInfo.get_ContentPrincipalInfo(); if (contentPrincipalInfo.attrs().mPrivateBrowsingId != 0) { @@ -21668,7 +21492,6 @@ OpenDatabaseOp::OpenDatabaseOp(Factory* aFactory, , mMetadata(new FullDatabaseMetadata(aParams.metadata())) , mRequestedVersion(aParams.metadata().version()) , mVersionChangeOp(nullptr) - , mTelemetryId(0) { if (mContentParent) { // This is a little scary but it looks safe to call this off the main thread @@ -21777,8 +21600,6 @@ OpenDatabaseOp::DoDatabaseWork() return rv; } - mTelemetryId = TelemetryIdForFile(dbFile); - #ifdef DEBUG nsString databaseFilePath; rv = dbFile->GetPath(databaseFilePath); @@ -21809,7 +21630,6 @@ OpenDatabaseOp::DoDatabaseWork() persistenceType, mGroup, mOrigin, - mTelemetryId, getter_AddRefs(connection)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -22692,7 +22512,6 @@ OpenDatabaseOp::EnsureDatabaseActor() mOptionalContentParentId, mGroup, mOrigin, - mTelemetryId, mMetadata, mFileManager, mDirectoryLock.forget(), @@ -23869,32 +23688,38 @@ TransactionDatabaseOperationBase::SendPreprocessInfoOrResults( MOZ_ASSERT(mTransaction); if (NS_WARN_IF(IsActorDestroyed())) { - // Don't send any notifications if the actor was destroyed already. + // Normally we wouldn't need to send any notifications if the actor was + // already destroyed, but this can be a VersionChangeOp which needs to + // notify its parent operation (OpenDatabaseOp) about the failure. + // So SendFailureResult needs to be called even when the actor was + // destroyed. Normal operations redundantly check if the actor was + // destroyed in SendSuccessResult and SendFailureResult, therefore it's + // ok to call it in all cases here. if (NS_SUCCEEDED(mResultCode)) { IDB_REPORT_INTERNAL_ERR(); mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - } else { - if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) { - // Aborted transactions always see their requests fail with ABORT_ERR, - // even if the request succeeded or failed with another error. - mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; - } else if (NS_SUCCEEDED(mResultCode)) { - if (aSendPreprocessInfo) { - // This should not release the IPDL reference. - mResultCode = SendPreprocessInfo(); - } else { - // This may release the IPDL reference. - mResultCode = SendSuccessResult(); - } + } else if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) { + // Aborted transactions always see their requests fail with ABORT_ERR, + // even if the request succeeded or failed with another error. + mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; + } + + if (NS_SUCCEEDED(mResultCode)) { + if (aSendPreprocessInfo) { + // This should not release the IPDL reference. + mResultCode = SendPreprocessInfo(); + } else { + // This may release the IPDL reference. + mResultCode = SendSuccessResult(); } + } - if (NS_FAILED(mResultCode)) { - // This should definitely release the IPDL reference. - if (!SendFailureResult(mResultCode)) { - // Abort the transaction. - mTransaction->Abort(mResultCode, /* aForce */ false); - } + if (NS_FAILED(mResultCode)) { + // This should definitely release the IPDL reference. + if (!SendFailureResult(mResultCode)) { + // Abort the transaction. + mTransaction->Abort(mResultCode, /* aForce */ false); } } @@ -24379,11 +24204,6 @@ CreateFileOp::DoDatabaseWork() "CreateFileOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - NS_WARNING("Refusing to create file because disk space is low!"); - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; @@ -24524,10 +24344,6 @@ CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection) "CreateObjectStoreOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not creating an object store with the same name as @@ -24851,10 +24667,6 @@ RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection) "RenameObjectStoreOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not renaming an object store with the same name as @@ -24944,7 +24756,6 @@ CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection) { MOZ_ASSERT(aConnection); aConnection->AssertIsOnConnectionThread(); - MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode()); MOZ_ASSERT(mMaybeUniqueIndexTable); PROFILER_LABEL("IndexedDB", @@ -24995,7 +24806,6 @@ CreateIndexOp::InsertDataFromObjectStoreInternal( { MOZ_ASSERT(aConnection); aConnection->AssertIsOnConnectionThread(); - MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode()); MOZ_ASSERT(mMaybeUniqueIndexTable); DebugOnly<void*> storageConnection = aConnection->GetStorageConnection(); @@ -25072,10 +24882,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) "CreateIndexOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not creating an index with the same name and object @@ -25952,10 +25758,6 @@ RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) "RenameIndexOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - #ifdef DEBUG { // Make sure that we're not renaming an index with the same name as another @@ -26440,10 +26242,6 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection) "ObjectStoreAddOrPutRequestOp::DoDatabaseWork", js::ProfileEntry::Category::STORAGE); - if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) { - return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; - } - DatabaseConnection::AutoSavepoint autoSave; nsresult rv = autoSave.Start(Transaction()); if (NS_WARN_IF(NS_FAILED(rv))) { diff --git a/dom/indexedDB/FileManager.h b/dom/indexedDB/FileManager.h index da917f431..0fba46ec0 100644 --- a/dom/indexedDB/FileManager.h +++ b/dom/indexedDB/FileManager.h @@ -58,8 +58,7 @@ public: nsIFile* aDatabaseFile, PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, - uint32_t aTelemetryId); + const nsACString& aOrigin); static nsresult GetUsage(nsIFile* aDirectory, uint64_t* aUsage); diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index 7ae35e981..be0295dc7 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -430,7 +430,7 @@ IDBCursor::Continue(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -536,7 +536,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key key; - aRv = key.SetFromJSVal(aCx, aKey); + aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -558,7 +558,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx, } Key primaryKey; - aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey); + aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey, /* aCallGetters */ true); if (aRv.Failed()) { return; } @@ -718,7 +718,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue, const KeyPath& keyPath = objectStore->GetKeyPath(); Key key; - aRv = keyPath.ExtractKey(aCx, aValue, key); + aRv = keyPath.ExtractKey(aCx, aValue, key, /* aCallGetters */ false); if (aRv.Failed()) { return nullptr; } @@ -948,7 +948,6 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceIndex) diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index 5592e7f93..6ef352801 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -1257,6 +1257,9 @@ IDBDatabase::LastRelease() AssertIsOnOwningThread(); CloseInternal(); + + // Make sure that file actors created after the database was closed are expired. + ExpireFileActors(/* aExpireAll */ true); if (mBackgroundActor) { mBackgroundActor->SendDeleteMeInternal(); diff --git a/dom/indexedDB/IDBFactory.cpp b/dom/indexedDB/IDBFactory.cpp index 663828978..66471fe24 100644 --- a/dom/indexedDB/IDBFactory.cpp +++ b/dom/indexedDB/IDBFactory.cpp @@ -47,12 +47,6 @@ namespace dom { using namespace mozilla::dom::quota; using namespace mozilla::ipc; -namespace { - -const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled"; - -} // namespace - class IDBFactory::BackgroundCreateCallback final : public nsIIPCBackgroundChildCreateCallback { @@ -130,12 +124,6 @@ IDBFactory::CreateForWindow(nsPIDOMWindowInner* aWindow, nsCOMPtr<nsIPrincipal> principal; nsresult rv = AllowedForWindowInternal(aWindow, getter_AddRefs(principal)); - if (!(NS_SUCCEEDED(rv) && nsContentUtils::IsSystemPrincipal(principal)) && - NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - *aFactory = nullptr; - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - if (rv == NS_ERROR_DOM_NOT_SUPPORTED_ERR) { NS_WARNING("IndexedDB is not permitted in a third-party window."); *aFactory = nullptr; @@ -246,12 +234,6 @@ IDBFactory::CreateForMainThreadJSInternal( MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aPrincipalInfo); - if (aPrincipalInfo->type() != PrincipalInfo::TSystemPrincipalInfo && - NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) { - *aFactory = nullptr; - return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; - } - IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate(); if (NS_WARN_IF(!mgr)) { IDB_REPORT_INTERNAL_ERR(); @@ -500,13 +482,13 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst, JS::Handle<JS::Value> aSecond, ErrorResult& aRv) { Key first, second; - nsresult rv = first.SetFromJSVal(aCx, aFirst); + nsresult rv = first.SetFromJSVal(aCx, aFirst, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; } - rv = second.SetFromJSVal(aCx, aSecond); + rv = second.SetFromJSVal(aCx, aSecond, /* aCallGetters */ true); if (NS_FAILED(rv)) { aRv.Throw(rv); return 0; @@ -883,7 +865,6 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_CLASS(IDBFactory) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBFactory) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index 657e744c9..af50926e6 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -652,7 +652,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END diff --git a/dom/indexedDB/IDBKeyRange.cpp b/dom/indexedDB/IDBKeyRange.cpp index 2de48a70c..168fb4a5a 100644 --- a/dom/indexedDB/IDBKeyRange.cpp +++ b/dom/indexedDB/IDBKeyRange.cpp @@ -24,7 +24,7 @@ GetKeyFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, Key& aKey) { - nsresult rv = aKey.SetFromJSVal(aCx, aVal); + nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB); return rv; @@ -239,7 +239,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange) diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 8a0b292ad..cbac30894 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -1084,7 +1084,7 @@ IDBObjectStore::AppendIndexUpdateInfo( if (!aMultiEntry) { Key key; - rv = aKeyPath.ExtractKey(aCx, aVal, key); + rv = aKeyPath.ExtractKey(aCx, aVal, key, /* aCallGetters */ false); // If an index's keyPath doesn't match an object, we ignore that object. if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) { @@ -1114,7 +1114,7 @@ IDBObjectStore::AppendIndexUpdateInfo( } bool isArray; - if (!JS_IsArrayObject(aCx, val, &isArray)) { + if (NS_WARN_IF(!JS_IsArrayObject(aCx, val, &isArray))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } @@ -1127,14 +1127,31 @@ IDBObjectStore::AppendIndexUpdateInfo( } for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) { - JS::Rooted<JS::Value> arrayItem(aCx); - if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) { + JS::RootedId indexId(aCx);
+ if (NS_WARN_IF(!JS_IndexToId(aCx, arrayIndex, &indexId))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ bool hasOwnProperty;
+ if (NS_WARN_IF(
+ !JS_HasOwnPropertyById(aCx, array, indexId, &hasOwnProperty))) {
+ IDB_REPORT_INTERNAL_ERR();
+ return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+ }
+
+ if (!hasOwnProperty) {
+ continue;
+ }
+
+ JS::RootedValue arrayItem(aCx);
+ if (NS_WARN_IF(!JS_GetPropertyById(aCx, array, indexId, &arrayItem))) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) || + if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. continue; @@ -1153,7 +1170,7 @@ IDBObjectStore::AppendIndexUpdateInfo( } else { Key value; - if (NS_FAILED(value.SetFromJSVal(aCx, val)) || + if (NS_FAILED(value.SetFromJSVal(aCx, val, /* aCallGetters */ false)) || value.IsUnset()) { // Not a value we can do anything with, ignore it. return NS_OK; @@ -1324,12 +1341,12 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, if (!HasValidKeyPath()) { // Out-of-line keys must be passed in. - rv = aKey.SetFromJSVal(aCx, aKeyVal); + rv = aKey.SetFromJSVal(aCx, aKeyVal, /* aCallGetters */ true); if (NS_FAILED(rv)) { return rv; } } else if (!isAutoIncrement) { - rv = GetKeyPath().ExtractKey(aCx, aValue, aKey); + rv = GetKeyPath().ExtractKey(aCx, aValue, aKey, /* aCallGetters */ false); if (NS_FAILED(rv)) { return rv; } @@ -1368,7 +1385,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, aValue, aKey, &GetAddInfoCallback, - &data); + &data, + /* aCallGetters */ false); } else { rv = GetAddInfoCallback(aCx, &data); } @@ -1758,7 +1776,6 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore) NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes) diff --git a/dom/indexedDB/IDBRequest.cpp b/dom/indexedDB/IDBRequest.cpp index 919d3adc7..e0e318059 100644 --- a/dom/indexedDB/IDBRequest.cpp +++ b/dom/indexedDB/IDBRequest.cpp @@ -417,8 +417,6 @@ IDBRequest::GetError(ErrorResult& aRv) NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest, IDBWrapperCache) - // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because - // DOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor) diff --git a/dom/indexedDB/IDBWrapperCache.cpp b/dom/indexedDB/IDBWrapperCache.cpp index df62514c8..ccc2bb43e 100644 --- a/dom/indexedDB/IDBWrapperCache.cpp +++ b/dom/indexedDB/IDBWrapperCache.cpp @@ -18,8 +18,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(IDBWrapperCache) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBWrapperCache, DOMEventTargetHelper) - // Don't need NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS because - // DOMEventTargetHelper does it for us. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBWrapperCache, diff --git a/dom/indexedDB/IndexedDatabaseManager.cpp b/dom/indexedDB/IndexedDatabaseManager.cpp index 62ba51c08..213de5cc9 100644 --- a/dom/indexedDB/IndexedDatabaseManager.cpp +++ b/dom/indexedDB/IndexedDatabaseManager.cpp @@ -8,11 +8,9 @@ #include "chrome/common/ipc_channel.h" // for IPC::Channel::kMaximumMessageSize #include "nsIConsoleService.h" -#include "nsIDiskSpaceWatcher.h" #include "nsIDOMWindow.h" #include "nsIEventTarget.h" #include "nsIFile.h" -#include "nsIObserverService.h" #include "nsIScriptError.h" #include "nsIScriptGlobalObject.h" @@ -64,11 +62,6 @@ #define IDB_STR "indexedDB" -// The two possible values for the data argument when receiving the disk space -// observer notification. -#define LOW_DISK_SPACE_DATA_FULL "full" -#define LOW_DISK_SPACE_DATA_FREE "free" - namespace mozilla { namespace dom { namespace indexedDB { @@ -313,8 +306,6 @@ Atomic<IndexedDatabaseManager::LoggingMode> IndexedDatabaseManager::sLoggingMode( IndexedDatabaseManager::Logging_Disabled); -mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false); - // static IndexedDatabaseManager* IndexedDatabaseManager::GetOrCreate() @@ -329,24 +320,6 @@ IndexedDatabaseManager::GetOrCreate() if (!gDBManager) { sIsMainProcess = XRE_IsParentProcess(); - if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) { - // See if we're starting up in low disk space conditions. - nsCOMPtr<nsIDiskSpaceWatcher> watcher = - do_GetService(DISKSPACEWATCHER_CONTRACTID); - if (watcher) { - bool isDiskFull; - if (NS_SUCCEEDED(watcher->GetIsDiskFull(&isDiskFull))) { - sLowDiskSpaceMode = isDiskFull; - } - else { - NS_WARNING("GetIsDiskFull failed!"); - } - } - else { - NS_WARNING("No disk space watcher component available!"); - } - } - RefPtr<IndexedDatabaseManager> instance(new IndexedDatabaseManager()); nsresult rv = instance->Init(); @@ -380,13 +353,6 @@ IndexedDatabaseManager::Init() // During Init() we can't yet call IsMainProcess(), just check sIsMainProcess // directly. if (sIsMainProcess) { - nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); - NS_ENSURE_STATE(obs); - - nsresult rv = - obs->AddObserver(this, DISKSPACEWATCHER_OBSERVER_TOPIC, false); - NS_ENSURE_SUCCESS(rv, rv); - mDeleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID); NS_ENSURE_STATE(mDeleteTimer); @@ -680,16 +646,6 @@ IndexedDatabaseManager::IsMainProcess() return sIsMainProcess; } -//static -bool -IndexedDatabaseManager::InLowDiskSpaceMode() -{ - NS_ASSERTION(gDBManager, - "InLowDiskSpaceMode() called before indexedDB has been " - "initialized!"); - return sLowDiskSpaceMode; -} - // static IndexedDatabaseManager::LoggingMode IndexedDatabaseManager::GetLoggingMode() @@ -1087,36 +1043,7 @@ IndexedDatabaseManager::GetLocale() NS_IMPL_ADDREF(IndexedDatabaseManager) NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy()) -NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver, nsITimerCallback) - -NS_IMETHODIMP -IndexedDatabaseManager::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - NS_ASSERTION(IsMainProcess(), "Wrong process!"); - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (!strcmp(aTopic, DISKSPACEWATCHER_OBSERVER_TOPIC)) { - NS_ASSERTION(aData, "No data?!"); - - const nsDependentString data(aData); - - if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FULL)) { - sLowDiskSpaceMode = true; - } - else if (data.EqualsLiteral(LOW_DISK_SPACE_DATA_FREE)) { - sLowDiskSpaceMode = false; - } - else { - NS_NOTREACHED("Unknown data value!"); - } - - return NS_OK; - } - - NS_NOTREACHED("Unknown topic!"); - return NS_ERROR_UNEXPECTED; -} +NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsITimerCallback) NS_IMETHODIMP IndexedDatabaseManager::Notify(nsITimer* aTimer) diff --git a/dom/indexedDB/IndexedDatabaseManager.h b/dom/indexedDB/IndexedDatabaseManager.h index d63c548ec..fb4376426 100644 --- a/dom/indexedDB/IndexedDatabaseManager.h +++ b/dom/indexedDB/IndexedDatabaseManager.h @@ -7,8 +7,6 @@ #ifndef mozilla_dom_indexeddatabasemanager_h__ #define mozilla_dom_indexeddatabasemanager_h__ -#include "nsIObserver.h" - #include "js/TypeDecls.h" #include "mozilla/Atomics.h" #include "mozilla/dom/quota/PersistenceType.h" @@ -43,8 +41,7 @@ class FileManagerInfo; } // namespace indexedDB class IndexedDatabaseManager final - : public nsIObserver - , public nsITimerCallback + : public nsITimerCallback { typedef mozilla::dom::quota::PersistenceType PersistenceType; typedef mozilla::dom::quota::QuotaManager QuotaManager; @@ -62,7 +59,6 @@ public: }; NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER NS_DECL_NSITIMERCALLBACK // Returns a non-owning reference. @@ -87,16 +83,6 @@ public: #endif static bool - InLowDiskSpaceMode() -#ifdef DEBUG - ; -#else - { - return !!sLowDiskSpaceMode; - } -#endif - - static bool InTestingMode(); static bool @@ -244,7 +230,6 @@ private: static bool sFullSynchronousMode; static LazyLogModule sLoggingModule; static Atomic<LoggingMode> sLoggingMode; - static mozilla::Atomic<bool> sLowDiskSpaceMode; }; } // namespace dom diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index 0f693b2c6..575734af2 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -201,8 +201,11 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const } nsresult -Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, - uint8_t aTypeOffset, uint16_t aRecursionDepth) +Key::EncodeJSValInternal(JSContext* aCx, + JS::Handle<JS::Value> aVal, + uint8_t aTypeOffset, + uint16_t aRecursionDepth, + bool aCallGetters) { static_assert(eMaxType * kMaxArrayCollapse < 256, "Unable to encode jsvals."); @@ -257,13 +260,18 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, for (uint32_t index = 0; index < length; index++) { JS::Rooted<JS::Value> val(aCx); - if (!JS_GetElement(aCx, obj, index, &val)) { + bool ok = aCallGetters ? JS_GetElement(aCx, obj, index, &val) + : JS_GetOwnElement(aCx, obj, index, &val); + if (!ok) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset, - aRecursionDepth + 1); + nsresult rv = EncodeJSValInternal(aCx, + val, + aTypeOffset, + aRecursionDepth + 1, + aCallGetters); if (NS_FAILED(rv)) { return rv; } @@ -406,9 +414,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd, nsresult Key::EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, - uint8_t aTypeOffset) + uint8_t aTypeOffset, + bool aCallGetters) { - return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0); + return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0, aCallGetters); } void @@ -741,7 +750,8 @@ Key::SetFromValueArray(mozIStorageValueArray* aValues, nsresult Key::SetFromJSVal(JSContext* aCx, - JS::Handle<JS::Value> aVal) + JS::Handle<JS::Value> aVal, + bool aCallGetters) { mBuffer.Truncate(); @@ -750,7 +760,7 @@ Key::SetFromJSVal(JSContext* aCx, return NS_OK; } - nsresult rv = EncodeJSVal(aCx, aVal, 0); + nsresult rv = EncodeJSVal(aCx, aVal, 0, aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; @@ -793,9 +803,15 @@ Key::ToJSVal(JSContext* aCx, } nsresult -Key::AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal) +Key::AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle<JS::Value> aVal, + bool aCallGetters) { - nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0); + nsresult rv = EncodeJSVal(aCx, + aVal, + aFirstOfArray ? eMaxType : 0, + aCallGetters); if (NS_FAILED(rv)) { Unset(); return rv; diff --git a/dom/indexedDB/Key.h b/dom/indexedDB/Key.h index 9d70ce6ad..a4fb65b48 100644 --- a/dom/indexedDB/Key.h +++ b/dom/indexedDB/Key.h @@ -203,7 +203,7 @@ public: } nsresult - SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal); + SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, bool aCallGetters); nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const; @@ -212,7 +212,10 @@ public: ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const; nsresult - AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal); + AppendItem(JSContext* aCx, + bool aFirstOfArray, + JS::Handle<JS::Value> aVal, + bool aCallGetters); nsresult ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const; @@ -283,7 +286,10 @@ private: // Encoding functions. These append the encoded value to the end of mBuffer nsresult - EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset); + EncodeJSVal(JSContext* aCx, + JS::Handle<JS::Value> aVal, + uint8_t aTypeOffset, + bool aCallGetters); void EncodeString(const nsAString& aString, uint8_t aTypeOffset); @@ -331,7 +337,8 @@ private: EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset, - uint16_t aRecursionDepth); + uint16_t aRecursionDepth, + bool aCallGetters); static nsresult DecodeJSValInternal(const unsigned char*& aPos, diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index dc8d10668..0221c9450 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -14,6 +14,7 @@ #include "xpcpublic.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/IDBObjectStoreBinding.h" namespace mozilla { @@ -100,7 +101,6 @@ GetJSValFromKeyPathString(JSContext* aCx, const char16_t* keyPathChars = token.BeginReading(); const size_t keyPathLen = token.Length(); - bool hasProp; if (!targetObject) { // We're still walking the chain of existing objects // http://w3c.github.io/IndexedDB/#dfn-evaluate-a-key-path-on-a-value @@ -116,16 +116,77 @@ GetJSValFromKeyPathString(JSContext* aCx, } obj = ¤tVal.toObject(); - bool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen, - &hasProp); + // We call JS_GetOwnUCPropertyDescriptor on purpose (as opposed to + // JS_GetUCPropertyDescriptor) to avoid searching the prototype chain. + JS::Rooted<JS::PropertyDescriptor> desc(aCx); + bool ok = JS_GetOwnUCPropertyDescriptor(aCx, obj, keyPathChars, + keyPathLen, &desc); IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); - if (hasProp) { - // Get if the property exists... - JS::Rooted<JS::Value> intermediate(aCx); - bool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &intermediate); - IDB_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + JS::Rooted<JS::Value> intermediate(aCx); + bool hasProp = false; + + if (desc.object()) { + intermediate = desc.value(); + hasProp = true; + } else { + // If we get here it means the object doesn't have the property or the + // property is available throuch a getter. We don't want to call any + // getters to avoid potential re-entrancy. + // The blob object is special since its properties are available + // only through getters but we still want to support them for key + // extraction. So they need to be handled manually. + Blob* blob; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) { + if (token.EqualsLiteral("size")) { + ErrorResult rv; + uint64_t size = blob->GetSize(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(size); + hasProp = true; + } else if (token.EqualsLiteral("type")) { + nsString type; + blob->GetType(type); + + JSString* string = + JS_NewUCStringCopyN(aCx, type.get(), type.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else { + RefPtr<File> file = blob->ToFile(); + if (file) { + if (token.EqualsLiteral("name")) { + nsString name; + file->GetName(name); + + JSString* string = + JS_NewUCStringCopyN(aCx, name.get(), name.Length()); + + intermediate = JS::StringValue(string); + hasProp = true; + } else if (token.EqualsLiteral("lastModified")) { + ErrorResult rv; + int64_t lastModifiedDate = file->GetLastModified(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + intermediate = JS_NumberValue(lastModifiedDate); + hasProp = true; + } else if (token.EqualsLiteral("lastModifiedDate")) { + ErrorResult rv; + Date lastModifiedDate = file->GetLastModifiedDate(rv); + MOZ_ALWAYS_TRUE(!rv.Failed()); + + lastModifiedDate.ToDateObject(aCx, &intermediate); + hasProp = true; + } + } + } + } + } + if (hasProp) { // Treat explicitly undefined as an error. if (intermediate.isUndefined()) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; @@ -311,11 +372,13 @@ KeyPath::AppendStringWithValidation(const nsAString& aString) } nsresult -KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const +KeyPath::ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const { uint32_t len = mStrings.Length(); JS::Rooted<JS::Value> value(aCx); - aKey.Unset(); for (uint32_t i = 0; i < len; ++i) { @@ -327,7 +390,10 @@ KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, + IsArray() && i == 0, + value, + aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset"); return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } @@ -376,9 +442,12 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, } nsresult -KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, - Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const +KeyPath::ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + ExtractOrCreateKeyCallback aCallback, + void* aClosure, + bool aCallGetters) const { NS_ASSERTION(IsString(), "This doesn't make sense!"); @@ -394,7 +463,7 @@ KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, return rv; } - if (NS_FAILED(aKey.AppendItem(aCx, false, value))) { + if (NS_FAILED(aKey.AppendItem(aCx, false, value, aCallGetters))) { NS_ASSERTION(aKey.IsUnset(), "Should be unset"); return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } diff --git a/dom/indexedDB/KeyPath.h b/dom/indexedDB/KeyPath.h index c133cdc4a..e6e5f57d4 100644 --- a/dom/indexedDB/KeyPath.h +++ b/dom/indexedDB/KeyPath.h @@ -72,7 +72,10 @@ public: Parse(const Nullable<OwningStringOrStringSequence>& aValue, KeyPath* aKeyPath); nsresult - ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const; + ExtractKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, + bool aCallGetters) const; nsresult ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, @@ -82,9 +85,12 @@ public: (*ExtractOrCreateKeyCallback)(JSContext* aCx, void* aClosure); nsresult - ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, Key& aKey, + ExtractOrCreateKey(JSContext* aCx, + const JS::Value& aValue, + Key& aKey, ExtractOrCreateKeyCallback aCallback, - void* aClosure) const; + void* aClosure, + bool aCallGetters) const; inline bool IsValid() const { return mType != NONEXISTENT; diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js index e6e27f3f3..ffe66ebcd 100644 --- a/dom/indexedDB/test/helpers.js +++ b/dom/indexedDB/test/helpers.js @@ -217,10 +217,6 @@ if (!window.runTest) { function finishTest() { - SpecialPowers.notifyObserversInParentProcess(null, - "disk-space-watcher", - "free"); - SimpleTest.executeSoon(function() { testGenerator.close(); testHarnessGenerator.close(); diff --git a/dom/indexedDB/test/mochitest.ini b/dom/indexedDB/test/mochitest.ini index 4ab55a9dc..ca65ea8b6 100644 --- a/dom/indexedDB/test/mochitest.ini +++ b/dom/indexedDB/test/mochitest.ini @@ -66,7 +66,6 @@ support-files = unit/test_locale_aware_indexes.js unit/test_locale_aware_index_getAll.js unit/test_locale_aware_index_getAllObjects.js - unit/test_lowDiskSpace.js unit/test_maximal_serialized_object_size.js unit/test_multientry.js unit/test_names_sorted.js @@ -214,7 +213,6 @@ skip-if = true [test_key_requirements.html] [test_keys.html] [test_leaving_page.html] -[test_lowDiskSpace.html] [test_maximal_serialized_object_size.html] [test_message_manager_ipc.html] # This test is only supposed to run in the main process. diff --git a/dom/indexedDB/test/test_globalObjects_other.xul b/dom/indexedDB/test/test_globalObjects_other.xul index eb180a9b4..b527d66bd 100644 --- a/dom/indexedDB/test/test_globalObjects_other.xul +++ b/dom/indexedDB/test/test_globalObjects_other.xul @@ -31,14 +31,8 @@ Cu.import("resource://gre/modules/Services.jsm"); for (var stage of [ "install", "startup", "shutdown", "uninstall" ]) { for (var symbol of [ "IDBKeyRange", "indexedDB" ]) { - let pref; - try { - pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage + - "." + symbol); - } - catch(ex) { - pref = false; - } + let pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage + + "." + symbol, false); ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'"); } } diff --git a/dom/indexedDB/test/test_lowDiskSpace.html b/dom/indexedDB/test/test_lowDiskSpace.html deleted file mode 100644 index cffd46549..000000000 --- a/dom/indexedDB/test/test_lowDiskSpace.html +++ /dev/null @@ -1,19 +0,0 @@ -<!-- - Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ ---> -<html> -<head> - <title>Indexed Database Low Disk Space Test</title> - - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> - - <script type="text/javascript;version=1.7" src="unit/test_lowDiskSpace.js"></script> - <script type="text/javascript;version=1.7" src="helpers.js"></script> - -</head> - -<body onload="runTest();"></body> - -</html> diff --git a/dom/indexedDB/test/unit/test_lowDiskSpace.js b/dom/indexedDB/test/unit/test_lowDiskSpace.js deleted file mode 100644 index eaea5797d..000000000 --- a/dom/indexedDB/test/unit/test_lowDiskSpace.js +++ /dev/null @@ -1,754 +0,0 @@ -/** - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -"use strict"; - -var disableWorkerTest = "This test uses SpecialPowers"; - -var self = this; - -var testGenerator = testSteps(); - -function testSteps() -{ - const dbName = self.window ? window.location.pathname : "test_lowDiskSpace"; - const dbVersion = 1; - - const objectStoreName = "foo"; - const objectStoreOptions = { keyPath: "foo" }; - - const indexName = "bar"; - const indexOptions = { unique: true }; - - const dbData = [ - { foo: 0, bar: 0 }, - { foo: 1, bar: 10 }, - { foo: 2, bar: 20 }, - { foo: 3, bar: 30 }, - { foo: 4, bar: 40 }, - { foo: 5, bar: 50 }, - { foo: 6, bar: 60 }, - { foo: 7, bar: 70 }, - { foo: 8, bar: 80 }, - { foo: 9, bar: 90 } - ]; - - let lowDiskMode = false; - function setLowDiskMode(val) { - let data = val ? "full" : "free"; - - if (val == lowDiskMode) { - info("Low disk mode is: " + data); - } - else { - info("Changing low disk mode to: " + data); - SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher", - data); - lowDiskMode = val; - } - } - - { // Make sure opening works from the beginning. - info("Test 1"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - is(event.type, "success", "Opened database without setting low disk mode"); - - let db = event.target.result; - db.close(); - } - - { // Make sure delete works in low disk mode. - info("Test 2"); - - setLowDiskMode(true); - - let request = indexedDB.deleteDatabase(dbName); - request.onerror = errorHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - is(event.type, "success", "Deleted database after setting low disk mode"); - } - - { // Make sure creating a db in low disk mode fails. - info("Test 3"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = expectedErrorHandler("QuotaExceededError"); - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "error", "Didn't create new database in low disk mode"); - } - - { // Make sure opening an already-existing db in low disk mode succeeds. - info("Test 4"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Created database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Opened existing database in low disk mode"); - - db = event.target.result; - db.close(); - } - - { // Make sure upgrading an already-existing db in low disk mode succeeds. - info("Test 5"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 1); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Created database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure creating objectStores in low disk mode fails. - info("Test 6"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 2); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let txn = event.target.transaction; - txn.onerror = expectedErrorHandler("AbortError"); - txn.onabort = grabEventAndContinueHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "abort", "Got correct event type"); - is(event.target.error.name, "QuotaExceededError", "Got correct error type"); - - request.onerror = expectedErrorHandler("AbortError"); - event = yield undefined; - } - - { // Make sure creating indexes in low disk mode fails. - info("Test 7"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion + 2); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName, dbVersion + 3); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - db = event.target.result; - db.onerror = errorHandler; - let txn = event.target.transaction; - txn.onerror = expectedErrorHandler("AbortError"); - txn.onabort = grabEventAndContinueHandler; - - objectStore = event.target.transaction.objectStore(objectStoreName); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "abort", "Got correct event type"); - is(event.target.error.name, "QuotaExceededError", "Got correct error type"); - - request.onerror = expectedErrorHandler("AbortError"); - event = yield undefined; - } - - { // Make sure deleting indexes in low disk mode succeeds. - info("Test 8"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion + 3); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = event.target.transaction.objectStore(objectStoreName); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - setLowDiskMode(true); - - request = indexedDB.open(dbName, dbVersion + 4); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - db = event.target.result; - db.onerror = errorHandler; - - objectStore = event.target.transaction.objectStore(objectStoreName); - objectStore.deleteIndex(indexName); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure deleting objectStores in low disk mode succeeds. - info("Test 9"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion + 5); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - db.deleteObjectStore(objectStoreName); - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - - // Reset everything. - indexedDB.deleteDatabase(dbName); - } - - - { // Add data that the rest of the tests will use. - info("Adding test data"); - - setLowDiskMode(false); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = grabEventAndContinueHandler; - request.onsuccess = unexpectedSuccessHandler; - let event = yield undefined; - - is(event.type, "upgradeneeded", "Upgrading database"); - - let db = event.target.result; - db.onerror = errorHandler; - - let objectStore = db.createObjectStore(objectStoreName, objectStoreOptions); - let index = objectStore.createIndex(indexName, indexName, indexOptions); - - for (let data of dbData) { - objectStore.add(data); - } - - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "success", "Upgraded database"); - ok(event.target.result === db, "Got the same database"); - - db.close(); - } - - { // Make sure read operations in readonly transactions succeed in low disk - // mode. - info("Test 10"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - - let requestCounter = new RequestCounter(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure read operations in readwrite transactions succeed in low disk - // mode. - info("Test 11"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - - let requestCounter = new RequestCounter(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure write operations in readwrite transactions fail in low disk - // mode. - info("Test 12"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let data = dbData[0]; - let newData = { foo: 999, bar: 999 }; - - let requestCounter = new RequestCounter(); - - objectStore.add(newData).onerror = requestCounter.errorHandler(); - objectStore.put(newData).onerror = requestCounter.errorHandler(); - - objectStore.get(data.foo).onsuccess = requestCounter.handler(); - objectStore.mozGetAll().onsuccess = requestCounter.handler(); - objectStore.count().onsuccess = requestCounter.handler(); - index.get(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAll().onsuccess = requestCounter.handler(); - index.getKey(data.bar).onsuccess = requestCounter.handler(); - index.mozGetAllKeys().onsuccess = requestCounter.handler(); - index.count().onsuccess = requestCounter.handler(); - - let objectStoreDataCount = 0; - - request = objectStore.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - objectStoreDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - objectStoreDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(objectStoreDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - indexDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - let indexKeyDataCount = 0; - - request = index.openCursor(); - request.onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - indexKeyDataCount++; - cursor.update(cursor.value).onerror = requestCounter.errorHandler(); - indexKeyDataCount % 2 ? cursor.continue() : cursor.advance(1); - } - else { - is(indexKeyDataCount, dbData.length, "Saw all data"); - requestCounter.decr(); - } - }; - requestCounter.incr(); - - // Wait for all requests. - yield undefined; - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - { // Make sure deleting operations in readwrite transactions succeed in low - // disk mode. - info("Test 13"); - - setLowDiskMode(true); - - let request = indexedDB.open(dbName, dbVersion); - request.onerror = errorHandler; - request.onupgradeneeded = unexpectedSuccessHandler; - request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; - - let db = event.target.result; - db.onerror = errorHandler; - - let transaction = db.transaction(objectStoreName, "readwrite"); - let objectStore = transaction.objectStore(objectStoreName); - let index = objectStore.index(indexName); - - let dataIndex = 0; - let data = dbData[dataIndex++]; - - let requestCounter = new RequestCounter(); - - objectStore.delete(data.foo).onsuccess = requestCounter.handler(); - - objectStore.openCursor().onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - cursor.delete().onsuccess = requestCounter.handler(); - } - requestCounter.decr(); - }; - requestCounter.incr(); - - index.openCursor(null, "prev").onsuccess = function(event) { - let cursor = event.target.result; - if (cursor) { - cursor.delete().onsuccess = requestCounter.handler(); - } - requestCounter.decr(); - }; - requestCounter.incr(); - - yield undefined; - - objectStore.count().onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.target.result, dbData.length - 3, "Actually deleted something"); - - objectStore.clear(); - objectStore.count().onsuccess = grabEventAndContinueHandler; - event = yield undefined; - - is(event.target.result, 0, "Actually cleared"); - - transaction.oncomplete = grabEventAndContinueHandler; - event = yield undefined; - - is(event.type, "complete", "Transaction succeeded"); - - db.close(); - } - - finishTest(); - yield undefined; -} - -function RequestCounter(expectedType) { - this._counter = 0; -} -RequestCounter.prototype = { - incr: function() { - this._counter++; - }, - - decr: function() { - if (!--this._counter) { - continueToNextStepSync(); - } - }, - - handler: function(type, preventDefault) { - this.incr(); - return function(event) { - is(event.type, type || "success", "Correct type"); - this.decr(); - }.bind(this); - }, - - errorHandler: function(eventType, errorName) { - this.incr(); - return function(event) { - is(event.type, eventType || "error", "Correct type"); - is(event.target.error.name, errorName || "QuotaExceededError", - "Correct error name"); - event.preventDefault(); - event.stopPropagation(); - this.decr(); - }.bind(this); - } -}; diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index def791f52..fe69b1f7b 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -66,9 +66,6 @@ function finishTest() resetWasm(); resetExperimental(); resetTesting(); - - SpecialPowers.notifyObserversInParentProcess(null, "disk-space-watcher", - "free"); } SpecialPowers.removeFiles(); diff --git a/dom/indexedDB/test/unit/xpcshell-parent-process.ini b/dom/indexedDB/test/unit/xpcshell-parent-process.ini index 04df5f552..2def60c34 100644 --- a/dom/indexedDB/test/unit/xpcshell-parent-process.ini +++ b/dom/indexedDB/test/unit/xpcshell-parent-process.ini @@ -46,7 +46,6 @@ skip-if = toolkit == 'android' [test_invalidate.js] # disabled for the moment. skip-if = true -[test_lowDiskSpace.js] [test_maximal_serialized_object_size.js] [test_metadata2Restore.js] [test_metadataRestore.js] |