Provisional / scheduled loads in subframes should not prevent a page from entering...
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Oct 2019 22:16:46 +0000 (22:16 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 3 Oct 2019 22:16:46 +0000 (22:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=202474

Reviewed by Alex Christensen.

Source/WebCore:

Provisional / scheduled loads in subframes should not prevent a page from entering the back/forward cache.
To address the issue, we now make sure to stop all loads before checking for PageCache eligibility.

Test: fast/history/page-cache-quick-redirect-iframe.html

* history/PageCache.cpp:
(WebCore::PageCache::addIfCacheable):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::stopForPageCache):
* loader/FrameLoader.h:

LayoutTests:

Add layout test coverage.

* fast/history/page-cache-subframes-with-provisional-load-expected.txt: Added.
* fast/history/page-cache-subframes-with-provisional-load.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/history/page-cache-subframes-with-provisional-load-expected.txt [new file with mode: 0644]
LayoutTests/fast/history/page-cache-subframes-with-provisional-load.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/history/PageCache.cpp
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/FrameLoader.h

index fd6277f..984d010 100644 (file)
@@ -1,5 +1,17 @@
 2019-10-03  Chris Dumez  <cdumez@apple.com>
 
+        Provisional / scheduled loads in subframes should not prevent a page from entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=202474
+
+        Reviewed by Alex Christensen.
+
+        Add layout test coverage.
+
+        * fast/history/page-cache-subframes-with-provisional-load-expected.txt: Added.
+        * fast/history/page-cache-subframes-with-provisional-load.html: Added.
+
+2019-10-03  Chris Dumez  <cdumez@apple.com>
+
         XMLHttpRequest sometimes prevents pages from entering the back/forward cache
         https://bugs.webkit.org/show_bug.cgi?id=202434
         <rdar://problem/55890340>
diff --git a/LayoutTests/fast/history/page-cache-subframes-with-provisional-load-expected.txt b/LayoutTests/fast/history/page-cache-subframes-with-provisional-load-expected.txt
new file mode 100644 (file)
index 0000000..016db02
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that iframes with a pending provisional or scheduled load do not prevent page caching.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+pageshow - not from cache
+pagehide - entering cache
+pageshow - from cache
+PASS Page restored from Page Cache.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+    
diff --git a/LayoutTests/fast/history/page-cache-subframes-with-provisional-load.html b/LayoutTests/fast/history/page-cache-subframes-with-provisional-load.html
new file mode 100644 (file)
index 0000000..cb9451f
--- /dev/null
@@ -0,0 +1,50 @@
+<!-- webkit-test-runner [ enablePageCache=true ] -->
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<iframe id="testFrame1" src="about:blank"></iframe>
+<iframe id="testFrame2" src="about:blank"></iframe>
+<iframe id="testFrame3" src="about:blank"></iframe>
+<iframe id="testFrame4" src="about:blank"></iframe>
+<iframe id="testFrame5" src="about:blank"></iframe>
+<a id="testLink" href="resources/page-cache-helper.html" style="display: none">Link</a>
+<script>
+description("Tests that iframes with a pending provisional or scheduled load do not prevent page caching.");
+jsTestIsAsync = true;
+
+window.addEventListener("pageshow", function(event) {
+    debug("pageshow - " + (event.persisted ? "" : "not ") + "from cache");
+
+    if (event.persisted) {
+        testPassed("Page restored from Page Cache.");
+        finishJSTest();
+    }
+});
+
+window.addEventListener("pagehide", function(event) {
+    debug("pagehide - " + (event.persisted ? "" : "not ") + "entering cache");
+    if (!event.persisted) {
+        testFailed("Page did not enter the page cache.");
+        finishJSTest();
+    }
+
+    // Trigger a quick redirect in the subframe.
+    testFrame3.contentWindow.location.replace("resources/dummy.html");
+});
+
+testFrame5.contentWindow.location.replace("resources/dummy.html");
+
+onload = () => {
+    testFrame4.contentWindow.location.replace("resources/dummy.html");
+    setTimeout(() => {
+         // Trigger a quick redirect in the subframe.
+         testFrame1.contentWindow.location.replace("resources/dummy.html");
+
+         testLink.click();
+
+         testFrame2.contentWindow.location.replace("resources/dummy.html");
+    }, 0);
+}
+</script>
+</html>
index 9c0e831..8fb7f16 100644 (file)
@@ -1,5 +1,23 @@
 2019-10-03  Chris Dumez  <cdumez@apple.com>
 
+        Provisional / scheduled loads in subframes should not prevent a page from entering the back/forward cache
+        https://bugs.webkit.org/show_bug.cgi?id=202474
+
+        Reviewed by Alex Christensen.
+
+        Provisional / scheduled loads in subframes should not prevent a page from entering the back/forward cache.
+        To address the issue, we now make sure to stop all loads before checking for PageCache eligibility.
+
+        Test: fast/history/page-cache-quick-redirect-iframe.html
+
+        * history/PageCache.cpp:
+        (WebCore::PageCache::addIfCacheable):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::stopForPageCache):
+        * loader/FrameLoader.h:
+
+2019-10-03  Chris Dumez  <cdumez@apple.com>
+
         XMLHttpRequest sometimes prevents pages from entering the back/forward cache
         https://bugs.webkit.org/show_bug.cgi?id=202434
         <rdar://problem/55890340>
