diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/indexeddb/server/IDBServer.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/server/IDBServer.cpp')
-rw-r--r-- | Source/WebCore/Modules/indexeddb/server/IDBServer.cpp | 682 |
1 files changed, 682 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp b/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp new file mode 100644 index 000000000..87476438c --- /dev/null +++ b/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp @@ -0,0 +1,682 @@ +/* + * Copyright (C) 2015 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "IDBServer.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBRequestData.h" +#include "IDBResultData.h" +#include "Logging.h" +#include "MemoryIDBBackingStore.h" +#include "SQLiteFileSystem.h" +#include "SQLiteIDBBackingStore.h" +#include "SecurityOrigin.h" +#include <wtf/CrossThreadCopier.h> +#include <wtf/Locker.h> +#include <wtf/MainThread.h> + +namespace WebCore { +namespace IDBServer { + +Ref<IDBServer> IDBServer::create(IDBBackingStoreTemporaryFileHandler& fileHandler) +{ + return adoptRef(*new IDBServer(fileHandler)); +} + +Ref<IDBServer> IDBServer::create(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler) +{ + return adoptRef(*new IDBServer(databaseDirectoryPath, fileHandler)); +} + +IDBServer::IDBServer(IDBBackingStoreTemporaryFileHandler& fileHandler) + : m_backingStoreTemporaryFileHandler(fileHandler) +{ + Locker<Lock> locker(m_databaseThreadCreationLock); + m_threadID = createThread(IDBServer::databaseThreadEntry, this, "IndexedDatabase Server"); +} + +IDBServer::IDBServer(const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler& fileHandler) + : m_databaseDirectoryPath(databaseDirectoryPath) + , m_backingStoreTemporaryFileHandler(fileHandler) +{ + LOG(IndexedDB, "IDBServer created at path %s", databaseDirectoryPath.utf8().data()); + + Locker<Lock> locker(m_databaseThreadCreationLock); + m_threadID = createThread(IDBServer::databaseThreadEntry, this, "IndexedDatabase Server"); +} + +void IDBServer::registerConnection(IDBConnectionToClient& connection) +{ + ASSERT(!m_connectionMap.contains(connection.identifier())); + m_connectionMap.set(connection.identifier(), &connection); +} + +void IDBServer::unregisterConnection(IDBConnectionToClient& connection) +{ + ASSERT(m_connectionMap.contains(connection.identifier())); + ASSERT(m_connectionMap.get(connection.identifier()) == &connection); + + connection.connectionToClientClosed(); + + m_connectionMap.remove(connection.identifier()); +} + +void IDBServer::registerTransaction(UniqueIDBDatabaseTransaction& transaction) +{ + ASSERT(!m_transactions.contains(transaction.info().identifier())); + m_transactions.set(transaction.info().identifier(), &transaction); +} + +void IDBServer::unregisterTransaction(UniqueIDBDatabaseTransaction& transaction) +{ + ASSERT(m_transactions.contains(transaction.info().identifier())); + ASSERT(m_transactions.get(transaction.info().identifier()) == &transaction); + + m_transactions.remove(transaction.info().identifier()); +} + +void IDBServer::registerDatabaseConnection(UniqueIDBDatabaseConnection& connection) +{ + ASSERT(!m_databaseConnections.contains(connection.identifier())); + m_databaseConnections.set(connection.identifier(), &connection); +} + +void IDBServer::unregisterDatabaseConnection(UniqueIDBDatabaseConnection& connection) +{ + ASSERT(m_databaseConnections.contains(connection.identifier())); + m_databaseConnections.remove(connection.identifier()); +} + +UniqueIDBDatabase& IDBServer::getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier& identifier) +{ + ASSERT(isMainThread()); + + auto uniqueIDBDatabase = m_uniqueIDBDatabaseMap.add(identifier, nullptr); + if (uniqueIDBDatabase.isNewEntry) + uniqueIDBDatabase.iterator->value = UniqueIDBDatabase::create(*this, identifier); + + return *uniqueIDBDatabase.iterator->value; +} + +std::unique_ptr<IDBBackingStore> IDBServer::createBackingStore(const IDBDatabaseIdentifier& identifier) +{ + ASSERT(!isMainThread()); + + if (m_databaseDirectoryPath.isEmpty()) + return MemoryIDBBackingStore::create(identifier); + + return std::make_unique<SQLiteIDBBackingStore>(identifier, m_databaseDirectoryPath, m_backingStoreTemporaryFileHandler); +} + +void IDBServer::openDatabase(const IDBRequestData& requestData) +{ + LOG(IndexedDB, "IDBServer::openDatabase"); + + auto& uniqueIDBDatabase = getOrCreateUniqueIDBDatabase(requestData.databaseIdentifier()); + + auto connection = m_connectionMap.get(requestData.requestIdentifier().connectionIdentifier()); + if (!connection) { + // If the connection back to the client is gone, there's no way to open the database as + // well as no way to message back failure. + return; + } + + uniqueIDBDatabase.openDatabaseConnection(*connection, requestData); +} + +void IDBServer::deleteDatabase(const IDBRequestData& requestData) +{ + LOG(IndexedDB, "IDBServer::deleteDatabase - %s", requestData.databaseIdentifier().debugString().utf8().data()); + ASSERT(isMainThread()); + + auto connection = m_connectionMap.get(requestData.requestIdentifier().connectionIdentifier()); + if (!connection) { + // If the connection back to the client is gone, there's no way to delete the database as + // well as no way to message back failure. + return; + } + + auto* database = m_uniqueIDBDatabaseMap.get(requestData.databaseIdentifier()); + if (!database) + database = &getOrCreateUniqueIDBDatabase(requestData.databaseIdentifier()); + + database->handleDelete(*connection, requestData); +} + +void IDBServer::closeUniqueIDBDatabase(UniqueIDBDatabase& database) +{ + LOG(IndexedDB, "IDBServer::closeUniqueIDBDatabase"); + ASSERT(isMainThread()); + + m_uniqueIDBDatabaseMap.remove(database.identifier()); +} + +void IDBServer::abortTransaction(const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBServer::abortTransaction"); + + auto transaction = m_transactions.get(transactionIdentifier); + if (!transaction) { + // If there is no transaction there is nothing to abort. + // We also have no access to a connection over which to message failure-to-abort. + return; + } + + transaction->abort(); +} + +void IDBServer::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info) +{ + LOG(IndexedDB, "IDBServer::createObjectStore"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->createObjectStore(requestData, info); +} + +void IDBServer::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName) +{ + LOG(IndexedDB, "IDBServer::deleteObjectStore"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->deleteObjectStore(requestData, objectStoreName); +} + +void IDBServer::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName) +{ + LOG(IndexedDB, "IDBServer::renameObjectStore"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->renameObjectStore(requestData, objectStoreIdentifier, newName); +} + +void IDBServer::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier) +{ + LOG(IndexedDB, "IDBServer::clearObjectStore"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->clearObjectStore(requestData, objectStoreIdentifier); +} + +void IDBServer::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info) +{ + LOG(IndexedDB, "IDBServer::createIndex"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->createIndex(requestData, info); +} + +void IDBServer::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName) +{ + LOG(IndexedDB, "IDBServer::deleteIndex"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->deleteIndex(requestData, objectStoreIdentifier, indexName); +} + +void IDBServer::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName) +{ + LOG(IndexedDB, "IDBServer::renameIndex"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + ASSERT(transaction->isVersionChange()); + transaction->renameIndex(requestData, objectStoreIdentifier, indexIdentifier, newName); +} + +void IDBServer::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode) +{ + LOG(IndexedDB, "IDBServer::putOrAdd"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->putOrAdd(requestData, keyData, value, overwriteMode); +} + +void IDBServer::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData) +{ + LOG(IndexedDB, "IDBServer::getRecord"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->getRecord(requestData, getRecordData); +} + +void IDBServer::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData) +{ + LOG(IndexedDB, "IDBServer::getAllRecords"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->getAllRecords(requestData, getAllRecordsData); +} + +void IDBServer::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) +{ + LOG(IndexedDB, "IDBServer::getCount"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->getCount(requestData, keyRangeData); +} + +void IDBServer::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData) +{ + LOG(IndexedDB, "IDBServer::deleteRecord"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->deleteRecord(requestData, keyRangeData); +} + +void IDBServer::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info) +{ + LOG(IndexedDB, "IDBServer::openCursor"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->openCursor(requestData, info); +} + +void IDBServer::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data) +{ + LOG(IndexedDB, "IDBServer::iterateCursor"); + + auto transaction = m_transactions.get(requestData.transactionIdentifier()); + if (!transaction) + return; + + transaction->iterateCursor(requestData, data); +} + +void IDBServer::establishTransaction(uint64_t databaseConnectionIdentifier, const IDBTransactionInfo& info) +{ + LOG(IndexedDB, "IDBServer::establishTransaction"); + + auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier); + if (!databaseConnection) + return; + + databaseConnection->establishTransaction(info); +} + +void IDBServer::commitTransaction(const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBServer::commitTransaction"); + + auto transaction = m_transactions.get(transactionIdentifier); + if (!transaction) { + // If there is no transaction there is nothing to commit. + // We also have no access to a connection over which to message failure-to-commit. + return; + } + + transaction->commit(); +} + +void IDBServer::didFinishHandlingVersionChangeTransaction(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBServer::didFinishHandlingVersionChangeTransaction - %s", transactionIdentifier.loggingString().utf8().data()); + + auto* connection = m_databaseConnections.get(databaseConnectionIdentifier); + if (!connection) + return; + + connection->didFinishHandlingVersionChange(transactionIdentifier); +} + +void IDBServer::databaseConnectionPendingClose(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBServer::databaseConnectionPendingClose - %" PRIu64, databaseConnectionIdentifier); + + auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier); + if (!databaseConnection) + return; + + databaseConnection->connectionPendingCloseFromClient(); +} + +void IDBServer::databaseConnectionClosed(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBServer::databaseConnectionClosed - %" PRIu64, databaseConnectionIdentifier); + + auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier); + if (!databaseConnection) + return; + + databaseConnection->connectionClosedFromClient(); +} + +void IDBServer::abortOpenAndUpgradeNeeded(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& transactionIdentifier) +{ + LOG(IndexedDB, "IDBServer::abortOpenAndUpgradeNeeded"); + + auto transaction = m_transactions.get(transactionIdentifier); + if (transaction) + transaction->abortWithoutCallback(); + + auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier); + if (!databaseConnection) + return; + + databaseConnection->connectionClosedFromClient(); +} + +void IDBServer::didFireVersionChangeEvent(uint64_t databaseConnectionIdentifier, const IDBResourceIdentifier& requestIdentifier) +{ + LOG(IndexedDB, "IDBServer::didFireVersionChangeEvent"); + + if (auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier)) + databaseConnection->didFireVersionChangeEvent(requestIdentifier); +} + +void IDBServer::openDBRequestCancelled(const IDBRequestData& requestData) +{ + LOG(IndexedDB, "IDBServer::openDBRequestCancelled"); + ASSERT(isMainThread()); + + auto* uniqueIDBDatabase = m_uniqueIDBDatabaseMap.get(requestData.databaseIdentifier()); + if (!uniqueIDBDatabase) + return; + + uniqueIDBDatabase->openDBRequestCancelled(requestData.requestIdentifier()); +} + +void IDBServer::confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) +{ + LOG(IndexedDB, "IDBServer::confirmDidCloseFromServer"); + + if (auto databaseConnection = m_databaseConnections.get(databaseConnectionIdentifier)) + databaseConnection->confirmDidCloseFromServer(); +} + +void IDBServer::getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) +{ + postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performGetAllDatabaseNames, serverConnectionIdentifier, mainFrameOrigin, openingOrigin, callbackID)); +} + +void IDBServer::performGetAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) +{ + String directory = IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(mainFrameOrigin, openingOrigin, m_databaseDirectoryPath); + + Vector<String> entries = listDirectory(directory, ASCIILiteral("*")); + Vector<String> databases; + databases.reserveInitialCapacity(entries.size()); + for (auto& entry : entries) { + String encodedName = lastComponentOfPathIgnoringTrailingSlash(entry); + databases.uncheckedAppend(SQLiteIDBBackingStore::databaseNameFromEncodedFilename(encodedName)); + } + + postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didGetAllDatabaseNames, serverConnectionIdentifier, callbackID, databases)); +} + +void IDBServer::didGetAllDatabaseNames(uint64_t serverConnectionIdentifier, uint64_t callbackID, const Vector<String>& databaseNames) +{ + auto connection = m_connectionMap.get(serverConnectionIdentifier); + if (!connection) + return; + + connection->didGetAllDatabaseNames(callbackID, databaseNames); +} + +void IDBServer::postDatabaseTask(CrossThreadTask&& task) +{ + m_databaseQueue.append(WTFMove(task)); +} + +void IDBServer::postDatabaseTaskReply(CrossThreadTask&& task) +{ + ASSERT(!isMainThread()); + m_databaseReplyQueue.append(WTFMove(task)); + + + Locker<Lock> locker(m_mainThreadReplyLock); + if (m_mainThreadReplyScheduled) + return; + + m_mainThreadReplyScheduled = true; + callOnMainThread([this] { + handleTaskRepliesOnMainThread(); + }); +} + +void IDBServer::databaseThreadEntry(void* threadData) +{ + ASSERT(threadData); + IDBServer* server = reinterpret_cast<IDBServer*>(threadData); + server->databaseRunLoop(); +} + +void IDBServer::databaseRunLoop() +{ + ASSERT(!isMainThread()); + { + Locker<Lock> locker(m_databaseThreadCreationLock); + } + + while (!m_databaseQueue.isKilled()) + m_databaseQueue.waitForMessage().performTask(); +} + +void IDBServer::handleTaskRepliesOnMainThread() +{ + { + Locker<Lock> locker(m_mainThreadReplyLock); + m_mainThreadReplyScheduled = false; + } + + while (auto task = m_databaseReplyQueue.tryGetMessage()) + task->performTask(); +} + +static uint64_t generateDeleteCallbackID() +{ + ASSERT(isMainThread()); + static uint64_t currentID = 0; + return ++currentID; +} + +void IDBServer::closeAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point modificationTime, std::function<void ()> completionHandler) +{ + uint64_t callbackID = generateDeleteCallbackID(); + auto addResult = m_deleteDatabaseCompletionHandlers.add(callbackID, WTFMove(completionHandler)); + ASSERT_UNUSED(addResult, addResult.isNewEntry); + + // If the modification time is in the future, don't both doing anything. + if (modificationTime > std::chrono::system_clock::now()) { + postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID)); + return; + } + + HashSet<RefPtr<UniqueIDBDatabase>> openDatabases; + for (auto* connection : m_databaseConnections.values()) + openDatabases.add(&connection->database()); + + for (auto& database : openDatabases) + database->immediateCloseForUserDelete(); + + postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performCloseAndDeleteDatabasesModifiedSince, modificationTime, callbackID)); +} + +void IDBServer::closeAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>& origins, std::function<void ()> completionHandler) +{ + uint64_t callbackID = generateDeleteCallbackID(); + auto addResult = m_deleteDatabaseCompletionHandlers.add(callbackID, WTFMove(completionHandler)); + ASSERT_UNUSED(addResult, addResult.isNewEntry); + + HashSet<RefPtr<UniqueIDBDatabase>> openDatabases; + for (auto* connection : m_databaseConnections.values()) { + const auto& identifier = connection->database().identifier(); + for (auto& origin : origins) { + if (identifier.isRelatedToOrigin(origin)) { + openDatabases.add(&connection->database()); + break; + } + } + } + + for (auto& database : openDatabases) + database->immediateCloseForUserDelete(); + + postDatabaseTask(createCrossThreadTask(*this, &IDBServer::performCloseAndDeleteDatabasesForOrigins, origins, callbackID)); +} + +static void removeAllDatabasesForOriginPath(const String& originPath, std::chrono::system_clock::time_point modifiedSince) +{ + Vector<String> databasePaths = listDirectory(originPath, "*"); + + for (auto& databasePath : databasePaths) { + String databaseFile = pathByAppendingComponent(databasePath, "IndexedDB.sqlite3"); + + if (modifiedSince > std::chrono::system_clock::time_point::min() && fileExists(databaseFile)) { + time_t modificationTime; + if (!getFileModificationTime(databaseFile, modificationTime)) + continue; + + if (std::chrono::system_clock::from_time_t(modificationTime) < modifiedSince) + continue; + } + + // Deleting this database means we need to delete all files that represent it. + // This includes: + // - The directory itself, which is named after the database. + // - IndexedDB.sqlite3 and related SQLite files. + // - Blob files that we stored in the directory. + // + // To be conservative, we should *not* try to delete files that are unexpected; + // We should only delete files we think we put there. + // + // IndexedDB blob files are named "N.blob" where N is a decimal integer, + // so those are the only blob files we should be trying to delete. + for (auto& blobPath : listDirectory(databasePath, "[0-9]*.blob")) { + // Globbing can't give us only filenames starting with 1-or-more digits. + // The above globbing gives us files that start with a digit and ends with ".blob", but there might be non-digits in between. + // We need to validate that each filename contains only digits before deleting it, as any other files are not ones we put there. + String filename = pathGetFileName(blobPath); + auto filenameLength = filename.length(); + + ASSERT(filenameLength >= 6); + ASSERT(filename.endsWith(".blob")); + + if (filename.length() < 6) + continue; + if (!filename.endsWith(".blob")) + continue; + + bool validFilename = true; + for (unsigned i = 0; i < filenameLength - 5; ++i) { + if (!isASCIIDigit(filename[i])) { + validFilename = false; + break; + } + } + + if (validFilename) + deleteFile(blobPath); + } + + // Now delete IndexedDB.sqlite3 and related SQLite files. + SQLiteFileSystem::deleteDatabaseFile(databaseFile); + + // And finally, if we can, delete the empty directory. + deleteEmptyDirectory(databasePath); + } + + // If no databases remain for this origin, we can delete the origin directory as well. + deleteEmptyDirectory(originPath); +} + +void IDBServer::performCloseAndDeleteDatabasesModifiedSince(std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID) +{ + if (!m_databaseDirectoryPath.isEmpty()) { + Vector<String> originPaths = listDirectory(m_databaseDirectoryPath, "*"); + for (auto& originPath : originPaths) + removeAllDatabasesForOriginPath(originPath, modifiedSince); + } + + postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID)); +} + +void IDBServer::performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>& origins, uint64_t callbackID) +{ + if (!m_databaseDirectoryPath.isEmpty()) { + for (const auto& origin : origins) { + String originPath = pathByAppendingComponent(m_databaseDirectoryPath, origin.databaseIdentifier()); + removeAllDatabasesForOriginPath(originPath, std::chrono::system_clock::time_point::min()); + } + } + + postDatabaseTaskReply(createCrossThreadTask(*this, &IDBServer::didPerformCloseAndDeleteDatabases, callbackID)); +} + +void IDBServer::didPerformCloseAndDeleteDatabases(uint64_t callbackID) +{ + auto callback = m_deleteDatabaseCompletionHandlers.take(callbackID); + ASSERT(callback); + callback(); +} + +} // namespace IDBServer +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) |