Title: [243339] trunk
Revision
243339
Author
[email protected]
Date
2019-03-21 15:52:18 -0700 (Thu, 21 Mar 2019)

Log Message

Cache API and IDB space usages should be initialized on first quota check
https://bugs.webkit.org/show_bug.cgi?id=195707

Reviewed by Chris Dumez.

Source/WebCore:

Add a way to require IDBServer to create a quota user for a given origin.
Make sure that removing a user might kick-in processing of pending requests.
In the case of processing pending requests, we should not decide on the first task
except if it is triggered by a request space response.
Update processPendingRequests accordingly.

Tests: http/tests/IndexedDB/storage-limit-1.https.html
       http/tests/IndexedDB/storage-limit-2.https.html

* Modules/indexeddb/server/IDBServer.h:
(WebCore::IDBServer::IDBServer::initializeQuotaUser):
* storage/StorageQuotaManager.cpp:
(WebCore::StorageQuotaManager::removeUser):
(WebCore::StorageQuotaManager::askForMoreSpace):
(WebCore::StorageQuotaManager::processPendingRequests):
* storage/StorageQuotaManager.h:

Source/WebKit:

When the quota manager is created, make sure it delays quota check decisions until IDB and Cache API quota users are initialized.
For IDB, the creation is synchronous but it may not be synchronous for Cache API.
For that purpose, add a temporary quota user that will stay uninitialized until these two quota users are added.
Once added, the temporary quota user is removed.
The addition of the real users is made asynchronously as this is triggered by the creation of one of the two quota users.

In the case of a Cache API caches being cleared, make sure to reset the size to zero and to redo the quota user initialization dance.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::QuotaUserInitializer::initialize):
(WebKit::QuotaUserInitializer::~QuotaUserInitializer):
(WebKit::QuotaUserInitializer::QuotaUserInitializer):
(WebKit::NetworkProcess::storageQuotaManager):
* NetworkProcess/cache/CacheStorageEngine.cpp:
(WebKit::CacheStorage::Engine::initializeQuotaUser):
* NetworkProcess/cache/CacheStorageEngine.h:
* NetworkProcess/cache/CacheStorageEngineCaches.cpp:
(WebKit::CacheStorage::Caches::clear):

LayoutTests:

* TestExpectations:
Marking http/tests/cache-storage/cache-clearing-origin.https.html as
flaky on iOS as it is already marked flaky in MacOS.
* platform/mac-wk2/TestExpectations:
* http/tests/IndexedDB/storage-limit-1.https-expected.txt: Added.
* http/tests/IndexedDB/storage-limit-1.https.html: Added.
* http/tests/IndexedDB/storage-limit-2.https-expected.txt: Added.
* http/tests/IndexedDB/storage-limit-2.https.html: Added.
* http/tests/IndexedDB/storage-limit.https.html:
* platform/mac-wk1/TestExpectations:
* platform/win/TestExpectations:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (243338 => 243339)


--- trunk/LayoutTests/ChangeLog	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/ChangeLog	2019-03-21 22:52:18 UTC (rev 243339)
@@ -1,3 +1,22 @@
+2019-03-21  Youenn Fablet  <[email protected]>
+
+        Cache API and IDB space usages should be initialized on first quota check
+        https://bugs.webkit.org/show_bug.cgi?id=195707
+
+        Reviewed by Chris Dumez.
+
+        * TestExpectations:
+        Marking http/tests/cache-storage/cache-clearing-origin.https.html as
+        flaky on iOS as it is already marked flaky in MacOS.
+        * platform/mac-wk2/TestExpectations:
+        * http/tests/IndexedDB/storage-limit-1.https-expected.txt: Added.
+        * http/tests/IndexedDB/storage-limit-1.https.html: Added.
+        * http/tests/IndexedDB/storage-limit-2.https-expected.txt: Added.
+        * http/tests/IndexedDB/storage-limit-2.https.html: Added.
+        * http/tests/IndexedDB/storage-limit.https.html:
+        * platform/mac-wk1/TestExpectations:
+        * platform/win/TestExpectations:
+
 2019-03-21  Said Abou-Hallawa  <[email protected]>
 
         Remove the SVG tear off objects for SVGPoint, SVGPointList and SVGAnimatedPointList

