Move ephemeral local storage from WebProcess to UIProcess
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Feb 2019 04:40:48 +0000 (04:40 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 27 Feb 2019 04:40:48 +0000 (04:40 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195074
<rdar://problem/47937975>

Reviewed by Geoff Garen.

Source/WebKit:

Before PSON, a page could navigate to another domain that navigates back and still have its local storage.
Since PSON makes it unreliable to retain the state in the WebProcess, move it to the process with the rest of the local storage.
If it's ephemeral, we obviously can't use the SQLite on-disk storage implementation, so use the same WebCore::StorageMap we used to in the WebProcess.

* UIProcess/WebStorage/StorageManager.cpp:
(WebKit::StorageManager::LocalStorageNamespace::LocalStorageNamespace):
(WebKit::StorageManager::StorageManager):
(WebKit::StorageManager::createLocalStorageMap):
(WebKit::StorageManager::createTransientLocalStorageMap):
(WebKit::StorageManager::createSessionStorageMap):
(WebKit::StorageManager::destroyStorageMap):
(WebKit::StorageManager::getValues):
(WebKit::StorageManager::setItem):
(WebKit::StorageManager::removeItem):
(WebKit::StorageManager::clear):
* UIProcess/WebStorage/StorageManager.h:
* UIProcess/WebStorage/StorageManager.messages.in:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::WebsiteDataStore):
* WebProcess/WebStorage/StorageAreaMap.cpp:
(WebKit::StorageAreaMap::StorageAreaMap):
(WebKit::StorageAreaMap::setItem):
(WebKit::StorageAreaMap::removeItem):
(WebKit::StorageAreaMap::clear):
(WebKit::StorageAreaMap::loadValuesIfNeeded):
* WebProcess/WebStorage/StorageNamespaceImpl.cpp:
(WebKit::StorageNamespaceImpl::createEphemeralLocalStorageNamespace):
(WebKit::StorageNamespaceImpl::storageArea):
(WebKit::StorageNamespaceImpl::copy):
(): Deleted.
(WebKit::StorageNamespaceImpl::ephemeralLocalStorageArea): Deleted.
* WebProcess/WebStorage/StorageNamespaceImpl.h:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242122 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/UIProcess/WebStorage/LocalStorageDatabaseTracker.cpp
Source/WebKit/UIProcess/WebStorage/StorageManager.cpp
Source/WebKit/UIProcess/WebStorage/StorageManager.h
Source/WebKit/UIProcess/WebStorage/StorageManager.messages.in
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Source/WebKit/WebProcess/WebStorage/StorageAreaMap.cpp
Source/WebKit/WebProcess/WebStorage/StorageNamespaceImpl.cpp
Source/WebKit/WebProcess/WebStorage/StorageNamespaceImpl.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

index 9df5642..6811441 100644 (file)
@@ -1,3 +1,44 @@
+2019-02-26  Alex Christensen  <achristensen@webkit.org>
+
+        Move ephemeral local storage from WebProcess to UIProcess
+        https://bugs.webkit.org/show_bug.cgi?id=195074
+        <rdar://problem/47937975>
+
+        Reviewed by Geoff Garen.
+
+        Before PSON, a page could navigate to another domain that navigates back and still have its local storage.
+        Since PSON makes it unreliable to retain the state in the WebProcess, move it to the process with the rest of the local storage.
+        If it's ephemeral, we obviously can't use the SQLite on-disk storage implementation, so use the same WebCore::StorageMap we used to in the WebProcess.
+
+        * UIProcess/WebStorage/StorageManager.cpp:
+        (WebKit::StorageManager::LocalStorageNamespace::LocalStorageNamespace):
+        (WebKit::StorageManager::StorageManager):
+        (WebKit::StorageManager::createLocalStorageMap):
+        (WebKit::StorageManager::createTransientLocalStorageMap):
+        (WebKit::StorageManager::createSessionStorageMap):
+        (WebKit::StorageManager::destroyStorageMap):
+        (WebKit::StorageManager::getValues):
+        (WebKit::StorageManager::setItem):
+        (WebKit::StorageManager::removeItem):
+        (WebKit::StorageManager::clear):
+        * UIProcess/WebStorage/StorageManager.h:
+        * UIProcess/WebStorage/StorageManager.messages.in:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::WebsiteDataStore):
+        * WebProcess/WebStorage/StorageAreaMap.cpp:
+        (WebKit::StorageAreaMap::StorageAreaMap):
+        (WebKit::StorageAreaMap::setItem):
+        (WebKit::StorageAreaMap::removeItem):
+        (WebKit::StorageAreaMap::clear):
+        (WebKit::StorageAreaMap::loadValuesIfNeeded):
+        * WebProcess/WebStorage/StorageNamespaceImpl.cpp:
+        (WebKit::StorageNamespaceImpl::createEphemeralLocalStorageNamespace):
+        (WebKit::StorageNamespaceImpl::storageArea):
+        (WebKit::StorageNamespaceImpl::copy):
+        (): Deleted.
+        (WebKit::StorageNamespaceImpl::ephemeralLocalStorageArea): Deleted.
+        * WebProcess/WebStorage/StorageNamespaceImpl.h:
+
 2019-02-20  Jer Noble  <jer.noble@apple.com>
 
         [Cocoa] Media elements will restart network buffering just before suspending
