RefPtr<IDBOpenDBRequest> IDBFactory::openInternal(ScriptExecutionContext* context, const String& name, unsigned long long version, ExceptionCode& ec) { if (name.isNull()) { ec = TypeError; return nullptr; } if (shouldThrowSecurityException(context)) { ec = SECURITY_ERR; return nullptr; } ASSERT(context->securityOrigin()); ASSERT(context->topOrigin()); IDBDatabaseIdentifier databaseIdentifier(name, *context->securityOrigin(), *context->topOrigin()); if (!databaseIdentifier.isValid()) { ec = TypeError; return nullptr; } auto request = IDBOpenDBRequest::createOpenRequest(m_connectionToServer.get(), context, databaseIdentifier, version); m_connectionToServer->openDatabase(request.get()); return adoptRef(&request.leakRef()); }
RefPtr<WebCore::IDBOpenDBRequest> IDBFactory::deleteDatabase(ScriptExecutionContext* context, const String& name, ExceptionCode& ec) { LOG(IndexedDB, "IDBFactory::deleteDatabase"); if (name.isNull()) { ec = TypeError; return nullptr; } if (shouldThrowSecurityException(context)) { ec = SECURITY_ERR; return nullptr; } ASSERT(context->securityOrigin()); ASSERT(context->topOrigin()); IDBDatabaseIdentifier databaseIdentifier(name, *context->securityOrigin(), *context->topOrigin()); if (!databaseIdentifier.isValid()) { ec = TypeError; return nullptr; } auto request = IDBOpenDBRequest::createDeleteRequest(m_connectionToServer.get(), context, databaseIdentifier); m_connectionToServer->deleteDatabase(request.get()); return adoptRef(&request.leakRef()); }
void UniqueIDBDatabase::handleOpenDatabaseOperations() { ASSERT(isMainThread()); LOG(IndexedDB, "(main) UniqueIDBDatabase::handleOpenDatabaseOperations"); // If a version change transaction is currently in progress, no new connections can be opened right now. // We will try again later. if (m_versionChangeDatabaseConnection) return; auto operation = m_pendingOpenDatabaseOperations.takeFirst(); // 3.3.1 Opening a database // If requested version is undefined, then let requested version be 1 if db was created in the previous step, // or the current version of db otherwise. uint64_t requestedVersion = operation->requestData().requestedVersion(); if (!requestedVersion) requestedVersion = m_databaseInfo->version() ? m_databaseInfo->version() : 1; // 3.3.1 Opening a database // If the database version higher than the requested version, abort these steps and return a VersionError. if (requestedVersion < m_databaseInfo->version()) { auto result = IDBResultData::error(operation->requestData().requestIdentifier(), IDBError(IDBExceptionCode::VersionError)); operation->connection().didOpenDatabase(result); return; } Ref<UniqueIDBDatabaseConnection> connection = UniqueIDBDatabaseConnection::create(*this, operation->connection()); UniqueIDBDatabaseConnection* rawConnection = &connection.get(); m_server.registerDatabaseConnection(*rawConnection); if (requestedVersion == m_databaseInfo->version()) { addOpenDatabaseConnection(WTF::move(connection)); auto result = IDBResultData::openDatabaseSuccess(operation->requestData().requestIdentifier(), *rawConnection); operation->connection().didOpenDatabase(result); return; } ASSERT(!m_versionChangeOperation); ASSERT(!m_versionChangeDatabaseConnection); m_versionChangeOperation = adoptRef(operation.leakRef()); m_versionChangeDatabaseConnection = rawConnection; // 3.3.7 "versionchange" transaction steps // If there's no other open connections to this database, the version change process can begin immediately. if (!hasAnyOpenConnections()) { startVersionChangeTransaction(); return; } // Otherwise we have to notify all those open connections and wait for them to close. notifyConnectionsOfVersionChange(); }
RefPtr<WebCore::IDBTransaction> IDBDatabase::transaction(const Vector<String>& objectStores, const String& modeString, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBDatabase::transaction"); ASSERT(currentThread() == originThreadID()); if (m_closePending) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing."); return nullptr; } if (objectStores.isEmpty()) { ec.code = IDBDatabaseException::InvalidAccessError; ec.message = ASCIILiteral("Failed to execute 'transaction' on 'IDBDatabase': The storeNames parameter was empty."); return nullptr; } IndexedDB::TransactionMode mode = IDBTransaction::stringToMode(modeString, ec.code); if (ec.code) { ec.message = makeString(ASCIILiteral("Failed to execute 'transaction' on 'IDBDatabase': The mode provided ('"), modeString, ASCIILiteral("') is not one of 'readonly' or 'readwrite'.")); return nullptr; } if (mode != IndexedDB::TransactionMode::ReadOnly && mode != IndexedDB::TransactionMode::ReadWrite) { ec.code = TypeError; return nullptr; } if (m_versionChangeTransaction && !m_versionChangeTransaction->isFinishedOrFinishing()) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running."); return nullptr; } for (auto& objectStoreName : objectStores) { if (m_info.hasObjectStore(objectStoreName)) continue; ec.code = IDBDatabaseException::NotFoundError; ec.message = ASCIILiteral("Failed to execute 'transaction' on 'IDBDatabase': One of the specified object stores was not found."); return nullptr; } auto info = IDBTransactionInfo::clientTransaction(m_connectionProxy.get(), objectStores, mode); auto transaction = IDBTransaction::create(*this, info); LOG(IndexedDB, "IDBDatabase::transaction - Added active transaction %s", info.identifier().loggingString().utf8().data()); m_activeTransactions.set(info.identifier(), &transaction.get()); return adoptRef(&transaction.leakRef()); }
RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCode& ec) { LOG(IndexedDB, "IDBTransaction::objectStore"); if (objectStoreName.isEmpty()) { ec = NOT_FOUND_ERR; return nullptr; } if (isFinishedOrFinishing()) { ec = INVALID_STATE_ERR; return nullptr; } auto iterator = m_referencedObjectStores.find(objectStoreName); if (iterator != m_referencedObjectStores.end()) return iterator->value; bool found = false; for (auto& objectStore : m_info.objectStores()) { if (objectStore == objectStoreName) { found = true; break; } } auto* info = m_database->info().infoForExistingObjectStore(objectStoreName); if (!info) { ec = NOT_FOUND_ERR; return nullptr; } // Version change transactions are scoped to every object store in the database. if (!found && !isVersionChange()) { ec = NOT_FOUND_ERR; return nullptr; } auto objectStore = IDBObjectStore::create(*info, *this); m_referencedObjectStores.set(objectStoreName, &objectStore.get()); return adoptRef(&objectStore.leakRef()); }
RefPtr<WebCore::IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext*, const Vector<String>& objectStores, const String& modeString, ExceptionCode& ec) { LOG(IndexedDB, "IDBDatabase::transaction"); if (m_closePending) { ec = INVALID_STATE_ERR; return nullptr; } if (objectStores.isEmpty()) { ec = INVALID_ACCESS_ERR; return nullptr; } IndexedDB::TransactionMode mode = IDBTransaction::stringToMode(modeString, ec); if (ec) return nullptr; if (mode != IndexedDB::TransactionMode::ReadOnly && mode != IndexedDB::TransactionMode::ReadWrite) { ec = TypeError; return nullptr; } if (m_versionChangeTransaction) { ec = INVALID_STATE_ERR; return nullptr; } for (auto& objectStoreName : objectStores) { if (m_info.hasObjectStore(objectStoreName)) continue; ec = NOT_FOUND_ERR; return nullptr; } auto info = IDBTransactionInfo::clientTransaction(m_serverConnection.get(), objectStores, mode); auto transaction = IDBTransaction::create(*this, info); m_activeTransactions.set(info.identifier(), &transaction.get()); return adoptRef(&transaction.leakRef()); }
RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBTransaction::objectStore"); if (isFinishedOrFinishing()) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The transaction finished."); return nullptr; } auto iterator = m_referencedObjectStores.find(objectStoreName); if (iterator != m_referencedObjectStores.end()) return iterator->value; bool found = false; for (auto& objectStore : m_info.objectStores()) { if (objectStore == objectStoreName) { found = true; break; } } auto* info = m_database->info().infoForExistingObjectStore(objectStoreName); if (!info) { ec.code = IDBDatabaseException::NotFoundError; ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found."); return nullptr; } // Version change transactions are scoped to every object store in the database. if (!info || (!found && !isVersionChange())) { ec.code = IDBDatabaseException::NotFoundError; ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found."); return nullptr; } auto objectStore = IDBObjectStore::create(*info, *this); m_referencedObjectStores.set(objectStoreName, &objectStore.get()); return adoptRef(&objectStore.leakRef()); }