index ac66211..e35942c 100644 (file)
@@ -421,7 +421,12 @@ bool PageCache::addIfCacheable(HistoryItem& item, Page* page)
     if (item.isInPageCache())
         return false;
 
-    if (!page || !canCache(*page))
+    if (!page)
+        return false;
+
+    page->mainFrame().loader().stopForPageCache();
+
+    if (!canCache(*page))
         return false;
 
     ASSERT_WITH_MESSAGE(!page->isUtilityPage(), "Utility pages such as SVGImage pages should never go into PageCache");
@@ -440,10 +445,7 @@ bool PageCache::addIfCacheable(HistoryItem& item, Page* page)
 
     // Stop all loads again before checking if we can still cache the page after firing the pagehide
     // event, since the page may have started ping loads in its pagehide event handler.
-    for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        if (auto* documentLoader = frame->loader().documentLoader())
-            documentLoader->stopLoading();
-    }
+    page->mainFrame().loader().stopForPageCache();
 
     // Check that the page is still page-cacheable after firing the pagehide event. The JS event handlers
     // could have altered the page in a way that could prevent caching.
index 57e6a32..8b869f7 100644 (file)
@@ -1845,6 +1845,27 @@ void FrameLoader::stopAllLoaders(ClearProvisionalItemPolicy clearProvisionalItem
     m_inStopAllLoaders = false;    
 }
 
+void FrameLoader::stopForPageCache()
+{
+    // Make sure there are no scheduled loads or policy checks.
+    policyChecker().stopCheck();
+    m_frame.navigationScheduler().cancel();
+
+    // Stop provisional loads in subframes (The one in the main frame is about to be committed).
+    if (!m_frame.isMainFrame()) {
+        if (m_provisionalDocumentLoader)
+            m_provisionalDocumentLoader->stopLoading();
+        setProvisionalDocumentLoader(nullptr);
+    }
+
+    // Stop current loads.
+    if (m_documentLoader)
+        m_documentLoader->stopLoading();
+
+    for (RefPtr<Frame> child = m_frame.tree().firstChild(); child; child = child->tree().nextSibling())
+        child->loader().stopForPageCache();
+}
+
 void FrameLoader::stopAllLoadersAndCheckCompleteness()
 {
     stopAllLoaders();
index 2602545..671bad4 100644 (file)
@@ -147,6 +147,7 @@ public:
     void stopAllLoadersAndCheckCompleteness();
     WEBCORE_EXPORT void stopAllLoaders(ClearProvisionalItemPolicy = ShouldClearProvisionalItem, StopLoadingPolicy = StopLoadingPolicy::PreventDuringUnloadEvents);
     WEBCORE_EXPORT void stopForUserCancel(bool deferCheckLoadComplete = false);
+    void stopForPageCache();
     void stop();
     void stopLoading(UnloadEventPolicy);
     bool closeURL();