index c3781df..b77fb50 100644 (file)
@@ -48,8 +48,6 @@ LocalStorageDatabaseTracker::LocalStorageDatabaseTracker(Ref<WorkQueue>&& queue,
     : 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();
 
index 81973ca..bed23b0 100644 (file)
@@ -107,6 +107,9 @@ private:
     HashMap<SecurityOriginData, StorageArea*> m_storageAreaMap;
 };
 
+// Suggested by https://www.w3.org/TR/webstorage/#disk-space
+const unsigned localStorageDatabaseQuotaInBytes = 5 * 1024 * 1024;
+
 class StorageManager::TransientLocalStorageNamespace : public ThreadSafeRefCounted<TransientLocalStorageNamespace> {
 public:
     static Ref<TransientLocalStorageNamespace> create()
@@ -156,7 +159,7 @@ private:
     {
     }
 
-    const unsigned m_quotaInBytes = 5 * 1024 * 1024;
+    const unsigned m_quotaInBytes = localStorageDatabaseQuotaInBytes;
 
     HashMap<SecurityOriginData, RefPtr<StorageArea>> m_storageAreaMap;
 };
@@ -326,7 +329,7 @@ Ref<StorageManager::LocalStorageNamespace> StorageManager::LocalStorageNamespace
 StorageManager::LocalStorageNamespace::LocalStorageNamespace(StorageManager* storageManager, uint64_t storageNamespaceID)
     : m_storageManager(storageManager)
     , m_storageNamespaceID(storageNamespaceID)
-    , m_quotaInBytes(5 * 1024 * 1024)
+    , m_quotaInBytes(localStorageDatabaseQuotaInBytes)
 {
 }
 
@@ -464,6 +467,7 @@ Ref<StorageManager> StorageManager::create(const String& localStorageDirectory)
 StorageManager::StorageManager(const String& localStorageDirectory)
     : m_queue(WorkQueue::create("com.apple.WebKit.StorageManager"))
     , m_localStorageDatabaseTracker(LocalStorageDatabaseTracker::create(m_queue.copyRef(), localStorageDirectory))
