Index: content/browser/frame_host/navigation_controller_impl_browsertest.cc |
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
index cc00ec2b6317a78a46e6b3b964649aac1c2b36eb..df0abf17426c08bb1ce88778bc4da654ebc9f901 100644 |
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
@@ -3140,6 +3140,130 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); |
} |
+// Similar to FrameNavigationEntry_BackWithRedirect but with same-origin frames. |
+// (This wasn't working initially). |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ FrameNavigationEntry_SameOriginBackWithRedirect) { |
+ // 1. Start on a page with an iframe. |
+ GURL initial_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/page_with_data_iframe.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), initial_url)); |
+ NavigationControllerImpl& controller = static_cast<NavigationControllerImpl&>( |
+ shell()->web_contents()->GetController()); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ EXPECT_EQ(initial_url, root->current_url()); |
+ EXPECT_EQ(1U, root->child_count()); |
+ NavigationEntryImpl* entry1 = controller.GetLastCommittedEntry(); |
+ if (SiteIsolationPolicy::UseSubframeNavigationEntries()) |
+ EXPECT_EQ(1U, entry1->root_node()->children.size()); |
+ |
+ // 2. Navigate the iframe to a page with a nested iframe. |
+ GURL frame_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/page_with_data_iframe.html")); |
+ GURL data_url("data:text/html,Subframe"); |
+ NavigateFrameToURL(root->child_at(0), frame_url); |
+ EXPECT_EQ(initial_url, root->current_url()); |
+ EXPECT_EQ(frame_url, root->child_at(0)->current_url()); |
+ EXPECT_EQ(data_url, root->child_at(0)->child_at(0)->current_url()); |
+ |
+ EXPECT_EQ(2, controller.GetEntryCount()); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+ NavigationEntryImpl* entry2 = controller.GetLastCommittedEntry(); |
+ // Verify subframe entries if they're enabled (e.g. in --site-per-process). |
+ if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { |
+ NavigationEntryImpl::TreeNode* root_node = entry2->root_node(); |
+ ASSERT_EQ(1U, root_node->children.size()); |
+ EXPECT_EQ(frame_url, root_node->children[0]->frame_entry->url()); |
+ EXPECT_EQ(data_url, |
+ root_node->children[0]->children[0]->frame_entry->url()); |
+ } |
+ |
+ // Cause the iframe to redirect when we come back later. It will go |
+ // same-origin to a page with an about:blank iframe. |
+ GURL frame_redirect_dest_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/page_with_iframe.html")); |
+ { |
+ TestNavigationObserver observer(shell()->web_contents()); |
+ std::string script = "history.replaceState({}, '', '/server-redirect?" + |
+ frame_redirect_dest_url.spec() + "')"; |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0), script)); |
+ observer.Wait(); |
+ } |
+ |
+ // We should not have lost subframe entries for the nested frame. |
+ EXPECT_EQ(2, controller.GetEntryCount()); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+ if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { |
+ FrameNavigationEntry* nested_entry = |
+ entry2->GetFrameEntry(root->child_at(0)->child_at(0)); |
+ EXPECT_TRUE(nested_entry); |
+ EXPECT_EQ(data_url, nested_entry->url()); |
+ } |
+ |
+ // 3. Navigate the main frame to a different page. When we come back, we'll |
+ // commit the main frame first and have no pending entry when navigating the |
+ // subframes. |
+ GURL url2(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), url2)); |
+ EXPECT_EQ(3, controller.GetEntryCount()); |
+ EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); |
+ |
+ // 4. Go back. The first iframe should redirect to a same-origin page with a |
+ // different nested iframe. |
+ { |
+ TestNavigationObserver back_load_observer(shell()->web_contents()); |
+ controller.GoBack(); |
+ back_load_observer.Wait(); |
+ } |
+ GURL blank_url(url::kAboutBlankURL); |
+ EXPECT_EQ(initial_url, root->current_url()); |
+ EXPECT_EQ(frame_redirect_dest_url, root->child_at(0)->current_url()); |
+ EXPECT_EQ(blank_url, root->child_at(0)->child_at(0)->current_url()); |
+ |
+ // Check the FrameNavigationEntries as well. |
+ EXPECT_EQ(3, controller.GetEntryCount()); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+ if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { |
+ EXPECT_EQ(frame_redirect_dest_url, |
+ entry2->GetFrameEntry(root->child_at(0))->url()); |
+ EXPECT_EQ(blank_url, |
+ entry2->GetFrameEntry(root->child_at(0)->child_at(0))->url()); |
+ } |
+ |
+ // Now cause the main frame to redirect to a page with no frames when we come |
+ // back to it. |
+ GURL redirect_dest_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_2.html")); |
+ { |
+ TestNavigationObserver observer(shell()->web_contents()); |
+ std::string script = "history.replaceState({}, '', '/server-redirect?" + |
+ redirect_dest_url.spec() + "')"; |
+ EXPECT_TRUE(ExecuteScript(root, script)); |
+ observer.Wait(); |
+ } |
+ |
+ // 5. Navigate the main frame to a different page. |
+ EXPECT_TRUE(NavigateToURL(shell(), url2)); |
+ EXPECT_EQ(3, controller.GetEntryCount()); |
+ EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); |
+ |
+ // 6. Go back, causing the main frame to redirect to a page with no frames. |
+ // All child items should be gone. |
+ { |
+ TestNavigationObserver back_load_observer(shell()->web_contents()); |
+ controller.GoBack(); |
+ back_load_observer.Wait(); |
+ } |
+ EXPECT_EQ(redirect_dest_url, root->current_url()); |
+ EXPECT_EQ(0U, root->child_count()); |
+ EXPECT_EQ(0U, entry2->root_node()->children.size()); |
+ EXPECT_EQ(3, controller.GetEntryCount()); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+} |
+ |
// Verify that subframes can be restored in a new NavigationController using the |
// PageState of an existing NavigationEntry. |
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |