Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp (254858 => 254859)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp 2020-01-21 17:55:47 UTC (rev 254858)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp 2020-01-21 17:57:36 UTC (rev 254859)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,6 +26,7 @@
#include "config.h"
#include "StorageAreaMap.h"
+#include "Logging.h"
#include "NetworkProcessConnection.h"
#include "StorageAreaImpl.h"
#include "StorageAreaMapMessages.h"
@@ -48,18 +49,11 @@
namespace WebKit {
using namespace WebCore;
-Ref<StorageAreaMap> StorageAreaMap::create(StorageNamespaceImpl* storageNamespace, Ref<WebCore::SecurityOrigin>&& securityOrigin)
-{
- return adoptRef(*new StorageAreaMap(storageNamespace, WTFMove(securityOrigin)));
-}
-
-StorageAreaMap::StorageAreaMap(StorageNamespaceImpl* storageNamespace, Ref<WebCore::SecurityOrigin>&& securityOrigin)
- : m_storageNamespace(storageNamespace)
- , m_storageType(storageNamespace->storageType())
- , m_quotaInBytes(storageNamespace->quotaInBytes())
+StorageAreaMap::StorageAreaMap(StorageNamespaceImpl& storageNamespace, Ref<WebCore::SecurityOrigin>&& securityOrigin)
+ : m_namespace(storageNamespace)
, m_securityOrigin(WTFMove(securityOrigin))
- , m_currentSeed(0)
- , m_hasPendingClear(false)
+ , m_quotaInBytes(storageNamespace.quotaInBytes())
+ , m_type(storageNamespace.storageType())
{
connect();
}
@@ -71,34 +65,27 @@
unsigned StorageAreaMap::length()
{
- loadValuesIfNeeded();
-
- return m_storageMap->length();
+ return ensureMap().length();
}
String StorageAreaMap::key(unsigned index)
{
- loadValuesIfNeeded();
-
- return m_storageMap->key(index);
+ return ensureMap().key(index);
}
String StorageAreaMap::item(const String& key)
{
- loadValuesIfNeeded();
-
- return m_storageMap->getItem(key);
+ return ensureMap().getItem(key);
}
void StorageAreaMap::setItem(Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException)
{
- loadValuesIfNeeded();
+ auto& map = ensureMap();
+ ASSERT(map.hasOneRef());
- ASSERT(m_storageMap->hasOneRef());
-
String oldValue;
quotaException = false;
- m_storageMap->setItem(key, value, oldValue, quotaException);
+ map.setItem(key, value, oldValue, quotaException);
if (quotaException)
return;
@@ -107,19 +94,19 @@
m_pendingValueChanges.add(key);
- if (m_storageMapID)
- WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::SetItem(*m_storageMapID, sourceArea->identifier(), m_currentSeed, key, value, sourceFrame->document()->url()), 0);
+ if (m_mapID)
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::SetItem(*m_mapID, sourceArea->identifier(), m_currentSeed, key, value, sourceFrame->document()->url()), 0);
else
- LOG_ERROR("StorageAreaMap::setItem fails because storage map ID is invalid");
+ RELEASE_LOG_ERROR(Storage, "StorageAreaMap::setItem failed because storage map ID is invalid");
}
void StorageAreaMap::removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key)
{
- loadValuesIfNeeded();
- ASSERT(m_storageMap->hasOneRef());
+ auto& map = ensureMap();
+ ASSERT(map.hasOneRef());
String oldValue;
- m_storageMap->removeItem(key, oldValue);
+ map.removeItem(key, oldValue);
if (oldValue.isNull())
return;
@@ -126,10 +113,10 @@
m_pendingValueChanges.add(key);
- if (m_storageMapID)
- WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::RemoveItem(*m_storageMapID, sourceArea->identifier(), m_currentSeed, key, sourceFrame->document()->url()), 0);
+ if (m_mapID)
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::RemoveItem(*m_mapID, sourceArea->identifier(), m_currentSeed, key, sourceFrame->document()->url()), 0);
else
- LOG_ERROR("StorageAreaMap::removeItem fails because storage map ID is invalid");
+ RELEASE_LOG_ERROR(Storage, "StorageAreaMap::removeItem failed because storage map ID is invalid");
}
void StorageAreaMap::clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea)
@@ -139,54 +126,51 @@
resetValues();
m_hasPendingClear = true;
- m_storageMap = StorageMap::create(m_quotaInBytes);
+ m_map = StorageMap::create(m_quotaInBytes);
- if (m_storageMapID)
- WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::Clear(*m_storageMapID, sourceArea->identifier(), m_currentSeed, sourceFrame->document()->url()), 0);
+ if (m_mapID)
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::StorageManagerSet::Clear(*m_mapID, sourceArea->identifier(), m_currentSeed, sourceFrame->document()->url()), 0);
else
- LOG_ERROR("StorageAreaMap::removeItem fails because storage map ID is invalid");
+ RELEASE_LOG_ERROR(Storage, "StorageAreaMap::clear failed because storage map ID is invalid");
}
bool StorageAreaMap::contains(const String& key)
{
- loadValuesIfNeeded();
-
- return m_storageMap->contains(key);
+ return ensureMap().contains(key);
}
void StorageAreaMap::resetValues()
{
- m_storageMap = nullptr;
+ m_map = nullptr;
m_pendingValueChanges.clear();
m_hasPendingClear = false;
- m_currentSeed++;
+ ++m_currentSeed;
}
-void StorageAreaMap::loadValuesIfNeeded()
+StorageMap& StorageAreaMap::ensureMap()
{
connect();
- if (m_storageMap)
- return;
+ if (!m_map) {
+ m_map = StorageMap::create(m_quotaInBytes);
- HashMap<String, String> values;
-
- if (m_storageMapID) {
- // The StorageManagerSet::GetValues() IPC may be very slow because it may need to fetch the values from disk and there may be a lot
- // of data.
- IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::GetValues(*m_storageMapID), Messages::StorageManagerSet::GetValues::Reply(values), 0);
- } else
- LOG_ERROR("StorageAreaMap::loadValuesIfNeeded fails to load from network process because storage map ID is invalid");
-
- m_storageMap = StorageMap::create(m_quotaInBytes);
- m_storageMap->importItems(WTFMove(values));
+ if (m_mapID) {
+ // We need to use a IPC::UnboundedSynchronousIPCScope to prevent UIProcess hangs in case we receive a synchronous IPC from the UIProcess while we're waiting for a response
+ // from our StorageManagerSet::GetValues() IPC. This IPC may be very slow because it may need to fetch the values from disk and there may be a lot of data.
+ IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope;
+ HashMap<String, String> values;
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::GetValues(*m_mapID), Messages::StorageManagerSet::GetValues::Reply(values), 0);
+ m_map->importItems(WTFMove(values));
+ } else
+ RELEASE_LOG_ERROR(Storage, "StorageAreaMap::ensureMap failed to load from network process because storage map ID is invalid");
+ }
+ return *m_map;
}
-void StorageAreaMap::didSetItem(uint64_t storageMapSeed, const String& key, bool quotaError)
+void StorageAreaMap::didSetItem(uint64_t mapSeed, const String& key, bool quotaError)
{
- if (m_currentSeed != storageMapSeed)
+ if (m_currentSeed != mapSeed)
return;
ASSERT(m_pendingValueChanges.contains(key));
@@ -199,9 +183,9 @@
m_pendingValueChanges.remove(key);
}
-void StorageAreaMap::didRemoveItem(uint64_t storageMapSeed, const String& key)
+void StorageAreaMap::didRemoveItem(uint64_t mapSeed, const String& key)
{
- if (m_currentSeed != storageMapSeed)
+ if (m_currentSeed != mapSeed)
return;
ASSERT(m_pendingValueChanges.contains(key));
@@ -208,9 +192,9 @@
m_pendingValueChanges.remove(key);
}
-void StorageAreaMap::didClear(uint64_t storageMapSeed)
+void StorageAreaMap::didClear(uint64_t mapSeed)
{
- if (m_currentSeed != storageMapSeed)
+ if (m_currentSeed != mapSeed)
return;
ASSERT(m_hasPendingClear);
@@ -220,7 +204,7 @@
bool StorageAreaMap::shouldApplyChangeForKey(const String& key) const
{
// We have not yet loaded anything from this storage map.
- if (!m_storageMap)
+ if (!m_map)
return false;
// Check if this storage area is currently waiting for the storage manager to update the given key.
@@ -234,7 +218,7 @@
void StorageAreaMap::applyChange(const String& key, const String& newValue)
{
- ASSERT(!m_storageMap || m_storageMap->hasOneRef());
+ ASSERT(!m_map || m_map->hasOneRef());
// There is at least one clear pending we don't want to apply any changes until we get the corresponding DidClear messages.
if (m_hasPendingClear)
@@ -242,13 +226,12 @@
if (!key) {
// A null key means clear.
- auto newStorageMap = StorageMap::create(m_quotaInBytes);
+ auto newMap = StorageMap::create(m_quotaInBytes);
// Any changes that were made locally after the clear must still be kept around in the new map.
- for (auto it = m_pendingValueChanges.begin().keys(), end = m_pendingValueChanges.end().keys(); it != end; ++it) {
- const String& key = *it;
-
- String value = m_storageMap->getItem(key);
+ for (auto& change : m_pendingValueChanges) {
+ auto& key = change.key;
+ String value = m_map->getItem(key);
if (!value) {
// This change must have been a pending remove, ignore it.
continue;
@@ -255,10 +238,10 @@
}
String oldValue;
- newStorageMap->setItemIgnoringQuota(key, oldValue);
+ newMap->setItemIgnoringQuota(key, oldValue);
}
- m_storageMap = WTFMove(newStorageMap);
+ m_map = WTFMove(newMap);
return;
}
@@ -268,11 +251,11 @@
if (!newValue) {
// A null new value means that the item should be removed.
String oldValue;
- m_storageMap->removeItem(key, oldValue);
+ m_map->removeItem(key, oldValue);
return;
}
- m_storageMap->setItemIgnoringQuota(key, newValue);
+ m_map->setItemIgnoringQuota(key, newValue);
}
void StorageAreaMap::dispatchStorageEvent(const Optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
@@ -282,7 +265,7 @@
applyChange(key, newValue);
}
- if (storageType() == StorageType::Session)
+ if (type() == StorageType::Session)
dispatchSessionStorageEvent(storageAreaImplID, key, oldValue, newValue, urlString);
else
dispatchLocalStorageEvent(storageAreaImplID, key, oldValue, newValue, urlString);
@@ -293,103 +276,92 @@
resetValues();
}
+static Vector<RefPtr<Frame>> framesForEventDispatching(Page& page, SecurityOrigin& origin, const Optional<StorageAreaImplIdentifier>& storageAreaImplID)
+{
+ Vector<RefPtr<Frame>> frames;
+ page.forEachDocument([&](auto& document) {
+ if (!document.securityOrigin().equal(&origin))
+ return;
+
+ auto* storage = document.domWindow() ? document.domWindow()->optionalSessionStorage() : nullptr;
+ if (!storage)
+ return;
+
+ auto& storageArea = static_cast<StorageAreaImpl&>(storage->area());
+ if (storageArea.identifier() == storageAreaImplID) {
+ // This is the storage area that caused the event to be dispatched.
+ return;
+ }
+
+ if (auto* frame = document.frame())
+ frames.append(frame);
+ });
+ return frames;
+}
+
void StorageAreaMap::dispatchSessionStorageEvent(const Optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
{
// Namespace IDs for session storage namespaces are equivalent to web page IDs
// so we can get the right page here.
- WebPage* webPage = WebProcess::singleton().webPage(m_storageNamespace->sessionStoragePageID());
+ auto* webPage = WebProcess::singleton().webPage(m_namespace.sessionStoragePageID());
if (!webPage)
return;
- Vector<RefPtr<Frame>> frames;
+ auto* page = webPage->corePage();
+ if (!page)
+ return;
- Page* page = webPage->corePage();
- for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- Document* document = frame->document();
- if (!document->securityOrigin().equal(m_securityOrigin.ptr()))
- continue;
-
- Storage* storage = document->domWindow()->optionalSessionStorage();
- if (!storage)
- continue;
-
- StorageAreaImpl& storageArea = static_cast<StorageAreaImpl&>(storage->area());
- if (storageArea.identifier() == storageAreaImplID) {
- // This is the storage area that caused the event to be dispatched.
- continue;
- }
-
- frames.append(frame);
- }
-
+ auto frames = framesForEventDispatching(*page, m_securityOrigin, storageAreaImplID);
StorageEventDispatcher::dispatchSessionStorageEventsToFrames(*page, frames, key, oldValue, newValue, urlString, m_securityOrigin->data());
}
void StorageAreaMap::dispatchLocalStorageEvent(const Optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
{
- ASSERT(isLocalStorage(storageType()));
+ ASSERT(isLocalStorage(type()));
Vector<RefPtr<Frame>> frames;
// Namespace IDs for local storage namespaces are equivalent to web page group IDs.
- PageGroup& pageGroup = *WebProcess::singleton().webPageGroup(m_storageNamespace->pageGroupID())->corePageGroup();
- const HashSet<Page*>& pages = pageGroup.pages();
- for (HashSet<Page*>::const_iterator it = pages.begin(), end = pages.end(); it != end; ++it) {
- for (Frame* frame = &(*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
- Document* document = frame->document();
- if (!document->securityOrigin().equal(m_securityOrigin.ptr()))
- continue;
+ auto& pageGroup = *WebProcess::singleton().webPageGroup(m_namespace.pageGroupID())->corePageGroup();
+ for (auto* page : pageGroup.pages())
+ frames.appendVector(framesForEventDispatching(*page, m_securityOrigin, storageAreaImplID));
- Storage* storage = document->domWindow()->optionalLocalStorage();
- if (!storage)
- continue;
-
- StorageAreaImpl& storageArea = static_cast<StorageAreaImpl&>(storage->area());
- if (storageArea.identifier() == storageAreaImplID) {
- // This is the storage area that caused the event to be dispatched.
- continue;
- }
-
- frames.append(frame);
- }
- }
-
StorageEventDispatcher::dispatchLocalStorageEventsToFrames(pageGroup, frames, key, oldValue, newValue, urlString, m_securityOrigin->data());
}
void StorageAreaMap::connect()
{
- if (m_storageMapID)
+ if (m_mapID)
return;
- switch (m_storageType) {
+ switch (m_type) {
case StorageType::Local:
case StorageType::TransientLocal:
- if (SecurityOrigin* topLevelOrigin = m_storageNamespace->topLevelOrigin())
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToTransientLocalStorageArea(WebProcess::singleton().sessionID(), m_storageNamespace->storageNamespaceID(), topLevelOrigin->data(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToTransientLocalStorageArea::Reply(m_storageMapID), 0);
+ if (SecurityOrigin* topLevelOrigin = m_namespace.topLevelOrigin())
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToTransientLocalStorageArea(WebProcess::singleton().sessionID(), m_namespace.storageNamespaceID(), topLevelOrigin->data(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToTransientLocalStorageArea::Reply(m_mapID), 0);
else
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToLocalStorageArea(WebProcess::singleton().sessionID(), m_storageNamespace->storageNamespaceID(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToLocalStorageArea::Reply(m_storageMapID), 0);
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToLocalStorageArea(WebProcess::singleton().sessionID(), m_namespace.storageNamespaceID(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToLocalStorageArea::Reply(m_mapID), 0);
break;
case StorageType::Session:
- WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToSessionStorageArea(WebProcess::singleton().sessionID(), m_storageNamespace->storageNamespaceID(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToSessionStorageArea::Reply(m_storageMapID), 0);
+ WebProcess::singleton().ensureNetworkProcessConnection().connection().sendSync(Messages::StorageManagerSet::ConnectToSessionStorageArea(WebProcess::singleton().sessionID(), m_namespace.storageNamespaceID(), m_securityOrigin->data()), Messages::StorageManagerSet::ConnectToSessionStorageArea::Reply(m_mapID), 0);
}
- if (m_storageMapID)
+ if (m_mapID)
WebProcess::singleton().registerStorageAreaMap(*this);
}
void StorageAreaMap::disconnect()
{
- if (!m_storageMapID)
+ if (!m_mapID)
return;
resetValues();
WebProcess::singleton().unregisterStorageAreaMap(*this);
- if (auto networkProcessConnection = WebProcess::singleton().existingNetworkProcessConnection())
- networkProcessConnection->connection().send(Messages::StorageManagerSet::DisconnectFromStorageArea(*m_storageMapID), 0);
+ if (auto* networkProcessConnection = WebProcess::singleton().existingNetworkProcessConnection())
+ networkProcessConnection->connection().send(Messages::StorageManagerSet::DisconnectFromStorageArea(*m_mapID), 0);
- m_storageMapID = { };
+ m_mapID = { };
}
} // namespace WebKit
Modified: trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h (254858 => 254859)
--- trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h 2020-01-21 17:55:47 UTC (rev 254858)
+++ trunk/Source/WebKit/WebProcess/WebStorage/StorageAreaMap.h 2020-01-21 17:57:36 UTC (rev 254859)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -46,12 +46,13 @@
class StorageAreaImpl;
class StorageNamespaceImpl;
-class StorageAreaMap : public RefCounted<StorageAreaMap>, private IPC::MessageReceiver, public CanMakeWeakPtr<StorageAreaMap> {
+class StorageAreaMap final : private IPC::MessageReceiver, public CanMakeWeakPtr<StorageAreaMap> {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- static Ref<StorageAreaMap> create(StorageNamespaceImpl*, Ref<WebCore::SecurityOrigin>&&);
+ StorageAreaMap(StorageNamespaceImpl&, Ref<WebCore::SecurityOrigin>&&);
~StorageAreaMap();
- WebCore::StorageType storageType() const { return m_storageType; }
+ WebCore::StorageType type() const { return m_type; }
unsigned length();
String key(unsigned index);
@@ -62,26 +63,23 @@
bool contains(const String& key);
// IPC::MessageReceiver
- void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
+ void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
const WebCore::SecurityOrigin& securityOrigin() const { return m_securityOrigin.get(); }
+ const Optional<StorageAreaIdentifier>& identifier() const { return m_mapID; }
- void connect();
void disconnect();
- const Optional<StorageAreaIdentifier>& identifier() const { return m_storageMapID; }
private:
- StorageAreaMap(StorageNamespaceImpl*, Ref<WebCore::SecurityOrigin>&&);
+ void didSetItem(uint64_t mapSeed, const String& key, bool quotaError);
+ void didRemoveItem(uint64_t mapSeed, const String& key);
+ void didClear(uint64_t mapSeed);
- void didSetItem(uint64_t storageMapSeed, const String& key, bool quotaError);
- void didRemoveItem(uint64_t storageMapSeed, const String& key);
- void didClear(uint64_t storageMapSeed);
-
void dispatchStorageEvent(const Optional<StorageAreaImplIdentifier>& sourceStorageAreaID, const String& key, const String& oldValue, const String& newValue, const String& urlString);
void clearCache();
void resetValues();
- void loadValuesIfNeeded();
+ WebCore::StorageMap& ensureMap();
bool shouldApplyChangeForKey(const String& key) const;
void applyChange(const String& key, const String& newValue);
@@ -89,19 +87,17 @@
void dispatchSessionStorageEvent(const Optional<StorageAreaImplIdentifier>&, const String& key, const String& oldValue, const String& newValue, const String& urlString);
void dispatchLocalStorageEvent(const Optional<StorageAreaImplIdentifier>&, const String& key, const String& oldValue, const String& newValue, const String& urlString);
- StorageNamespaceImpl* m_storageNamespace;
+ void connect();
- Optional<StorageAreaIdentifier> m_storageMapID;
-
- WebCore::StorageType m_storageType;
- unsigned m_quotaInBytes;
+ StorageNamespaceImpl& m_namespace;
Ref<WebCore::SecurityOrigin> m_securityOrigin;
-
- RefPtr<WebCore::StorageMap> m_storageMap;
-
- uint64_t m_currentSeed;
- bool m_hasPendingClear;
+ RefPtr<WebCore::StorageMap> m_map;
+ Optional<StorageAreaIdentifier> m_mapID;
HashCountedSet<String> m_pendingValueChanges;
+ uint64_t m_currentSeed { 0 };
+ unsigned m_quotaInBytes;
+ WebCore::StorageType m_type;
+ bool m_hasPendingClear { false };
};
} // namespace WebKit