+    , m_isEphemeral(localStorageDirectory.isNull())
 {
     // Make sure the encoding is initialized before we start dispatching things to the queue.
     UTF8Encoding();
@@ -673,6 +677,7 @@ void StorageManager::deleteLocalStorageEntriesForOrigins(const Vector<WebCore::S
 
 void StorageManager::createLocalStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData)
 {
+    ASSERT(!m_isEphemeral);
     std::pair<IPC::Connection::UniqueID, uint64_t> connectionAndStorageMapIDPair(connection.uniqueID(), storageMapID);
 
     // FIXME: This should be a message check.
@@ -736,6 +741,10 @@ void StorageManager::createTransientLocalStorageMap(IPC::Connection& connection,
 
 void StorageManager::createSessionStorageMap(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageNamespaceID, SecurityOriginData&& securityOriginData)
 {
+    if (m_isEphemeral) {
+        m_ephemeralStorage.add(securityOriginData, WebCore::StorageMap::create(localStorageDatabaseQuotaInBytes));
+        return;
+    }
     // FIXME: This should be a message check.
     ASSERT(m_sessionStorageNamespaces.isValidKey(storageNamespaceID));
 
@@ -785,10 +794,14 @@ void StorageManager::destroyStorageMap(IPC::Connection& connection, uint64_t sto
     m_storageAreasByConnection.remove(connectionAndStorageMapIDPair);
 }
 
-void StorageManager::getValues(IPC::Connection& connection, uint64_t storageMapID, uint64_t storageMapSeed, CompletionHandler<void(const HashMap<String, String>&)>&& completionHandler)
+void StorageManager::getValues(IPC::Connection& connection, WebCore::SecurityOriginData&& securityOriginData, uint64_t storageMapID, uint64_t storageMapSeed, CompletionHandler<void(const HashMap<String, String>&)>&& completionHandler)
 {
     StorageArea* storageArea = findStorageArea(connection, storageMapID);
     if (!storageArea) {
+        if (m_isEphemeral) {
+            if (auto storageMap = m_ephemeralStorage.get(securityOriginData))
+                return completionHandler(storageMap->items());
+        }
         // This is a session storage area for a page that has already been closed. Ignore it.
         return completionHandler({ });
     }
@@ -797,10 +810,17 @@ void StorageManager::getValues(IPC::Connection& connection, uint64_t storageMapI
     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, WebCore::SecurityOriginData&& securityOriginData, 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) {
+        if (m_isEphemeral) {
+            if (auto storageMap = m_ephemeralStorage.get(securityOriginData)) {
+                String oldValue;
+                bool quotaException;
+                storageMap->setItem(key, value, oldValue, quotaException);
+            }
+        }
         // This is a session storage area for a page that has already been closed. Ignore it.
         return;
     }
@@ -810,10 +830,16 @@ void StorageManager::setItem(IPC::Connection& connection, uint64_t storageMapID,
     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, WebCore::SecurityOriginData&& securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString)
 {
     StorageArea* storageArea = findStorageArea(connection, storageMapID);
     if (!storageArea) {
+        if (m_isEphemeral) {
+            if (auto storageMap = m_ephemeralStorage.get(securityOriginData)) {
+                String oldValue;
+                storageMap->removeItem(key, oldValue);
+            }
+        }
         // This is a session storage area for a page that has already been closed. Ignore it.
         return;
     }
@@ -822,10 +848,12 @@ void StorageManager::removeItem(IPC::Connection& connection, uint64_t storageMap
     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, WebCore::SecurityOriginData&& securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString)
 {
     StorageArea* storageArea = findStorageArea(connection, storageMapID);
     if (!storageArea) {
+        if (m_isEphemeral)
+            m_ephemeralStorage.remove(securityOriginData);
         // This is a session storage area for a page that has already been closed. Ignore it.
         return;
     }
index 1c1c7f7..3866ff9 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "Connection.h"
 #include "LocalStorageDatabaseTracker.h"
+#include <WebCore/SecurityOriginData.h>
+#include <WebCore/StorageMap.h>
 #include <wtf/Forward.h>
 #include <wtf/Function.h>
 #include <wtf/HashSet.h>
@@ -81,10 +83,10 @@ private:
     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, CompletionHandler<void(const HashMap<String, String>&)>&&);
-    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 getValues(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t storageMapSeed, CompletionHandler<void(const HashMap<String, String>&)>&&);
+    void setItem(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageAreaID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& value, const String& urlString);
+    void removeItem(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& key, const String& urlString);
+    void clear(IPC::Connection&, WebCore::SecurityOriginData&&, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, const String& urlString);
 
     class StorageArea;
     StorageArea* findStorageArea(IPC::Connection&, uint64_t) const;
@@ -106,6 +108,9 @@ private:
     HashMap<uint64_t, RefPtr<SessionStorageNamespace>> m_sessionStorageNamespaces;
 
     HashMap<std::pair<IPC::Connection::UniqueID, uint64_t>, RefPtr<StorageArea>> m_storageAreasByConnection;
+
+    HashMap<WebCore::SecurityOriginData, Ref<WebCore::StorageMap>> m_ephemeralStorage;
+    bool m_isEphemeral { false };
 };
 
 } // namespace WebKit
index 58cbcfb..efef369 100644 (file)
@@ -26,9 +26,9 @@ messages -> StorageManager {
     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) Delayed WantsConnection
+    GetValues(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t storageMapSeed) -> (HashMap<String, String> values) Delayed WantsConnection
 
-    SetItem(uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String key, String value, String urlString) WantsConnection
-    RemoveItem(uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String key, String urlString) WantsConnection
-    Clear(uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String urlString) WantsConnection
+    SetItem(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String key, String value, String urlString) WantsConnection
+    RemoveItem(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String key, String urlString) WantsConnection
+    Clear(struct WebCore::SecurityOriginData securityOriginData, uint64_t storageMapID, uint64_t sourceStorageAreaID, uint64_t storageMapSeed, String urlString) WantsConnection
 }
index 94bd327..ab17dfa 100644 (file)
@@ -117,6 +117,7 @@ WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
     : m_sessionID(sessionID)
     , m_resolvedConfiguration(WebsiteDataStoreConfiguration::create())
     , m_configuration(m_resolvedConfiguration->copy())
+    , m_storageManager(StorageManager::create({ }))
     , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create(isPersistent() ? m_configuration->deviceIdHashSaltsStorageDirectory() : String()))
     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
 #if ENABLE(WEB_AUTHN)
index ac9ea6f..c3176c7 100644 (file)
@@ -84,7 +84,7 @@ StorageAreaMap::StorageAreaMap(StorageNamespaceImpl* storageNamespace, Ref<WebCo
         break;
 
     case StorageType::EphemeralLocal:
-        // The UI process is not involved for EphemeralLocal storages.
+        ASSERT_NOT_REACHED();
         return;
     }
 
@@ -139,7 +139,7 @@ void StorageAreaMap::setItem(Frame* sourceFrame, StorageAreaImpl* sourceArea, co
 
     m_pendingValueChanges.add(key);
 
-    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::SetItem(m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, key, value, sourceFrame->document()->url()), 0);
+    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::SetItem(m_securityOrigin->data(), m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, key, value, sourceFrame->document()->url()), 0);
 }
 
 void StorageAreaMap::removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key)
