diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/Storage/StorageManager.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/Storage/StorageManager.cpp | 612 |
1 files changed, 414 insertions, 198 deletions
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 |