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 8fc6ec99bb8c6def3a697740ff1ec3739b2e5cd8..9da1815d34e2761cea478673847016d6d5c1a547 100644 |
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
@@ -469,59 +469,6 @@ class NoNavigationsObserver : public WebContentsObserver { |
} |
}; |
-} // namespace |
- |
-// Some pages create a popup, then write an iframe into it. This causes a |
-// subframe navigation without having any committed entry. Such navigations |
-// just get thrown on the ground, but we shouldn't crash. |
-// |
-// This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them, |
-// the initial window.open() and the iframe creation, don't try to create |
-// navigation entries, and the third, the new navigation, tries to. |
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) { |
- NavigateToURL(shell(), GURL(url::kAboutBlankURL)); |
- EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
- |
- FrameTreeNode* root = |
- static_cast<WebContentsImpl*>(shell()->web_contents())-> |
- GetFrameTree()->root(); |
- |
- // Pop open a new window. |
- ShellAddedObserver new_shell_observer; |
- std::string script = "window.open()"; |
- EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
- Shell* new_shell = new_shell_observer.GetShell(); |
- ASSERT_NE(new_shell->web_contents(), shell()->web_contents()); |
- FrameTreeNode* new_root = |
- static_cast<WebContentsImpl*>(new_shell->web_contents())-> |
- GetFrameTree()->root(); |
- |
- // Make a new iframe in it. |
- NoNavigationsObserver observer(new_shell->web_contents()); |
- script = "var iframe = document.createElement('iframe');" |
- "iframe.src = 'data:text/html,<p>some page</p>';" |
- "document.body.appendChild(iframe);"; |
- EXPECT_TRUE(ExecuteScript(new_root->current_frame_host(), script)); |
- // The success check is of the last-committed entry, and there is none. |
- WaitForLoadStopWithoutSuccessCheck(new_shell->web_contents()); |
- |
- ASSERT_EQ(1U, new_root->child_count()); |
- ASSERT_NE(nullptr, new_root->child_at(0)); |
- |
- // Navigate it. |
- GURL frame_url = embedded_test_server()->GetURL( |
- "/navigation_controller/simple_page_2.html"); |
- script = "location.assign('" + frame_url.spec() + "')"; |
- EXPECT_TRUE( |
- ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
- |
- // Success is not crashing, and not navigating. |
- EXPECT_EQ(nullptr, |
- new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
-} |
- |
-namespace { |
- |
class FrameNavigateParamsCapturer : public WebContentsObserver { |
public: |
// Observes navigation for the specified |node|. |
@@ -680,6 +627,79 @@ class LoadCommittedCapturer : public WebContentsObserver { |
} // namespace |
+// Some pages create a popup, then write an iframe into it. This causes a |
+// subframe navigation without having any committed entry. Such navigations |
+// just get thrown on the ground, but we shouldn't crash. |
+// |
+// This test actually hits NAVIGATION_TYPE_NAV_IGNORE four times. Two of them, |
+// the initial window.open() and the iframe creation, don't try to create |
+// navigation entries, and the third and fourth, the new navigations, try to. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) { |
+ // Navigate to a page to force the renderer process to start. |
+ EXPECT_TRUE(NavigateToURL(shell(), GURL(url::kAboutBlankURL))); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ |
+ // Pop open a new window with no last committed entry. |
+ ShellAddedObserver new_shell_observer; |
+ { |
+ std::string script = "window.open()"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ } |
+ Shell* new_shell = new_shell_observer.GetShell(); |
+ ASSERT_NE(new_shell->web_contents(), shell()->web_contents()); |
+ FrameTreeNode* new_root = |
+ static_cast<WebContentsImpl*>(new_shell->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ EXPECT_FALSE( |
+ new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
+ |
+ // Make a new iframe in it. |
+ NoNavigationsObserver observer(new_shell->web_contents()); |
+ { |
+ LoadCommittedCapturer capturer(new_shell->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = 'data:text/html,<p>some page</p>';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(new_root->current_frame_host(), script)); |
+ capturer.Wait(); |
+ } |
+ ASSERT_EQ(1U, new_root->child_count()); |
+ ASSERT_NE(nullptr, new_root->child_at(0)); |
+ |
+ // Navigate it cross-site. |
+ GURL frame_url = embedded_test_server()->GetURL( |
+ "foo.com", "/navigation_controller/simple_page_2.html"); |
+ { |
+ LoadCommittedCapturer capturer(new_shell->web_contents()); |
+ std::string script = "location.assign('" + frame_url.spec() + "')"; |
+ EXPECT_TRUE( |
+ ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
+ capturer.Wait(); |
+ } |
+ |
+ // Success is not crashing, and not navigating. |
+ EXPECT_EQ(nullptr, |
+ new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
+ |
+ // A nested iframe with a cross-site URL should also be able to commit. |
+ GURL grandchild_url(embedded_test_server()->GetURL( |
+ "bar.com", "/navigation_controller/simple_page_1.html")); |
+ { |
+ LoadCommittedCapturer capturer(new_shell->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + grandchild_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE( |
+ ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
+ capturer.Wait(); |
+ } |
+ ASSERT_EQ(1U, new_root->child_at(0)->child_count()); |
+ EXPECT_EQ(grandchild_url, new_root->child_at(0)->child_at(0)->current_url()); |
+} |
+ |
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
ErrorPageReplacement) { |
NavigationController& controller = shell()->web_contents()->GetController(); |
@@ -1571,6 +1591,198 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
} |
} |
+// Verify the tree of FrameNavigationEntries when a nested iframe commits inside |
+// the initial blank page of a loading iframe. Prevents regression of |
+// https://crbug.com/600743. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ FrameNavigationEntry_SlowNestedAutoSubframe) { |
+ GURL main_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ |
+ // 1. Create a iframe with a URL that doesn't commit. |
+ GURL slow_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_2.html")); |
+ TestNavigationManager subframe_delayer(shell()->web_contents(), slow_url); |
+ { |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + slow_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ } |
+ subframe_delayer.WaitForWillStartRequest(); |
+ |
+ // Stop the request so that we can wait for load stop below, without ending up |
+ // with a commit for this frame. |
+ shell()->web_contents()->Stop(); |
+ |
+ // 2. A nested iframe with a cross-site URL should be able to commit. |
+ GURL foo_url(embedded_test_server()->GetURL( |
+ "foo.com", "/navigation_controller/simple_page_1.html")); |
+ { |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + foo_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
+ WaitForLoadStopWithoutSuccessCheck(shell()->web_contents()); |
+ } |
+ |
+ // TODO(creis): Check subframe entries once we create them in this case. |
+ // See https://crbug.com/608402. |
+ EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url()); |
+} |
+ |
+// Verify the tree of FrameNavigationEntries when a nested iframe commits inside |
+// the initial blank page of an iframe with no committed entry. Prevents |
+// regression of https://crbug.com/600743. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ FrameNavigationEntry_NoCommitNestedAutoSubframe) { |
+ GURL main_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ |
+ // 1. Create a iframe with a URL that doesn't commit. |
+ GURL no_commit_url(embedded_test_server()->GetURL("/nocontent")); |
+ { |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + no_commit_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ } |
+ EXPECT_EQ(GURL(), root->child_at(0)->current_url()); |
+ |
+ // 2. A nested iframe with a cross-site URL should be able to commit. |
+ GURL foo_url(embedded_test_server()->GetURL( |
+ "foo.com", "/navigation_controller/simple_page_1.html")); |
+ { |
+ LoadCommittedCapturer capturer(shell()->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + foo_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
+ capturer.Wait(); |
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
+ } |
+ |
+ // TODO(creis): Check subframe entries once we create them in this case. |
+ // See https://crbug.com/608402. |
+ EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url()); |
+} |
+ |
+// Verify the tree of FrameNavigationEntries when a nested iframe commits after |
+// going back in-page, in which case its parent might not have been in the |
+// NavigationEntry. Prevents regression of https://crbug.com/600743. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ FrameNavigationEntry_BackNestedAutoSubframe) { |
+ GURL main_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ |
+ // 1. Navigate in-page. |
+ { |
+ FrameNavigateParamsCapturer capturer(root); |
+ std::string script = "history.pushState({}, 'foo', 'foo')"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ capturer.Wait(); |
+ EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type); |
+ EXPECT_TRUE(capturer.details().is_in_page); |
+ } |
+ |
+ // 2. Create an iframe. |
+ GURL child_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_2.html")); |
+ { |
+ LoadCommittedCapturer capturer(shell()->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + child_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ capturer.Wait(); |
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
+ } |
+ |
+ // 3. Go back in-page. |
+ { |
+ TestNavigationObserver back_load_observer(shell()->web_contents()); |
+ shell()->web_contents()->GetController().GoBack(); |
+ back_load_observer.Wait(); |
+ } |
+ |
+ // 4. A nested iframe with a cross-site URL should be able to commit. |
+ GURL grandchild_url(embedded_test_server()->GetURL( |
+ "foo.com", "/navigation_controller/simple_page_1.html")); |
+ { |
+ LoadCommittedCapturer capturer(shell()->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + grandchild_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
+ capturer.Wait(); |
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
+ } |
+ |
+ // TODO(creis): Check subframe entries once we create them in this case. |
+ // See https://crbug.com/608402. |
+ EXPECT_EQ(grandchild_url, root->child_at(0)->child_at(0)->current_url()); |
+} |
+ |
+// Verify the tree of FrameNavigationEntries when a nested iframe commits after |
+// its parent changes its name, in which case we might not find the parent |
+// FrameNavigationEntry. Prevents regression of https://crbug.com/600743. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ FrameNavigationEntry_RenameNestedAutoSubframe) { |
+ GURL main_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html")); |
+ EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ |
+ // 1. Create an iframe. |
+ GURL child_url(embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_2.html")); |
+ { |
+ LoadCommittedCapturer capturer(shell()->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + child_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
+ capturer.Wait(); |
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
+ } |
+ |
+ // 2. Change the iframe's name. |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), |
+ "window.name = 'foo';")); |
+ |
+ // 3. A nested iframe with a cross-site URL should be able to commit. |
+ GURL bar_url(embedded_test_server()->GetURL( |
+ "bar.com", "/navigation_controller/simple_page_1.html")); |
+ { |
+ LoadCommittedCapturer capturer(shell()->web_contents()); |
+ std::string script = "var iframe = document.createElement('iframe');" |
+ "iframe.src = '" + bar_url.spec() + "';" |
+ "document.body.appendChild(iframe);"; |
+ EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
+ |
+ capturer.Wait(); |
+ EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
+ } |
+ |
+ // TODO(creis): Check subframe entries once we create them in this case. |
+ // See https://crbug.com/608402. |
+ EXPECT_EQ(bar_url, root->child_at(0)->child_at(0)->current_url()); |
+} |
+ |
// Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME |
// commits. |
// TODO(creis): Test updating entries for history auto subframe navigations. |