@@ -155,7 +155,7 @@ void StorageAreaMap::removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* so
 
     m_pendingValueChanges.add(key);
 
-    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::RemoveItem(m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, key, sourceFrame->document()->url()), 0);
+    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::RemoveItem(m_securityOrigin->data(), m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, key, sourceFrame->document()->url()), 0);
 }
 
 void StorageAreaMap::clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea)
@@ -164,7 +164,7 @@ void StorageAreaMap::clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceA
 
     m_hasPendingClear = true;
     m_storageMap = StorageMap::create(m_quotaInBytes);
-    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::Clear(m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, sourceFrame->document()->url()), 0);
+    WebProcess::singleton().parentProcessConnection()->send(Messages::StorageManager::Clear(m_securityOrigin->data(), m_storageMapID, sourceArea->storageAreaID(), m_currentSeed, sourceFrame->document()->url()), 0);
 }
 
 bool StorageAreaMap::contains(const String& key)
@@ -193,7 +193,7 @@ void StorageAreaMap::loadValuesIfNeeded()
     // FIXME: This should use a special sendSync flag to indicate that we don't want to process incoming messages while waiting for a reply.
     // (This flag does not yet exist). Since loadValuesIfNeeded() ends up being called from within JavaScript code, processing incoming synchronous messages
     // could lead to weird reentrency bugs otherwise.
-    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::StorageManager::GetValues(m_storageMapID, m_currentSeed), Messages::StorageManager::GetValues::Reply(values), 0);
+    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::StorageManager::GetValues(m_securityOrigin->data(), m_storageMapID, m_currentSeed), Messages::StorageManager::GetValues::Reply(values), 0);
 
     m_storageMap = StorageMap::create(m_quotaInBytes);
     m_storageMap->importItems(values);
