diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/Storage')
7 files changed, 643 insertions, 339 deletions
diff --git a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp index 2595f074b..67ecb8945 100644 --- a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp +++ b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp @@ -27,13 +27,14 @@ #include "LocalStorageDatabase.h" #include "LocalStorageDatabaseTracker.h" -#include "WorkQueue.h" #include <WebCore/FileSystem.h> #include <WebCore/SQLiteStatement.h> #include <WebCore/SQLiteTransaction.h> #include <WebCore/SecurityOrigin.h> #include <WebCore/StorageMap.h> +#include <WebCore/SuddenTermination.h> #include <wtf/PassRefPtr.h> +#include <wtf/WorkQueue.h> #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> @@ -45,16 +46,16 @@ static const int maximumItemsToUpdate = 100; namespace WebKit { -PassRefPtr<LocalStorageDatabase> LocalStorageDatabase::create(PassRefPtr<WorkQueue> queue, PassRefPtr<LocalStorageDatabaseTracker> tracker, PassRefPtr<SecurityOrigin> securityOrigin) +Ref<LocalStorageDatabase> LocalStorageDatabase::create(Ref<WorkQueue>&& queue, Ref<LocalStorageDatabaseTracker>&& tracker, const SecurityOriginData& securityOrigin) { - return adoptRef(new LocalStorageDatabase(queue, tracker, securityOrigin)); + return adoptRef(*new LocalStorageDatabase(WTFMove(queue), WTFMove(tracker), securityOrigin)); } -LocalStorageDatabase::LocalStorageDatabase(PassRefPtr<WorkQueue> queue, PassRefPtr<LocalStorageDatabaseTracker> tracker, PassRefPtr<SecurityOrigin> securityOrigin) - : m_queue(queue) - , m_tracker(tracker) +LocalStorageDatabase::LocalStorageDatabase(Ref<WorkQueue>&& queue, Ref<LocalStorageDatabaseTracker>&& tracker, const SecurityOriginData& securityOrigin) + : m_queue(WTFMove(queue)) + , m_tracker(WTFMove(tracker)) , m_securityOrigin(securityOrigin) - , m_databasePath(m_tracker->databasePath(m_securityOrigin.get())) + , m_databasePath(m_tracker->databasePath(m_securityOrigin)) , m_failedToOpenDatabase(false) , m_didImportItems(false) , m_isClosed(false) @@ -79,7 +80,7 @@ void LocalStorageDatabase::openDatabase(DatabaseOpeningStrategy openingStrategy) } if (m_database.isOpen()) - m_tracker->didOpenDatabaseWithOrigin(m_securityOrigin.get()); + m_tracker->didOpenDatabaseWithOrigin(m_securityOrigin); } bool LocalStorageDatabase::tryToOpenDatabase(DatabaseOpeningStrategy openingStrategy) @@ -171,7 +172,7 @@ void LocalStorageDatabase::importItems(StorageMap& storageMap) return; SQLiteStatement query(m_database, "SELECT key, value FROM ItemTable"); - if (query.prepare() != SQLResultOk) { + if (query.prepare() != SQLITE_OK) { LOG_ERROR("Unable to select items from ItemTable for local storage"); return; } @@ -179,12 +180,15 @@ void LocalStorageDatabase::importItems(StorageMap& storageMap) HashMap<String, String> items; int result = query.step(); - while (result == SQLResultRow) { - items.set(query.getColumnText(0), query.getColumnBlobAsString(1)); + while (result == SQLITE_ROW) { + String key = query.getColumnText(0); + String value = query.getColumnBlobAsString(1); + if (!key.isNull() && !value.isNull()) + items.set(key, value); result = query.step(); } - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("Error reading items from ItemTable for local storage"); return; } @@ -226,7 +230,7 @@ void LocalStorageDatabase::close() m_database.close(); if (isEmpty) - m_tracker->deleteDatabaseWithOrigin(m_securityOrigin.get()); + m_tracker->deleteDatabaseWithOrigin(m_securityOrigin); } void LocalStorageDatabase::itemDidChange(const String& key, const String& value) @@ -240,8 +244,15 @@ void LocalStorageDatabase::scheduleDatabaseUpdate() if (m_didScheduleDatabaseUpdate) return; + if (!m_disableSuddenTerminationWhileWritingToLocalStorage) + m_disableSuddenTerminationWhileWritingToLocalStorage = std::make_unique<SuddenTerminationDisabler>(); + m_didScheduleDatabaseUpdate = true; - m_queue->dispatchAfter(databaseUpdateInterval, bind(&LocalStorageDatabase::updateDatabase, this)); + + RefPtr<LocalStorageDatabase> localStorageDatabase(this); + m_queue->dispatchAfter(databaseUpdateInterval, [localStorageDatabase] { + localStorageDatabase->updateDatabase(); + }); } void LocalStorageDatabase::updateDatabase() @@ -256,6 +267,8 @@ void LocalStorageDatabase::updateDatabase() if (m_changedItems.size() <= maximumItemsToUpdate) { // There are few enough changed items that we can just always write all of them. m_changedItems.swap(changedItems); + updateDatabaseWithChangedItems(changedItems); + m_disableSuddenTerminationWhileWritingToLocalStorage = nullptr; } else { for (int i = 0; i < maximumItemsToUpdate; ++i) { auto it = m_changedItems.begin(); @@ -268,9 +281,8 @@ void LocalStorageDatabase::updateDatabase() // Reschedule the update for the remaining items. scheduleDatabaseUpdate(); + updateDatabaseWithChangedItems(changedItems); } - - updateDatabaseWithChangedItems(changedItems); } void LocalStorageDatabase::updateDatabaseWithChangedItems(const HashMap<String, String>& changedItems) @@ -284,26 +296,26 @@ void LocalStorageDatabase::updateDatabaseWithChangedItems(const HashMap<String, m_shouldClearItems = false; SQLiteStatement clearStatement(m_database, "DELETE FROM ItemTable"); - if (clearStatement.prepare() != SQLResultOk) { + if (clearStatement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database"); return; } int result = clearStatement.step(); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("Failed to clear all items in the local storage database - %i", result); return; } } SQLiteStatement insertStatement(m_database, "INSERT INTO ItemTable VALUES (?, ?)"); - if (insertStatement.prepare() != SQLResultOk) { + if (insertStatement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database"); return; } SQLiteStatement deleteStatement(m_database, "DELETE FROM ItemTable WHERE key=?"); - if (deleteStatement.prepare() != SQLResultOk) { + if (deleteStatement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database"); return; } @@ -322,7 +334,7 @@ void LocalStorageDatabase::updateDatabaseWithChangedItems(const HashMap<String, statement.bindBlob(2, it->value); int result = statement.step(); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("Failed to update item in the local storage database - %i", result); break; } @@ -339,13 +351,13 @@ bool LocalStorageDatabase::databaseIsEmpty() return false; SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable"); - if (query.prepare() != SQLResultOk) { + if (query.prepare() != SQLITE_OK) { LOG_ERROR("Unable to count number of rows in ItemTable for local storage"); return false; } int result = query.step(); - if (result != SQLResultRow) { + if (result != SQLITE_ROW) { LOG_ERROR("No results when counting number of rows in ItemTable for local storage"); return false; } diff --git a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h index 1acd6b253..9992031f4 100644 --- a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h +++ b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h @@ -23,20 +23,20 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef LocalStorageDatabase_h -#define LocalStorageDatabase_h +#pragma once #include <WebCore/SQLiteDatabase.h> +#include <WebCore/SecurityOriginData.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/RefPtr.h> #include <wtf/ThreadSafeRefCounted.h> - -class WorkQueue; +#include <wtf/WorkQueue.h> namespace WebCore { class SecurityOrigin; class StorageMap; +class SuddenTerminationDisabler; } namespace WebKit { @@ -45,7 +45,7 @@ class LocalStorageDatabaseTracker; class LocalStorageDatabase : public ThreadSafeRefCounted<LocalStorageDatabase> { public: - static PassRefPtr<LocalStorageDatabase> create(PassRefPtr<WorkQueue>, PassRefPtr<LocalStorageDatabaseTracker>, PassRefPtr<WebCore::SecurityOrigin>); + static Ref<LocalStorageDatabase> create(Ref<WorkQueue>&&, Ref<LocalStorageDatabaseTracker>&&, const WebCore::SecurityOriginData&); ~LocalStorageDatabase(); // Will block until the import is complete. @@ -59,7 +59,7 @@ public: void close(); private: - LocalStorageDatabase(PassRefPtr<WorkQueue>, PassRefPtr<LocalStorageDatabaseTracker>, PassRefPtr<WebCore::SecurityOrigin>); + LocalStorageDatabase(Ref<WorkQueue>&&, Ref<LocalStorageDatabaseTracker>&&, const WebCore::SecurityOriginData&); enum DatabaseOpeningStrategy { CreateIfNonExistent, @@ -78,9 +78,9 @@ private: bool databaseIsEmpty(); - RefPtr<WorkQueue> m_queue; - RefPtr<LocalStorageDatabaseTracker> m_tracker; - RefPtr<WebCore::SecurityOrigin> m_securityOrigin; + Ref<WorkQueue> m_queue; + Ref<LocalStorageDatabaseTracker> m_tracker; + WebCore::SecurityOriginData m_securityOrigin; String m_databasePath; WebCore::SQLiteDatabase m_database; @@ -91,9 +91,9 @@ private: bool m_didScheduleDatabaseUpdate; bool m_shouldClearItems; HashMap<String, String> m_changedItems; + + std::unique_ptr<WebCore::SuddenTerminationDisabler> m_disableSuddenTerminationWhileWritingToLocalStorage; }; } // namespace WebKit - -#endif // LocalStorageDatabase_h diff --git a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.cpp b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.cpp index d0f771e7c..3e86b05ca 100644 --- a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.cpp +++ b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.cpp @@ -26,53 +26,56 @@ #include "config.h" #include "LocalStorageDatabaseTracker.h" -#include "WorkQueue.h" #include <WebCore/FileSystem.h> +#include <WebCore/SQLiteFileSystem.h> #include <WebCore/SQLiteStatement.h> #include <WebCore/SecurityOrigin.h> +#include <WebCore/SecurityOriginData.h> +#include <WebCore/TextEncoding.h> +#include <wtf/MainThread.h> +#include <wtf/WorkQueue.h> #include <wtf/text/CString.h> using namespace WebCore; namespace WebKit { -PassRefPtr<LocalStorageDatabaseTracker> LocalStorageDatabaseTracker::create(PassRefPtr<WorkQueue> queue) +Ref<LocalStorageDatabaseTracker> LocalStorageDatabaseTracker::create(Ref<WorkQueue>&& queue, const String& localStorageDirectory) { - return adoptRef(new LocalStorageDatabaseTracker(queue)); + return adoptRef(*new LocalStorageDatabaseTracker(WTFMove(queue), localStorageDirectory)); } -LocalStorageDatabaseTracker::LocalStorageDatabaseTracker(PassRefPtr<WorkQueue> queue) - : m_queue(queue) +LocalStorageDatabaseTracker::LocalStorageDatabaseTracker(Ref<WorkQueue>&& queue, const String& localStorageDirectory) + : m_queue(WTFMove(queue)) + , m_localStorageDirectory(localStorageDirectory.isolatedCopy()) { + ASSERT(!m_localStorageDirectory.isEmpty()); + + // Make sure the encoding is initialized before we start dispatching things to the queue. + UTF8Encoding(); + + m_queue->dispatch([protectedThis = makeRef(*this)]() mutable { + protectedThis->importOriginIdentifiers(); + }); } LocalStorageDatabaseTracker::~LocalStorageDatabaseTracker() { } -void LocalStorageDatabaseTracker::setLocalStorageDirectory(const String& localStorageDirectory) +String LocalStorageDatabaseTracker::databasePath(const SecurityOriginData& securityOrigin) const { - // FIXME: We should come up with a better idiom for safely copying strings across threads. - RefPtr<StringImpl> copiedLocalStorageDirectory; - if (localStorageDirectory.impl()) - copiedLocalStorageDirectory = localStorageDirectory.impl()->isolatedCopy(); - - m_queue->dispatch(bind(&LocalStorageDatabaseTracker::setLocalStorageDirectoryInternal, this, copiedLocalStorageDirectory.release())); + return databasePath(securityOrigin.databaseIdentifier() + ".localstorage"); } -String LocalStorageDatabaseTracker::databasePath(SecurityOrigin* securityOrigin) const +void LocalStorageDatabaseTracker::didOpenDatabaseWithOrigin(const SecurityOriginData& securityOrigin) { - return databasePath(securityOrigin->databaseIdentifier() + ".localstorage"); + addDatabaseWithOriginIdentifier(securityOrigin.databaseIdentifier(), databasePath(securityOrigin)); } -void LocalStorageDatabaseTracker::didOpenDatabaseWithOrigin(SecurityOrigin* securityOrigin) +void LocalStorageDatabaseTracker::deleteDatabaseWithOrigin(const SecurityOriginData& securityOrigin) { - addDatabaseWithOriginIdentifier(securityOrigin->databaseIdentifier(), databasePath(securityOrigin)); -} - -void LocalStorageDatabaseTracker::deleteDatabaseWithOrigin(SecurityOrigin* securityOrigin) -{ - removeDatabaseWithOriginIdentifier(securityOrigin->databaseIdentifier()); + removeDatabaseWithOriginIdentifier(securityOrigin.databaseIdentifier()); } void LocalStorageDatabaseTracker::deleteAllDatabases() @@ -84,19 +87,19 @@ void LocalStorageDatabaseTracker::deleteAllDatabases() return; SQLiteStatement statement(m_database, "SELECT origin, path FROM Origins"); - if (statement.prepare() != SQLResultOk) { + if (statement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare statement."); return; } int result; - while ((result = statement.step()) == SQLResultRow) { + while ((result = statement.step()) == SQLITE_ROW) { deleteFile(statement.getColumnText(1)); // FIXME: Call out to the client. } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Failed to read in all origins from the database."); if (m_database.isOpen()) @@ -110,7 +113,7 @@ void LocalStorageDatabaseTracker::deleteAllDatabases() return; SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins"); - if (deleteStatement.prepare() != SQLResultOk) { + if (deleteStatement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare deletion of all origins"); return; } @@ -123,35 +126,97 @@ void LocalStorageDatabaseTracker::deleteAllDatabases() deleteEmptyDirectory(m_localStorageDirectory); } -Vector<RefPtr<WebCore::SecurityOrigin>> LocalStorageDatabaseTracker::origins() const +static std::optional<time_t> fileCreationTime(const String& filePath) +{ + time_t time; + return getFileCreationTime(filePath, time) ? time : std::optional<time_t>(std::nullopt); +} + +static std::optional<time_t> fileModificationTime(const String& filePath) +{ + time_t time; + if (!getFileModificationTime(filePath, time)) + return std::nullopt; + + return time; +} + +Vector<SecurityOriginData> LocalStorageDatabaseTracker::deleteDatabasesModifiedSince(std::chrono::system_clock::time_point time) +{ + ASSERT(!isMainThread()); + importOriginIdentifiers(); + Vector<String> originIdentifiersToDelete; + + for (const String& origin : m_origins) { + String filePath = pathForDatabaseWithOriginIdentifier(origin); + + auto modificationTime = fileModificationTime(filePath); + if (!modificationTime) + continue; + + if (modificationTime.value() >= std::chrono::system_clock::to_time_t(time)) + originIdentifiersToDelete.append(origin); + } + + Vector<SecurityOriginData> deletedDatabaseOrigins; + deletedDatabaseOrigins.reserveInitialCapacity(originIdentifiersToDelete.size()); + + for (const auto& originIdentifier : originIdentifiersToDelete) { + removeDatabaseWithOriginIdentifier(originIdentifier); + + if (auto origin = SecurityOriginData::fromDatabaseIdentifier(originIdentifier)) + deletedDatabaseOrigins.uncheckedAppend(*origin); + else + ASSERT_NOT_REACHED(); + } + + return deletedDatabaseOrigins; +} + +Vector<SecurityOriginData> LocalStorageDatabaseTracker::origins() const { - Vector<RefPtr<SecurityOrigin>> origins; + Vector<SecurityOriginData> origins; origins.reserveInitialCapacity(m_origins.size()); - for (HashSet<String>::const_iterator it = m_origins.begin(), end = m_origins.end(); it != end; ++it) - origins.uncheckedAppend(SecurityOrigin::createFromDatabaseIdentifier(*it)); + for (const String& originIdentifier : m_origins) { + if (auto origin = SecurityOriginData::fromDatabaseIdentifier(originIdentifier)) + origins.uncheckedAppend(*origin); + else + ASSERT_NOT_REACHED(); + } return origins; } -void LocalStorageDatabaseTracker::setLocalStorageDirectoryInternal(StringImpl* localStorageDirectory) +Vector<LocalStorageDatabaseTracker::OriginDetails> LocalStorageDatabaseTracker::originDetails() { - if (m_database.isOpen()) - m_database.close(); + Vector<OriginDetails> result; + result.reserveInitialCapacity(m_origins.size()); - m_localStorageDirectory = localStorageDirectory; - m_origins.clear(); + for (const String& origin : m_origins) { + String filePath = pathForDatabaseWithOriginIdentifier(origin); + + OriginDetails details; + details.originIdentifier = origin.isolatedCopy(); + details.creationTime = fileCreationTime(filePath); + details.modificationTime = fileModificationTime(filePath); + result.uncheckedAppend(details); + } - m_queue->dispatch(bind(&LocalStorageDatabaseTracker::importOriginIdentifiers, this)); + return result; } String LocalStorageDatabaseTracker::databasePath(const String& filename) const { if (!makeAllDirectories(m_localStorageDirectory)) { - LOG_ERROR("Unabled to create LocalStorage database path %s", m_localStorageDirectory.utf8().data()); + LOG_ERROR("Unable to create LocalStorage database path %s", m_localStorageDirectory.utf8().data()); return String(); } +#if PLATFORM(IOS) + platformMaybeExcludeFromBackup(); +#endif + return pathByAppendingComponent(m_localStorageDirectory, filename); } @@ -192,17 +257,17 @@ void LocalStorageDatabaseTracker::importOriginIdentifiers() if (m_database.isOpen()) { SQLiteStatement statement(m_database, "SELECT origin FROM Origins"); - if (statement.prepare() != SQLResultOk) { + if (statement.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare statement."); return; } int result; - while ((result = statement.step()) == SQLResultRow) + while ((result = statement.step()) == SQLITE_ROW) m_origins.add(statement.getColumnText(0)); - if (result != SQLResultDone) { + if (result != SQLITE_DONE) { LOG_ERROR("Failed to read in all origins from the database."); return; } @@ -250,7 +315,7 @@ void LocalStorageDatabaseTracker::addDatabaseWithOriginIdentifier(const String& return; SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)"); - if (statement.prepare() != SQLResultOk) { + if (statement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.utf8().data()); return; } @@ -258,7 +323,7 @@ void LocalStorageDatabaseTracker::addDatabaseWithOriginIdentifier(const String& statement.bindText(1, originIdentifier); statement.bindText(2, databasePath); - if (statement.step() != SQLResultDone) + if (statement.step() != SQLITE_DONE) LOG_ERROR("Unable to establish origin '%s' in the tracker", originIdentifier.utf8().data()); m_origins.add(originIdentifier); @@ -277,7 +342,7 @@ void LocalStorageDatabaseTracker::removeDatabaseWithOriginIdentifier(const Strin return; SQLiteStatement deleteStatement(m_database, "DELETE FROM Origins where origin=?"); - if (deleteStatement.prepare() != SQLResultOk) { + if (deleteStatement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare deletion of origin '%s'", originIdentifier.ascii().data()); return; } @@ -287,13 +352,13 @@ void LocalStorageDatabaseTracker::removeDatabaseWithOriginIdentifier(const Strin return; } - deleteFile(path); + SQLiteFileSystem::deleteDatabaseFile(path); m_origins.remove(originIdentifier); if (m_origins.isEmpty()) { - // There are no origins left, go ahead and delete the tracker database. + // There are no origins left; delete the tracker database. m_database.close(); - deleteFile(trackerDatabasePath()); + SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); deleteEmptyDirectory(m_localStorageDirectory); } @@ -306,7 +371,7 @@ String LocalStorageDatabaseTracker::pathForDatabaseWithOriginIdentifier(const St return String(); SQLiteStatement pathStatement(m_database, "SELECT path FROM Origins WHERE origin=?"); - if (pathStatement.prepare() != SQLResultOk) { + if (pathStatement.prepare() != SQLITE_OK) { LOG_ERROR("Unable to prepare selection of path for origin '%s'", originIdentifier.utf8().data()); return String(); } @@ -314,7 +379,7 @@ String LocalStorageDatabaseTracker::pathForDatabaseWithOriginIdentifier(const St pathStatement.bindText(1, originIdentifier); int result = pathStatement.step(); - if (result != SQLResultRow) + if (result != SQLITE_ROW) return String(); return pathStatement.getColumnText(0); diff --git a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.h b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.h index e16428907..7ceb1916d 100644 --- a/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.h +++ b/Source/WebKit2/UIProcess/Storage/LocalStorageDatabaseTracker.h @@ -23,43 +23,51 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef LocalStorageDatabaseTracker_h -#define LocalStorageDatabaseTracker_h +#pragma once #include <WebCore/SQLiteDatabase.h> #include <wtf/HashSet.h> -#include <wtf/PassRefPtr.h> +#include <wtf/Optional.h> #include <wtf/RefPtr.h> #include <wtf/ThreadSafeRefCounted.h> +#include <wtf/WorkQueue.h> #include <wtf/text/StringHash.h> #include <wtf/text/WTFString.h> namespace WebCore { class SecurityOrigin; +struct SecurityOriginData; } -class WorkQueue; - namespace WebKit { +struct LocalStorageDetails; + class LocalStorageDatabaseTracker : public ThreadSafeRefCounted<LocalStorageDatabaseTracker> { public: - static PassRefPtr<LocalStorageDatabaseTracker> create(PassRefPtr<WorkQueue>); + static Ref<LocalStorageDatabaseTracker> create(Ref<WorkQueue>&&, const String& localStorageDirectory); ~LocalStorageDatabaseTracker(); - void setLocalStorageDirectory(const String&); - String databasePath(WebCore::SecurityOrigin*) const; + String databasePath(const WebCore::SecurityOriginData&) const; - void didOpenDatabaseWithOrigin(WebCore::SecurityOrigin*); - void deleteDatabaseWithOrigin(WebCore::SecurityOrigin*); + void didOpenDatabaseWithOrigin(const WebCore::SecurityOriginData&); + void deleteDatabaseWithOrigin(const WebCore::SecurityOriginData&); void deleteAllDatabases(); - Vector<RefPtr<WebCore::SecurityOrigin>> origins() const; + // Returns a vector of the origins whose databases have been deleted. + Vector<WebCore::SecurityOriginData> deleteDatabasesModifiedSince(std::chrono::system_clock::time_point); -private: - explicit LocalStorageDatabaseTracker(PassRefPtr<WorkQueue>); + Vector<WebCore::SecurityOriginData> origins() const; - void setLocalStorageDirectoryInternal(StringImpl*); + struct OriginDetails { + String originIdentifier; + std::optional<time_t> creationTime; + std::optional<time_t> modificationTime; + }; + Vector<OriginDetails> originDetails(); + +private: + LocalStorageDatabaseTracker(Ref<WorkQueue>&&, const String& localStorageDirectory); String databasePath(const String& filename) const; String trackerDatabasePath() const; @@ -82,8 +90,12 @@ private: WebCore::SQLiteDatabase m_database; HashSet<String> m_origins; + +#if PLATFORM(IOS) + void platformMaybeExcludeFromBackup() const; + + mutable bool m_hasExcludedFromBackup { false }; +#endif }; } // namespace WebKit - -#endif // LocalStorageDatabaseTracker_h diff --git a/Source/WebKit2/UIProcess/Storage/StorageManager.cpp b/Source/WebKit2/UIProcess/Storage/StorageManager.cpp index c08acc4ad..5803e2cb3 100644 --- a/Source/WebKit2/UIProcess/Storage/StorageManager.cpp +++ b/Source/WebKit2/UIProcess/Storage/StorageManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,14 +28,16 @@ #include "LocalStorageDatabase.h" #include "LocalStorageDatabaseTracker.h" -#include "SecurityOriginData.h" #include "StorageAreaMapMessages.h" #include "StorageManagerMessages.h" #include "WebProcessProxy.h" -#include "WorkQueue.h" +#include <WebCore/SecurityOriginData.h> #include <WebCore/SecurityOriginHash.h> #include <WebCore/StorageMap.h> #include <WebCore/TextEncoding.h> +#include <memory> +#include <wtf/WorkQueue.h> +#include <wtf/threads/BinarySemaphore.h> using namespace WebCore; @@ -43,36 +45,38 @@ namespace WebKit { class StorageManager::StorageArea : public ThreadSafeRefCounted<StorageManager::StorageArea> { public: - static PassRefPtr<StorageArea> create(LocalStorageNamespace*, PassRefPtr<SecurityOrigin>, unsigned quotaInBytes); + static Ref<StorageArea> create(LocalStorageNamespace*, const SecurityOriginData&, unsigned quotaInBytes); ~StorageArea(); - SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); } + const WebCore::SecurityOriginData& securityOrigin() const { return m_securityOrigin; } - void addListener(IPC::Connection*, uint64_t storageMapID); - void removeListener(IPC::Connection*, uint64_t storageMapID); + void addListener(IPC::Connection&, uint64_t storageMapID); + void removeListener(IPC::Connection&, uint64_t storageMapID); - PassRefPtr<StorageArea> clone() const; + Ref<StorageArea> clone() const; void setItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException); void removeItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString); void clear(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& urlString); - const HashMap<String, String>& items(); + const HashMap<String, String>& items() const; void clear(); + bool isSessionStorage() const { return !m_localStorageNamespace; } + private: - explicit StorageArea(LocalStorageNamespace*, PassRefPtr<SecurityOrigin>, unsigned quotaInBytes); + explicit StorageArea(LocalStorageNamespace*, const SecurityOriginData&, unsigned quotaInBytes); - void openDatabaseAndImportItemsIfNeeded(); + void openDatabaseAndImportItemsIfNeeded() const; void dispatchEvents(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString) const; // Will be null if the storage area belongs to a session storage namespace. LocalStorageNamespace* m_localStorageNamespace; - RefPtr<LocalStorageDatabase> m_localStorageDatabase; - bool m_didImportItemsFromDatabase; + mutable RefPtr<LocalStorageDatabase> m_localStorageDatabase; + mutable bool m_didImportItemsFromDatabase { false }; - RefPtr<SecurityOrigin> m_securityOrigin; + SecurityOriginData m_securityOrigin; unsigned m_quotaInBytes; RefPtr<StorageMap> m_storageMap; @@ -81,15 +85,15 @@ private: class StorageManager::LocalStorageNamespace : public ThreadSafeRefCounted<LocalStorageNamespace> { public: - static PassRefPtr<LocalStorageNamespace> create(StorageManager*, uint64_t storageManagerID); + static Ref<LocalStorageNamespace> create(StorageManager*, uint64_t storageManagerID); ~LocalStorageNamespace(); StorageManager* storageManager() const { return m_storageManager; } - PassRefPtr<StorageArea> getOrCreateStorageArea(PassRefPtr<SecurityOrigin>); + Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&&); void didDestroyStorageArea(StorageArea*); - void clearStorageAreasMatchingOrigin(SecurityOrigin*); + void clearStorageAreasMatchingOrigin(const SecurityOriginData&); void clearAllStorageAreas(); private: @@ -100,17 +104,70 @@ private: unsigned m_quotaInBytes; // We don't hold an explicit reference to the StorageAreas; they are kept alive by the m_storageAreasByConnection map in StorageManager. - HashMap<RefPtr<SecurityOrigin>, StorageArea*> m_storageAreaMap; + HashMap<SecurityOriginData, StorageArea*> m_storageAreaMap; +}; + +class StorageManager::TransientLocalStorageNamespace : public ThreadSafeRefCounted<TransientLocalStorageNamespace> { +public: + static Ref<TransientLocalStorageNamespace> create() + { + return adoptRef(*new TransientLocalStorageNamespace()); + } + + ~TransientLocalStorageNamespace() + { + } + + Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&& securityOrigin) + { + return *m_storageAreaMap.ensure(securityOrigin, [this, securityOrigin]() mutable { + return StorageArea::create(nullptr, WTFMove(securityOrigin), m_quotaInBytes); + }).iterator->value.copyRef(); + } + + Vector<SecurityOriginData> origins() const + { + Vector<SecurityOriginData> origins; + + for (const auto& storageArea : m_storageAreaMap.values()) { + if (!storageArea->items().isEmpty()) + origins.append(storageArea->securityOrigin()); + } + + return origins; + } + + void clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin) + { + for (auto& storageArea : m_storageAreaMap.values()) { + if (storageArea->securityOrigin() == securityOrigin) + storageArea->clear(); + } + } + + void clearAllStorageAreas() + { + for (auto& storageArea : m_storageAreaMap.values()) + storageArea->clear(); + } + +private: + explicit TransientLocalStorageNamespace() + { + } + + const unsigned m_quotaInBytes = 5 * 1024 * 1024; + + HashMap<SecurityOriginData, RefPtr<StorageArea>> m_storageAreaMap; }; -PassRefPtr<StorageManager::StorageArea> StorageManager::StorageArea::create(LocalStorageNamespace* localStorageNamespace, PassRefPtr<SecurityOrigin> securityOrigin, unsigned quotaInBytes) +auto StorageManager::StorageArea::create(LocalStorageNamespace* localStorageNamespace, const SecurityOriginData& securityOrigin, unsigned quotaInBytes) -> Ref<StorageManager::StorageArea> { - return adoptRef(new StorageArea(localStorageNamespace, securityOrigin, quotaInBytes)); + return adoptRef(*new StorageArea(localStorageNamespace, securityOrigin, quotaInBytes)); } -StorageManager::StorageArea::StorageArea(LocalStorageNamespace* localStorageNamespace, PassRefPtr<SecurityOrigin> securityOrigin, unsigned quotaInBytes) +StorageManager::StorageArea::StorageArea(LocalStorageNamespace* localStorageNamespace, const SecurityOriginData& securityOrigin, unsigned quotaInBytes) : m_localStorageNamespace(localStorageNamespace) - , m_didImportItemsFromDatabase(false) , m_securityOrigin(securityOrigin) , m_quotaInBytes(quotaInBytes) , m_storageMap(StorageMap::create(m_quotaInBytes)) @@ -128,26 +185,26 @@ StorageManager::StorageArea::~StorageArea() m_localStorageNamespace->didDestroyStorageArea(this); } -void StorageManager::StorageArea::addListener(IPC::Connection* connection, uint64_t storageMapID) +void StorageManager::StorageArea::addListener(IPC::Connection& connection, uint64_t storageMapID) { - ASSERT(!m_eventListeners.contains(std::make_pair(connection, storageMapID))); - m_eventListeners.add(std::make_pair(connection, storageMapID)); + ASSERT(!m_eventListeners.contains(std::make_pair(&connection, storageMapID))); + m_eventListeners.add(std::make_pair(&connection, storageMapID)); } -void StorageManager::StorageArea::removeListener(IPC::Connection* connection, uint64_t storageMapID) +void StorageManager::StorageArea::removeListener(IPC::Connection& connection, uint64_t storageMapID) { - ASSERT(m_eventListeners.contains(std::make_pair(connection, storageMapID))); - m_eventListeners.remove(std::make_pair(connection, storageMapID)); + ASSERT(isSessionStorage() || m_eventListeners.contains(std::make_pair(&connection, storageMapID))); + m_eventListeners.remove(std::make_pair(&connection, storageMapID)); } -PassRefPtr<StorageManager::StorageArea> StorageManager::StorageArea::clone() const +Ref<StorageManager::StorageArea> StorageManager::StorageArea::clone() const { ASSERT(!m_localStorageNamespace); - RefPtr<StorageArea> storageArea = StorageArea::create(0, m_securityOrigin, m_quotaInBytes); + auto storageArea = StorageArea::create(nullptr, m_securityOrigin, m_quotaInBytes); storageArea->m_storageMap = m_storageMap; - return storageArea.release(); + return storageArea; } void StorageManager::StorageArea::setItem(IPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& value, const String& urlString, bool& quotaException) @@ -156,9 +213,9 @@ void StorageManager::StorageArea::setItem(IPC::Connection* sourceConnection, uin String oldValue; - RefPtr<StorageMap> newStorageMap = m_storageMap->setItem(key, value, oldValue, quotaException); + auto newStorageMap = m_storageMap->setItem(key, value, oldValue, quotaException); if (newStorageMap) - m_storageMap = newStorageMap.release(); + m_storageMap = WTFMove(newStorageMap); if (quotaException) return; @@ -174,9 +231,9 @@ void StorageManager::StorageArea::removeItem(IPC::Connection* sourceConnection, openDatabaseAndImportItemsIfNeeded(); String oldValue; - RefPtr<StorageMap> newStorageMap = m_storageMap->removeItem(key, oldValue); + auto newStorageMap = m_storageMap->removeItem(key, oldValue); if (newStorageMap) - m_storageMap = newStorageMap.release(); + m_storageMap = WTFMove(newStorageMap); if (oldValue.isNull()) return; @@ -202,7 +259,7 @@ void StorageManager::StorageArea::clear(IPC::Connection* sourceConnection, uint6 dispatchEvents(sourceConnection, sourceStorageAreaID, String(), String(), String(), urlString); } -const HashMap<String, String>& StorageManager::StorageArea::items() +const HashMap<String, String>& StorageManager::StorageArea::items() const { openDatabaseAndImportItemsIfNeeded(); @@ -222,14 +279,14 @@ void StorageManager::StorageArea::clear() it->first->send(Messages::StorageAreaMap::ClearCache(), it->second); } -void StorageManager::StorageArea::openDatabaseAndImportItemsIfNeeded() +void StorageManager::StorageArea::openDatabaseAndImportItemsIfNeeded() const { if (!m_localStorageNamespace) return; // We open the database here even if we've already imported our items to ensure that the database is open if we need to write to it. if (!m_localStorageDatabase) - m_localStorageDatabase = LocalStorageDatabase::create(m_localStorageNamespace->storageManager()->m_queue, m_localStorageNamespace->storageManager()->m_localStorageDatabaseTracker, m_securityOrigin.get()); + m_localStorageDatabase = LocalStorageDatabase::create(m_localStorageNamespace->storageManager()->m_queue.copyRef(), m_localStorageNamespace->storageManager()->m_localStorageDatabaseTracker.copyRef(), m_securityOrigin); if (m_didImportItemsFromDatabase) return; @@ -247,9 +304,9 @@ void StorageManager::StorageArea::dispatchEvents(IPC::Connection* sourceConnecti } } -PassRefPtr<StorageManager::LocalStorageNamespace> StorageManager::LocalStorageNamespace::create(StorageManager* storageManager, uint64_t storageNamespaceID) +Ref<StorageManager::LocalStorageNamespace> StorageManager::LocalStorageNamespace::create(StorageManager* storageManager, uint64_t storageNamespaceID) { - return adoptRef(new LocalStorageNamespace(storageManager, storageNamespaceID)); + return adoptRef(*new LocalStorageNamespace(storageManager, storageNamespaceID)); } // FIXME: The quota value is copied from GroupSettings.cpp. @@ -266,16 +323,16 @@ StorageManager::LocalStorageNamespace::~LocalStorageNamespace() ASSERT(m_storageAreaMap.isEmpty()); } -PassRefPtr<StorageManager::StorageArea> StorageManager::LocalStorageNamespace::getOrCreateStorageArea(PassRefPtr<SecurityOrigin> securityOrigin) +auto StorageManager::LocalStorageNamespace::getOrCreateStorageArea(SecurityOriginData&& securityOrigin) -> Ref<StorageArea> { - auto result = m_storageAreaMap.add(securityOrigin, nullptr); - if (!result.isNewEntry) - return result.iterator->value; + auto& slot = m_storageAreaMap.add(securityOrigin, nullptr).iterator->value; + if (slot) + return *slot; - RefPtr<StorageArea> storageArea = StorageArea::create(this, result.iterator->key, m_quotaInBytes); - result.iterator->value = storageArea.get(); + auto storageArea = StorageArea::create(this, WTFMove(securityOrigin), m_quotaInBytes); + slot = &storageArea.get(); - return storageArea.release(); + return storageArea; } void StorageManager::LocalStorageNamespace::didDestroyStorageArea(StorageArea* storageArea) @@ -290,23 +347,23 @@ void StorageManager::LocalStorageNamespace::didDestroyStorageArea(StorageArea* s m_storageManager->m_localStorageNamespaces.remove(m_storageNamespaceID); } -void StorageManager::LocalStorageNamespace::clearStorageAreasMatchingOrigin(SecurityOrigin* securityOrigin) +void StorageManager::LocalStorageNamespace::clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin) { - for (auto it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it) { - if (it->key->equal(securityOrigin)) - it->value->clear(); + for (const auto& originAndStorageArea : m_storageAreaMap) { + if (originAndStorageArea.key == securityOrigin) + originAndStorageArea.value->clear(); } } void StorageManager::LocalStorageNamespace::clearAllStorageAreas() { - for (auto it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it) - it->value->clear(); + for (auto* storageArea : m_storageAreaMap.values()) + storageArea->clear(); } class StorageManager::SessionStorageNamespace : public ThreadSafeRefCounted<SessionStorageNamespace> { public: - static PassRefPtr<SessionStorageNamespace> create(IPC::Connection* allowedConnection, unsigned quotaInBytes); + static Ref<SessionStorageNamespace> create(unsigned quotaInBytes); ~SessionStorageNamespace(); bool isEmpty() const { return m_storageAreaMap.isEmpty(); } @@ -314,27 +371,52 @@ public: IPC::Connection* allowedConnection() const { return m_allowedConnection.get(); } void setAllowedConnection(IPC::Connection*); - PassRefPtr<StorageArea> getOrCreateStorageArea(PassRefPtr<SecurityOrigin>); + Ref<StorageArea> getOrCreateStorageArea(SecurityOriginData&&); void cloneTo(SessionStorageNamespace& newSessionStorageNamespace); + Vector<SecurityOriginData> origins() const + { + Vector<SecurityOriginData> origins; + + for (const auto& storageArea : m_storageAreaMap.values()) { + if (!storageArea->items().isEmpty()) + origins.append(storageArea->securityOrigin()); + } + + return origins; + } + + void clearStorageAreasMatchingOrigin(const SecurityOriginData& securityOrigin) + { + for (auto& storageArea : m_storageAreaMap.values()) { + if (storageArea->securityOrigin() == securityOrigin) + storageArea->clear(); + } + } + + void clearAllStorageAreas() + { + for (auto& storageArea : m_storageAreaMap.values()) + storageArea->clear(); + } + private: - SessionStorageNamespace(IPC::Connection* allowedConnection, unsigned quotaInBytes); + explicit SessionStorageNamespace(unsigned quotaInBytes); RefPtr<IPC::Connection> m_allowedConnection; unsigned m_quotaInBytes; - HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageArea>> m_storageAreaMap; + HashMap<SecurityOriginData, RefPtr<StorageArea>> m_storageAreaMap; }; -PassRefPtr<StorageManager::SessionStorageNamespace> StorageManager::SessionStorageNamespace::create(IPC::Connection* allowedConnection, unsigned quotaInBytes) +Ref<StorageManager::SessionStorageNamespace> StorageManager::SessionStorageNamespace::create(unsigned quotaInBytes) { - return adoptRef(new SessionStorageNamespace(allowedConnection, quotaInBytes)); + return adoptRef(*new SessionStorageNamespace(quotaInBytes)); } -StorageManager::SessionStorageNamespace::SessionStorageNamespace(IPC::Connection* allowedConnection, unsigned quotaInBytes) - : m_allowedConnection(allowedConnection) - , m_quotaInBytes(quotaInBytes) +StorageManager::SessionStorageNamespace::SessionStorageNamespace(unsigned quotaInBytes) + : m_quotaInBytes(quotaInBytes) { } @@ -349,31 +431,29 @@ void StorageManager::SessionStorageNamespace::setAllowedConnection(IPC::Connecti m_allowedConnection = allowedConnection; } -PassRefPtr<StorageManager::StorageArea> StorageManager::SessionStorageNamespace::getOrCreateStorageArea(PassRefPtr<SecurityOrigin> securityOrigin) +auto StorageManager::SessionStorageNamespace::getOrCreateStorageArea(SecurityOriginData&& securityOrigin) -> Ref<StorageArea> { - auto result = m_storageAreaMap.add(securityOrigin, nullptr); - if (result.isNewEntry) - result.iterator->value = StorageArea::create(0, result.iterator->key, m_quotaInBytes); - - return result.iterator->value; + return *m_storageAreaMap.ensure(securityOrigin, [this, securityOrigin]() mutable { + return StorageArea::create(nullptr, WTFMove(securityOrigin), m_quotaInBytes); + }).iterator->value.copyRef(); } void StorageManager::SessionStorageNamespace::cloneTo(SessionStorageNamespace& newSessionStorageNamespace) { ASSERT_UNUSED(newSessionStorageNamespace, newSessionStorageNamespace.isEmpty()); - for (HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageArea>>::const_iterator it = m_storageAreaMap.begin(), end = m_storageAreaMap.end(); it != end; ++it) - newSessionStorageNamespace.m_storageAreaMap.add(it->key, it->value->clone()); + for (auto& pair : m_storageAreaMap) + newSessionStorageNamespace.m_storageAreaMap.add(pair.key, pair.value->clone()); } -PassRefPtr<StorageManager> StorageManager::create() +Ref<StorageManager> StorageManager::create(const String& localStorageDirectory) { - return adoptRef(new StorageManager); + return adoptRef(*new StorageManager(localStorageDirectory)); } -StorageManager::StorageManager() +StorageManager::StorageManager(const String& localStorageDirectory) : m_queue(WorkQueue::create("com.apple.WebKit.StorageManager")) - , m_localStorageDatabaseTracker(LocalStorageDatabaseTracker::create(m_queue)) + , m_localStorageDatabaseTracker(LocalStorageDatabaseTracker::create(m_queue.copyRef(), localStorageDirectory)) { // Make sure the encoding is initialized before we start dispatching things to the queue. UTF8Encoding(); @@ -383,61 +463,204 @@ StorageManager::~StorageManager() { } -void StorageManager::setLocalStorageDirectory(const String& localStorageDirectory) +void StorageManager::createSessionStorageNamespace(uint64_t storageNamespaceID, unsigned quotaInBytes) { - m_localStorageDatabaseTracker->setLocalStorageDirectory(localStorageDirectory); -} + m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID, quotaInBytes]() mutable { + ASSERT(!m_sessionStorageNamespaces.contains(storageNamespaceID)); -void StorageManager::createSessionStorageNamespace(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes) -{ - m_queue->dispatch(bind(&StorageManager::createSessionStorageNamespaceInternal, this, storageNamespaceID, RefPtr<IPC::Connection>(allowedConnection), quotaInBytes)); + m_sessionStorageNamespaces.set(storageNamespaceID, SessionStorageNamespace::create(quotaInBytes)); + }); } void StorageManager::destroySessionStorageNamespace(uint64_t storageNamespaceID) { - m_queue->dispatch(bind(&StorageManager::destroySessionStorageNamespaceInternal, this, storageNamespaceID)); + m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID] { + ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID)); + m_sessionStorageNamespaces.remove(storageNamespaceID); + }); } void StorageManager::setAllowedSessionStorageNamespaceConnection(uint64_t storageNamespaceID, IPC::Connection* allowedConnection) { - m_queue->dispatch(bind(&StorageManager::setAllowedSessionStorageNamespaceConnectionInternal, this, storageNamespaceID, RefPtr<IPC::Connection>(allowedConnection))); + m_queue->dispatch([this, protectedThis = makeRef(*this), connection = RefPtr<IPC::Connection>(allowedConnection), storageNamespaceID]() mutable { + ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID)); + + m_sessionStorageNamespaces.get(storageNamespaceID)->setAllowedConnection(connection.get()); + }); } void StorageManager::cloneSessionStorageNamespace(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID) { - m_queue->dispatch(bind(&StorageManager::cloneSessionStorageNamespaceInternal, this, storageNamespaceID, newStorageNamespaceID)); + m_queue->dispatch([this, protectedThis = makeRef(*this), storageNamespaceID, newStorageNamespaceID] { + SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID); + if (!sessionStorageNamespace) { + // FIXME: We can get into this situation if someone closes the originating page from within a + // createNewPage callback. We bail for now, but we should really find a way to keep the session storage alive + // so we we'll clone the session storage correctly. + return; + } + + SessionStorageNamespace* newSessionStorageNamespace = m_sessionStorageNamespaces.get(newStorageNamespaceID); + ASSERT(newSessionStorageNamespace); + + sessionStorageNamespace->cloneTo(*newSessionStorageNamespace); + }); +} + +void StorageManager::processWillOpenConnection(WebProcessProxy&, IPC::Connection& connection) +{ + connection.addWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName(), m_queue.get(), this); +} + +void StorageManager::processDidCloseConnection(WebProcessProxy&, IPC::Connection& connection) +{ + connection.removeWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName()); + + m_queue->dispatch([this, protectedThis = makeRef(*this), connection = Ref<IPC::Connection>(connection)]() mutable { + Vector<std::pair<RefPtr<IPC::Connection>, uint64_t>> connectionAndStorageMapIDPairsToRemove; + for (auto& storageArea : m_storageAreasByConnection) { + if (storageArea.key.first != connection.ptr()) + continue; + + storageArea.value->removeListener(*storageArea.key.first, storageArea.key.second); + connectionAndStorageMapIDPairsToRemove.append(storageArea.key); + } + + for (auto& pair : connectionAndStorageMapIDPairsToRemove) + m_storageAreasByConnection.remove(pair); + }); +} + +void StorageManager::getSessionStorageOrigins(std::function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler) +{ + m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable { + HashSet<SecurityOriginData> origins; + + for (const auto& sessionStorageNamespace : m_sessionStorageNamespaces.values()) { + for (auto& origin : sessionStorageNamespace->origins()) + origins.add(origin); + } + + RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable { + completionHandler(WTFMove(origins)); + }); + }); +} + +void StorageManager::deleteSessionStorageOrigins(std::function<void()>&& completionHandler) +{ + m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable { + for (auto& sessionStorageNamespace : m_sessionStorageNamespaces.values()) + sessionStorageNamespace->clearAllStorageAreas(); + + RunLoop::main().dispatch(WTFMove(completionHandler)); + }); +} + +void StorageManager::deleteSessionStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>& origins, std::function<void()>&& completionHandler) +{ + Vector<WebCore::SecurityOriginData> copiedOrigins; + copiedOrigins.reserveInitialCapacity(origins.size()); + + for (auto& origin : origins) + copiedOrigins.uncheckedAppend(origin.isolatedCopy()); + + m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigins = WTFMove(copiedOrigins), completionHandler = WTFMove(completionHandler)]() mutable { + for (auto& origin : copiedOrigins) { + for (auto& sessionStorageNamespace : m_sessionStorageNamespaces.values()) + sessionStorageNamespace->clearStorageAreasMatchingOrigin(origin); + } + + RunLoop::main().dispatch(WTFMove(completionHandler)); + }); } -void StorageManager::processWillOpenConnection(WebProcessProxy* webProcessProxy) +void StorageManager::getLocalStorageOrigins(std::function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler) { - webProcessProxy->connection()->addWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName(), m_queue.get(), this); + m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable { + HashSet<SecurityOriginData> origins; + + for (auto& origin : m_localStorageDatabaseTracker->origins()) + origins.add(origin); + + for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values()) { + for (auto& origin : transientLocalStorageNamespace->origins()) + origins.add(origin); + } + + RunLoop::main().dispatch([origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable { + completionHandler(WTFMove(origins)); + }); + }); } -void StorageManager::processWillCloseConnection(WebProcessProxy* webProcessProxy) +void StorageManager::getLocalStorageOriginDetails(std::function<void (Vector<LocalStorageDatabaseTracker::OriginDetails>)>&& completionHandler) { - webProcessProxy->connection()->removeWorkQueueMessageReceiver(Messages::StorageManager::messageReceiverName()); + m_queue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable { + auto originDetails = m_localStorageDatabaseTracker->originDetails(); - m_queue->dispatch(bind(&StorageManager::invalidateConnectionInternal, this, RefPtr<IPC::Connection>(webProcessProxy->connection()))); + RunLoop::main().dispatch([originDetails = WTFMove(originDetails), completionHandler = WTFMove(completionHandler)]() mutable { + completionHandler(WTFMove(originDetails)); + }); + }); } -void StorageManager::getOrigins(FunctionDispatcher* callbackDispatcher, void* context, void (*callback)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context)) +void StorageManager::deleteLocalStorageEntriesForOrigin(SecurityOriginData&& securityOrigin) { - m_queue->dispatch(bind(&StorageManager::getOriginsInternal, this, RefPtr<FunctionDispatcher>(callbackDispatcher), context, callback)); + m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigin = securityOrigin.isolatedCopy()]() mutable { + for (auto& localStorageNamespace : m_localStorageNamespaces.values()) + localStorageNamespace->clearStorageAreasMatchingOrigin(copiedOrigin); + + for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values()) + transientLocalStorageNamespace->clearStorageAreasMatchingOrigin(copiedOrigin); + + m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(copiedOrigin); + }); } -void StorageManager::deleteEntriesForOrigin(SecurityOrigin* securityOrigin) +void StorageManager::deleteLocalStorageOriginsModifiedSince(std::chrono::system_clock::time_point time, std::function<void()>&& completionHandler) { - m_queue->dispatch(bind(&StorageManager::deleteEntriesForOriginInternal, this, RefPtr<SecurityOrigin>(securityOrigin))); + m_queue->dispatch([this, protectedThis = makeRef(*this), time, completionHandler = WTFMove(completionHandler)]() mutable { + auto deletedOrigins = m_localStorageDatabaseTracker->deleteDatabasesModifiedSince(time); + + for (const auto& origin : deletedOrigins) { + for (auto& localStorageNamespace : m_localStorageNamespaces.values()) + localStorageNamespace->clearStorageAreasMatchingOrigin(origin); + } + + for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values()) + transientLocalStorageNamespace->clearAllStorageAreas(); + + RunLoop::main().dispatch(WTFMove(completionHandler)); + }); } -void StorageManager::deleteAllEntries() +void StorageManager::deleteLocalStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>& origins, std::function<void()>&& completionHandler) { - m_queue->dispatch(bind(&StorageManager::deleteAllEntriesInternal, this)); + Vector<SecurityOriginData> copiedOrigins; + copiedOrigins.reserveInitialCapacity(origins.size()); + + for (auto& origin : origins) + copiedOrigins.uncheckedAppend(origin.isolatedCopy()); + + m_queue->dispatch([this, protectedThis = makeRef(*this), copiedOrigins = WTFMove(copiedOrigins), completionHandler = WTFMove(completionHandler)]() mutable { + for (auto& origin : copiedOrigins) { + for (auto& localStorageNamespace : m_localStorageNamespaces.values()) + localStorageNamespace->clearStorageAreasMatchingOrigin(origin); + + for (auto& transientLocalStorageNamespace : m_transientLocalStorageNamespaces.values()) + transientLocalStorageNamespace->clearStorageAreasMatchingOrigin(origin); + + m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(origin); + } + + RunLoop::main().dispatch(WTFMove(completionHandler)); + }); } -void StorageManager::createLocalStorageMap(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData& securityOriginData) +void StorageManager::createLocalStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData) { - std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID); + std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(&connection, storageMapID); // FIXME: This should be a message check. ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair))); @@ -453,16 +676,51 @@ void StorageManager::createLocalStorageMap(IPC::Connection* connection, uint64_t // FIXME: This should be a message check. ASSERT(localStorageNamespace); - RefPtr<StorageArea> storageArea = localStorageNamespace->getOrCreateStorageArea(securityOriginData.securityOrigin()); + auto storageArea = localStorageNamespace->getOrCreateStorageArea(WTFMove(securityOriginData)); + storageArea->addListener(connection, storageMapID); + + result.iterator->value = WTFMove(storageArea); +} + +void StorageManager::createTransientLocalStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& topLevelOriginData, SecurityOriginData&& origin) +{ + // FIXME: This should be a message check. + ASSERT(m_storageAreasByConnection.isValidKey({ &connection, storageMapID })); + + // See if we already have session storage for this connection/origin combo. + // If so, update the map with the new ID, otherwise keep on trucking. + for (auto it = m_storageAreasByConnection.begin(), end = m_storageAreasByConnection.end(); it != end; ++it) { + if (it->key.first != &connection) + continue; + Ref<StorageArea> area = *it->value; + if (!area->isSessionStorage()) + continue; + if (!origin.securityOrigin()->isSameSchemeHostPort(area->securityOrigin().securityOrigin().get())) + continue; + area->addListener(connection, storageMapID); + m_storageAreasByConnection.remove(it); + m_storageAreasByConnection.add({ &connection, storageMapID }, WTFMove(area)); + return; + } + + auto& slot = m_storageAreasByConnection.add({ &connection, storageMapID }, nullptr).iterator->value; + + // FIXME: This should be a message check. + ASSERT(!slot); + + TransientLocalStorageNamespace* transientLocalStorageNamespace = getOrCreateTransientLocalStorageNamespace(storageNamespaceID, WTFMove(topLevelOriginData)); + + auto storageArea = transientLocalStorageNamespace->getOrCreateStorageArea(WTFMove(origin)); storageArea->addListener(connection, storageMapID); - result.iterator->value = storageArea.release(); + slot = WTFMove(storageArea); } -void StorageManager::createSessionStorageMap(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData& securityOriginData) +void StorageManager::createSessionStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData) { // FIXME: This should be a message check. - ASSERT((HashMap<uint64_t, RefPtr<SessionStorageNamespace>>::isValidKey(storageNamespaceID))); + ASSERT(m_sessionStorageNamespaces.isValidKey(storageNamespaceID)); + SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID); if (!sessionStorageNamespace) { // We're getting an incoming message from the web process that's for session storage for a web page @@ -470,43 +728,46 @@ void StorageManager::createSessionStorageMap(IPC::Connection* connection, uint64 return; } - std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID); - // FIXME: This should be a message check. - ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair))); + ASSERT(m_storageAreasByConnection.isValidKey({ &connection, storageMapID })); - HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::AddResult result = m_storageAreasByConnection.add(connectionAndStorageMapIDPair, nullptr); + auto& slot = m_storageAreasByConnection.add({ &connection, storageMapID }, nullptr).iterator->value; // FIXME: This should be a message check. - ASSERT(result.isNewEntry); + ASSERT(!slot); // FIXME: This should be a message check. - ASSERT(connection == sessionStorageNamespace->allowedConnection()); + ASSERT(&connection == sessionStorageNamespace->allowedConnection()); - RefPtr<StorageArea> storageArea = sessionStorageNamespace->getOrCreateStorageArea(securityOriginData.securityOrigin()); + auto storageArea = sessionStorageNamespace->getOrCreateStorageArea(WTFMove(securityOriginData)); storageArea->addListener(connection, storageMapID); - result.iterator->value = storageArea.release(); + slot = WTFMove(storageArea); } -void StorageManager::destroyStorageMap(IPC::Connection* connection, uint64_t storageMapID) +void StorageManager::destroyStorageMap(IPC::Connection& connection, uint64_t storageMapID) { - std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID); + std::pair<RefPtr<IPC::Connection>, uint64_t> connectionAndStorageMapIDPair(&connection, storageMapID); // FIXME: This should be a message check. - ASSERT((HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair))); + ASSERT(m_storageAreasByConnection.isValidKey(connectionAndStorageMapIDPair)); - HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::iterator it = m_storageAreasByConnection.find(connectionAndStorageMapIDPair); + auto it = m_storageAreasByConnection.find(connectionAndStorageMapIDPair); if (it == m_storageAreasByConnection.end()) { // The connection has been removed because the last page was closed. return; } it->value->removeListener(connection, storageMapID); + + // Don't remove session storage maps. The web process may reconnect and expect the data to still be around. + if (it->value->isSessionStorage()) + return; + m_storageAreasByConnection.remove(connectionAndStorageMapIDPair); } -void StorageManager::getValues(IPC::Connection* connection, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values) +void StorageManager::getValues(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values) { StorageArea* storageArea = findStorageArea(connection, storageMapID); if (!storageArea) { @@ -515,10 +776,10 @@ void StorageManager::getValues(IPC::Connection* connection, uint64_t storageMapI } values = storageArea->items(); - connection->send(Messages::StorageAreaMap::DidGetValues(storageMapSeed), storageMapID); + connection.send(Messages::StorageAreaMap::DidGetValues(storageMapSeed), storageMapID); } -void StorageManager::setItem(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString) +void StorageManager::setItem(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString) { StorageArea* storageArea = findStorageArea(connection, storageMapID); if (!storageArea) { @@ -527,11 +788,11 @@ void StorageManager::setItem(IPC::Connection* connection, uint64_t storageMapID, } bool quotaError; - storageArea->setItem(connection, sourceStorageAreaID, key, value, urlString, quotaError); - connection->send(Messages::StorageAreaMap::DidSetItem(storageMapSeed, key, quotaError), storageMapID); + storageArea->setItem(&connection, sourceStorageAreaID, key, value, urlString, quotaError); + connection.send(Messages::StorageAreaMap::DidSetItem(storageMapSeed, key, quotaError), storageMapID); } -void StorageManager::removeItem(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString) +void StorageManager::removeItem(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString) { StorageArea* storageArea = findStorageArea(connection, storageMapID); if (!storageArea) { @@ -539,11 +800,11 @@ void StorageManager::removeItem(IPC::Connection* connection, uint64_t storageMap return; } - storageArea->removeItem(connection, sourceStorageAreaID, key, urlString); - connection->send(Messages::StorageAreaMap::DidRemoveItem(storageMapSeed, key), storageMapID); + storageArea->removeItem(&connection, sourceStorageAreaID, key, urlString); + connection.send(Messages::StorageAreaMap::DidRemoveItem(storageMapSeed, key), storageMapID); } -void StorageManager::clear(IPC::Connection* connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString) +void StorageManager::clear(IPC::Connection& connection, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString) { StorageArea* storageArea = findStorageArea(connection, storageMapID); if (!storageArea) { @@ -551,105 +812,60 @@ void StorageManager::clear(IPC::Connection* connection, uint64_t storageMapID, u return; } - storageArea->clear(connection, sourceStorageAreaID, urlString); - connection->send(Messages::StorageAreaMap::DidClear(storageMapSeed), storageMapID); -} - -void StorageManager::createSessionStorageNamespaceInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes) -{ - ASSERT(!m_sessionStorageNamespaces.contains(storageNamespaceID)); - - m_sessionStorageNamespaces.set(storageNamespaceID, SessionStorageNamespace::create(allowedConnection, quotaInBytes)); + storageArea->clear(&connection, sourceStorageAreaID, urlString); + connection.send(Messages::StorageAreaMap::DidClear(storageMapSeed), storageMapID); } -void StorageManager::destroySessionStorageNamespaceInternal(uint64_t storageNamespaceID) +void StorageManager::applicationWillTerminate() { - ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID)); - m_sessionStorageNamespaces.remove(storageNamespaceID); -} - -void StorageManager::setAllowedSessionStorageNamespaceConnectionInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection) -{ - ASSERT(m_sessionStorageNamespaces.contains(storageNamespaceID)); - - m_sessionStorageNamespaces.get(storageNamespaceID)->setAllowedConnection(allowedConnection); -} - -void StorageManager::cloneSessionStorageNamespaceInternal(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID) -{ - SessionStorageNamespace* sessionStorageNamespace = m_sessionStorageNamespaces.get(storageNamespaceID); - ASSERT(sessionStorageNamespace); + BinarySemaphore semaphore; + m_queue->dispatch([this, &semaphore] { + Vector<std::pair<RefPtr<IPC::Connection>, uint64_t>> connectionAndStorageMapIDPairsToRemove; + for (auto& connectionStorageAreaPair : m_storageAreasByConnection) { + connectionStorageAreaPair.value->removeListener(*connectionStorageAreaPair.key.first, connectionStorageAreaPair.key.second); + connectionAndStorageMapIDPairsToRemove.append(connectionStorageAreaPair.key); + } - SessionStorageNamespace* newSessionStorageNamespace = m_sessionStorageNamespaces.get(newStorageNamespaceID); - ASSERT(newSessionStorageNamespace); + for (auto& connectionStorageAreaPair : connectionAndStorageMapIDPairsToRemove) + m_storageAreasByConnection.remove(connectionStorageAreaPair); - sessionStorageNamespace->cloneTo(*newSessionStorageNamespace); + semaphore.signal(); + }); + semaphore.wait(WallTime::infinity()); } -void StorageManager::invalidateConnectionInternal(IPC::Connection* connection) +StorageManager::StorageArea* StorageManager::findStorageArea(IPC::Connection& connection, uint64_t storageMapID) const { - Vector<std::pair<RefPtr<IPC::Connection>, uint64_t>> connectionAndStorageMapIDPairsToRemove; - HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>> storageAreasByConnection = m_storageAreasByConnection; - for (HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::const_iterator it = storageAreasByConnection.begin(), end = storageAreasByConnection.end(); it != end; ++it) { - if (it->key.first != connection) - continue; - - it->value->removeListener(it->key.first.get(), it->key.second); - connectionAndStorageMapIDPairsToRemove.append(it->key); - } - - for (size_t i = 0; i < connectionAndStorageMapIDPairsToRemove.size(); ++i) - m_storageAreasByConnection.remove(connectionAndStorageMapIDPairsToRemove[i]); -} + std::pair<IPC::Connection*, uint64_t> connectionAndStorageMapIDPair(&connection, storageMapID); -StorageManager::StorageArea* StorageManager::findStorageArea(IPC::Connection* connection, uint64_t storageMapID) const -{ - std::pair<IPC::Connection*, uint64_t> connectionAndStorageMapIDPair(connection, storageMapID); - if (!HashMap<std::pair<RefPtr<IPC::Connection>, uint64_t>, RefPtr<StorageArea>>::isValidKey(connectionAndStorageMapIDPair)) - return 0; + if (!m_storageAreasByConnection.isValidKey(connectionAndStorageMapIDPair)) + return nullptr; return m_storageAreasByConnection.get(connectionAndStorageMapIDPair); } StorageManager::LocalStorageNamespace* StorageManager::getOrCreateLocalStorageNamespace(uint64_t storageNamespaceID) { - if (!HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::isValidKey(storageNamespaceID)) - return 0; - - HashMap<uint64_t, RefPtr<LocalStorageNamespace>>::AddResult result = m_localStorageNamespaces.add(storageNamespaceID, nullptr); - if (result.isNewEntry) - result.iterator->value = LocalStorageNamespace::create(this, storageNamespaceID); - - return result.iterator->value.get(); -} + if (!m_localStorageNamespaces.isValidKey(storageNamespaceID)) + return nullptr; -static void callCallbackFunction(void* context, void (*callbackFunction)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context), Vector<RefPtr<WebCore::SecurityOrigin>>* securityOriginsPtr) -{ - OwnPtr<Vector<RefPtr<WebCore::SecurityOrigin>>> securityOrigins = adoptPtr(securityOriginsPtr); - callbackFunction(*securityOrigins, context); -} + auto& slot = m_localStorageNamespaces.add(storageNamespaceID, nullptr).iterator->value; + if (!slot) + slot = LocalStorageNamespace::create(this, storageNamespaceID); -void StorageManager::getOriginsInternal(FunctionDispatcher* dispatcher, void* context, void (*callbackFunction)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context)) -{ - OwnPtr<Vector<RefPtr<WebCore::SecurityOrigin>>> securityOrigins = adoptPtr(new Vector<RefPtr<WebCore::SecurityOrigin>>(m_localStorageDatabaseTracker->origins())); - dispatcher->dispatch(bind(callCallbackFunction, context, callbackFunction, securityOrigins.leakPtr())); + return slot.get(); } -void StorageManager::deleteEntriesForOriginInternal(SecurityOrigin* securityOrigin) +StorageManager::TransientLocalStorageNamespace* StorageManager::getOrCreateTransientLocalStorageNamespace(uint64_t storageNamespaceID, WebCore::SecurityOriginData&& topLevelOrigin) { - for (auto it = m_localStorageNamespaces.begin(), end = m_localStorageNamespaces.end(); it != end; ++it) - it->value->clearStorageAreasMatchingOrigin(securityOrigin); + if (!m_transientLocalStorageNamespaces.isValidKey({ storageNamespaceID, topLevelOrigin })) + return nullptr; - m_localStorageDatabaseTracker->deleteDatabaseWithOrigin(securityOrigin); -} - -void StorageManager::deleteAllEntriesInternal() -{ - for (auto it = m_localStorageNamespaces.begin(), end = m_localStorageNamespaces.end(); it != end; ++it) - it->value->clearAllStorageAreas(); + auto& slot = m_transientLocalStorageNamespaces.add({ storageNamespaceID, WTFMove(topLevelOrigin) }, nullptr).iterator->value; + if (!slot) + slot = TransientLocalStorageNamespace::create(); - m_localStorageDatabaseTracker->deleteAllDatabases(); + return slot.get(); } - } // namespace WebKit diff --git a/Source/WebKit2/UIProcess/Storage/StorageManager.h b/Source/WebKit2/UIProcess/Storage/StorageManager.h index 93bb66c55..52f093e01 100644 --- a/Source/WebKit2/UIProcess/Storage/StorageManager.h +++ b/Source/WebKit2/UIProcess/Storage/StorageManager.h @@ -23,87 +23,87 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef StorageManager_h -#define StorageManager_h +#pragma once #include "Connection.h" +#include "LocalStorageDatabaseTracker.h" +#include <WebCore/SecurityOriginData.h> +#include <WebCore/SecurityOriginHash.h> +#include <chrono> #include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> +#include <wtf/HashSet.h> #include <wtf/ThreadSafeRefCounted.h> #include <wtf/text/StringHash.h> -class WorkQueue; - namespace WebCore { class SecurityOrigin; } namespace WebKit { -struct SecurityOriginData; class LocalStorageDatabaseTracker; class WebProcessProxy; class StorageManager : public IPC::Connection::WorkQueueMessageReceiver { public: - static PassRefPtr<StorageManager> create(); + static Ref<StorageManager> create(const String& localStorageDirectory); ~StorageManager(); - void setLocalStorageDirectory(const String&); - - void createSessionStorageNamespace(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes); + void createSessionStorageNamespace(uint64_t storageNamespaceID, unsigned quotaInBytes); void destroySessionStorageNamespace(uint64_t storageNamespaceID); void setAllowedSessionStorageNamespaceConnection(uint64_t storageNamespaceID, IPC::Connection* allowedConnection); void cloneSessionStorageNamespace(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID); - void processWillOpenConnection(WebProcessProxy*); - void processWillCloseConnection(WebProcessProxy*); + void processWillOpenConnection(WebProcessProxy&, IPC::Connection&); + void processDidCloseConnection(WebProcessProxy&, IPC::Connection&); + void applicationWillTerminate(); + + void getSessionStorageOrigins(std::function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler); + void deleteSessionStorageOrigins(std::function<void()>&& completionHandler); + void deleteSessionStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>&, std::function<void()>&& completionHandler); + + void getLocalStorageOrigins(std::function<void(HashSet<WebCore::SecurityOriginData>&&)>&& completionHandler); + void deleteLocalStorageEntriesForOrigin(WebCore::SecurityOriginData&&); + + void deleteLocalStorageOriginsModifiedSince(std::chrono::system_clock::time_point, std::function<void()>&& completionHandler); + void deleteLocalStorageEntriesForOrigins(const Vector<WebCore::SecurityOriginData>&, std::function<void()>&& completionHandler); - // FIXME: Instead of a context + C function, this should take a WTF::Function, but we currently don't - // support arguments in functions. - void getOrigins(FunctionDispatcher* callbackDispatcher, void* context, void (*callback)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context)); - void deleteEntriesForOrigin(WebCore::SecurityOrigin*); - void deleteAllEntries(); + void getLocalStorageOriginDetails(std::function<void(Vector<LocalStorageDatabaseTracker::OriginDetails>)>&& completionHandler); private: - StorageManager(); + explicit StorageManager(const String& localStorageDirectory); // IPC::Connection::WorkQueueMessageReceiver. - virtual void didReceiveMessage(IPC::Connection*, IPC::MessageDecoder&) override; - virtual void didReceiveSyncMessage(IPC::Connection*, IPC::MessageDecoder&, std::unique_ptr<IPC::MessageEncoder>& replyEncoder) override; + void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override; + void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>& replyEncoder) override; // Message handlers. - void createLocalStorageMap(IPC::Connection*, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData&); - void createSessionStorageMap(IPC::Connection*, uint64_t storageMapID, uint64_t storageNamespaceID, const SecurityOriginData&); - void destroyStorageMap(IPC::Connection*, uint64_t storageMapID); + void createLocalStorageMap(IPC::Connection&, uint64_t storageMapID, uint64_t storageNamespaceID, WebCore::SecurityOriginData&&); + void createTransientLocalStorageMap(IPC::Connection&, uint64_t storageMapID, uint64_t storageNamespaceID, WebCore::SecurityOriginData&& topLevelOriginData, WebCore::SecurityOriginData&&); + void createSessionStorageMap(IPC::Connection&, uint64_t storageMapID, uint64_t storageNamespaceID, WebCore::SecurityOriginData&&); + void destroyStorageMap(IPC::Connection&, uint64_t storageMapID); - void getValues(IPC::Connection*, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values); - void setItem(IPC::Connection*, uint64_t storageAreaID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString); - void removeItem(IPC::Connection*, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString); - void clear(IPC::Connection*, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString); - - void createSessionStorageNamespaceInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection, unsigned quotaInBytes); - void destroySessionStorageNamespaceInternal(uint64_t storageNamespaceID); - void setAllowedSessionStorageNamespaceConnectionInternal(uint64_t storageNamespaceID, IPC::Connection* allowedConnection); - void cloneSessionStorageNamespaceInternal(uint64_t storageNamespaceID, uint64_t newStorageNamespaceID); - - void invalidateConnectionInternal(IPC::Connection*); + void getValues(IPC::Connection&, uint64_t storageMapID, uint64_t storageMapSeed, HashMap<String, String>& values); + void setItem(IPC::Connection&, uint64_t storageAreaID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString); + void removeItem(IPC::Connection&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString); + void clear(IPC::Connection&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString); class StorageArea; - StorageArea* findStorageArea(IPC::Connection*, uint64_t) const; + StorageArea* findStorageArea(IPC::Connection&, uint64_t) const; class LocalStorageNamespace; LocalStorageNamespace* getOrCreateLocalStorageNamespace(uint64_t storageNamespaceID); - void getOriginsInternal(FunctionDispatcher* callbackDispatcher, void* context, void (*callback)(const Vector<RefPtr<WebCore::SecurityOrigin>>& securityOrigins, void* context)); - void deleteEntriesForOriginInternal(WebCore::SecurityOrigin*); - void deleteAllEntriesInternal(); + class TransientLocalStorageNamespace; + TransientLocalStorageNamespace* getOrCreateTransientLocalStorageNamespace(uint64_t storageNamespaceID, WebCore::SecurityOriginData&& topLevelOrigin); - RefPtr<WorkQueue> m_queue; + Ref<WorkQueue> m_queue; - RefPtr<LocalStorageDatabaseTracker> m_localStorageDatabaseTracker; + Ref<LocalStorageDatabaseTracker> m_localStorageDatabaseTracker; HashMap<uint64_t, RefPtr<LocalStorageNamespace>> m_localStorageNamespaces; + HashMap<std::pair<uint64_t, WebCore::SecurityOriginData>, RefPtr<TransientLocalStorageNamespace>> m_transientLocalStorageNamespaces; + class SessionStorageNamespace; HashMap<uint64_t, RefPtr<SessionStorageNamespace>> m_sessionStorageNamespaces; @@ -111,5 +111,3 @@ private: }; } // namespace WebKit - -#endif // StorageManager_h diff --git a/Source/WebKit2/UIProcess/Storage/StorageManager.messages.in b/Source/WebKit2/UIProcess/Storage/StorageManager.messages.in index 59b8f3639..25789f74c 100644 --- a/Source/WebKit2/UIProcess/Storage/StorageManager.messages.in +++ b/Source/WebKit2/UIProcess/Storage/StorageManager.messages.in @@ -21,8 +21,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. messages -> StorageManager { - CreateLocalStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, WebKit::SecurityOriginData securityOriginData) WantsConnection - CreateSessionStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, WebKit::SecurityOriginData securityOriginData) WantsConnection + CreateLocalStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, struct WebCore::SecurityOriginData securityOriginData) WantsConnection + CreateTransientLocalStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, struct WebCore::SecurityOriginData topLevelSecurityOriginData, struct WebCore::SecurityOriginData securityOriginData) WantsConnection + CreateSessionStorageMap(uint64_t storageMapID, uint64_t storageNamespaceID, struct WebCore::SecurityOriginData securityOriginData) WantsConnection DestroyStorageMap(uint64_t storageMapID) WantsConnection GetValues(uint64_t storageMapID, uint64_t storageMapSeed) -> (HashMap<String, String> values) WantsConnection |