diff -r 000000000000 -r 6474c204b198 dom/indexedDB/ipc/IndexedDBChild.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/indexedDB/ipc/IndexedDBChild.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1382 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "base/basictypes.h" + +#include "IndexedDBChild.h" + +#include "nsIInputStream.h" + +#include "mozilla/Assertions.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/quota/Client.h" +#include "mozilla/dom/quota/QuotaManager.h" + +#include "AsyncConnectionHelper.h" +#include "DatabaseInfo.h" +#include "IDBEvents.h" +#include "IDBFactory.h" +#include "IDBIndex.h" +#include "IDBObjectStore.h" +#include "IDBTransaction.h" + +USING_INDEXEDDB_NAMESPACE + +using namespace mozilla::dom; +using mozilla::dom::quota::Client; +using mozilla::dom::quota::QuotaManager; + +namespace { + +class IPCOpenDatabaseHelper : public AsyncConnectionHelper +{ +public: + IPCOpenDatabaseHelper(IDBDatabase* aDatabase, IDBOpenDBRequest* aRequest) + : AsyncConnectionHelper(aDatabase, aRequest) + { + MOZ_ASSERT(aRequest); + } + + virtual nsresult UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) + MOZ_OVERRIDE; + + virtual ChildProcessSendResult + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; + + virtual nsresult + GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) MOZ_OVERRIDE; + + virtual nsresult + OnSuccess() MOZ_OVERRIDE + { + static_cast(mRequest.get())->SetTransaction(nullptr); + return AsyncConnectionHelper::OnSuccess(); + } + + virtual void + OnError() MOZ_OVERRIDE + { + static_cast(mRequest.get())->SetTransaction(nullptr); + AsyncConnectionHelper::OnError(); + } + + virtual nsresult + DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; +}; + +class IPCSetVersionHelper : public AsyncConnectionHelper +{ + nsRefPtr mOpenRequest; + uint64_t mOldVersion; + uint64_t mRequestedVersion; + +public: + IPCSetVersionHelper(IDBTransaction* aTransaction, IDBOpenDBRequest* aRequest, + uint64_t aOldVersion, uint64_t aRequestedVersion) + : AsyncConnectionHelper(aTransaction, aRequest), + mOpenRequest(aRequest), mOldVersion(aOldVersion), + mRequestedVersion(aRequestedVersion) + { + MOZ_ASSERT(aTransaction); + MOZ_ASSERT(aRequest); + } + + virtual nsresult UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) + MOZ_OVERRIDE; + + virtual ChildProcessSendResult + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; + + virtual nsresult + DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; + + virtual already_AddRefed + CreateSuccessEvent(mozilla::dom::EventTarget* aOwner) MOZ_OVERRIDE; + + virtual nsresult + GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) MOZ_OVERRIDE; +}; + +class IPCDeleteDatabaseHelper : public AsyncConnectionHelper +{ +public: + IPCDeleteDatabaseHelper(IDBRequest* aRequest) + : AsyncConnectionHelper(static_cast(nullptr), aRequest) + { } + + virtual nsresult UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) + MOZ_OVERRIDE; + + virtual ChildProcessSendResult + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; + + virtual nsresult + GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) MOZ_OVERRIDE; + + virtual nsresult + DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; +}; + +class VersionChangeRunnable : public nsRunnable +{ + nsRefPtr mDatabase; + uint64_t mOldVersion; + uint64_t mNewVersion; + +public: + VersionChangeRunnable(IDBDatabase* aDatabase, const uint64_t& aOldVersion, + const uint64_t& aNewVersion) + : mDatabase(aDatabase), mOldVersion(aOldVersion), mNewVersion(aNewVersion) + { + MOZ_ASSERT(aDatabase); + } + + NS_IMETHOD Run() MOZ_OVERRIDE + { + if (mDatabase->IsClosed()) { + return NS_OK; + } + + nsRefPtr event = + IDBVersionChangeEvent::Create(mDatabase, mOldVersion, mNewVersion); + MOZ_ASSERT(event); + + bool dummy; + nsresult rv = mDatabase->DispatchEvent(event, &dummy); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } +}; + +} // anonymous namespace + +/******************************************************************************* + * IndexedDBChild + ******************************************************************************/ + +IndexedDBChild::IndexedDBChild(const nsCString& aASCIIOrigin) +: mFactory(nullptr), mASCIIOrigin(aASCIIOrigin) +#ifdef DEBUG + , mDisconnected(false) +#endif +{ + MOZ_COUNT_CTOR(IndexedDBChild); +} + +IndexedDBChild::~IndexedDBChild() +{ + MOZ_COUNT_DTOR(IndexedDBChild); + MOZ_ASSERT(!mFactory); +} + +void +IndexedDBChild::SetFactory(IDBFactory* aFactory) +{ + MOZ_ASSERT(aFactory); + MOZ_ASSERT(!mFactory); + + aFactory->SetActor(this); + mFactory = aFactory; +} + +void +IndexedDBChild::Disconnect() +{ +#ifdef DEBUG + MOZ_ASSERT(!mDisconnected); + mDisconnected = true; +#endif + + const InfallibleTArray& databases = + ManagedPIndexedDBDatabaseChild(); + for (uint32_t i = 0; i < databases.Length(); ++i) { + static_cast(databases[i])->Disconnect(); + } +} + +void +IndexedDBChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mFactory) { + mFactory->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mFactory = nullptr; +#endif + } +} + +PIndexedDBDatabaseChild* +IndexedDBChild::AllocPIndexedDBDatabaseChild( + const nsString& aName, + const uint64_t& aVersion, + const PersistenceType& aPersistenceType) +{ + return new IndexedDBDatabaseChild(aName, aVersion); +} + +bool +IndexedDBChild::DeallocPIndexedDBDatabaseChild(PIndexedDBDatabaseChild* aActor) +{ + delete aActor; + return true; +} + +PIndexedDBDeleteDatabaseRequestChild* +IndexedDBChild::AllocPIndexedDBDeleteDatabaseRequestChild( + const nsString& aName, + const PersistenceType& aPersistenceType) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +IndexedDBChild::DeallocPIndexedDBDeleteDatabaseRequestChild( + PIndexedDBDeleteDatabaseRequestChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBDatabaseChild + ******************************************************************************/ + +IndexedDBDatabaseChild::IndexedDBDatabaseChild(const nsString& aName, + uint64_t aVersion) +: mDatabase(nullptr), mName(aName), mVersion(aVersion) +{ + MOZ_COUNT_CTOR(IndexedDBDatabaseChild); +} + +IndexedDBDatabaseChild::~IndexedDBDatabaseChild() +{ + MOZ_COUNT_DTOR(IndexedDBDatabaseChild); + MOZ_ASSERT(!mDatabase); + MOZ_ASSERT(!mStrongDatabase); +} + +void +IndexedDBDatabaseChild::SetRequest(IDBOpenDBRequest* aRequest) +{ + MOZ_ASSERT(aRequest); + MOZ_ASSERT(!mRequest); + + mRequest = aRequest; +} + +void +IndexedDBDatabaseChild::Disconnect() +{ + const InfallibleTArray& transactions = + ManagedPIndexedDBTransactionChild(); + for (uint32_t i = 0; i < transactions.Length(); ++i) { + static_cast(transactions[i])->Disconnect(); + } +} + +bool +IndexedDBDatabaseChild::EnsureDatabase( + IDBOpenDBRequest* aRequest, + const DatabaseInfoGuts& aDBInfo, + const InfallibleTArray& aOSInfo) +{ + nsCString databaseId; + if (mDatabase) { + databaseId = mDatabase->Id(); + } + else { + QuotaManager::GetStorageId(aDBInfo.persistenceType, aDBInfo.origin, + Client::IDB, aDBInfo.name, databaseId); + } + MOZ_ASSERT(!databaseId.IsEmpty()); + + nsRefPtr dbInfo; + if (DatabaseInfo::Get(databaseId, getter_AddRefs(dbInfo))) { + dbInfo->version = aDBInfo.version; + } + else { + nsRefPtr newInfo = new DatabaseInfo(); + + *static_cast(newInfo.get()) = aDBInfo; + newInfo->id = databaseId; + + if (!DatabaseInfo::Put(newInfo)) { + NS_WARNING("Out of memory!"); + return false; + } + + newInfo.swap(dbInfo); + + // This is more or less copied from IDBFactory::SetDatabaseMetadata. + for (uint32_t i = 0; i < aOSInfo.Length(); i++) { + nsRefPtr newInfo = new ObjectStoreInfo(); + *static_cast(newInfo.get()) = aOSInfo[i]; + + if (!dbInfo->PutObjectStore(newInfo)) { + NS_WARNING("Out of memory!"); + return false; + } + } + } + + if (!mDatabase) { + nsRefPtr database = + IDBDatabase::Create(aRequest, aRequest->Factory(), dbInfo.forget(), + aDBInfo.origin, nullptr, nullptr); + if (!database) { + NS_WARNING("Failed to create database!"); + return false; + } + + database->SetActor(this); + + mDatabase = database; + mStrongDatabase = database.forget(); + } + + return true; +} + +void +IndexedDBDatabaseChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mDatabase) { + mDatabase->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mDatabase = nullptr; +#endif + } +} + +bool +IndexedDBDatabaseChild::RecvSuccess( + const DatabaseInfoGuts& aDBInfo, + const InfallibleTArray& aOSInfo) +{ +#ifdef DEBUG + { + IndexedDBChild* manager = static_cast(Manager()); + MOZ_ASSERT(aDBInfo.origin == manager->ASCIIOrigin()); + MOZ_ASSERT(aDBInfo.name == mName); + MOZ_ASSERT(!mVersion || aDBInfo.version == mVersion); + } +#endif + + MOZ_ASSERT(mRequest); + + nsRefPtr request; + mRequest.swap(request); + + nsRefPtr openHelper; + mOpenHelper.swap(openHelper); + + if (!EnsureDatabase(request, aDBInfo, aOSInfo)) { + return false; + } + + MOZ_ASSERT(mStrongDatabase); + nsRefPtr database; + mStrongDatabase.swap(database); + + if (openHelper) { + request->Reset(); + } + else { + openHelper = new IPCOpenDatabaseHelper(mDatabase, request); + } + + ImmediateRunEventTarget target; + if (NS_FAILED(openHelper->Dispatch(&target))) { + NS_WARNING("Dispatch of IPCOpenDatabaseHelper failed!"); + return false; + } + + return true; +} + +bool +IndexedDBDatabaseChild::RecvError(const nsresult& aRv) +{ + MOZ_ASSERT(mRequest); + + nsRefPtr request; + mRequest.swap(request); + + nsRefPtr database; + mStrongDatabase.swap(database); + + nsRefPtr openHelper; + mOpenHelper.swap(openHelper); + + if (openHelper) { + request->Reset(); + } + else { + openHelper = new IPCOpenDatabaseHelper(nullptr, request); + } + + openHelper->SetError(aRv); + + ImmediateRunEventTarget target; + if (NS_FAILED(openHelper->Dispatch(&target))) { + NS_WARNING("Dispatch of IPCOpenDatabaseHelper failed!"); + return false; + } + + return true; +} + +bool +IndexedDBDatabaseChild::RecvBlocked(const uint64_t& aOldVersion) +{ + MOZ_ASSERT(mRequest); + MOZ_ASSERT(!mDatabase); + + nsCOMPtr runnable = + IDBVersionChangeEvent::CreateBlockedRunnable(mRequest, aOldVersion, mVersion); + + ImmediateRunEventTarget target; + if (NS_FAILED(target.Dispatch(runnable, NS_DISPATCH_NORMAL))) { + NS_WARNING("Dispatch of blocked event failed!"); + } + + return true; +} + +bool +IndexedDBDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion, + const uint64_t& aNewVersion) +{ + MOZ_ASSERT(mDatabase); + + nsCOMPtr runnable = + new VersionChangeRunnable(mDatabase, aOldVersion, aNewVersion); + + ImmediateRunEventTarget target; + if (NS_FAILED(target.Dispatch(runnable, NS_DISPATCH_NORMAL))) { + NS_WARNING("Dispatch of versionchange event failed!"); + } + + return true; +} + +bool +IndexedDBDatabaseChild::RecvInvalidate() +{ + if (mDatabase) { + mDatabase->Invalidate(); + } + return true; +} + +bool +IndexedDBDatabaseChild::RecvPIndexedDBTransactionConstructor( + PIndexedDBTransactionChild* aActor, + const TransactionParams& aParams) +{ + // This only happens when the parent has created a version-change transaction + // for us. + + IndexedDBTransactionChild* actor = + static_cast(aActor); + MOZ_ASSERT(!actor->GetTransaction()); + + MOZ_ASSERT(aParams.type() == + TransactionParams::TVersionChangeTransactionParams); + + const VersionChangeTransactionParams& params = + aParams.get_VersionChangeTransactionParams(); + + const DatabaseInfoGuts& dbInfo = params.dbInfo(); + const InfallibleTArray& osInfo = params.osInfo(); + uint64_t oldVersion = params.oldVersion(); + + MOZ_ASSERT(dbInfo.origin == + static_cast(Manager())->ASCIIOrigin()); + MOZ_ASSERT(dbInfo.name == mName); + MOZ_ASSERT(!mVersion || dbInfo.version == mVersion); + MOZ_ASSERT(!mVersion || oldVersion < mVersion); + + MOZ_ASSERT(mRequest); + MOZ_ASSERT(!mDatabase); + MOZ_ASSERT(!mOpenHelper); + + if (!EnsureDatabase(mRequest, dbInfo, osInfo)) { + return false; + } + + nsRefPtr helper = + new IPCOpenDatabaseHelper(mDatabase, mRequest); + + Sequence storesToOpen; + nsRefPtr transaction = + IDBTransaction::CreateInternal(mDatabase, storesToOpen, + IDBTransaction::VERSION_CHANGE, false, true); + NS_ENSURE_TRUE(transaction, false); + + nsRefPtr versionHelper = + new IPCSetVersionHelper(transaction, mRequest, oldVersion, mVersion); + + mDatabase->EnterSetVersionTransaction(); + mDatabase->mPreviousDatabaseInfo->version = oldVersion; + + actor->SetTransaction(transaction); + + ImmediateRunEventTarget target; + if (NS_FAILED(versionHelper->Dispatch(&target))) { + NS_WARNING("Dispatch of IPCSetVersionHelper failed!"); + return false; + } + + mOpenHelper = helper.forget(); + return true; +} + +PIndexedDBTransactionChild* +IndexedDBDatabaseChild::AllocPIndexedDBTransactionChild( + const TransactionParams& aParams) +{ + MOZ_ASSERT(aParams.type() == + TransactionParams::TVersionChangeTransactionParams); + return new IndexedDBTransactionChild(); +} + +bool +IndexedDBDatabaseChild::DeallocPIndexedDBTransactionChild( + PIndexedDBTransactionChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBTransactionChild + ******************************************************************************/ + +IndexedDBTransactionChild::IndexedDBTransactionChild() +: mTransaction(nullptr) +{ + MOZ_COUNT_CTOR(IndexedDBTransactionChild); +} + +IndexedDBTransactionChild::~IndexedDBTransactionChild() +{ + MOZ_COUNT_DTOR(IndexedDBTransactionChild); + MOZ_ASSERT(!mTransaction); + MOZ_ASSERT(!mStrongTransaction); +} + +void +IndexedDBTransactionChild::SetTransaction(IDBTransaction* aTransaction) +{ + MOZ_ASSERT(aTransaction); + MOZ_ASSERT(!mTransaction); + + aTransaction->SetActor(this); + + mTransaction = aTransaction; + mStrongTransaction = aTransaction; +} + +void +IndexedDBTransactionChild::Disconnect() +{ + const InfallibleTArray& objectStores = + ManagedPIndexedDBObjectStoreChild(); + for (uint32_t i = 0; i < objectStores.Length(); ++i) { + static_cast(objectStores[i])->Disconnect(); + } +} + +void +IndexedDBTransactionChild::FireCompleteEvent(nsresult aRv) +{ + MOZ_ASSERT(mTransaction); + MOZ_ASSERT(mStrongTransaction); + + nsRefPtr transaction; + mStrongTransaction.swap(transaction); + + if (transaction->GetMode() == IDBTransaction::VERSION_CHANGE) { + transaction->Database()->ExitSetVersionTransaction(); + } + + nsRefPtr helper = new CommitHelper(transaction, aRv); + + ImmediateRunEventTarget target; + if (NS_FAILED(target.Dispatch(helper, NS_DISPATCH_NORMAL))) { + NS_WARNING("Dispatch of CommitHelper failed!"); + } +} + +void +IndexedDBTransactionChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mStrongTransaction) { + // We're being torn down before we received a complete event from the parent + // so fake one here. + FireCompleteEvent(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + MOZ_ASSERT(!mStrongTransaction); + } + + if (mTransaction) { + mTransaction->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mTransaction = nullptr; +#endif + } +} + +bool +IndexedDBTransactionChild::RecvComplete(const CompleteParams& aParams) +{ + MOZ_ASSERT(mTransaction); + MOZ_ASSERT(mStrongTransaction); + + nsresult resultCode; + + switch (aParams.type()) { + case CompleteParams::TCompleteResult: + resultCode = NS_OK; + break; + case CompleteParams::TAbortResult: + resultCode = aParams.get_AbortResult().errorCode(); + if (NS_SUCCEEDED(resultCode)) { + resultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR; + } + break; + + default: + MOZ_CRASH("Unknown union type!"); + } + + FireCompleteEvent(resultCode); + return true; +} + +PIndexedDBObjectStoreChild* +IndexedDBTransactionChild::AllocPIndexedDBObjectStoreChild( + const ObjectStoreConstructorParams& aParams) +{ + MOZ_CRASH("Caller is supposed to manually construct an object store!"); +} + +bool +IndexedDBTransactionChild::DeallocPIndexedDBObjectStoreChild( + PIndexedDBObjectStoreChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBObjectStoreChild + ******************************************************************************/ + +IndexedDBObjectStoreChild::IndexedDBObjectStoreChild( + IDBObjectStore* aObjectStore) +: mObjectStore(aObjectStore) +{ + MOZ_COUNT_CTOR(IndexedDBObjectStoreChild); + aObjectStore->SetActor(this); +} + +IndexedDBObjectStoreChild::~IndexedDBObjectStoreChild() +{ + MOZ_COUNT_DTOR(IndexedDBObjectStoreChild); + MOZ_ASSERT(!mObjectStore); +} + +void +IndexedDBObjectStoreChild::Disconnect() +{ + const InfallibleTArray& requests = + ManagedPIndexedDBRequestChild(); + for (uint32_t i = 0; i < requests.Length(); ++i) { + static_cast(requests[i])->Disconnect(); + } + + const InfallibleTArray& indexes = + ManagedPIndexedDBIndexChild(); + for (uint32_t i = 0; i < indexes.Length(); ++i) { + static_cast(indexes[i])->Disconnect(); + } + + const InfallibleTArray& cursors = + ManagedPIndexedDBCursorChild(); + for (uint32_t i = 0; i < cursors.Length(); ++i) { + static_cast(cursors[i])->Disconnect(); + } +} + +void +IndexedDBObjectStoreChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mObjectStore) { + mObjectStore->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mObjectStore = nullptr; +#endif + } +} + +bool +IndexedDBObjectStoreChild::RecvPIndexedDBCursorConstructor( + PIndexedDBCursorChild* aActor, + const ObjectStoreCursorConstructorParams& aParams) +{ + IndexedDBCursorChild* actor = static_cast(aActor); + + IndexedDBObjectStoreRequestChild* requestActor = + static_cast(aParams.requestChild()); + NS_ASSERTION(requestActor, "Must have an actor here!"); + + nsRefPtr request = requestActor->GetRequest(); + NS_ASSERTION(request, "Must have a request here!"); + + size_t direction = static_cast(aParams.direction()); + + nsRefPtr cursor; + nsresult rv; + + typedef ipc::OptionalStructuredCloneReadInfo CursorUnionType; + + switch (aParams.optionalCloneInfo().type()) { + case CursorUnionType::TSerializedStructuredCloneReadInfo: { + nsTArray blobs; + IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs); + + const SerializedStructuredCloneReadInfo& cloneInfo = + aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo(); + + rv = mObjectStore->OpenCursorFromChildProcess(request, direction, + aParams.key(), cloneInfo, + blobs, + getter_AddRefs(cursor)); + NS_ENSURE_SUCCESS(rv, false); + + MOZ_ASSERT(blobs.IsEmpty(), "Should have swapped blob elements!"); + } break; + + case CursorUnionType::Tvoid_t: + MOZ_ASSERT(aParams.blobsChild().IsEmpty()); + + rv = mObjectStore->OpenCursorFromChildProcess(request, direction, + aParams.key(), + getter_AddRefs(cursor)); + NS_ENSURE_SUCCESS(rv, false); + break; + + default: + MOZ_CRASH("Unknown union type!"); + } + + actor->SetCursor(cursor); + return true; +} + +PIndexedDBRequestChild* +IndexedDBObjectStoreChild::AllocPIndexedDBRequestChild( + const ObjectStoreRequestParams& aParams) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +IndexedDBObjectStoreChild::DeallocPIndexedDBRequestChild( + PIndexedDBRequestChild* aActor) +{ + delete aActor; + return false; +} + +PIndexedDBIndexChild* +IndexedDBObjectStoreChild::AllocPIndexedDBIndexChild( + const IndexConstructorParams& aParams) +{ + MOZ_CRASH("Caller is supposed to manually construct an index!"); +} + +bool +IndexedDBObjectStoreChild::DeallocPIndexedDBIndexChild(PIndexedDBIndexChild* aActor) +{ + delete aActor; + return true; +} + +PIndexedDBCursorChild* +IndexedDBObjectStoreChild::AllocPIndexedDBCursorChild( + const ObjectStoreCursorConstructorParams& aParams) +{ + return new IndexedDBCursorChild(); +} + +bool +IndexedDBObjectStoreChild::DeallocPIndexedDBCursorChild( + PIndexedDBCursorChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBIndexChild + ******************************************************************************/ + +IndexedDBIndexChild::IndexedDBIndexChild(IDBIndex* aIndex) +: mIndex(aIndex) +{ + MOZ_COUNT_CTOR(IndexedDBIndexChild); + aIndex->SetActor(this); +} + +IndexedDBIndexChild::~IndexedDBIndexChild() +{ + MOZ_COUNT_DTOR(IndexedDBIndexChild); + MOZ_ASSERT(!mIndex); +} + +void +IndexedDBIndexChild::Disconnect() +{ + const InfallibleTArray& requests = + ManagedPIndexedDBRequestChild(); + for (uint32_t i = 0; i < requests.Length(); ++i) { + static_cast(requests[i])->Disconnect(); + } + + const InfallibleTArray& cursors = + ManagedPIndexedDBCursorChild(); + for (uint32_t i = 0; i < cursors.Length(); ++i) { + static_cast(cursors[i])->Disconnect(); + } +} + +void +IndexedDBIndexChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mIndex) { + mIndex->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mIndex = nullptr; +#endif + } +} + +bool +IndexedDBIndexChild::RecvPIndexedDBCursorConstructor( + PIndexedDBCursorChild* aActor, + const IndexCursorConstructorParams& aParams) +{ + IndexedDBCursorChild* actor = static_cast(aActor); + + IndexedDBObjectStoreRequestChild* requestActor = + static_cast(aParams.requestChild()); + NS_ASSERTION(requestActor, "Must have an actor here!"); + + nsRefPtr request = requestActor->GetRequest(); + NS_ASSERTION(request, "Must have a request here!"); + + size_t direction = static_cast(aParams.direction()); + + nsRefPtr cursor; + nsresult rv; + + typedef ipc::OptionalStructuredCloneReadInfo CursorUnionType; + + switch (aParams.optionalCloneInfo().type()) { + case CursorUnionType::TSerializedStructuredCloneReadInfo: { + nsTArray blobs; + IDBObjectStore::ConvertActorsToBlobs(aParams.blobsChild(), blobs); + + const SerializedStructuredCloneReadInfo& cloneInfo = + aParams.optionalCloneInfo().get_SerializedStructuredCloneReadInfo(); + + rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(), + aParams.objectKey(), cloneInfo, + blobs, + getter_AddRefs(cursor)); + NS_ENSURE_SUCCESS(rv, false); + } break; + + case CursorUnionType::Tvoid_t: + MOZ_ASSERT(aParams.blobsChild().IsEmpty()); + + rv = mIndex->OpenCursorFromChildProcess(request, direction, aParams.key(), + aParams.objectKey(), + getter_AddRefs(cursor)); + NS_ENSURE_SUCCESS(rv, false); + break; + + default: + MOZ_CRASH("Unknown union type!"); + } + + actor->SetCursor(cursor); + return true; +} + +PIndexedDBRequestChild* +IndexedDBIndexChild::AllocPIndexedDBRequestChild(const IndexRequestParams& aParams) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +IndexedDBIndexChild::DeallocPIndexedDBRequestChild(PIndexedDBRequestChild* aActor) +{ + delete aActor; + return true; +} + +PIndexedDBCursorChild* +IndexedDBIndexChild::AllocPIndexedDBCursorChild( + const IndexCursorConstructorParams& aParams) +{ + return new IndexedDBCursorChild(); +} + +bool +IndexedDBIndexChild::DeallocPIndexedDBCursorChild(PIndexedDBCursorChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBCursorChild + ******************************************************************************/ + +IndexedDBCursorChild::IndexedDBCursorChild() +: mCursor(nullptr) +{ + MOZ_COUNT_CTOR(IndexedDBCursorChild); +} + +IndexedDBCursorChild::~IndexedDBCursorChild() +{ + MOZ_COUNT_DTOR(IndexedDBCursorChild); + MOZ_ASSERT(!mCursor); + MOZ_ASSERT(!mStrongCursor); +} + +void +IndexedDBCursorChild::SetCursor(IDBCursor* aCursor) +{ + MOZ_ASSERT(aCursor); + MOZ_ASSERT(!mCursor); + + aCursor->SetActor(this); + + mCursor = aCursor; + mStrongCursor = aCursor; +} + +void +IndexedDBCursorChild::Disconnect() +{ + const InfallibleTArray& requests = + ManagedPIndexedDBRequestChild(); + for (uint32_t i = 0; i < requests.Length(); ++i) { + static_cast(requests[i])->Disconnect(); + } +} + +void +IndexedDBCursorChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mCursor) { + mCursor->SetActor(static_cast(nullptr)); +#ifdef DEBUG + mCursor = nullptr; +#endif + } +} + +PIndexedDBRequestChild* +IndexedDBCursorChild::AllocPIndexedDBRequestChild(const CursorRequestParams& aParams) +{ + MOZ_CRASH("Caller is supposed to manually construct a request!"); +} + +bool +IndexedDBCursorChild::DeallocPIndexedDBRequestChild(PIndexedDBRequestChild* aActor) +{ + delete aActor; + return true; +} + +/******************************************************************************* + * IndexedDBRequestChildBase + ******************************************************************************/ + +IndexedDBRequestChildBase::IndexedDBRequestChildBase( + AsyncConnectionHelper* aHelper) +: mHelper(aHelper) +{ + MOZ_COUNT_CTOR(IndexedDBRequestChildBase); +} + +IndexedDBRequestChildBase::~IndexedDBRequestChildBase() +{ + MOZ_COUNT_DTOR(IndexedDBRequestChildBase); +} + +IDBRequest* +IndexedDBRequestChildBase::GetRequest() const +{ + return mHelper ? mHelper->GetRequest() : nullptr; +} + +void +IndexedDBRequestChildBase::Disconnect() +{ + if (mHelper) { + IDBRequest* request = mHelper->GetRequest(); + + if (request->IsPending()) { + request->SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); + + IDBTransaction* transaction = mHelper->GetTransaction(); + if (transaction) { + transaction->OnRequestDisconnected(); + } + } + } +} + +bool +IndexedDBRequestChildBase::Recv__delete__(const ResponseValue& aResponse) +{ + MOZ_CRASH("This should be overridden!"); +} + +/******************************************************************************* + * IndexedDBObjectStoreRequestChild + ******************************************************************************/ + +IndexedDBObjectStoreRequestChild::IndexedDBObjectStoreRequestChild( + AsyncConnectionHelper* aHelper, + IDBObjectStore* aObjectStore, + RequestType aRequestType) +: IndexedDBRequestChildBase(aHelper), mObjectStore(aObjectStore), + mRequestType(aRequestType) +{ + MOZ_COUNT_CTOR(IndexedDBObjectStoreRequestChild); + MOZ_ASSERT(aHelper); + MOZ_ASSERT(aObjectStore); + MOZ_ASSERT(aRequestType > ParamsUnionType::T__None && + aRequestType <= ParamsUnionType::T__Last); +} + +IndexedDBObjectStoreRequestChild::~IndexedDBObjectStoreRequestChild() +{ + MOZ_COUNT_DTOR(IndexedDBObjectStoreRequestChild); +} + +bool +IndexedDBObjectStoreRequestChild::Recv__delete__(const ResponseValue& aResponse) +{ + switch (aResponse.type()) { + case ResponseValue::Tnsresult: + break; + case ResponseValue::TGetResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetParams); + break; + case ResponseValue::TGetAllResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetAllParams); + break; + case ResponseValue::TGetAllKeysResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetAllKeysParams); + break; + case ResponseValue::TAddResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TAddParams); + break; + case ResponseValue::TPutResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TPutParams); + break; + case ResponseValue::TDeleteResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TDeleteParams); + break; + case ResponseValue::TClearResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TClearParams); + break; + case ResponseValue::TCountResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TCountParams); + break; + case ResponseValue::TOpenCursorResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TOpenCursorParams || + mRequestType == ParamsUnionType::TOpenKeyCursorParams); + break; + + default: + MOZ_CRASH("Received invalid response parameters!"); + } + + nsresult rv = mHelper->OnParentProcessRequestComplete(aResponse); + NS_ENSURE_SUCCESS(rv, false); + + return true; +} + +/******************************************************************************* + * IndexedDBIndexRequestChild + ******************************************************************************/ + +IndexedDBIndexRequestChild::IndexedDBIndexRequestChild( + AsyncConnectionHelper* aHelper, + IDBIndex* aIndex, + RequestType aRequestType) +: IndexedDBRequestChildBase(aHelper), mIndex(aIndex), mRequestType(aRequestType) +{ + MOZ_COUNT_CTOR(IndexedDBIndexRequestChild); + MOZ_ASSERT(aHelper); + MOZ_ASSERT(aIndex); + MOZ_ASSERT(aRequestType > ParamsUnionType::T__None && + aRequestType <= ParamsUnionType::T__Last); +} + +IndexedDBIndexRequestChild::~IndexedDBIndexRequestChild() +{ + MOZ_COUNT_DTOR(IndexedDBIndexRequestChild); +} + +bool +IndexedDBIndexRequestChild::Recv__delete__(const ResponseValue& aResponse) +{ + switch (aResponse.type()) { + case ResponseValue::Tnsresult: + break; + case ResponseValue::TGetResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetParams); + break; + case ResponseValue::TGetKeyResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetKeyParams); + break; + case ResponseValue::TGetAllResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetAllParams); + break; + case ResponseValue::TGetAllKeysResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TGetAllKeysParams); + break; + case ResponseValue::TCountResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TCountParams); + break; + case ResponseValue::TOpenCursorResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TOpenCursorParams || + mRequestType == ParamsUnionType::TOpenKeyCursorParams); + break; + + default: + MOZ_CRASH("Received invalid response parameters!"); + } + + nsresult rv = mHelper->OnParentProcessRequestComplete(aResponse); + NS_ENSURE_SUCCESS(rv, false); + + return true; +} + +/******************************************************************************* + * IndexedDBCursorRequestChild + ******************************************************************************/ + +IndexedDBCursorRequestChild::IndexedDBCursorRequestChild( + AsyncConnectionHelper* aHelper, + IDBCursor* aCursor, + RequestType aRequestType) +: IndexedDBRequestChildBase(aHelper), mCursor(aCursor), + mRequestType(aRequestType) +{ + MOZ_COUNT_CTOR(IndexedDBCursorRequestChild); + MOZ_ASSERT(aHelper); + MOZ_ASSERT(aCursor); + MOZ_ASSERT(aRequestType > ParamsUnionType::T__None && + aRequestType <= ParamsUnionType::T__Last); +} + +IndexedDBCursorRequestChild::~IndexedDBCursorRequestChild() +{ + MOZ_COUNT_DTOR(IndexedDBCursorRequestChild); +} + +bool +IndexedDBCursorRequestChild::Recv__delete__(const ResponseValue& aResponse) +{ + switch (aResponse.type()) { + case ResponseValue::Tnsresult: + break; + case ResponseValue::TContinueResponse: + MOZ_ASSERT(mRequestType == ParamsUnionType::TContinueParams); + break; + + default: + MOZ_CRASH("Received invalid response parameters!"); + } + + nsresult rv = mHelper->OnParentProcessRequestComplete(aResponse); + NS_ENSURE_SUCCESS(rv, false); + + return true; +} + +/******************************************************************************* + * IndexedDBDeleteDatabaseRequestChild + ******************************************************************************/ + +IndexedDBDeleteDatabaseRequestChild::IndexedDBDeleteDatabaseRequestChild( + IDBFactory* aFactory, + IDBOpenDBRequest* aOpenRequest, + const nsACString& aDatabaseId) +: mFactory(aFactory), mOpenRequest(aOpenRequest), mDatabaseId(aDatabaseId) +{ + MOZ_COUNT_CTOR(IndexedDBDeleteDatabaseRequestChild); + MOZ_ASSERT(aFactory); + MOZ_ASSERT(aOpenRequest); + MOZ_ASSERT(!aDatabaseId.IsEmpty()); +} + +IndexedDBDeleteDatabaseRequestChild::~IndexedDBDeleteDatabaseRequestChild() +{ + MOZ_COUNT_DTOR(IndexedDBDeleteDatabaseRequestChild); +} + +bool +IndexedDBDeleteDatabaseRequestChild::Recv__delete__(const nsresult& aRv) +{ + nsRefPtr helper = + new IPCDeleteDatabaseHelper(mOpenRequest); + + if (NS_SUCCEEDED(aRv)) { + DatabaseInfo::Remove(mDatabaseId); + } + else { + helper->SetError(aRv); + } + + ImmediateRunEventTarget target; + if (NS_FAILED(helper->Dispatch(&target))) { + NS_WARNING("Dispatch of IPCSetVersionHelper failed!"); + return false; + } + + return true; +} + +bool +IndexedDBDeleteDatabaseRequestChild::RecvBlocked( + const uint64_t& aCurrentVersion) +{ + MOZ_ASSERT(mOpenRequest); + + nsCOMPtr runnable = + IDBVersionChangeEvent::CreateBlockedRunnable(mOpenRequest, + aCurrentVersion, 0); + + ImmediateRunEventTarget target; + if (NS_FAILED(target.Dispatch(runnable, NS_DISPATCH_NORMAL))) { + NS_WARNING("Dispatch of blocked event failed!"); + } + + return true; +} + +/******************************************************************************* + * Helpers + ******************************************************************************/ + +nsresult +IPCOpenDatabaseHelper::UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) +{ + NS_NOTREACHED("Should never get here!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; +} + +AsyncConnectionHelper::ChildProcessSendResult +IPCOpenDatabaseHelper::SendResponseToChildProcess(nsresult aResultCode) +{ + MOZ_CRASH("Don't call me!"); +} + +nsresult +IPCOpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) +{ + MOZ_CRASH("Don't call me!"); +} + +nsresult +IPCOpenDatabaseHelper::GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) +{ + return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, mDatabase), + aVal); +} + +nsresult +IPCSetVersionHelper::UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) +{ + NS_NOTREACHED("Should never get here!"); + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; +} + +AsyncConnectionHelper::ChildProcessSendResult +IPCSetVersionHelper::SendResponseToChildProcess(nsresult aResultCode) +{ + MOZ_CRASH("Don't call me!"); +} + +nsresult +IPCSetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection) +{ + MOZ_CRASH("Don't call me!"); +} + +already_AddRefed +IPCSetVersionHelper::CreateSuccessEvent(mozilla::dom::EventTarget* aOwner) +{ + return IDBVersionChangeEvent::CreateUpgradeNeeded(aOwner, + mOldVersion, + mRequestedVersion); +} + +nsresult +IPCSetVersionHelper::GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) +{ + mOpenRequest->SetTransaction(mTransaction); + + return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, mDatabase), + aVal); +} + +nsresult +IPCDeleteDatabaseHelper::UnpackResponseFromParentProcess( + const ResponseValue& aResponseValue) +{ + MOZ_CRASH("Don't call me!"); +} + +AsyncConnectionHelper::ChildProcessSendResult +IPCDeleteDatabaseHelper::SendResponseToChildProcess(nsresult aResultCode) +{ + MOZ_CRASH("Don't call me!"); +} + +nsresult +IPCDeleteDatabaseHelper::GetSuccessResult(JSContext* aCx, JS::MutableHandle aVal) +{ + aVal.setUndefined(); + return NS_OK; +} + +nsresult +IPCDeleteDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection) +{ + MOZ_CRASH("Don't call me!"); +}