index 2639945..7ba5f55 100644 (file)
@@ -47,7 +47,7 @@ Ref<StorageNamespaceImpl> StorageNamespaceImpl::createSessionStorageNamespace(ui
 
 Ref<StorageNamespaceImpl> StorageNamespaceImpl::createEphemeralLocalStorageNamespace(uint64_t identifier, unsigned quotaInBytes)
 {
-    return adoptRef(*new StorageNamespaceImpl(StorageType::EphemeralLocal, identifier, nullptr, quotaInBytes));
+    return createSessionStorageNamespace(identifier, quotaInBytes);
 }
 
 Ref<StorageNamespaceImpl> StorageNamespaceImpl::createLocalStorageNamespace(uint64_t identifier, unsigned quotaInBytes)
@@ -79,9 +79,6 @@ void StorageNamespaceImpl::didDestroyStorageAreaMap(StorageAreaMap& map)
 
 Ref<StorageArea> StorageNamespaceImpl::storageArea(const SecurityOriginData& securityOrigin)
 {
-    if (m_storageType == StorageType::EphemeralLocal)
-        return ephemeralLocalStorageArea(securityOrigin);
-
     RefPtr<StorageAreaMap> map;
 
     auto& slot = m_storageAreaMaps.add(securityOrigin, nullptr).iterator->value;
@@ -94,106 +91,6 @@ Ref<StorageArea> StorageNamespaceImpl::storageArea(const SecurityOriginData& sec
     return StorageAreaImpl::create(map.releaseNonNull());
 }
 
-class StorageNamespaceImpl::EphemeralStorageArea final : public StorageArea {
-public:
-    static Ref<EphemeralStorageArea> create(const SecurityOriginData& origin, unsigned quotaInBytes)
-    {
-        return adoptRef(*new EphemeralStorageArea(origin, quotaInBytes));
-    }
-
-    Ref<EphemeralStorageArea> copy()
-    {
-        return adoptRef(*new EphemeralStorageArea(*this));
-    }
-
-private:
-    EphemeralStorageArea(const SecurityOriginData& origin, unsigned quotaInBytes)
-        : m_securityOriginData(origin)
-        , m_storageMap(StorageMap::create(quotaInBytes))
-    {
-    }
-
-    EphemeralStorageArea(EphemeralStorageArea& other)
-        : m_securityOriginData(other.m_securityOriginData)
-        , m_storageMap(other.m_storageMap)
-    {
-    }
-
-    // WebCore::StorageArea.
-    unsigned length()
-    {
-        return m_storageMap->length();
-    }
-
-    String key(unsigned index)
-    {
-        return m_storageMap->key(index);
-    }
-
-    String item(const String& key)
-    {
-        return m_storageMap->getItem(key);
-    }
-
-    void setItem(Frame*, const String& key, const String& value, bool& quotaException)
-    {
-        String oldValue;
-        if (auto newMap = m_storageMap->setItem(key, value, oldValue, quotaException))
-            m_storageMap = WTFMove(newMap);
-    }
-
-    void removeItem(Frame*, const String& key)
-    {
-        String oldValue;
-        if (auto newMap = m_storageMap->removeItem(key, oldValue))
-            m_storageMap = WTFMove(newMap);
-    }
-
-    void clear(Frame*)
-    {
-        if (!m_storageMap->length())
-            return;
-
-        m_storageMap = StorageMap::create(m_storageMap->quota());
-    }
-
-    bool contains(const String& key)
-    {
-        return m_storageMap->contains(key);
-    }
-
-    StorageType storageType() const
-    {
-        return StorageType::EphemeralLocal;
-    }
-
-    size_t memoryBytesUsedByCache()
-    {
-        return 0;
-    }
-
-    void incrementAccessCount() { }
-    void decrementAccessCount() { }
-    void closeDatabaseIfIdle() { }
-
-    const SecurityOriginData& securityOrigin() const
-    {
-        return m_securityOriginData;
-    }
-
-    SecurityOriginData m_securityOriginData;
-    RefPtr<StorageMap> m_storageMap;
-};
-
-Ref<StorageArea> StorageNamespaceImpl::ephemeralLocalStorageArea(const SecurityOriginData& securityOrigin)
-{
-    auto& slot = m_ephemeralLocalStorageAreas.add(securityOrigin, nullptr).iterator->value;
-    if (!slot)
-        slot = StorageNamespaceImpl::EphemeralStorageArea::create(securityOrigin, m_quotaInBytes);
-    ASSERT(slot);
-    return *slot;
-}
-
 Ref<StorageNamespace> StorageNamespaceImpl::copy(Page* newPage)
 {
     ASSERT(m_storageNamespaceID);
@@ -204,9 +101,6 @@ Ref<StorageNamespace> StorageNamespaceImpl::copy(Page* newPage)
     ASSERT(m_storageType == StorageType::EphemeralLocal);
     auto newNamespace = adoptRef(*new StorageNamespaceImpl(m_storageType, m_storageNamespaceID, m_topLevelOrigin.get(), m_quotaInBytes));
 
-    for (auto& iter : m_ephemeralLocalStorageAreas)
-        newNamespace->m_ephemeralLocalStorageAreas.set(iter.key, iter.value->copy());
-
     return WTFMove(newNamespace);
 }
 
index 97db0b8..6757e3b 100644 (file)
@@ -59,8 +59,6 @@ private:
     Ref<WebCore::StorageArea> storageArea(const WebCore::SecurityOriginData&) override;
     Ref<WebCore::StorageNamespace> copy(WebCore::Page*) override;
 
-    Ref<WebCore::StorageArea> ephemeralLocalStorageArea(const WebCore::SecurityOriginData&);
-
     const WebCore::StorageType m_storageType;
     const uint64_t m_storageNamespaceID;
 
@@ -70,9 +68,6 @@ private:
     const unsigned m_quotaInBytes;
 
     HashMap<WebCore::SecurityOriginData, StorageAreaMap*> m_storageAreaMaps;
-
-    class EphemeralStorageArea;
-    HashMap<WebCore::SecurityOriginData, RefPtr<EphemeralStorageArea>> m_ephemeralLocalStorageAreas;
 };
 
 } // namespace WebKit