Modified: trunk/LayoutTests/TestExpectations (243338 => 243339)


--- trunk/LayoutTests/TestExpectations	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/TestExpectations	2019-03-21 22:52:18 UTC (rev 243339)
@@ -2236,6 +2236,7 @@
 webkit.org/b/90980 fast/forms/textarea/textarea-state-restore.html [ Pass Timeout ]
 
 webkit.org/b/182928 http/tests/cache-storage/cache-representation.https.html [ Pass Failure ]
+webkit.org/b/193976 http/tests/cache-storage/cache-clearing-origin.https.html [ Pass Failure ]
 
 webkit.org/b/116621 fast/replaced/preferred-widths.html [ Pass Failure ]
 

Deleted: trunk/LayoutTests/http/tests/IndexedDB/resources/storage-limit.js (243338 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/resources/storage-limit.js	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/http/tests/IndexedDB/resources/storage-limit.js	2019-03-21 22:52:18 UTC (rev 243339)
@@ -1,39 +0,0 @@
-if (window.testRunner)
-    testRunner.setAllowStorageQuotaIncrease(false);
-
-description("This test makes sure that storage of indexedDB does not grow unboundedly.");
-
-window.caches.open("test").then(cache => {
-    return cache.put(new Request("/test"), new Response(new Uint8Array(204800)));
-}).then(() => {
-    indexedDBTest(prepareDatabase, onOpenSuccess, {'suffix': '-1'});
-}).catch(e => {
-    testFailed("Cache API store operation failed: " + e);
-    finishJSTest();
-});
-
-function prepareDatabase(event)
-{
-    evalAndLog("db = event.target.result");
-    evalAndLog("store = db.createObjectStore('store')");
-}
-
-// Quota for test is 400ko, but IDB is eating some of it when initializing files.
-// Let's make sure that 200ko is fine but 200ko after 200ko is not fine.
-async function onOpenSuccess(event)
-{
-    evalAndLog("db = event.target.result");
-    evalAndLog("store = db.transaction('store', 'readwrite').objectStore('store')");
-    evalAndLog("request = store.add(new Uint8Array(204800), 'key')");
-    request._onerror_ = function(event) {
-        shouldBeTrue("'error' in request");
-        shouldBe("request.error.code", "DOMException.QUOTA_EXCEEDED_ERR");
-        shouldBeEqualToString("request.error.name", "QuotaExceededError");
-        finishJSTest();
-    }
-
-    request._onsuccess_ = function(event) {
-        testFailed("Add operation should fail because storage limit is reached, but succeeded.");
-        finishJSTest();
-    }
-}

Added: trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https-expected.txt (0 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https-expected.txt	2019-03-21 22:52:18 UTC (rev 243339)
@@ -0,0 +1,21 @@
+This test makes sure that storage of indexedDB and Cache API do not grow unboundedly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+db = event.target.result
+store = db.createObjectStore('store')
+db = event.target.result
+store = db.transaction('store', 'readwrite').objectStore('store')
+request = store.add(new Uint8Array(300 * 1024), 'key')
+PASS 'error' in request is true
+PASS request.error.code is DOMException.QUOTA_EXCEEDED_ERR
+PASS request.error.name is "QuotaExceededError"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Copied: trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https.html (from rev 243338, trunk/LayoutTests/http/tests/IndexedDB/resources/storage-limit.js) (0 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/IndexedDB/storage-limit-1.https.html	2019-03-21 22:52:18 UTC (rev 243339)
@@ -0,0 +1,57 @@
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+if (window.testRunner)
+    testRunner.setAllowStorageQuotaIncrease(false);
+
+description("This test makes sure that storage of indexedDB  and Cache API do not grow unboundedly.");
+
+window.caches.open("test").then(cache => {
+    return cache.put(new Request("/test"), new Response(new Uint8Array(200 * 1024)));
+}).then(async() => {
+    // Let's terminate the network process so that all the opened quota users are gone for IDB quota check.
+    if (window.testRunner)
+        testRunner.terminateNetworkProcess();
+    while (true) {
+        try {
+            await fetch(".");
+            break;
+        } catch (e) { }
+    }
+    indexedDBTest(prepareDatabase, onOpenSuccess, {'suffix': '-1'});
+}).catch(e => {
+    testFailed("Cache API store operation failed: " + e);
+    finishJSTest();
+});
+
+function prepareDatabase(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.createObjectStore('store')");
+}
+
+// Quota for test is 400ko, but IDB is eating some of it when initializing files.
+// Let's make sure that 200ko is fine but 300ko after 200ko is not fine.
+async function onOpenSuccess(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.transaction('store', 'readwrite').objectStore('store')");
+    evalAndLog("request = store.add(new Uint8Array(300 * 1024), 'key')");
+    request._onerror_ = function(event) {
+        shouldBeTrue("'error' in request");
+        shouldBe("request.error.code", "DOMException.QUOTA_EXCEEDED_ERR");
+        shouldBeEqualToString("request.error.name", "QuotaExceededError");
+        finishJSTest();
+    }
+
+    request._onsuccess_ = function(event) {
+        testFailed("Add operation should fail because storage limit is reached, but succeeded.");
+        finishJSTest();
+    }
+}</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https-expected.txt (0 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https-expected.txt	2019-03-21 22:52:18 UTC (rev 243339)
@@ -0,0 +1,21 @@
+CONSOLE MESSAGE: Cache API operation failed: Quota exceeded
+This test makes sure that storage of indexedDB and Cache API do not grow unboundedly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+indexedDB = self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.msIndexedDB || self.OIndexedDB;
+
+indexedDB.deleteDatabase(dbname)
+indexedDB.open(dbname)
+db = event.target.result
+store = db.createObjectStore('store')
+db = event.target.result
+store = db.transaction('store', 'readwrite').objectStore('store')
+request = store.add(new Uint8Array(204800), 'key')
+finished idb processing
+Cache API store operation failed: QuotaExceededError: Quota exceeded
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https.html (0 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/IndexedDB/storage-limit-2.https.html	2019-03-21 22:52:18 UTC (rev 243339)
@@ -0,0 +1,62 @@
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<script>
+if (window.testRunner)
+    testRunner.setAllowStorageQuotaIncrease(false);
+
+description("This test makes sure that storage of indexedDB and Cache API do not grow unboundedly.");
+
+indexedDBTest(prepareDatabase, onOpenSuccess, {'suffix': '-1'});
+
+function prepareDatabase(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.createObjectStore('store')");
+}
+
+// Quota for test is 400ko, but IDB is eating some of it when initializing files.
+// Let's make sure that 200ko is fine but 200ko after 200ko is not fine.
+async function onOpenSuccess(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.transaction('store', 'readwrite').objectStore('store')");
+    evalAndLog("request = store.add(new Uint8Array(204800), 'key')");
+    request._onerror_ = function(event) {
+        testFailed("Add operation should fail because storage limit is reached, but succeeded.");
+        finishJSTest();
+    }
+
+    request._onsuccess_ = async (event) => {
+        debug("finished idb processing");
+        // Let's terminate the network process so that all the opened quota users are gone for Cache API quota check.
+        if (window.testRunner)
+            testRunner.terminateNetworkProcess();
+        while (true) {
+            try {
+                await fetch(".");
+                break;
+            } catch (e) { }
+        }
+        cacheTest();
+    }
+}
+
+function cacheTest()
+{
+    window.caches.open("test").then(cache => {
+        return cache.put(new Request("/test"), new Response(new Uint8Array(304800)));
+    }).then(() => {
+        testFailed("Cache API store operation succeeded");
+        finishJSTest();
+    }).catch(e => {
+        debug("Cache API store operation failed: " + e);
+        finishJSTest();
+    });
+}
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/http/tests/IndexedDB/storage-limit.https.html (243338 => 243339)


--- trunk/LayoutTests/http/tests/IndexedDB/storage-limit.https.html	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/http/tests/IndexedDB/storage-limit.https.html	2019-03-21 22:52:18 UTC (rev 243339)
@@ -4,6 +4,46 @@
 <script src=""
 </head>
 <body>
-<script src=""
+<script>
+if (window.testRunner)
+    testRunner.setAllowStorageQuotaIncrease(false);
+
+description("This test makes sure that storage of indexedDB does not grow unboundedly.");
+
+window.caches.open("test").then(cache => {
+    return cache.put(new Request("/test"), new Response(new Uint8Array(204800)));
+}).then(() => {
+    indexedDBTest(prepareDatabase, onOpenSuccess, {'suffix': '-1'});
+}).catch(e => {
+    testFailed("Cache API store operation failed: " + e);
+    finishJSTest();
+});
+
+function prepareDatabase(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.createObjectStore('store')");
+}
+
+// Quota for test is 400ko, but IDB is eating some of it when initializing files.
+// Let's make sure that 200ko is fine but 200ko after 200ko is not fine.
+async function onOpenSuccess(event)
+{
+    evalAndLog("db = event.target.result");
+    evalAndLog("store = db.transaction('store', 'readwrite').objectStore('store')");
+    evalAndLog("request = store.add(new Uint8Array(204800), 'key')");
+    request._onerror_ = function(event) {
+        shouldBeTrue("'error' in request");
+        shouldBe("request.error.code", "DOMException.QUOTA_EXCEEDED_ERR");
+        shouldBeEqualToString("request.error.name", "QuotaExceededError");
+        finishJSTest();
+    }
+
+    request._onsuccess_ = function(event) {
+        testFailed("Add operation should fail because storage limit is reached, but succeeded.");
+        finishJSTest();
+    }
+}
+</script>
 </body>
 </html>

Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (243338 => 243339)


--- trunk/LayoutTests/platform/mac-wk1/TestExpectations	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations	2019-03-21 22:52:18 UTC (rev 243339)
@@ -164,6 +164,8 @@
 
 # Quota check missing in WK1
 http/tests/IndexedDB/storage-limit.https.html [ Skip ]
+http/tests/IndexedDB/storage-limit-1.https.html [ Skip ]
+http/tests/IndexedDB/storage-limit-2.https.html [ Skip ]
 storage/indexeddb/storage-limit.html [ Skip ]
 
 # Skip WebRTC for now in WK1

Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (243338 => 243339)


--- trunk/LayoutTests/platform/mac-wk2/TestExpectations	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations	2019-03-21 22:52:18 UTC (rev 243339)
@@ -912,8 +912,6 @@
 
 webkit.org/b/191658 [ Sierra Release ] fast/layers/no-clipping-overflow-hidden-added-after-transform.html [ Pass ImageOnlyFailure ]
 
-webkit.org/b/193976 http/tests/cache-storage/cache-clearing-origin.https.html [ Pass Failure ]
-
 webkit.org/b/194826 http/tests/resourceLoadStatistics/do-not-block-top-level-navigation-redirect.html [ Pass Timeout ]
 
 webkit.org/b/194368 http/tests/workers/service/basic-register-exceptions.html [ Pass Failure ]

Modified: trunk/LayoutTests/platform/win/TestExpectations (243338 => 243339)


--- trunk/LayoutTests/platform/win/TestExpectations	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/LayoutTests/platform/win/TestExpectations	2019-03-21 22:52:18 UTC (rev 243339)
@@ -2375,6 +2375,8 @@
 
 storage/indexeddb/storage-limit.html [ Skip ]
 http/tests/IndexedDB/storage-limit.https.html [ Skip ]
+http/tests/IndexedDB/storage-limit-1.https.html [ Skip ]
+http/tests/IndexedDB/storage-limit-2.https.html [ Skip ]
 
 # Assertion failures: Not investigated
 [ Debug ] http/tests/security/isolatedWorld/storage-properties.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (243338 => 243339)


--- trunk/Source/WebCore/ChangeLog	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebCore/ChangeLog	2019-03-21 22:52:18 UTC (rev 243339)
@@ -1,3 +1,27 @@
+2019-03-21  Youenn Fablet  <[email protected]>
+
+        Cache API and IDB space usages should be initialized on first quota check
+        https://bugs.webkit.org/show_bug.cgi?id=195707
+
+        Reviewed by Chris Dumez.
+
+        Add a way to require IDBServer to create a quota user for a given origin.
+        Make sure that removing a user might kick-in processing of pending requests.
+        In the case of processing pending requests, we should not decide on the first task
+        except if it is triggered by a request space response.
+        Update processPendingRequests accordingly.
+
+        Tests: http/tests/IndexedDB/storage-limit-1.https.html
+               http/tests/IndexedDB/storage-limit-2.https.html
+
+        * Modules/indexeddb/server/IDBServer.h:
+        (WebCore::IDBServer::IDBServer::initializeQuotaUser):
+        * storage/StorageQuotaManager.cpp:
+        (WebCore::StorageQuotaManager::removeUser):
+        (WebCore::StorageQuotaManager::askForMoreSpace):
+        (WebCore::StorageQuotaManager::processPendingRequests):
+        * storage/StorageQuotaManager.h:
+
 2019-03-21  Alex Christensen  <[email protected]>
 
         Fix iOS build after r243337

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp (243338 => 243339)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp	2019-03-21 22:52:18 UTC (rev 243339)
@@ -784,7 +784,7 @@
         callback();
 }
 
-IDBServer::QuotaUser& IDBServer::quotaUser(const ClientOrigin& origin)
+IDBServer::QuotaUser& IDBServer::ensureQuotaUser(const ClientOrigin& origin)
 {
     return *m_quotaUsers.ensure(origin, [this, &origin] {
         return std::make_unique<QuotaUser>(*this, m_quotaManagerGetter(m_sessionID, origin), ClientOrigin { origin });
@@ -810,12 +810,12 @@
 
 void IDBServer::finishComputingSpaceUsedForOrigin(const ClientOrigin& origin, uint64_t spaceUsed)
 {
-    quotaUser(origin).initializeSpaceUsed(spaceUsed);
+    ensureQuotaUser(origin).initializeSpaceUsed(spaceUsed);
 }
 
 void IDBServer::requestSpace(const ClientOrigin& origin, uint64_t taskSize, CompletionHandler<void(StorageQuotaManager::Decision)>&& callback)
 {
-    auto* quotaManager = quotaUser(origin).manager();
+    auto* quotaManager = ensureQuotaUser(origin).manager();
     if (!quotaManager) {
         callback(StorageQuotaManager::Decision::Deny);
         return;
@@ -832,17 +832,17 @@
 
 void IDBServer::setSpaceUsed(const ClientOrigin& origin, uint64_t taskSize)
 {
-    quotaUser(origin).setSpaceUsed(taskSize);
+    ensureQuotaUser(origin).setSpaceUsed(taskSize);
 }
 
 void IDBServer::increasePotentialSpaceUsed(const ClientOrigin& origin, uint64_t taskSize)
 {
-    quotaUser(origin).increasePotentialSpaceUsed(taskSize);
+    ensureQuotaUser(origin).increasePotentialSpaceUsed(taskSize);
 }
 
 void IDBServer::decreasePotentialSpaceUsed(const ClientOrigin& origin, uint64_t spaceUsed)
 {
-    quotaUser(origin).decreasePotentialSpaceUsed(spaceUsed);
+    ensureQuotaUser(origin).decreasePotentialSpaceUsed(spaceUsed);
 }
 
 void IDBServer::upgradeFilesIfNecessary()

Modified: trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h (243338 => 243339)


--- trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebCore/Modules/indexeddb/server/IDBServer.h	2019-03-21 22:52:18 UTC (rev 243339)
@@ -125,6 +125,8 @@
     void setSpaceUsed(const ClientOrigin&, uint64_t spaceUsed);
     void resetSpaceUsed(const ClientOrigin&);
 
+    void initializeQuotaUser(const ClientOrigin& origin) { ensureQuotaUser(origin); }
+
 private:
     IDBServer(PAL::SessionID, IDBBackingStoreTemporaryFileHandler&, QuotaManagerGetter&&, WTF::Function<void(bool)>&&);
     IDBServer(PAL::SessionID, const String& databaseDirectoryPath, IDBBackingStoreTemporaryFileHandler&, QuotaManagerGetter&&, WTF::Function<void(bool)>&&);
@@ -175,7 +177,7 @@
         CompletionHandler<void()> m_initializationCallback;
     };
 
-    QuotaUser& quotaUser(const ClientOrigin&);
+    WEBCORE_EXPORT QuotaUser& ensureQuotaUser(const ClientOrigin&);
     void startComputingSpaceUsedForOrigin(const ClientOrigin&);
     void computeSpaceUsedForOrigin(const ClientOrigin&);
     void finishComputingSpaceUsedForOrigin(const ClientOrigin&, uint64_t spaceUsed);

Modified: trunk/Source/WebCore/storage/StorageQuotaManager.cpp (243338 => 243339)


--- trunk/Source/WebCore/storage/StorageQuotaManager.cpp	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.cpp	2019-03-21 22:52:18 UTC (rev 243339)
@@ -69,7 +69,7 @@
             return;
 
         updateQuotaBasedOnSpaceUsage();
-        processPendingRequests({ });
+        processPendingRequests({ }, ShouldDequeueFirstPendingRequest::No);
     });
 }
 
@@ -81,6 +81,14 @@
     return spaceUsage() + spaceIncrease > m_quota;
 }
 
+void StorageQuotaManager::removeUser(StorageQuotaUser& user)
+{
+    ASSERT(m_users.contains(&user) || m_pendingInitializationUsers.contains(&user));
+    m_users.remove(&user);
+    if (m_pendingInitializationUsers.remove(&user) && m_pendingInitializationUsers.isEmpty())
+        processPendingRequests({ }, ShouldDequeueFirstPendingRequest::No);
+}
+
 void StorageQuotaManager::requestSpace(uint64_t spaceIncrease, RequestCallback&& callback)
 {
     if (!m_pendingRequests.isEmpty() || !m_pendingInitializationUsers.isEmpty()) {
@@ -99,14 +107,17 @@
 void StorageQuotaManager::askForMoreSpace(uint64_t spaceIncrease)
 {
     ASSERT(shouldAskForMoreSpace(spaceIncrease));
+    ASSERT(!m_isWaitingForSpaceIncreaseResponse);
+    m_isWaitingForSpaceIncreaseResponse = true;
     m_spaceIncreaseRequester(m_quota, spaceUsage(), spaceIncrease, [this, weakThis = makeWeakPtr(*this)](Optional<uint64_t> newQuota) {
         if (!weakThis)
             return;
-        processPendingRequests(newQuota);
+        m_isWaitingForSpaceIncreaseResponse = false;
+        processPendingRequests(newQuota, ShouldDequeueFirstPendingRequest::Yes);
     });
 }
 
-void StorageQuotaManager::processPendingRequests(Optional<uint64_t> newQuota)
+void StorageQuotaManager::processPendingRequests(Optional<uint64_t> newQuota, ShouldDequeueFirstPendingRequest shouldDequeueFirstPendingRequest)
 {
     if (m_pendingRequests.isEmpty())
         return;
@@ -114,10 +125,18 @@
     if (newQuota)
         m_quota = *newQuota;
 
-    auto request = m_pendingRequests.takeFirst();
-    auto decision = shouldAskForMoreSpace(request.spaceIncrease) ? Decision::Deny : Decision::Grant;
-    request.callback(decision);
+    if (m_isWaitingForSpaceIncreaseResponse)
+        return;
 
+    if (!m_pendingInitializationUsers.isEmpty())
+        return;
+
+    if (shouldDequeueFirstPendingRequest == ShouldDequeueFirstPendingRequest::Yes) {
+        auto request = m_pendingRequests.takeFirst();
+        auto decision = shouldAskForMoreSpace(request.spaceIncrease) ? Decision::Deny : Decision::Grant;
+        request.callback(decision);
+    }
+
     while (!m_pendingRequests.isEmpty()) {
         auto& request = m_pendingRequests.first();
 

Modified: trunk/Source/WebCore/storage/StorageQuotaManager.h (243338 => 243339)


--- trunk/Source/WebCore/storage/StorageQuotaManager.h	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebCore/storage/StorageQuotaManager.h	2019-03-21 22:52:18 UTC (rev 243339)
@@ -50,12 +50,7 @@
     static constexpr uint64_t defaultThirdPartyQuota() { return 100 * MB; }
 
     WEBCORE_EXPORT void addUser(StorageQuotaUser&);
-    void removeUser(StorageQuotaUser& user)
-    {
-        ASSERT(m_users.contains(&user) || m_pendingInitializationUsers.contains(&user));
-        m_pendingInitializationUsers.remove(&user);
-        m_users.remove(&user);
-    }
+    WEBCORE_EXPORT void removeUser(StorageQuotaUser&);
 
     enum class Decision { Deny, Grant };
     using RequestCallback = CompletionHandler<void(Decision)>;
@@ -68,9 +63,13 @@
     uint64_t spaceUsage() const;
     bool shouldAskForMoreSpace(uint64_t spaceIncrease) const;
     void askForMoreSpace(uint64_t spaceIncrease);
-    void processPendingRequests(Optional<uint64_t>);
 
+    enum class ShouldDequeueFirstPendingRequest { No, Yes };
+    void processPendingRequests(Optional<uint64_t>, ShouldDequeueFirstPendingRequest);
+
     uint64_t m_quota { 0 };
+
+    bool m_isWaitingForSpaceIncreaseResponse { false };
     SpaceIncreaseRequester m_spaceIncreaseRequester;
     HashSet<const StorageQuotaUser*> m_pendingInitializationUsers;
     HashSet<const StorageQuotaUser*> m_users;

Modified: trunk/Source/WebKit/ChangeLog (243338 => 243339)


--- trunk/Source/WebKit/ChangeLog	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/ChangeLog	2019-03-21 22:52:18 UTC (rev 243339)
@@ -1,3 +1,29 @@
+2019-03-21  Youenn Fablet  <[email protected]>
+
+        Cache API and IDB space usages should be initialized on first quota check
+        https://bugs.webkit.org/show_bug.cgi?id=195707
+
+        Reviewed by Chris Dumez.
+
+        When the quota manager is created, make sure it delays quota check decisions until IDB and Cache API quota users are initialized.
+        For IDB, the creation is synchronous but it may not be synchronous for Cache API.
+        For that purpose, add a temporary quota user that will stay uninitialized until these two quota users are added.
+        Once added, the temporary quota user is removed.
+        The addition of the real users is made asynchronously as this is triggered by the creation of one of the two quota users.
+
+        In the case of a Cache API caches being cleared, make sure to reset the size to zero and to redo the quota user initialization dance.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::QuotaUserInitializer::initialize):
+        (WebKit::QuotaUserInitializer::~QuotaUserInitializer):
+        (WebKit::QuotaUserInitializer::QuotaUserInitializer):
+        (WebKit::NetworkProcess::storageQuotaManager):
+        * NetworkProcess/cache/CacheStorageEngine.cpp:
+        (WebKit::CacheStorage::Engine::initializeQuotaUser):
+        * NetworkProcess/cache/CacheStorageEngine.h:
+        * NetworkProcess/cache/CacheStorageEngineCaches.cpp:
+        (WebKit::CacheStorage::Caches::clear):
+
 2019-03-21  Per Arne Vollan  <[email protected]>
 
         [iOS][macOS] Fix sandbox call violations

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp	2019-03-21 22:52:18 UTC (rev 243339)
@@ -2394,6 +2394,49 @@
     parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
 }
 
+class QuotaUserInitializer final : public WebCore::StorageQuotaUser {
+public:
+    explicit QuotaUserInitializer(StorageQuotaManager& manager)
+        : m_manager(makeWeakPtr(manager))
+    {
+        manager.addUser(*this);
+    }
+
+    ~QuotaUserInitializer()
+    {
+        if (m_manager)
+            m_manager->removeUser(*this);
+        if (m_callback)
+            m_callback();
+    }
+
+private:
+    // StorageQuotaUser API.
+    uint64_t spaceUsed() const final
+    {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    void whenInitialized(CompletionHandler<void()>&& callback) final
+    {
+        m_callback = WTFMove(callback);
+    }
+
+    WeakPtr<StorageQuotaManager> m_manager;
+    CompletionHandler<void()> m_callback;
+};
+
+void NetworkProcess::initializeQuotaUsers(StorageQuotaManager& manager, PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    RunLoop::main().dispatch([this, weakThis = makeWeakPtr(this), sessionID, origin, user = std::make_unique<QuotaUserInitializer>(manager)]() mutable {
+        if (!weakThis)
+            return;
+        this->idbServer(sessionID).initializeQuotaUser(origin);
+        CacheStorage::Engine::initializeQuotaUser(*this, sessionID, origin, [user = WTFMove(user)] { });
+    });
+}
+
 StorageQuotaManager& NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
 {
     auto& storageQuotaManagers = m_storageQuotaManagers.ensure(sessionID, [] {
@@ -2401,9 +2444,11 @@
     }).iterator->value;
     return *storageQuotaManagers.managersPerOrigin.ensure(origin, [this, &storageQuotaManagers, sessionID, &origin] {
         auto quota = origin.topOrigin == origin.clientOrigin ? storageQuotaManagers.defaultQuota : storageQuotaManagers.defaultThirdPartyQuota;
-        return std::make_unique<StorageQuotaManager>(quota, [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
+        auto manager = std::make_unique<StorageQuotaManager>(quota, [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
             this->requestStorageSpace(sessionID, origin, quota, currentSpace, spaceIncrease, WTFMove(callback));
         });
+        initializeQuotaUsers(*manager, sessionID, origin);
+        return manager;
     }).iterator->value;
 }
 

Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h	2019-03-21 22:52:18 UTC (rev 243339)
@@ -383,6 +383,7 @@
     void clearCachedCredentials();
 
     void setCacheStorageParameters(PAL::SessionID, uint64_t quota, String&& cacheStorageDirectory, SandboxExtension::Handle&&);
+    void initializeQuotaUsers(WebCore::StorageQuotaManager&, PAL::SessionID, const WebCore::ClientOrigin&);
 
     // FIXME: This should take a session ID so we can identify which disk cache to delete.
     void clearDiskCache(WallTime modifiedSince, CompletionHandler<void()>&&);

Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.cpp	2019-03-21 22:52:18 UTC (rev 243339)
@@ -185,6 +185,15 @@
     });
 }
 
+void Engine::initializeQuotaUser(NetworkProcess& networkProcess, PAL::SessionID sessionID, const WebCore::ClientOrigin& clientOrigin, CompletionHandler<void()>&& completionHandler)
+{
+    from(networkProcess, sessionID, [clientOrigin, completionHandler = WTFMove(completionHandler)](auto& engine) mutable {
+        engine.readCachesFromDisk(clientOrigin, [completionHandler = WTFMove(completionHandler)](auto&& cachesOrError) mutable {
+            completionHandler();
+        });
+    });
+}
+
 Engine::Engine(PAL::SessionID sessionID, NetworkProcess& process, String&& rootPath)
     : m_sessionID(sessionID)
     , m_networkProcess(makeWeakPtr(process))

Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngine.h	2019-03-21 22:52:18 UTC (rev 243339)
@@ -80,6 +80,8 @@
     static void clearAllCaches(NetworkProcess&, PAL::SessionID, CompletionHandler<void()>&&);
     static void clearCachesForOrigin(NetworkProcess&, PAL::SessionID, WebCore::SecurityOriginData&&, CompletionHandler<void()>&&);
 
+    static void initializeQuotaUser(NetworkProcess&, PAL::SessionID, const WebCore::ClientOrigin&, CompletionHandler<void()>&&);
+
     bool shouldPersist() const { return !!m_ioQueue;}
 
     void writeFile(const String& filename, NetworkCache::Data&&, WebCore::DOMCacheEngine::CompletionCallback&&);

Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.cpp	2019-03-21 22:52:18 UTC (rev 243339)
@@ -260,11 +260,13 @@
         m_storage->clear(String { }, -WallTime::infinity(), [protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)]() mutable {
             ASSERT(RunLoop::isMain());
             protectedThis->clearMemoryRepresentation();
+            protectedThis->resetSpaceUsed();
             completionHandler();
         });
         return;
     }
     clearMemoryRepresentation();
+    resetSpaceUsed();
     clearPendingWritingCachesToDiskCallbacks();
     completionHandler();
 }
@@ -601,6 +603,15 @@
     m_storage->remove(key);
 }
 
+void Caches::resetSpaceUsed()
+{
+    m_size = 0;
+    if (m_quotaManager) {
+        m_quotaManager->removeUser(*this);
+        m_quotaManager->addUser(*this);
+    }
+}
+
 void Caches::clearMemoryRepresentation()
 {
     if (!m_isInitialized) {

Modified: trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h (243338 => 243339)


--- trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h	2019-03-21 22:51:32 UTC (rev 243338)
+++ trunk/Source/WebKit/NetworkProcess/cache/CacheStorageEngineCaches.h	2019-03-21 22:52:18 UTC (rev 243339)
@@ -78,6 +78,7 @@
 
     void clear(WTF::CompletionHandler<void()>&&);
     void clearMemoryRepresentation();
+    void resetSpaceUsed();
 
     uint64_t storageSize() const;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to