Fragment navigations should interrupt a provisional load of a different document
authormihaip@chromium.org <mihaip@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Sep 2011 02:16:46 +0000 (02:16 +0000)
committermihaip@chromium.org <mihaip@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Sep 2011 02:16:46 +0000 (02:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=64556

Source/WebCore:

Reviewed by Adam Barth.

Tests: http/tests/history/back-with-fragment-change.php
       http/tests/navigation/navigation-interrupted-by-fragment.html

* loader/FrameLoader.cpp: Stop provisional load if a fragment commits.
* loader/HistoryController.cpp: Don't commit the wrong provisional item.

LayoutTests:

Reviewed by Adam Barth.

Required page-dismissal-modal-dialogs-iframe.html to be updated since
the dummy <a href="#"> link was clicked after the provisional load was
kicked off, thus causing it to to be aborted.

* fast/loader/page-dismissal-modal-dialogs.html:
* fast/loader/resources/page-dismissal-modal-dialogs-iframe.html:
* http/tests/history/back-with-fragment-change-expected.txt: Added.
* http/tests/history/back-with-fragment-change.php: Added.
* http/tests/history/resources/back-with-fragment-change-target.html: Added.
* http/tests/navigation/navigation-interrupted-by-fragment-expected.txt: Added.
* http/tests/navigation/navigation-interrupted-by-fragment.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/loader/page-dismissal-modal-dialogs.html
LayoutTests/fast/loader/resources/page-dismissal-modal-dialogs-iframe.html
LayoutTests/http/tests/history/back-with-fragment-change-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/history/back-with-fragment-change.php [new file with mode: 0644]
LayoutTests/http/tests/history/resources/back-with-fragment-change-target.html [new file with mode: 0644]
LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/loader/FrameLoader.cpp
Source/WebCore/loader/HistoryController.cpp

index e5a3b90..6119747 100644 (file)
@@ -1,3 +1,22 @@
+2011-09-15  Mihai Parparita  <mihaip@chromium.org>
+
+        Fragment navigations should interrupt a provisional load of a different document
+        https://bugs.webkit.org/show_bug.cgi?id=64556
+
+        Reviewed by Adam Barth.
+
+        Required page-dismissal-modal-dialogs-iframe.html to be updated since
+        the dummy <a href="#"> link was clicked after the provisional load was
+        kicked off, thus causing it to to be aborted.
+
+        * fast/loader/page-dismissal-modal-dialogs.html:
+        * fast/loader/resources/page-dismissal-modal-dialogs-iframe.html:
+        * http/tests/history/back-with-fragment-change-expected.txt: Added.
+        * http/tests/history/back-with-fragment-change.php: Added.
+        * http/tests/history/resources/back-with-fragment-change-target.html: Added.
+        * http/tests/navigation/navigation-interrupted-by-fragment-expected.txt: Added.
+        * http/tests/navigation/navigation-interrupted-by-fragment.html: Added.
+
 2011-09-15  Keishi Hattori  <keishi@webkit.org>
 
         [chromium] skipping tests due to r95188
index b7dd50b..c5f34e4 100644 (file)
@@ -29,7 +29,7 @@ addEventListener("load", function() {
 }, false);
 </script></head><body><div>
 
-<a href=# onclick="showMessages('mainFrame click')" id=anchor>anchor</a>
+<span onclick="showMessages('mainFrame click')" id=anchor>anchor</span>
 <iframe src=resources/page-dismissal-modal-dialogs-iframe.html></iframe>
 
 This page registers handlers for various types of unload events and attempts to
index 2ed696e..5753f2a 100644 (file)
@@ -2,5 +2,5 @@
 <html><head><meta charset=utf-8><title>Page Dismissal Modal Dialogs iFrame</title><script>
 parent.registerEvents("iFrame", window, parent);
 </script></head><body><div>
-<a href=# onclick="parent.showMessages('iFrame click')" id=anchor>anchor</a>
+<span onclick="parent.showMessages('iFrame click')" id=anchor>anchor</span>
 </div></body></html>
diff --git a/LayoutTests/http/tests/history/back-with-fragment-change-expected.txt b/LayoutTests/http/tests/history/back-with-fragment-change-expected.txt
new file mode 100644 (file)
index 0000000..6a80bf1
--- /dev/null
@@ -0,0 +1,9 @@
+main frame - has 1 onunload handler(s)
+CONSOLE MESSAGE: line 19: Visited fragment and waited.
+PASS
+
+============== Back Forward List ==============
+        http://127.0.0.1:8000/history/back-with-fragment-change.php  **nav target**
+        http://127.0.0.1:8000/history/resources/back-with-fragment-change-target.html  **nav target**
+curr->  http://127.0.0.1:8000/history/resources/back-with-fragment-change-target.html#foo  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/history/back-with-fragment-change.php b/LayoutTests/http/tests/history/back-with-fragment-change.php
new file mode 100644 (file)
index 0000000..efc8c1d
--- /dev/null
@@ -0,0 +1,45 @@
+<!--
+We intentionally want the page to load slowly (every time, hence no caching), so
+that when back-with-fragment-change-target.html calls history.back(), the load
+is provisional for a while (long enough for the window.location = '#foo' script
+to run and stop that load).
+-->
+<?php
+
+sleep(2);
+
+header("Cache-control: no-cache, no-store");
+header("Pragma: no-cache");
+?>
+
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpBackForwardList();
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+onload = function() {
+    if (sessionStorage.didNavigate) {
+        console.log('Should not have ended up back at the test start page');
+        delete sessionStorage.didNavigate;
+        if (window.layoutTestController)
+            layoutTestController.notifyDone();
+        return;
+    }
+
+    // Change the location in a timeout to make sure it generates a history entry
+    setTimeout(function() {
+            window.location = 'resources/back-with-fragment-change-target.html'
+            sessionStorage.didNavigate = true;
+        }, 0);
+}
+
+// Make sure there's no page cache.
+onunload = function() { };
+</script>
+<p>
+Tests that a history navigation that is aborted by a fragment change doesn't
+update the provisional history item. This test relies on
+<code>layoutTestController.dumpBackForwardList</code> to verify correctness
+and thus can only be run via DumpRenderTree.</p>
diff --git a/LayoutTests/http/tests/history/resources/back-with-fragment-change-target.html b/LayoutTests/http/tests/history/resources/back-with-fragment-change-target.html
new file mode 100644 (file)
index 0000000..07fbadd
--- /dev/null
@@ -0,0 +1,25 @@
+<script>
+onload = function() {
+    setTimeout(function() {
+        // Start to go back (runs asynchonously)
+        history.back();
+        // But immediately cancel that load of a history item and navigate to
+        // a fragment on the page instead. We should remain on this page and
+        // a history item should be added (with past ones not being affected)
+        setTimeout(function(){window.location = '#foo'}, 0);
+    }, 0);
+}
+  
+onhashchange = function() {
+    setTimeout(done, 100);
+}
+
+function done() {
+    delete sessionStorage.didNavigate;
+    console.log('Visited fragment and waited.');
+    if (window.layoutTestController) {
+        layoutTestController.notifyDone();
+    }
+}
+</script>
+PASS
diff --git a/LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment-expected.txt b/LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment-expected.txt
new file mode 100644 (file)
index 0000000..081014c
--- /dev/null
@@ -0,0 +1,8 @@
+CONSOLE MESSAGE: line 23: First visit.
+CONSOLE MESSAGE: line 17: Visited fragment and waited.
+This test checks that interrupting a slow navigation with a fragment navigation will cancel the first navigation.
+
+============== Back Forward List ==============
+        http://127.0.0.1:8000/navigation/navigation-interrupted-by-fragment.html  **nav target**
+curr->  http://127.0.0.1:8000/navigation/navigation-interrupted-by-fragment.html#abc  **nav target**
+===============================================
diff --git a/LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment.html b/LayoutTests/http/tests/navigation/navigation-interrupted-by-fragment.html
new file mode 100644 (file)
index 0000000..f7c213f
--- /dev/null
@@ -0,0 +1,26 @@
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpBackForwardList();
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+onload = function() {
+    window.location = 'resources/slow-resource.pl?delay=100';
+    setTimeout(function() {window.location = 'navigation-interrupted-by-fragment.html#abc'}, 10);
+}
+
+onhashchange = function() {
+    setTimeout(done, 100);
+}
+
+function done() {
+    console.log('Visited fragment and waited.');
+    if (window.layoutTestController) {
+        layoutTestController.notifyDone();
+    }
+}
+
+console.log('First visit.');
+
+</script>
+<p>This test checks that interrupting a slow navigation with a fragment navigation will cancel the first navigation.
index b2fea08..c77ac00 100644 (file)
@@ -1,3 +1,16 @@
+2011-09-15  Mihai Parparita  <mihaip@chromium.org>
+
+        Fragment navigations should interrupt a provisional load of a different document
+        https://bugs.webkit.org/show_bug.cgi?id=64556
+
+        Reviewed by Adam Barth.
+        
+        Tests: http/tests/history/back-with-fragment-change.php
+               http/tests/navigation/navigation-interrupted-by-fragment.html
+
+        * loader/FrameLoader.cpp: Stop provisional load if a fragment commits.
+        * loader/HistoryController.cpp: Don't commit the wrong provisional item.
+
 2011-09-15  Adrienne Walker  <enne@google.com>
 
         [chromium] Add temporary diagnostics for LayerTreeHost::commitTo crash
index 71784d9..f5ba51b 100644 (file)
@@ -2705,6 +2705,12 @@ void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ
     if (!shouldContinue)
         return;
 
+    // If we have a provisional request for a different document, a fragment scroll should cancel it.
+    if (m_provisionalDocumentLoader && !equalIgnoringFragmentIdentifier(m_provisionalDocumentLoader->request().url(), request.url())) {
+        m_provisionalDocumentLoader->stopLoading();
+        setProvisionalDocumentLoader(0);
+    }
+
     bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList;    
     loadInSameDocument(request.url(), 0, !isRedirect);
 }
index 1635b45..2e4684d 100644 (file)
@@ -525,6 +525,11 @@ void HistoryController::recursiveUpdateForSameDocumentNavigation()
     if (!m_provisionalItem)
         return;
 
+    // The provisional item may represent a different pending navigation.
+    // Don't commit it if it isn't a same document navigation.
+    if (m_currentItem && !m_currentItem->shouldDoSameDocumentNavigationTo(m_provisionalItem.get()))
+        return;
+
     // Commit the provisional item.
     m_frameLoadComplete = false;
     m_previousItem = m_currentItem;