Title: [167231] releases/WebKitGTK/webkit-2.4/Source/WebCore
Revision
167231
Author
[email protected]
Date
2014-04-14 02:47:41 -0700 (Mon, 14 Apr 2014)

Log Message

Merge r165145 - ASSERT(newestManifest) fails in WebCore::ApplicationCacheGroup::didFinishLoadingManifest()
https://bugs.webkit.org/show_bug.cgi?id=129753
<rdar://problem/12069835>

Reviewed by Alexey Proskuryakov.

Fixes an issue where an assertion failure would occur when visiting a web site whose on-disk
app cache doesn't contain a manifest resource.

For some reason an app cache for a web site may be partially written to disk. In particular, the
app cache may only contain a CacheGroups entry. That is, the manifest resource and origin records
may not be persisted to disk. From looking over the code, we're unclear how such a situation can occur
and hence have been unable to create such an app cache. We were able to reproduce this issue using
an app cache database file that was provided by a person that was affected by this issue.

No test included because it's not straightforward to write a test for this change.

* loader/appcache/ApplicationCacheGroup.cpp:
(WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): Assert that m_cacheBeingUpdated->manifestResource()
is non-null. Currently we only document this assumption in a code comment. Also separated a single assertion
_expression_ into two assertion expressions to make it straightforward to identify the failing sub-_expression_
on failure.
* loader/appcache/ApplicationCacheStorage.cpp:
(WebCore::ApplicationCacheStorage::store): Modified to call ApplicationCacheStorage::deleteCacheGroupRecord()
to remove a cache group and associated cache records (if applicable) before inserting a cache group entry.
This replacement approach will ultimately repair incomplete app cache data for people affected by this bug.
(WebCore::ApplicationCacheStorage::loadCache): Log an error and return nullptr if the cache we loaded doesn't
have a manifest resource.
(WebCore::ApplicationCacheStorage::deleteCacheGroupRecord): Added.
(WebCore::ApplicationCacheStorage::deleteCacheGroup): Extracted deletion logic for cache group record into
ApplicationCacheStorage::deleteCacheGroupRecord().
* loader/appcache/ApplicationCacheStorage.h:

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.4/Source/WebCore/ChangeLog (167230 => 167231)


--- releases/WebKitGTK/webkit-2.4/Source/WebCore/ChangeLog	2014-04-14 09:43:41 UTC (rev 167230)
+++ releases/WebKitGTK/webkit-2.4/Source/WebCore/ChangeLog	2014-04-14 09:47:41 UTC (rev 167231)
@@ -1,3 +1,39 @@
+2014-03-05  Daniel Bates  <[email protected]>
+            And Alexey Proskuryakov  <[email protected]>
+
+        ASSERT(newestManifest) fails in WebCore::ApplicationCacheGroup::didFinishLoadingManifest()
+        https://bugs.webkit.org/show_bug.cgi?id=129753
+        <rdar://problem/12069835>
+
+        Reviewed by Alexey Proskuryakov.
+
+        Fixes an issue where an assertion failure would occur when visiting a web site whose on-disk
+        app cache doesn't contain a manifest resource.
+
+        For some reason an app cache for a web site may be partially written to disk. In particular, the
+        app cache may only contain a CacheGroups entry. That is, the manifest resource and origin records
+        may not be persisted to disk. From looking over the code, we're unclear how such a situation can occur
+        and hence have been unable to create such an app cache. We were able to reproduce this issue using
+        an app cache database file that was provided by a person that was affected by this issue.
+
+        No test included because it's not straightforward to write a test for this change.
+
+        * loader/appcache/ApplicationCacheGroup.cpp:
+        (WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): Assert that m_cacheBeingUpdated->manifestResource()
+        is non-null. Currently we only document this assumption in a code comment. Also separated a single assertion
+        _expression_ into two assertion expressions to make it straightforward to identify the failing sub-_expression_
+        on failure.
+        * loader/appcache/ApplicationCacheStorage.cpp:
+        (WebCore::ApplicationCacheStorage::store): Modified to call ApplicationCacheStorage::deleteCacheGroupRecord()
+        to remove a cache group and associated cache records (if applicable) before inserting a cache group entry.
+        This replacement approach will ultimately repair incomplete app cache data for people affected by this bug.
+        (WebCore::ApplicationCacheStorage::loadCache): Log an error and return nullptr if the cache we loaded doesn't
+        have a manifest resource.
+        (WebCore::ApplicationCacheStorage::deleteCacheGroupRecord): Added.
+        (WebCore::ApplicationCacheStorage::deleteCacheGroup): Extracted deletion logic for cache group record into
+        ApplicationCacheStorage::deleteCacheGroupRecord().
+        * loader/appcache/ApplicationCacheStorage.h:
+
 2014-03-05  David Kilzer  <[email protected]>
 
         Fix crash in CompositeEditCommand::cloneParagraphUnderNewElement()