index 4212113..05251bc 100644 (file)
@@ -1,3 +1,13 @@
+2019-02-26  Alex Christensen  <achristensen@webkit.org>
+
+        Move ephemeral local storage from WebProcess to UIProcess
+        https://bugs.webkit.org/show_bug.cgi?id=195074
+        <rdar://problem/47937975>
+
+        Reviewed by Geoff Garen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2019-02-20  Jer Noble  <jer.noble@apple.com>
 
         [Cocoa] Media elements will restart network buffering just before suspending
index 2a5ba06..9f18282 100644 (file)
@@ -4398,6 +4398,58 @@ TEST(ProcessSwap, SwapOnLoadHTMLString)
     done = false;
 }
 
+TEST(ProcessSwap, EphemeralLocalStorage)
+{
+    auto processPoolConfiguration = psonProcessPoolConfiguration();
+    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+    
+    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [webViewConfiguration setProcessPool:processPool.get()];
+    [webViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]];
+    auto handler = adoptNS([[PSONScheme alloc] init]);
+    [handler addMappingFromURLString:@"pson://www.webkit.org/iframe.html" toData:"<script>window.localStorage.setItem('c','d')</script>"];
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
+    
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://webkit.org/"]]];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [webView evaluateJavaScript:@"window.localStorage.setItem('a','b')" completionHandler:^(id, NSError *) {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://example.com/"]]];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://webkit.org/"]]];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [webView evaluateJavaScript:@"window.localStorage.getItem('a')" completionHandler:^(id result, NSError *) {
+        EXPECT_TRUE([@"b" isEqualToString:result]);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    
+    done = false;
+    [webView loadHTMLString:@"<html><iframe src='pson://www.webkit.org/iframe.html'></iframe></html>" baseURL:[NSURL URLWithString:@"http://www.example.com/"]];
+    TestWebKitAPI::Util::run(&done);
+
+    done = false;
+    [webView evaluateJavaScript:@"window.localStorage.getItem('a')" completionHandler:^(id result, NSError *) {
+        EXPECT_FALSE([@"b" isEqualToString:result]);
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+}
+
 TEST(ProcessSwap, UsePrewarmedProcessAfterTerminatingNetworkProcess)
 {
     auto processPoolConfiguration = psonProcessPoolConfiguration();