WebKit Bugzilla
Attachment 356969 Details for
Bug 192556
: IndexedDB: quota should be able to increase
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192556-20181210100329.patch (text/plain), 74.42 KB, created by
Sihui Liu
on 2018-12-10 10:03:30 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Sihui Liu
Created:
2018-12-10 10:03:30 PST
Size:
74.42 KB
patch
obsolete
>Subversion Revision: 238853 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index d85b8dac7d0fc41a6c106843784721cd6e154864..0ea2722993b274ec01694ec82ac6657e0d6506bb 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,92 @@ >+2018-12-10 Sihui Liu <sihui_liu@apple.com> >+ >+ IndexedDB: quota should be able to increase >+ https://bugs.webkit.org/show_bug.cgi?id=192556 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Modified test to include new behavior: storage/indexeddb/storage-limit.html >+ >+ * Modules/indexeddb/IDBDatabaseIdentifier.cpp: >+ (WebCore::IDBDatabaseIdentifier::originString const): >+ * Modules/indexeddb/IDBDatabaseIdentifier.h: >+ * Modules/indexeddb/IDBOpenDBRequest.cpp: >+ (WebCore::IDBOpenDBRequest::requestCompleted): >+ * Modules/indexeddb/IDBRequest.cpp: >+ (WebCore::IDBRequest::completeRequestAndDispatchEvent): >+ (WebCore::IDBRequest::databaseExceededQuota): >+ * Modules/indexeddb/IDBRequest.h: >+ * Modules/indexeddb/client/IDBConnectionProxy.cpp: >+ (WebCore::IDBClient::IDBConnectionProxy::updateQuotaForOrigin): >+ * Modules/indexeddb/client/IDBConnectionProxy.h: >+ * Modules/indexeddb/client/IDBConnectionToServer.cpp: >+ (WebCore::IDBClient::IDBConnectionToServer::updateQuotaForOrigin): >+ * Modules/indexeddb/client/IDBConnectionToServer.h: >+ * Modules/indexeddb/client/IDBConnectionToServerDelegate.h: >+ * Modules/indexeddb/server/IDBServer.cpp: >+ (WebCore::IDBServer::IDBServer::quotaDatabasePath): >+ (WebCore::IDBServer::IDBServer::openQuotaDatabase): >+ (WebCore::IDBServer::IDBServer::quotaForOrigin): >+ (WebCore::IDBServer::IDBServer::setQuotaInDatabase): >+ (WebCore::IDBServer::IDBServer::deleteOriginFromDatabase): >+ (WebCore::IDBServer::IDBServer::mayDeleteQuotaDatabase): >+ (WebCore::IDBServer::IDBServer::mayDeleteOriginFromDatabase): >+ (WebCore::IDBServer::IDBServer::setQuotaForOrigin): >+ (WebCore::IDBServer::IDBServer::isQuotaFullForOrigin): >+ (WebCore::IDBServer::IDBServer::createBackingStore): >+ (WebCore::IDBServer::IDBServer::closeAndTakeUniqueIDBDatabase): >+ (WebCore::IDBServer::IDBServer::performCloseAndDeleteDatabasesForOrigins): >+ * Modules/indexeddb/server/IDBServer.h: >+ * Modules/indexeddb/server/SQLiteIDBBackingStore.cpp: >+ (WebCore::IDBServer::SQLiteIDBBackingStore::originDiskUsage): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::databaseSize const): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::maximumSize const): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::beginTransaction): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::createObjectStore): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::renameObjectStore): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::createIndex): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::uncheckedPutIndexRecord): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::renameIndex): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::addRecord): >+ (WebCore::IDBServer::SQLiteIDBBackingStore::uncheckedSetKeyGeneratorValue): >+ * Modules/indexeddb/server/SQLiteIDBBackingStore.h: >+ * Modules/indexeddb/server/UniqueIDBDatabase.cpp: >+ (WebCore::IDBServer::UniqueIDBDatabase::deleteBackingStore): >+ (WebCore::IDBServer::UniqueIDBDatabase::openBackingStore): >+ (WebCore::IDBServer::UniqueIDBDatabase::setQuota): >+ (WebCore::IDBServer::UniqueIDBDatabase::performSetQuota): >+ * Modules/indexeddb/server/UniqueIDBDatabase.h: >+ * Modules/indexeddb/shared/IDBError.cpp: >+ (WebCore::IDBError::IDBError): >+ (WebCore::IDBError::isolatedCopy const): >+ (WebCore::IDBError::operator=): >+ * Modules/indexeddb/shared/IDBError.h: >+ (WebCore::IDBError::IDBError): >+ (WebCore::IDBError::quotaDetails const): >+ (WebCore::IDBError::encode const): >+ (WebCore::IDBError::decode): >+ * Modules/indexeddb/shared/IDBQuotaDetails.h: Added. >+ (WebCore::IDBQuotaDetails::IDBQuotaDetails): >+ (WebCore::IDBQuotaDetails::isolatedCopy const): >+ (WebCore::IDBQuotaDetails::databaseName const): >+ (WebCore::IDBQuotaDetails::origin const): >+ (WebCore::IDBQuotaDetails::quota const): >+ (WebCore::IDBQuotaDetails::usage const): >+ (WebCore::IDBQuotaDetails::databaseUsage const): >+ (WebCore::IDBQuotaDetails::expectedDatabaseUsage const): >+ (WebCore::IDBQuotaDetails::loggingString const): >+ (WebCore::IDBQuotaDetails::encode const): >+ (WebCore::IDBQuotaDetails::decode): >+ * Modules/indexeddb/shared/InProcessIDBServer.cpp: >+ (WebCore::InProcessIDBServer::updateQuotaForOrigin): >+ * Modules/indexeddb/shared/InProcessIDBServer.h: >+ * WebCore.xcodeproj/project.pbxproj: >+ * loader/EmptyClients.h: >+ * page/ChromeClient.h: >+ * page/SecurityOriginData.cpp: >+ (WebCore::SecurityOriginData::fromOriginIdentifier): >+ * page/SecurityOriginData.h: >+ > 2018-12-04 Carlos Garcia Campos <cgarcia@igalia.com> > > [SOUP] Move URLSoup back to WebCore after r238771 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 315e7fba7e0a93dc02601f1f02b5295bc42f924d..3b1a650dd82e5d834c485f3082b99e8d470f97aa 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,23 @@ >+2018-12-10 Sihui Liu <sihui_liu@apple.com> >+ >+ IndexedDB: quota should be able to increase >+ https://bugs.webkit.org/show_bug.cgi?id=192556 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * NetworkProcess/IndexedDB/WebIDBConnectionToClient.cpp: >+ (WebKit::WebIDBConnectionToClient::updateQuotaForOrigin): >+ * NetworkProcess/IndexedDB/WebIDBConnectionToClient.h: >+ * NetworkProcess/IndexedDB/WebIDBConnectionToClient.messages.in: >+ * UIProcess/WebPageProxy.cpp: >+ (WebKit::WebPageProxy::exceededDatabaseQuota): >+ * WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp: >+ (WebKit::WebIDBConnectionToServer::updateQuotaForOrigin): >+ * WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h: >+ * WebProcess/WebCoreSupport/WebChromeClient.cpp: >+ (WebKit::WebChromeClient::exceededDatabaseQuota): >+ * WebProcess/WebCoreSupport/WebChromeClient.h: >+ > 2018-12-04 Carlos Eduardo Ramalho <cadubentzen@gmail.com> > > [WPE] Add gtk-doc >diff --git a/Source/WebKitLegacy/mac/ChangeLog b/Source/WebKitLegacy/mac/ChangeLog >index 06b61dabf5682c77846868e6ea5ec290c6638707..fcb6ba90600fc50d124a49a0510f12c75f0a5cb2 100644 >--- a/Source/WebKitLegacy/mac/ChangeLog >+++ b/Source/WebKitLegacy/mac/ChangeLog >@@ -1,3 +1,14 @@ >+2018-12-10 Sihui Liu <sihui_liu@apple.com> >+ >+ IndexedDB: quota should be able to increase >+ https://bugs.webkit.org/show_bug.cgi?id=192556 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * WebCoreSupport/WebChromeClient.h: >+ * WebCoreSupport/WebChromeClient.mm: >+ (WebChromeClient::exceededDatabaseQuota): >+ > 2018-12-03 Alex Christensen <achristensen@webkit.org> > > Add WKWebProcessPlugInLoadDelegate SPI willStartProvisionalLoadForFrame with a completion handler >diff --git a/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp b/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp >index c7fdfd0dd6545f8c6fe5342fb3646fe9a84694b9..60358a3079eef928e85798ef694a8de286bf82b1 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.cpp >@@ -74,6 +74,17 @@ String IDBDatabaseIdentifier::databaseDirectoryRelativeToRoot(const SecurityOrig > return FileSystem::pathByAppendingComponent(mainFrameDirectory, openingOrigin.databaseIdentifier()); > } > >+String IDBDatabaseIdentifier::originString() const >+{ >+ StringBuilder stringBuilder; >+ >+ stringBuilder.append(m_mainFrameOrigin.databaseIdentifier()); >+ stringBuilder.append('/'); >+ stringBuilder.append(m_openingOrigin.databaseIdentifier()); >+ >+ return stringBuilder.toString(); >+} >+ > #if !LOG_DISABLED > String IDBDatabaseIdentifier::debugString() const > { >diff --git a/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h b/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h >index 7de4cdad3e1dcdb01c3aaf44f025671762d25bb7..48c0c273f8b3cdffc6704561e4a762e7b5b82ddb 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h >+++ b/Source/WebCore/Modules/indexeddb/IDBDatabaseIdentifier.h >@@ -93,6 +93,8 @@ public: > template<class Encoder> void encode(Encoder&) const; > template<class Decoder> static std::optional<IDBDatabaseIdentifier> decode(Decoder&); > >+ String originString() const; >+ > #if !LOG_DISABLED > String debugString() const; > #endif >diff --git a/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp b/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp >index 91ce9c4cb9454cebaa104f8943cb42bf51c635d2..d8e96ac2f3bf58af6957dc172ffa9ccfe2673879 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBOpenDBRequest.cpp >@@ -205,6 +205,8 @@ void IDBOpenDBRequest::requestCompleted(const IDBResultData& data) > switch (data.type()) { > case IDBResultType::Error: > onError(data); >+ if (data.error().code() == QuotaExceededError) >+ databaseExceededQuota(data.error().quotaDetails()); > break; > case IDBResultType::OpenDatabaseSuccess: > onSuccess(data); >diff --git a/Source/WebCore/Modules/indexeddb/IDBRequest.cpp b/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >index 6f5ce0e972653f6573ad5db76a4fccd49f22da9b..28e7d1cf2df8063d412b02cf1c353de03c41a936 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >+++ b/Source/WebCore/Modules/indexeddb/IDBRequest.cpp >@@ -28,6 +28,8 @@ > > #if ENABLE(INDEXED_DATABASE) > >+#include "Chrome.h" >+#include "ChromeClient.h" > #include "DOMException.h" > #include "Event.h" > #include "EventDispatcher.h" >@@ -501,9 +503,11 @@ void IDBRequest::completeRequestAndDispatchEvent(const IDBResultData& resultData > m_readyState = ReadyState::Done; > > m_idbError = resultData.error(); >- if (!m_idbError.isNull()) >+ if (!m_idbError.isNull()) { > onError(); >- else >+ if (m_idbError.code() == QuotaExceededError) >+ databaseExceededQuota(m_idbError.quotaDetails()); >+ } else > onSuccess(); > } > >@@ -532,6 +536,19 @@ void IDBRequest::setResult(Ref<IDBDatabase>&& database) > m_result = Result { RefPtr<IDBDatabase> { WTFMove(database) } }; > } > >+void IDBRequest::databaseExceededQuota(const IDBQuotaDetails& details) >+{ >+ uint64_t newQuota = 0; >+ if (is<Document>(*scriptExecutionContext())) { >+ Document& document = downcast<Document>(*scriptExecutionContext()); >+ if (Page* page = document.page()) >+ newQuota = page->chrome().client().exceededDatabaseQuota(*document.frame(), details); >+ } >+ >+ if (newQuota) >+ m_connectionProxy->updateQuotaForOrigin(details.origin(), newQuota); >+} >+ > } // namespace WebCore > > #endif // ENABLE(INDEXED_DATABASE) >diff --git a/Source/WebCore/Modules/indexeddb/IDBRequest.h b/Source/WebCore/Modules/indexeddb/IDBRequest.h >index e625cd3c7fbdc8913d6d49aa340ed9bb7239b5e8..3b1f2505809ec0449d1ebbd9c210a82f31eb8dbe 100644 >--- a/Source/WebCore/Modules/indexeddb/IDBRequest.h >+++ b/Source/WebCore/Modules/indexeddb/IDBRequest.h >@@ -117,6 +117,8 @@ public: > > bool hasPendingActivity() const final; > >+ void databaseExceededQuota(const IDBQuotaDetails&); >+ > protected: > IDBRequest(ScriptExecutionContext&, IDBClient::IDBConnectionProxy&); > >diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp >index 15ac07e46445f43414d45f8b128666cb27c4c00c..c3c5feda3eafe0c333d76111a88e804b901a0ad9 100644 >--- a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp >+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.cpp >@@ -493,6 +493,11 @@ void IDBConnectionProxy::getAllDatabaseNames(const SecurityOrigin& mainFrameOrig > m_connectionToServer.getAllDatabaseNames(mainFrameOrigin, openingOrigin, WTFMove(callback)); > } > >+void IDBConnectionProxy::updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) >+{ >+ callConnectionOnMainThread(&IDBConnectionToServer::updateQuotaForOrigin, originIdentifierString, quota); >+} >+ > void IDBConnectionProxy::registerDatabaseConnection(IDBDatabase& database) > { > Locker<Lock> locker(m_databaseConnectionMapLock); >diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h >index 2d039bf0fa8e951ed3ad3d2a4cb5ce5926f77f25..0be11448a6bbe0a5109294f42736664a42111563 100644 >--- a/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h >+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionProxy.h >@@ -118,6 +118,8 @@ public: > > void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, WTF::Function<void (const Vector<String>&)>&&); > >+ void updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota); >+ > void registerDatabaseConnection(IDBDatabase&); > void unregisterDatabaseConnection(IDBDatabase&); > >diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp >index fb50f6944ceaf07bac105054a925e1b3a939a25d..31947d047901855a3da78695c0b5b6deed6d2a5a 100644 >--- a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp >+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.cpp >@@ -525,6 +525,15 @@ void IDBConnectionToServer::didGetAllDatabaseNames(uint64_t callbackID, const Ve > callback(databaseNames); > } > >+void IDBConnectionToServer::updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) >+{ >+ LOG(IndexedDB, "IDBConnectionToServer::updateQuotaForOrigin %s", originIdentifierString.utf8().data()); >+ ASSERT(isMainThread()); >+ >+ if (m_serverConnectionIsValid) >+ m_delegate->updateQuotaForOrigin(originIdentifierString, quota); >+} >+ > } // namespace IDBClient > } // namespace WebCore > >diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h >index 851c342c4053c2f12daba2dc1341a7eef051707b..9ca4c92212e8e84d54368ea4d32493877b7a98d9 100644 >--- a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h >+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServer.h >@@ -140,6 +140,8 @@ public: > void getAllDatabaseNames(const SecurityOrigin& mainFrameOrigin, const SecurityOrigin& openingOrigin, WTF::Function<void (const Vector<String>&)>&&); > WEBCORE_EXPORT void didGetAllDatabaseNames(uint64_t callbackID, const Vector<String>& databaseNames); > >+ void updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota); >+ > private: > IDBConnectionToServer(IDBConnectionToServerDelegate&); > >diff --git a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h >index f217926ae06913ada8c3083e61fb2acefd8341e1..ecb7db96464adc688d384a2a04e6dc45f6badda2 100644 >--- a/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h >+++ b/Source/WebCore/Modules/indexeddb/client/IDBConnectionToServerDelegate.h >@@ -88,6 +88,8 @@ public: > > virtual void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) = 0; > >+ virtual void updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) = 0; >+ > virtual void ref() = 0; > virtual void deref() = 0; > }; >diff --git a/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp b/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp >index cb17ba1d579b6d2599ff4c5bcefdfe2faef4bea0..c730f655e7212efa6f0ae24027403e80e671406f 100644 >--- a/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp >+++ b/Source/WebCore/Modules/indexeddb/server/IDBServer.cpp >@@ -34,6 +34,7 @@ > #include "MemoryIDBBackingStore.h" > #include "SQLiteFileSystem.h" > #include "SQLiteIDBBackingStore.h" >+#include "SQLiteStatement.h" > #include "SecurityOrigin.h" > #include <wtf/CrossThreadCopier.h> > #include <wtf/Locker.h> >@@ -108,6 +109,153 @@ void IDBServer::unregisterDatabaseConnection(UniqueIDBDatabaseConnection& connec > m_databaseConnections.remove(connection.identifier()); > } > >+String IDBServer::quotaDatabasePath() const >+{ >+ if (!SQLiteFileSystem::ensureDatabaseDirectoryExists(m_databaseDirectoryPath)) { >+ LOG_ERROR("Unable to create IDB database path %s", m_databaseDirectoryPath.utf8().data()); >+ return String(); >+ } >+ return FileSystem::pathByAppendingComponent(m_databaseDirectoryPath, "Quota.db"); >+} >+ >+void IDBServer::openQuotaDatabase() >+{ >+ ASSERT(!isMainThread()); >+ >+ if (m_quotaDatabase.isOpen()) >+ return; >+ >+ auto databasePath = quotaDatabasePath(); >+ if (!databasePath) >+ return; >+ >+ if (!m_quotaDatabase.open(databasePath)) { >+ LOG_ERROR("Failed to open quotaDatabase at path %s.", databasePath.ascii().data()); >+ return; >+ } >+ m_quotaDatabase.disableThreadingChecks(); >+ >+ if (m_quotaDatabase.tableExists("Quota")) >+ return; >+ >+ if (!m_quotaDatabase.executeCommand("CREATE TABLE Quota (origin TEXT UNIQUE ON CONFLICT REPLACE, quota INTEGER NOT NULL ON CONFLICT FAIL);")) >+ LOG_ERROR("Failed to create Quota table."); >+} >+ >+uint64_t IDBServer::quotaForOrigin(const String& originIdentifierString) >+{ >+ ASSERT(!isMainThread()); >+ >+ uint64_t quota = m_perOriginQuota; >+ >+ openQuotaDatabase(); >+ if (!m_quotaDatabase.isOpen()) >+ return quota; >+ >+ SQLiteStatement statement(m_quotaDatabase, "SELECT quota FROM Quota where origin=?;"); >+ if (statement.prepare() != SQLITE_OK) { >+ LOG_ERROR("Failed to prepare getting quota for origin %s in quota database.", originIdentifierString.utf8().data()); >+ return quota; >+ } >+ statement.bindText(1, originIdentifierString); >+ >+ auto result = statement.step(); >+ if (result == SQLITE_ROW) >+ quota = statement.getColumnInt64(0); >+ else if (result == SQLITE_DONE) >+ setQuotaInDatabase(originIdentifierString, quota); >+ else >+ LOG_ERROR("Failed to get quota for origin %s in quota database.", originIdentifierString.utf8().data()); >+ >+ return quota; >+} >+ >+void IDBServer::setQuotaInDatabase(const String& originIdentifierString, uint64_t quota) >+{ >+ ASSERT(!isMainThread()); >+ >+ openQuotaDatabase(); >+ if (!m_quotaDatabase.isOpen()) >+ return; >+ >+ SQLiteStatement statement(m_quotaDatabase, "INSERT OR REPLACE INTO Quota VALUES (?, ?)"); >+ if (statement.prepare() != SQLITE_OK) { >+ LOG_ERROR("Failed to prepare insertion for origin %s in quota database", originIdentifierString.utf8().data()); >+ return; >+ } >+ >+ statement.bindText(1, originIdentifierString); >+ statement.bindInt64(2, quota); >+ >+ if (statement.step() != SQLITE_DONE) >+ LOG_ERROR("Failed to execute insertion for origin %s in quota database", originIdentifierString.utf8().data()); >+} >+ >+void IDBServer::deleteOriginFromDatabase(const String& originIdentifierString) >+{ >+ ASSERT(!isMainThread()); >+ >+ openQuotaDatabase(); >+ if (!m_quotaDatabase.isOpen()) >+ return; >+ >+ SQLiteStatement statement(m_quotaDatabase, "DELETE FROM Quota WHERE origin LIKE ?"); >+ if (statement.prepare() != SQLITE_OK) { >+ LOG_ERROR("Failed to prepare deletion for origin %s in quota database", originIdentifierString.utf8().data()); >+ return; >+ } >+ >+ statement.bindText(1, makeString("%", originIdentifierString)); >+ if (!statement.executeCommand()) { >+ LOG_ERROR("Failed to execute deletion for origin %s in quota database", originIdentifierString.utf8().data()); >+ return; >+ } >+ >+ mayDeleteQuotaDatabase(); >+} >+ >+void IDBServer::mayDeleteQuotaDatabase() >+{ >+ bool isEmpty = true; >+ SQLiteStatement statement(m_quotaDatabase, "SELECT quota FROM Quota"); >+ if (statement.prepare() != SQLITE_OK) >+ LOG_ERROR("Failed to get number of entries in quota database."); >+ else if (statement.step() == SQLITE_ROW) >+ isEmpty = false; >+ >+ if (isEmpty) { >+ m_quotaDatabase.close(); >+ SQLiteFileSystem::deleteDatabaseFile(quotaDatabasePath()); >+ SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_databaseDirectoryPath); >+ } >+} >+ >+void IDBServer::mayDeleteOriginFromDatabase(const IDBDatabaseIdentifier& identifier) >+{ >+ if (!FileSystem::fileExists(identifier.databaseDirectoryRelativeToRoot(m_databaseDirectoryPath))) >+ deleteOriginFromDatabase(identifier.originString()); >+} >+ >+void IDBServer::setQuotaForOrigin(const String& originIdentifierString, uint64_t quota) >+{ >+ ASSERT(isMainThread()); >+ >+ for (auto& databaseIdentifier : m_uniqueIDBDatabaseMap.keys()) { >+ if (databaseIdentifier.originString() == originIdentifierString) >+ m_uniqueIDBDatabaseMap.get(databaseIdentifier)->setQuota(quota); >+ } >+ >+ postDatabaseTask(createCrossThreadTask(*this, &IDBServer::setQuotaInDatabase, originIdentifierString, quota)); >+} >+ >+bool IDBServer::isQuotaFullForOrigin(const IDBDatabaseIdentifier& identifier, IDBQuotaDetails& details) >+{ >+ auto quota = quotaForOrigin(identifier.originString()); >+ auto usage = SQLiteIDBBackingStore::originDiskUsage(identifier.databaseDirectoryRelativeToRoot(m_databaseDirectoryPath)); >+ details = { identifier.databaseName(), identifier.originString(), quota, usage, 0, QuotaIncreaseSize }; >+ return quota <= usage; >+} >+ > UniqueIDBDatabase& IDBServer::getOrCreateUniqueIDBDatabase(const IDBDatabaseIdentifier& identifier) > { > ASSERT(isMainThread()); >@@ -126,7 +274,7 @@ std::unique_ptr<IDBBackingStore> IDBServer::createBackingStore(const IDBDatabase > if (m_databaseDirectoryPath.isEmpty()) > return MemoryIDBBackingStore::create(identifier); > >- return std::make_unique<SQLiteIDBBackingStore>(identifier, m_databaseDirectoryPath, m_backingStoreTemporaryFileHandler, m_perOriginQuota); >+ return std::make_unique<SQLiteIDBBackingStore>(identifier, m_databaseDirectoryPath, m_backingStoreTemporaryFileHandler, quotaForOrigin(identifier.originString())); > } > > void IDBServer::openDatabase(const IDBRequestData& requestData) >@@ -170,6 +318,10 @@ std::unique_ptr<UniqueIDBDatabase> IDBServer::closeAndTakeUniqueIDBDatabase(Uniq > ASSERT(isMainThread()); > > auto uniquePointer = m_uniqueIDBDatabaseMap.take(database.identifier()); >+ >+ if (m_uniqueIDBDatabaseMap.isEmpty() && m_quotaDatabase.isOpen()) >+ m_quotaDatabase.close(); >+ > ASSERT(uniquePointer); > > return uniquePointer; >@@ -634,6 +786,8 @@ void IDBServer::performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOr > originPath = FileSystem::pathByAppendingComponent(topOriginPath, origin.databaseIdentifier()); > removeAllDatabasesForOriginPath(originPath, -WallTime::infinity()); > } >+ >+ deleteOriginFromDatabase(origin.databaseIdentifier()); > } > } > >diff --git a/Source/WebCore/Modules/indexeddb/server/IDBServer.h b/Source/WebCore/Modules/indexeddb/server/IDBServer.h >index fa89aa5cc4147377df675e2d7d6c6f709a5eff0a..4fa137d4579774fb0e81cdf94e7efcb18fdcd0f7 100644 >--- a/Source/WebCore/Modules/indexeddb/server/IDBServer.h >+++ b/Source/WebCore/Modules/indexeddb/server/IDBServer.h >@@ -29,6 +29,7 @@ > > #include "IDBConnectionToClient.h" > #include "IDBDatabaseIdentifier.h" >+#include "SQLiteDatabase.h" > #include "UniqueIDBDatabase.h" > #include "UniqueIDBDatabaseConnection.h" > #include <wtf/CrossThreadTaskHandler.h> >@@ -48,7 +49,7 @@ struct IDBGetRecordData; > > namespace IDBServer { > >-const uint64_t defaultPerOriginQuota = 500 * MB; >+const uint64_t defaultPerOriginQuota = 5 * MB; > > class IDBBackingStoreTemporaryFileHandler; > >@@ -91,6 +92,11 @@ public: > > WEBCORE_EXPORT void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID); > >+ WEBCORE_EXPORT void setQuotaForOrigin(const String& originString, uint64_t); >+ >+ void mayDeleteOriginFromDatabase(const IDBDatabaseIdentifier&); >+ bool isQuotaFullForOrigin(const IDBDatabaseIdentifier&, IDBQuotaDetails&); >+ > void postDatabaseTask(CrossThreadTask&&); > void postDatabaseTaskReply(CrossThreadTask&&); > >@@ -122,6 +128,13 @@ private: > void performCloseAndDeleteDatabasesForOrigins(const Vector<SecurityOriginData>&, uint64_t callbackID); > void didPerformCloseAndDeleteDatabases(uint64_t callbackID); > >+ String quotaDatabasePath() const; >+ void openQuotaDatabase(); >+ uint64_t quotaForOrigin(const String& originString); >+ void setQuotaInDatabase(const String& originString, uint64_t quota); >+ void deleteOriginFromDatabase(const String& originString); >+ void mayDeleteQuotaDatabase(); >+ > HashMap<uint64_t, RefPtr<IDBConnectionToClient>> m_connectionMap; > HashMap<IDBDatabaseIdentifier, std::unique_ptr<UniqueIDBDatabase>> m_uniqueIDBDatabaseMap; > >@@ -134,6 +147,7 @@ private: > IDBBackingStoreTemporaryFileHandler& m_backingStoreTemporaryFileHandler; > > uint64_t m_perOriginQuota { defaultPerOriginQuota }; >+ SQLiteDatabase m_quotaDatabase; > }; > > } // namespace IDBServer >diff --git a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp >index a8a48067c0dc677de95b0f63555298d235295060..4f896acc1fd98c4606a7dd94c7c1e0cde5a42686 100644 >--- a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp >+++ b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp >@@ -849,20 +849,31 @@ uint64_t SQLiteIDBBackingStore::quotaForOrigin() const > return std::min(diskFreeSpaceSize / 2, m_quota); > } > >+uint64_t SQLiteIDBBackingStore::originDiskUsage(const String& absoluteOriginDirectory) >+{ >+ uint64_t diskUsage = 0; >+ for (auto& directory : FileSystem::listDirectory(absoluteOriginDirectory, "*")) { >+ for (auto& file : FileSystem::listDirectory(directory, "*.sqlite3*"_s)) >+ diskUsage += SQLiteFileSystem::getDatabaseFileSize(file); >+ } >+ >+ return diskUsage; >+} >+ >+uint64_t SQLiteIDBBackingStore::databaseSize() const >+{ >+ return SQLiteFileSystem::getDatabaseFileSize(fullDatabasePath()); >+} >+ > uint64_t SQLiteIDBBackingStore::maximumSize() const > { > ASSERT(!isMainThread()); > > // The maximum size for one database file is the quota for its origin, minus size of all databases within that origin, > // and plus current size of the database file. >- uint64_t databaseFileSize = SQLiteFileSystem::getDatabaseFileSize(fullDatabasePath()); >+ uint64_t databaseFileSize = databaseSize(); > uint64_t quota = quotaForOrigin(); >- >- uint64_t diskUsage = 0; >- for (auto& directory : FileSystem::listDirectory(m_absoluteDatabaseDirectory, "*")) { >- for (auto& file : FileSystem::listDirectory(directory, "*.sqlite3"_s)) >- diskUsage += SQLiteFileSystem::getDatabaseFileSize(file); >- } >+ uint64_t diskUsage = originDiskUsage(m_absoluteDatabaseDirectory); > ASSERT(diskUsage >= databaseFileSize); > > if (quota < diskUsage) >@@ -897,7 +908,7 @@ IDBError SQLiteIDBBackingStore::beginTransaction(const IDBTransactionInfo& info) > || sql.bindText(1, String::number(info.newVersion())) != SQLITE_OK > || sql.step() != SQLITE_DONE) { > if (m_sqliteDB->lastError() == SQLITE_FULL) >- error = IDBError { QuotaExceededError, "Failed to store new database version in database because no enough space for domain"_s }; >+ error = IDBError { QuotaExceededError, "Failed to store new database version in database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > else > error = IDBError { UnknownError, "Failed to store new database version in database"_s }; > } >@@ -984,7 +995,7 @@ IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& t > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not add object store '%s' to ObjectStoreInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Could not create object store because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Could not create object store because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Could not create object store"_s }; > } > } >@@ -996,7 +1007,7 @@ IDBError SQLiteIDBBackingStore::createObjectStore(const IDBResourceIdentifier& t > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not seed initial key generator value for ObjectStoreInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Could not seed initial key generator value for object store because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Could not seed initial key generator value for object store because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Could not seed initial key generator value for object store"_s }; > } > } >@@ -1123,7 +1134,7 @@ IDBError SQLiteIDBBackingStore::renameObjectStore(const IDBResourceIdentifier& t > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not update name for object store id %" PRIi64 " in ObjectStoreInfo table (%i) - %s", objectStoreIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Could not rename object store because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Could not rename object store because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Could not rename object store"_s }; > } > } >@@ -1208,7 +1219,7 @@ IDBError SQLiteIDBBackingStore::createIndex(const IDBResourceIdentifier& transac > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not add index '%s' to IndexInfo table (%i) - %s", info.name().utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Unable to create index in database because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Unable to create index in database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Unable to create index in database"_s }; > } > >@@ -1352,7 +1363,7 @@ IDBError SQLiteIDBBackingStore::uncheckedPutIndexRecord(int64_t objectStoreID, i > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not put index record for index %" PRIi64 " in object store %" PRIi64 " in Records table (%i) - %s", indexID, objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Error putting index record into database because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Error putting index record into database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Error putting index record into database"_s }; > } > } >@@ -1443,7 +1454,7 @@ IDBError SQLiteIDBBackingStore::renameIndex(const IDBResourceIdentifier& transac > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not update name for index id (%" PRIi64 ", %" PRIi64 ") in IndexInfo table (%i) - %s", objectStoreIdentifier, indexIdentifier, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Could not rename index because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Could not rename index because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Could not rename index"_s }; > } > } >@@ -1784,7 +1795,7 @@ IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transacti > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not put record for object store %" PRIi64 " in Records table (%i) - %s", objectStoreInfo.identifier(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Unable to store record in object store because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Unable to store record in object store because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Unable to store record in object store"_s }; > } > >@@ -1818,7 +1829,7 @@ IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transacti > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Unable to record Blob record in database"); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Unable to record Blob record in database because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Unable to record Blob record in database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Unable to record Blob record in database"_s }; > } > } >@@ -1853,7 +1864,7 @@ IDBError SQLiteIDBBackingStore::addRecord(const IDBResourceIdentifier& transacti > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Unable to record Blob file record in database"); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Unable to record Blob file in database because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Unable to record Blob file in database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { UnknownError, "Unable to record Blob file record in database"_s }; > } > } >@@ -2392,7 +2403,7 @@ IDBError SQLiteIDBBackingStore::uncheckedSetKeyGeneratorValue(int64_t objectStor > || sql->step() != SQLITE_DONE) { > LOG_ERROR("Could not update key generator value (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); > if (m_sqliteDB->lastError() == SQLITE_FULL) >- return IDBError { QuotaExceededError, "Error storing new key generator value in database because no enough space for domain"_s }; >+ return IDBError { QuotaExceededError, "Error storing new key generator value in database because no enough space for domain"_s, { m_identifier.databaseName(), m_identifier.originString(), m_quota, originDiskUsage(m_absoluteDatabaseDirectory), databaseSize(), databaseSize() + QuotaIncreaseSize } }; > return IDBError { ConstraintError, "Error storing new key generator value in database" }; > } > >diff --git a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h >index da67123902ec311317f687d2e01665a5a6284045..6862d9afa34f8b0457ca6f6034b3b9ffc6518078 100644 >--- a/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h >+++ b/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.h >@@ -43,6 +43,8 @@ class SQLiteStatement; > > namespace IDBServer { > >+const uint64_t QuotaIncreaseSize = 5 * MB; >+ > class SQLiteIDBCursor; > > class SQLiteIDBBackingStore : public IDBBackingStore { >@@ -95,12 +97,15 @@ public: > > static String databaseNameFromEncodedFilename(const String&); > >+ static uint64_t originDiskUsage(const String&); >+ > private: > String filenameForDatabaseName() const; > String fullDatabasePath() const; > > uint64_t quotaForOrigin() const; > uint64_t maximumSize() const; >+ uint64_t databaseSize() const; > > bool ensureValidRecordsTable(); > bool ensureValidIndexRecordsTable(); >diff --git a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp >index fc07ef1451b97e075cd3a56f620093a349c0cbc9..caa0b5eae0d76790d33680b7c695ef02371edff3 100644 >--- a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp >+++ b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.cpp >@@ -256,6 +256,7 @@ void UniqueIDBDatabase::deleteBackingStore(const IDBDatabaseIdentifier& identifi > deletedVersion = databaseInfo.version(); > backingStore->deleteBackingStore(); > } >+ m_server.mayDeleteOriginFromDatabase(m_identifier); > > postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didDeleteBackingStore, deletedVersion)); > } >@@ -612,12 +613,20 @@ void UniqueIDBDatabase::openBackingStore(const IDBDatabaseIdentifier& identifier > LOG(IndexedDB, "(db) UniqueIDBDatabase::openBackingStore (%p)", this); > > ASSERT(!m_backingStore); >- m_backingStore = m_server.createBackingStore(identifier); >- m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions(); >- m_backingStoreIsEphemeral = m_backingStore->isEphemeral(); > >+ // Check if there is space for new database. >+ IDBError error; >+ IDBQuotaDetails details; > IDBDatabaseInfo databaseInfo; >- auto error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo); >+ if (m_server.isQuotaFullForOrigin(identifier, details)) >+ error = IDBError { QuotaExceededError, "Failed to create new database because no enough space for domain"_s, details }; >+ else { >+ m_backingStore = m_server.createBackingStore(identifier); >+ m_backingStoreSupportsSimultaneousTransactions = m_backingStore->supportsSimultaneousTransactions(); >+ m_backingStoreIsEphemeral = m_backingStore->isEphemeral(); >+ >+ error = m_backingStore->getOrEstablishDatabaseInfo(databaseInfo); >+ } > > postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didOpenBackingStore, databaseInfo, error)); > } >@@ -1921,6 +1930,12 @@ void UniqueIDBDatabase::forgetErrorCallback(uint64_t callbackIdentifier) > > void UniqueIDBDatabase::setQuota(uint64_t quota) > { >+ postDatabaseTask(createCrossThreadTask(*this, &UniqueIDBDatabase::performSetQuota, quota)); >+} >+ >+void UniqueIDBDatabase::performSetQuota(uint64_t quota) >+{ >+ ASSERT(!isMainThread()); > if (m_backingStore) > m_backingStore->setQuota(quota); > } >diff --git a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h >index d46dfa903cfb35ed7c3538e21c3e2d6c4ab87480..0bb32421b71ffde98bb7189ce784e7d8010a76bb 100644 >--- a/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h >+++ b/Source/WebCore/Modules/indexeddb/server/UniqueIDBDatabase.h >@@ -167,6 +167,8 @@ private: > void performUnconditionalDeleteBackingStore(); > void shutdownForClose(); > >+ void performSetQuota(uint64_t quota); >+ > // Main thread callbacks > void didDeleteBackingStore(uint64_t deletedVersion); > void didOpenBackingStore(const IDBDatabaseInfo&, const IDBError&); >diff --git a/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp b/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp >index ae314b24ee72caa0969e6c3b9b6e76e9acac3398..9d78b0de735d2a58cc2f6b75feeaa5e62c9b4a1f 100644 >--- a/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp >+++ b/Source/WebCore/Modules/indexeddb/shared/IDBError.cpp >@@ -32,21 +32,23 @@ > > namespace WebCore { > >-IDBError::IDBError(std::optional<ExceptionCode> code, const String& message) >+IDBError::IDBError(std::optional<ExceptionCode> code, const String& message, const IDBQuotaDetails& details) > : m_code(code) > , m_message(message) >+ , m_quotaDetails(details) > { > } > > IDBError IDBError::isolatedCopy() const > { >- return IDBError { m_code, m_message.isolatedCopy() }; >+ return IDBError { m_code, m_message.isolatedCopy(), m_quotaDetails.isolatedCopy() }; > } > > IDBError& IDBError::operator=(const IDBError& other) > { > m_code = other.m_code; > m_message = other.m_message; >+ m_quotaDetails = other.m_quotaDetails; > return *this; > } > >diff --git a/Source/WebCore/Modules/indexeddb/shared/IDBError.h b/Source/WebCore/Modules/indexeddb/shared/IDBError.h >index 0a28967b169565d04c639043969dd8e770dccb33..d5f31a81b424b2a1474a8db97d5d1b1e7f6131b1 100644 >--- a/Source/WebCore/Modules/indexeddb/shared/IDBError.h >+++ b/Source/WebCore/Modules/indexeddb/shared/IDBError.h >@@ -29,13 +29,14 @@ > > #include "DOMException.h" > #include "ExceptionCode.h" >+#include "IDBQuotaDetails.h" > #include <wtf/text/WTFString.h> > > namespace WebCore { > > class IDBError { > public: >- WEBCORE_EXPORT explicit IDBError(std::optional<ExceptionCode> = std::nullopt, const String& message = { }); >+ WEBCORE_EXPORT explicit IDBError(std::optional<ExceptionCode> = std::nullopt, const String& message = { }, const IDBQuotaDetails& details = { }); > > static IDBError userDeleteError() > { >@@ -54,6 +55,7 @@ public: > std::optional<ExceptionCode> code() const { return m_code; } > String name() const; > String message() const; >+ IDBQuotaDetails quotaDetails() const { return m_quotaDetails; }; > > bool isNull() const { return !m_code; } > >@@ -65,6 +67,7 @@ public: > private: > std::optional<ExceptionCode> m_code; > String m_message; >+ IDBQuotaDetails m_quotaDetails; > }; > > template<class Encoder> >@@ -75,7 +78,7 @@ void IDBError::encode(Encoder& encoder) const > encoder.encodeEnum(m_code.value()); > } else > encoder << false; >- encoder << m_message; >+ encoder << m_message << m_quotaDetails; > } > > template<class Decoder> >@@ -96,6 +99,9 @@ bool IDBError::decode(Decoder& decoder, IDBError& error) > if (!decoder.decode(error.m_message)) > return false; > >+ if (!decoder.decode(error.m_quotaDetails)) >+ return false; >+ > return true; > } > >diff --git a/Source/WebCore/Modules/indexeddb/shared/IDBQuotaDetails.h b/Source/WebCore/Modules/indexeddb/shared/IDBQuotaDetails.h >new file mode 100644 >index 0000000000000000000000000000000000000000..5625d92f07a7f4eaf5bb39b1c43fda8d4620fb50 >--- /dev/null >+++ b/Source/WebCore/Modules/indexeddb/shared/IDBQuotaDetails.h >@@ -0,0 +1,106 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(INDEXED_DATABASE) >+ >+namespace WebCore { >+ >+class IDBQuotaDetails { >+public: >+ IDBQuotaDetails() = default; >+ IDBQuotaDetails(const String& name, const String& origin, uint64_t quota, uint64_t usage, uint64_t dbUsage, uint64_t expectedDBUsage = 0) >+ : m_databaseName(name) >+ , m_originIdentifier(origin) >+ , m_quota(quota) >+ , m_usage(usage) >+ , m_databaseUsage(dbUsage) >+ , m_expectedDatabaseUsage(expectedDBUsage) { } >+ >+ IDBQuotaDetails isolatedCopy() const >+ { >+ return { m_databaseName.isolatedCopy(), m_originIdentifier.isolatedCopy(), m_quota, m_usage, m_databaseUsage }; >+ } >+ >+ const String& databaseName() const { return m_databaseName; } >+ const String& origin() const { return m_originIdentifier; } >+ uint64_t quota() const { return m_quota; } >+ uint64_t usage() const { return m_usage; } >+ uint64_t databaseUsage() const { return m_databaseUsage; } >+ uint64_t expectedDatabaseUsage() const { return m_expectedDatabaseUsage; } >+ >+#if !LOG_DISABLED >+ String loggingString() const >+ { >+ return makeString(m_databaseName, "@", m_originIdentifier, ": ", String::number(m_quota / MB), "MB quota, ", String::number(m_usage / MB), "MB total usage, ", String::number(m_databaseUsage / MB), "MB database usage, ", String::number(m_expectedDatabaseUsage / MB), "MB expected database usage"); >+ } >+#endif >+ >+ template<class Encoder> void encode(Encoder&) const; >+ template<class Decoder> static bool decode(Decoder&, IDBQuotaDetails&); >+ >+private: >+ String m_databaseName; >+ String m_originIdentifier; >+ uint64_t m_quota; >+ uint64_t m_usage; >+ uint64_t m_databaseUsage; >+ uint64_t m_expectedDatabaseUsage; >+}; >+ >+template<class Encoder> >+void IDBQuotaDetails::encode(Encoder& encoder) const >+{ >+ encoder << m_databaseName << m_originIdentifier << m_quota << m_usage << m_databaseUsage << m_expectedDatabaseUsage; >+} >+ >+template<class Decoder> >+bool IDBQuotaDetails::decode(Decoder& decoder, IDBQuotaDetails& details) >+{ >+ if (!decoder.decode(details.m_databaseName)) >+ return false; >+ >+ if (!decoder.decode(details.m_originIdentifier)) >+ return false; >+ >+ if (!decoder.decode(details.m_quota)) >+ return false; >+ >+ if (!decoder.decode(details.m_usage)) >+ return false; >+ >+ if (!decoder.decode(details.m_databaseUsage)) >+ return false; >+ >+ if (!decoder.decode(details.m_expectedDatabaseUsage)) >+ return false; >+ >+ return true; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(INDEXED_DATABASE) >diff --git a/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp b/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp >index 61aeb8f7d70151b942285acdccf81bfb1ea42626..26c41d536b96f19cc3e298628797320b9bd15ff5 100644 >--- a/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp >+++ b/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.cpp >@@ -446,6 +446,12 @@ void InProcessIDBServer::accessToTemporaryFileComplete(const String& path) > FileSystem::deleteFile(path); > } > >+void InProcessIDBServer::updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) >+{ >+ UNUSED_PARAM(originIdentifierString); >+ UNUSED_PARAM(quota); >+} >+ > } // namespace WebCore > > #endif // ENABLE(INDEXED_DATABASE) >diff --git a/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h b/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h >index c7944d1b36f7359d3cb617069c30121885534973..2c2ac7f3c8eb1c3c2e88c4063631ef5301d7d347 100644 >--- a/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h >+++ b/Source/WebCore/Modules/indexeddb/shared/InProcessIDBServer.h >@@ -82,6 +82,7 @@ public: > void openDBRequestCancelled(const IDBRequestData&) final; > void confirmDidCloseFromServer(uint64_t databaseConnectionIdentifier) final; > void getAllDatabaseNames(const SecurityOriginData& mainFrameOrigin, const SecurityOriginData& openingOrigin, uint64_t callbackID) final; >+ void updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) final; > > // IDBConnectionToClient > uint64_t identifier() const override; >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 66f7b8d4c51ca80691c8211f305eab3688d00e6e..cf52caf3bfc73ff558d93a55b7510c37211d125d 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -2659,6 +2659,7 @@ > 9392F1420AD185F400691BD4 /* RenderCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F1410AD185F400691BD4 /* RenderCounter.h */; }; > 9392F14C0AD1861B00691BD4 /* CounterNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 9392F14B0AD1861B00691BD4 /* CounterNode.h */; }; > 9393E600151A99F200066F06 /* CSSImageSetValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9393E5FE151A99F200066F06 /* CSSImageSetValue.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 9397534721B7586000B2742B /* IDBQuotaDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 9397534521B7515C00B2742B /* IDBQuotaDetails.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 939885C408B7E3D100E707C4 /* EventNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 939885C208B7E3D100E707C4 /* EventNames.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 939B02EF0EA2DBC400C54570 /* WidthIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 939B02ED0EA2DBC400C54570 /* WidthIterator.h */; }; > 93A806151E03B51C008A1F26 /* DoubleRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 93A806111E03B51C008A1F26 /* DoubleRange.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -10500,6 +10501,7 @@ > 9393E5FE151A99F200066F06 /* CSSImageSetValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSImageSetValue.h; sourceTree = "<group>"; }; > 93955A4103D72932008635CE /* RenderTreeAsText.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeAsText.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; }; > 93955A4203D72932008635CE /* RenderTreeAsText.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeAsText.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; }; >+ 9397534521B7515C00B2742B /* IDBQuotaDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBQuotaDetails.h; sourceTree = "<group>"; }; > 939885C108B7E3D100E707C4 /* EventNames.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventNames.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; }; > 939885C208B7E3D100E707C4 /* EventNames.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = EventNames.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; }; > 939B02EC0EA2DBC400C54570 /* WidthIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WidthIterator.cpp; sourceTree = "<group>"; }; >@@ -18213,6 +18215,7 @@ > 51E269351DD3BD91006B6A58 /* IDBIterateCursorData.h */, > 5160712C1BD8307200DBC4F2 /* IDBObjectStoreInfo.cpp */, > 5160712D1BD8307200DBC4F2 /* IDBObjectStoreInfo.h */, >+ 9397534521B7515C00B2742B /* IDBQuotaDetails.h */, > 510A58F51BACC4A500C19282 /* IDBRequestData.cpp */, > 510A58F61BACC4A500C19282 /* IDBRequestData.h */, > 5145B1071BC4890B00E86219 /* IDBResourceIdentifier.cpp */, >@@ -28006,8 +28009,8 @@ > CD318623199F1E2A0030A0F7 /* CDMPrivateMediaSourceAVFObjC.h in Headers */, > CDE595971BF26E2100A1CBE8 /* CDMSessionMediaSourceAVFObjC.h in Headers */, > 5FA904CA178E61F5004C8A2D /* CertificateInfo.h in Headers */, >- 91B8F0B521953D65000C2B00 /* CertificateInfoBase.h in Headers */, >- FE36FD1516C7826500F887C1 /* ChangeVersionData.h in Headers */, >+ 91B8F0B521953D65000C2B00 /* CertificateInfoBase.h in Headers */, >+ FE36FD1516C7826500F887C1 /* ChangeVersionData.h in Headers */, > 97BC69DD1505F076001B74AC /* ChangeVersionWrapper.h in Headers */, > FD315FFF12B0267600C1A359 /* ChannelMergerNode.h in Headers */, > FD31600212B0267600C1A359 /* ChannelSplitterNode.h in Headers */, >@@ -28976,6 +28979,7 @@ > 5185FCA01BB4C4E80012898F /* IDBObjectStore.h in Headers */, > 5160712F1BD8307800DBC4F2 /* IDBObjectStoreInfo.h in Headers */, > 5185FCA41BB4C4E80012898F /* IDBOpenDBRequest.h in Headers */, >+ 9397534721B7586000B2742B /* IDBQuotaDetails.h in Headers */, > 5185FCA71BB4C4E80012898F /* IDBRecordIdentifier.h in Headers */, > 5185FCA91BB4C4E80012898F /* IDBRequest.h in Headers */, > 514129991C6976900059E714 /* IDBRequestCompletionEvent.h in Headers */, >diff --git a/Source/WebCore/loader/EmptyClients.h b/Source/WebCore/loader/EmptyClients.h >index ae588f784d204aa95b276cc7a3250728c7f7b614..5735ceed34e30d11e58f976d69030c7902038e25 100644 >--- a/Source/WebCore/loader/EmptyClients.h >+++ b/Source/WebCore/loader/EmptyClients.h >@@ -124,6 +124,7 @@ class EmptyChromeClient : public ChromeClient { > void print(Frame&) final { } > > void exceededDatabaseQuota(Frame&, const String&, DatabaseDetails) final { } >+ uint64_t exceededDatabaseQuota(Frame&, IDBQuotaDetails) final { return 0; } > > void reachedMaxAppCacheSize(int64_t) final { } > void reachedApplicationCacheOriginQuota(SecurityOrigin&, int64_t) final { } >diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h >index 08f583e2ece9606d6e4e0f019f8416b4f8994ff1..68406bfd02caa43945213c2f3badd1a56932f4ad 100644 >--- a/Source/WebCore/page/ChromeClient.h >+++ b/Source/WebCore/page/ChromeClient.h >@@ -33,6 +33,7 @@ > #include "GraphicsLayer.h" > #include "HTMLMediaElementEnums.h" > #include "HostWindow.h" >+#include "IDBQuotaDetails.h" > #include "Icon.h" > #include "LayerFlushThrottleState.h" > #include "MediaProducer.h" >@@ -209,6 +210,7 @@ public: > virtual void pageExtendedBackgroundColorDidChange(Color) const { } > > virtual void exceededDatabaseQuota(Frame&, const String& databaseName, DatabaseDetails) = 0; >+ virtual uint64_t exceededDatabaseQuota(Frame&, IDBQuotaDetails) = 0; > > // Callback invoked when the application cache fails to save a cache object > // because storing it would grow the database file past its defined maximum >diff --git a/Source/WebCore/page/SecurityOriginData.cpp b/Source/WebCore/page/SecurityOriginData.cpp >index b7f83cee2674d55acfcc98e9e1139a407151a0a6..23b51fe7a031bba8a47a3559e3387ed585b4401f 100644 >--- a/Source/WebCore/page/SecurityOriginData.cpp >+++ b/Source/WebCore/page/SecurityOriginData.cpp >@@ -64,6 +64,7 @@ Ref<SecurityOrigin> SecurityOriginData::securityOrigin() const > } > > static const char separatorCharacter = '_'; >+static const char separatorCharacterForOrigins = '/'; > > String SecurityOriginData::databaseIdentifier() const > { >@@ -120,6 +121,15 @@ std::optional<SecurityOriginData> SecurityOriginData::fromDatabaseIdentifier(con > return SecurityOriginData { protocol, host, static_cast<uint16_t>(port) }; > } > >+std::optional<SecurityOriginData> SecurityOriginData::fromOriginIdentifier(const String& originIdentifier) >+{ >+ auto seperator = originIdentifier.find(separatorCharacterForOrigins); >+ if (seperator != notFound) >+ return fromDatabaseIdentifier(originIdentifier.substring(0, seperator)); >+ >+ return fromDatabaseIdentifier(originIdentifier); >+} >+ > SecurityOriginData SecurityOriginData::isolatedCopy() const > { > SecurityOriginData result; >diff --git a/Source/WebCore/page/SecurityOriginData.h b/Source/WebCore/page/SecurityOriginData.h >index 27762ea21d6d2065e9dd0146db979b332ec456c0..fbb0842768b1c5e96a2c9498582749cec50b3970 100644 >--- a/Source/WebCore/page/SecurityOriginData.h >+++ b/Source/WebCore/page/SecurityOriginData.h >@@ -70,6 +70,7 @@ struct SecurityOriginData { > // file names. This format should be used in storage APIs only. > WEBCORE_EXPORT String databaseIdentifier() const; > WEBCORE_EXPORT static std::optional<SecurityOriginData> fromDatabaseIdentifier(const String&); >+ WEBCORE_EXPORT static std::optional<SecurityOriginData> fromOriginIdentifier(const String&); > > template<class Encoder> void encode(Encoder&) const; > template<class Decoder> static std::optional<SecurityOriginData> decode(Decoder&); >diff --git a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.cpp b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.cpp >index 1af259e9e601fb895b77f4edc3d59ae086a38fd6..20e61864308843c0078faad686af593002ef378d 100644 >--- a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.cpp >+++ b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.cpp >@@ -360,6 +360,11 @@ void WebIDBConnectionToClient::getAllDatabaseNames(uint64_t serverConnectionIden > NetworkProcess::singleton().idbServer(m_sessionID).getAllDatabaseNames(serverConnectionIdentifier, topOrigin, openingOrigin, callbackID); > } > >+void WebIDBConnectionToClient::updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota) >+{ >+ NetworkProcess::singleton().idbServer(m_sessionID).setQuotaForOrigin(originIdentifierString, quota); >+} >+ > } // namespace WebKit > > #endif // ENABLE(INDEXED_DATABASE) >diff --git a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.h b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.h >index 5926b00213a72b3073f2c047c60b1ec4449c7f80..9bf908876167bd0b45e02c6529697b28ef4c6a31 100644 >--- a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.h >+++ b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.h >@@ -121,6 +121,8 @@ public: > > void getAllDatabaseNames(uint64_t serverConnectionIdentifier, const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID); > >+ void updateQuotaForOrigin(const String& originIdentifierString, uint64_t quota); >+ > void disconnectedFromWebProcess(); > > void didReceiveMessage(IPC::Connection&, IPC::Decoder&); >diff --git a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.messages.in b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.messages.in >index 4aab0267d7b354326c57749e070082eeb83770f1..6805abe2cea4aaa92931af9223ce43e70510ec9d 100644 >--- a/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.messages.in >+++ b/Source/WebKit/NetworkProcess/IndexedDB/WebIDBConnectionToClient.messages.in >@@ -52,5 +52,6 @@ messages -> WebIDBConnectionToClient { > ConfirmDidCloseFromServer(uint64_t databaseConnectionIdentifier); > > GetAllDatabaseNames(uint64_t serverConnectionIdentifier, struct WebCore::SecurityOriginData topOrigin, struct WebCore::SecurityOriginData openingOrigin, uint64_t callbackID); >+ UpdateQuotaForOrigin(String originIdentifier, uint64_t quota); > } > #endif // ENABLE(INDEXED_DATABASE) >diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp >index 77fc452e0a9468c31d71e634a59c923958dca2df..bebd720c36acfe51b0981fe2c72f30eb52807b02 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.cpp >+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp >@@ -6647,7 +6647,7 @@ void WebPageProxy::exceededDatabaseQuota(uint64_t frameID, const String& originI > WebFrameProxy* frame = m_process->webFrame(record->frameID); > MESSAGE_CHECK(frame); > >- auto origin = API::SecurityOrigin::create(SecurityOriginData::fromDatabaseIdentifier(record->originIdentifier)->securityOrigin()); >+ auto origin = API::SecurityOrigin::create(SecurityOriginData::fromOriginIdentifier(record->originIdentifier)->securityOrigin()); > m_uiClient->exceededDatabaseQuota(this, frame, origin.ptr(), record->databaseName, record->displayName, record->currentQuota, record->currentOriginUsage, record->currentDatabaseUsage, record->expectedUsage, WTFMove(record->reply)); > record = records.next(); > } >diff --git a/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp b/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp >index 42e73c8225da91f00b8f1f4e6bf93de074658d1f..d2fd34e6162e5c9d20209230674705a780d9dca1 100644 >--- a/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp >+++ b/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.cpp >@@ -219,6 +219,11 @@ void WebIDBConnectionToServer::getAllDatabaseNames(const WebCore::SecurityOrigin > send(Messages::WebIDBConnectionToClient::GetAllDatabaseNames(m_identifier, topOrigin, openingOrigin, callbackID)); > } > >+void WebIDBConnectionToServer::updateQuotaForOrigin(const String& originIdentifier, uint64_t quota) >+{ >+ send(Messages::WebIDBConnectionToClient::UpdateQuotaForOrigin(originIdentifier, quota)); >+} >+ > void WebIDBConnectionToServer::didDeleteDatabase(const IDBResultData& result) > { > m_connectionToServer->didDeleteDatabase(result); >diff --git a/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h b/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h >index 8fe9cb9c0c0402831c98e0f6d0ce67f0eb144200..ef4d0d5d7318ec5ce721174b9222bd3585f25447 100644 >--- a/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h >+++ b/Source/WebKit/WebProcess/Databases/IndexedDB/WebIDBConnectionToServer.h >@@ -76,6 +76,8 @@ public: > > void getAllDatabaseNames(const WebCore::SecurityOriginData& topOrigin, const WebCore::SecurityOriginData& openingOrigin, uint64_t callbackID) final; > >+ void updateQuotaForOrigin(const String& originIdentifier, uint64_t quota) final; >+ > void ref() override { RefCounted<WebIDBConnectionToServer>::ref(); } > void deref() override { RefCounted<WebIDBConnectionToServer>::deref(); } > >diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp >index b31b117f0edab398b25124064e16227faf786255..8b0324b86e661522ec2d24c0aff4334c137f6d3d 100644 >--- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp >+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp >@@ -730,6 +730,21 @@ void WebChromeClient::exceededDatabaseQuota(Frame& frame, const String& database > tracker.setQuota(originData, newQuota); > } > >+uint64_t WebChromeClient::exceededDatabaseQuota(Frame& frame, IDBQuotaDetails details) >+{ >+ WebFrame* webFrame = WebFrame::fromCoreFrame(frame); >+ ASSERT(webFrame); >+ >+ uint64_t newQuota = 0; >+ RefPtr<API::SecurityOrigin> securityOrigin = API::SecurityOrigin::create(SecurityOriginData::fromOriginIdentifier(details.origin())->securityOrigin()); >+ newQuota = m_page.injectedBundleUIClient().didExceedDatabaseQuota(&m_page, securityOrigin.get(), details.databaseName(), details.databaseName(), details.quota(), details.usage(), details.databaseUsage(), details.expectedDatabaseUsage()); >+ >+ if (!newQuota) >+ WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPageProxy::ExceededDatabaseQuota(webFrame->frameID(), details.origin(), details.databaseName(), details.databaseName(), details.quota(), details.usage(), details.databaseUsage(), details.expectedDatabaseUsage()), Messages::WebPageProxy::ExceededDatabaseQuota::Reply(newQuota), m_page.pageID(), Seconds::infinity(), IPC::SendSyncOption::InformPlatformProcessWillSuspend); >+ >+ return newQuota; >+} >+ > void WebChromeClient::reachedMaxAppCacheSize(int64_t) > { > notImplemented(); >diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h >index 4315126b0648e3447fc0b9cfbc88023c001bfca9..3fbba1135e0da963d9422312e4bcac19919503ce 100644 >--- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h >+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h >@@ -131,6 +131,7 @@ private: > void print(WebCore::Frame&) final; > > void exceededDatabaseQuota(WebCore::Frame&, const String& databaseName, WebCore::DatabaseDetails) final; >+ uint64_t exceededDatabaseQuota(WebCore::Frame&, WebCore::IDBQuotaDetails) final; > > void reachedMaxAppCacheSize(int64_t spaceNeeded) final; > void reachedApplicationCacheOriginQuota(WebCore::SecurityOrigin&, int64_t spaceNeeded) final; >diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h b/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h >index 37a32f87687164f039be98b3d0e7e72635a1a8d9..4b3f1e430be54c88d827dd7fd45ded962c7eeba3 100644 >--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h >+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h >@@ -118,6 +118,7 @@ private: > > void print(WebCore::Frame&) final; > void exceededDatabaseQuota(WebCore::Frame&, const String& databaseName, WebCore::DatabaseDetails) final; >+ uint64_t exceededDatabaseQuota(WebCore::Frame&, WebCore::IDBQuotaDetails) final; > void reachedMaxAppCacheSize(int64_t spaceNeeded) final; > void reachedApplicationCacheOriginQuota(WebCore::SecurityOrigin&, int64_t totalSpaceNeeded) final; > >diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm b/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm >index 4c5d18dc02ccff2b7eab98050921a67a98f69cc5..6c19e018c88902eed1c0dc1d03fedde0803b5dc9 100644 >--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm >+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm >@@ -687,6 +687,17 @@ void WebChromeClient::exceededDatabaseQuota(Frame& frame, const String& database > END_BLOCK_OBJC_EXCEPTIONS; > } > >+uint64_t WebChromeClient::exceededDatabaseQuota(Frame& frame, WebCore::IDBQuotaDetails detail) >+{ >+ BEGIN_BLOCK_OBJC_EXCEPTIONS; >+ >+ WebSecurityOrigin *webOrigin = [[WebSecurityOrigin alloc] _initWithWebCoreSecurityOrigin:&frame.document()->securityOrigin()]; >+ CallUIDelegate(m_webView, @selector(webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:), kit(&frame), webOrigin, (NSString *)detail.databaseName()); >+ [webOrigin release]; >+ >+ END_BLOCK_OBJC_EXCEPTIONS; >+} >+ > void WebChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded) > { > // FIXME: Free some space. >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 5d6c9c0b90a41b0d5e59237ba15659e416f2526d..b2ab061862912156648b3c8db08eeb473c8c92ee 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,22 @@ >+2018-12-10 Sihui Liu <sihui_liu@apple.com> >+ >+ IndexedDB: quota should be able to increase >+ https://bugs.webkit.org/show_bug.cgi?id=192556 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * storage/indexeddb/resources/storage-limit.js: >+ (test): >+ (cleanOpenDatabase): >+ (openDatabase): >+ (onOpenError): >+ (onOpenSuccess): >+ (onAddError): >+ (prepareDatabase): Deleted. >+ (onOpenSuccess.request.onerror): Deleted. >+ (onOpenSuccess.request.onsuccess): Deleted. >+ * storage/indexeddb/storage-limit-expected.txt: >+ > 2018-12-04 Devin Rousso <drousso@apple.com> > > Web Inspector: Audit: tests should support async operations >diff --git a/LayoutTests/storage/indexeddb/resources/storage-limit.js b/LayoutTests/storage/indexeddb/resources/storage-limit.js >index 0d57b6c693f7d073bda9c3cc12905b0c5867c224..b4d0078c552cb17fbb723872c94a244a4c4a1b75 100644 >--- a/LayoutTests/storage/indexeddb/resources/storage-limit.js >+++ b/LayoutTests/storage/indexeddb/resources/storage-limit.js >@@ -2,37 +2,89 @@ if (this.importScripts) { > importScripts('../../../resources/js-test.js'); > importScripts('shared.js'); > } >+description("This test makes sure that indexedDB has a quota and the quota can grow."); > >-var quota = 1024 * 1024; // 1 MB >-description("This test makes sure that storage of indexedDB does not grow unboundedly."); >+const initialQuota = 0; >+const newQuota1 = Math.round(0.6 * 1024 * 1024); >+const newQuota2 = 5 * 1024 * 1024; >+const arraySize = Math.round(0.3 * 1024 * 1024 + 1); > >-if (window.testRunner) >- testRunner.setIDBPerOriginQuota(quota); >+function test() { >+ if (window.testRunner) { >+ testRunner.setIDBPerOriginQuota(initialQuota); >+ testRunner.databaseDefaultQuota = newQuota1; >+ } > >-indexedDBTest(prepareDatabase, onOpenSuccess); >+ evalAndLog("arr = new Uint8Array(" + arraySize + ")"); >+ cleanOpenDatabase("dbWithQuota", unexpectedSuccessCallback, onOpenError); >+} > >-function prepareDatabase(event) >+function cleanOpenDatabase(name, successCallack, errorCallack) > { >- preamble(event); >- evalAndLog("db = event.target.result"); >- evalAndLog("store = db.createObjectStore('store')"); >+ var deleteRequest = indexedDB.deleteDatabase('" + name + "'); >+ deleteRequest.onerror = unexpectedErrorCallback; >+ deleteRequest.onsuccess = () => { >+ openDatabase(name, successCallack, errorCallack); >+ } > } > >-function onOpenSuccess(event) >+function openDatabase(name, successCallack, errorCallack) > { >- preamble(event); >- evalAndLog("db = event.target.result"); >- evalAndLog("store = db.transaction('store', 'readwrite').objectStore('store')"); >- evalAndLog("request = store.add(new Uint8Array(" + (quota + 1) + "), 0)"); >- request.onerror = function(event) { >- shouldBeTrue("'error' in request"); >- shouldBe("request.error.code", "DOMException.QUOTA_EXCEEDED_ERR"); >- shouldBeEqualToString("request.error.name", "QuotaExceededError"); >- finishJSTest(); >+ preamble(); >+ openRequest = evalAndLog("indexedDB.open('"+ name +"')"); >+ openRequest.onupgradeneeded = () => { >+ request = evalAndLog("openRequest.result.createObjectStore('testObjectStore')"); >+ request.onerror = unexpectedErrorCallback; > } >+ openRequest.onsuccess = successCallack; >+ openRequest.onerror = errorCallack; >+} >+ >+function onOpenError() >+{ >+ shouldBeTrue("'error' in openRequest"); >+ shouldBe("openRequest.error.code", "DOMException.QUOTA_EXCEEDED_ERR"); >+ shouldBeEqualToString("openRequest.error.name", "QuotaExceededError"); > >- request.onsuccess = function(event) { >- testFailed("Add operation should fail because storage limit is reached, but succeeded."); >- finishJSTest(); >+ openDatabase("dbWithQuota", onOpenSuccess, unexpectedErrorCallback); >+} >+ >+function onOpenSuccess() >+{ >+ db = evalAndLog("db = event.target.result"); >+ if (db.name == "dbWithQuota") >+ addToDatabase(() => { }, unexpectedErrorCallback, () => { >+ cleanOpenDatabase("dbWithoutQuota", onOpenSuccess, unexpectedErrorCallback); >+ }); >+ else { >+ if (window.testRunner) >+ testRunner.databaseDefaultQuota = newQuota2; >+ addToDatabase(unexpectedSuccessCallback, onAddError, () => { }); > } >-} >\ No newline at end of file >+} >+ >+function addToDatabase(successCallack, errorCallack, completeCallack) >+{ >+ evalAndLog("tx = db.transaction('testObjectStore', 'readwrite')"); >+ evalAndLog("store = tx.objectStore('testObjectStore')"); >+ tx.oncomplete = completeCallack; >+ request = evalAndLog("request = store.add(arr, 0)"); >+ request.onsuccess = successCallack; >+ request.onerror = errorCallack; >+} >+ >+function onAddError() >+{ >+ shouldBeTrue("'error' in request"); >+ shouldBe("request.error.code", "DOMException.QUOTA_EXCEEDED_ERR"); >+ shouldBeEqualToString("request.error.name", "QuotaExceededError"); >+ >+ addToDatabase(finish, unexpectedErrorCallback, () => { }); >+} >+ >+function finish() >+{ >+ finishJSTest(); >+} >+ >+test(); >diff --git a/LayoutTests/storage/indexeddb/storage-limit-expected.txt b/LayoutTests/storage/indexeddb/storage-limit-expected.txt >index c314a44af6d700063c4ae0fbde47538b0aecb10d..91e1c315dfa65fc83ba560b49574db26346d2f03 100644 >--- a/LayoutTests/storage/indexeddb/storage-limit-expected.txt >+++ b/LayoutTests/storage/indexeddb/storage-limit-expected.txt >@@ -1,24 +1,37 @@ >-This test makes sure that storage of indexedDB does not grow unboundedly. >+This test makes sure that indexedDB has a quota and the quota can grow. > > 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; >+arr = new Uint8Array(314574) > >-indexedDB.deleteDatabase(dbname) >-indexedDB.open(dbname) >+openDatabase(): >+indexedDB.open('dbWithQuota') >+PASS 'error' in openRequest is true >+PASS openRequest.error.code is DOMException.QUOTA_EXCEEDED_ERR >+PASS openRequest.error.name is "QuotaExceededError" > >-prepareDatabase(): >+openDatabase(): >+indexedDB.open('dbWithQuota') >+openRequest.result.createObjectStore('testObjectStore') > db = event.target.result >-store = db.createObjectStore('store') >+tx = db.transaction('testObjectStore', 'readwrite') >+store = tx.objectStore('testObjectStore') >+request = store.add(arr, 0) > >-onOpenSuccess(): >+openDatabase(): >+indexedDB.open('dbWithoutQuota') >+openRequest.result.createObjectStore('testObjectStore') > db = event.target.result >-store = db.transaction('store', 'readwrite').objectStore('store') >-request = store.add(new Uint8Array(1048577), 0) >+tx = db.transaction('testObjectStore', 'readwrite') >+store = tx.objectStore('testObjectStore') >+request = store.add(arr, 0) > PASS 'error' in request is true > PASS request.error.code is DOMException.QUOTA_EXCEEDED_ERR > PASS request.error.name is "QuotaExceededError" >+tx = db.transaction('testObjectStore', 'readwrite') >+store = tx.objectStore('testObjectStore') >+request = store.add(arr, 0) > PASS successfullyParsed is true > > TEST COMPLETE
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192556
:
356969
|
356991
|
356997
|
357001
|
357003
|
357088
|
357089
|
357092
|
357095
|
357096
|
357097
|
357107