Modified: releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp (167230 => 167231)


--- releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp	2014-04-14 09:43:41 UTC (rev 167230)
+++ releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp	2014-04-14 09:47:41 UTC (rev 167231)
@@ -898,7 +898,9 @@
             // a failure of the cache storage to save the newest cache due to hitting
             // the maximum size. In such a case, m_manifestResource may be 0, as
             // the manifest was already set on the newest cache object.
-            ASSERT(cacheStorage().isMaximumSizeReached() && m_calledReachedMaxAppCacheSize);
+            ASSERT(m_cacheBeingUpdated->manifestResource());
+            ASSERT(cacheStorage().isMaximumSizeReached());
+            ASSERT(m_calledReachedMaxAppCacheSize);
         }
 
         RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? RefPtr<ApplicationCache>() : m_newestCache;

Modified: releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp (167230 => 167231)


--- releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp	2014-04-14 09:43:41 UTC (rev 167230)
+++ releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp	2014-04-14 09:47:41 UTC (rev 167231)
@@ -694,6 +694,12 @@
     ASSERT(group->storageID() == 0);
     ASSERT(journal);
 
+    // For some reason, an app cache may be partially written to disk. In particular, there may be
+    // a cache group with an identical manifest URL and associated cache entries. We want to remove
+    // this cache group and its associated cache entries so that we can create it again (below) as
+    // a way to repair it.
+    deleteCacheGroupRecord(group->manifestURL());
+
     SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
     if (statement.prepare() != SQLResultOk)
         return false;
@@ -1176,7 +1182,12 @@
 
     if (result != SQLResultDone)
         LOG_ERROR("Could not load cache resources, error \"%s\"", m_database.lastErrorMsg());
-    
+
+    if (!cache->manifestResource()) {
+        LOG_ERROR("Could not load application cache because there was no manifest resource");
+        return nullptr;
+    }
+
     // Load the online whitelist
     SQLiteStatement whitelistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?");
     if (whitelistStatement.prepare() != SQLResultOk)
@@ -1418,6 +1429,36 @@
     return true;
 }
 
+bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL)
+{
+    ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
+    SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
+    if (idStatement.prepare() != SQLResultOk)
+        return false;
+
+    idStatement.bindText(1, manifestURL);
+
+    int result = idStatement.step();
+    if (result != SQLResultRow)
+        return false;
+
+    int64_t groupId = idStatement.getColumnInt64(0);
+
+    SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
+    if (cacheStatement.prepare() != SQLResultOk)
+        return false;
+
+    SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
+    if (groupStatement.prepare() != SQLResultOk)
+        return false;
+
+    cacheStatement.bindInt64(1, groupId);
+    executeStatement(cacheStatement);
+    groupStatement.bindInt64(1, groupId);
+    executeStatement(groupStatement);
+    return true;
+}
+
 bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL)
 {
     SQLiteTransactionInProgressAutoCounter transactionCounter;
@@ -1432,36 +1473,10 @@
         openDatabase(false);
         if (!m_database.isOpen())
             return false;
-
-        SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
-        if (idStatement.prepare() != SQLResultOk)
+        if (!deleteCacheGroupRecord(manifestURL)) {
+            LOG_ERROR("Could not delete cache group record, error \"%s\"", m_database.lastErrorMsg());
             return false;
-
-        idStatement.bindText(1, manifestURL);
-
-        int result = idStatement.step();
-        if (result == SQLResultDone)
-            return false;
-
-        if (result != SQLResultRow) {
-            LOG_ERROR("Could not load cache group id, error \"%s\"", m_database.lastErrorMsg());
-            return false;
         }
-
-        int64_t groupId = idStatement.getColumnInt64(0);
-
-        SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
-        if (cacheStatement.prepare() != SQLResultOk)
-            return false;
-
-        SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
-        if (groupStatement.prepare() != SQLResultOk)
-            return false;
-
-        cacheStatement.bindInt64(1, groupId);
-        executeStatement(cacheStatement);
-        groupStatement.bindInt64(1, groupId);
-        executeStatement(groupStatement);
     }
 
     deleteTransaction.commit();

Modified: releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.h (167230 => 167231)


--- releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.h	2014-04-14 09:43:41 UTC (rev 167230)
+++ releases/WebKitGTK/webkit-2.4/Source/WebCore/loader/appcache/ApplicationCacheStorage.h	2014-04-14 09:47:41 UTC (rev 167231)
@@ -110,6 +110,7 @@
     bool store(ApplicationCacheGroup*, GroupStorageIDJournal*);
     bool store(ApplicationCache*, ResourceStorageIDJournal*);
     bool store(ApplicationCacheResource*, unsigned cacheStorageID);
+    bool deleteCacheGroupRecord(const String& manifestURL);
 
     bool ensureOriginRecord(const SecurityOrigin*);
     bool shouldStoreResourceAsFlatFile(ApplicationCacheResource*);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to