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 a6aef93555b1e3c66be8b3febefcc3bca5261bc6..70a4bc77cfe0cc19cab15d43536e97acb45fecff 100644 |
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
@@ -17,6 +17,7 @@ |
#include "content/browser/frame_host/navigation_entry_impl.h" |
#include "content/browser/loader/resource_dispatcher_host_impl.h" |
#include "content/browser/web_contents/web_contents_impl.h" |
+#include "content/common/page_state_serialization.h" |
#include "content/common/site_isolation_policy.h" |
#include "content/public/browser/navigation_handle.h" |
#include "content/public/browser/render_view_host.h" |
@@ -3521,4 +3522,92 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
EXPECT_EQ(frame_url_1, frame->current_url()); |
} |
+// Ensure that we do not corrupt a NavigationEntry's PageState if a subframe |
+// forward navigation commits after we've already started another forward |
+// navigation in the main frame. See https://crbug.com/597322. |
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
+ ForwardInSubframeWithPendingForward) { |
+ // Navigate to a page with an iframe. |
+ GURL url_a(embedded_test_server()->GetURL( |
+ "/navigation_controller/page_with_data_iframe.html")); |
+ GURL frame_url_a1("data:text/html,Subframe"); |
+ NavigateToURL(shell(), url_a); |
alexmos
2016/04/02 00:18:54
nit: EXPECT_TRUE
Charlie Reis
2016/04/04 16:22:06
Done.
|
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
alexmos
2016/04/02 00:18:54
Does this add anything over NavigateToURL?
Charlie Reis
2016/04/04 16:22:06
Done.
|
+ |
+ NavigationController& controller = shell()->web_contents()->GetController(); |
+ FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
+ ->GetFrameTree() |
+ ->root(); |
+ ASSERT_EQ(1U, root->child_count()); |
+ EXPECT_EQ(url_a, root->current_url()); |
+ FrameTreeNode* frame = root->child_at(0); |
+ ASSERT_NE(nullptr, frame); |
alexmos
2016/04/02 00:18:54
nit: this seems redundant with the child_count ASS
Charlie Reis
2016/04/04 16:22:06
Done.
|
+ EXPECT_EQ(frame_url_a1, frame->current_url()); |
+ |
+ // Navigate the iframe to a second page. |
+ GURL frame_url_a2 = embedded_test_server()->GetURL( |
+ "/navigation_controller/simple_page_1.html"); |
+ NavigateFrameToURL(frame, frame_url_a2); |
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
alexmos
2016/04/02 00:18:54
This shouldn't be necessary anymore after Nasko fi
Charlie Reis
2016/04/04 16:22:06
Done.
|
+ |
+ EXPECT_EQ(2, controller.GetEntryCount()); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+ EXPECT_EQ(url_a, root->current_url()); |
+ EXPECT_EQ(frame_url_a2, frame->current_url()); |
+ |
+ // Navigate the top-level frame to another page with an iframe. |
+ GURL url_b(embedded_test_server()->GetURL( |
+ "/navigation_controller/page_with_iframe.html")); |
+ GURL frame_url_b1(url::kAboutBlankURL); |
+ NavigateToURL(shell(), url_b); |
alexmos
2016/04/02 00:18:54
nit: EXPECT_TRUE
Charlie Reis
2016/04/04 16:22:06
Done.
|
+ EXPECT_EQ(3, controller.GetEntryCount()); |
+ EXPECT_EQ(url_b, root->current_url()); |
+ EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); |
+ |
+ // Go back two entries. The original frame URL should be back. |
+ ASSERT_TRUE(controller.CanGoToOffset(-2)); |
+ controller.GoToOffset(-2); |
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
+ |
+ EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); |
+ EXPECT_EQ(url_a, root->current_url()); |
+ EXPECT_EQ(frame_url_a1, root->child_at(0)->current_url()); |
+ |
+ // Go forward two times in a row, being careful that the subframe commits |
+ // after the second forward navigation begins but before the main frame |
+ // commits. |
+ TestNavigationManager subframe_delayer(shell()->web_contents(), frame_url_a2); |
+ TestNavigationManager mainframe_delayer(shell()->web_contents(), url_b); |
+ controller.GoForward(); |
+ subframe_delayer.WaitForWillStartRequest(); |
+ controller.GoForward(); |
+ mainframe_delayer.WaitForWillStartRequest(); |
+ EXPECT_EQ(2, controller.GetPendingEntryIndex()); |
+ |
+ // Let the subframe commit. |
+ subframe_delayer.ResumeNavigation(); |
+ subframe_delayer.WaitForNavigationFinished(); |
+ EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
+ EXPECT_EQ(url_a, root->current_url()); |
+ EXPECT_EQ(frame_url_a2, root->child_at(0)->current_url()); |
+ |
+ // Let the main frame commit. |
+ mainframe_delayer.ResumeNavigation(); |
+ mainframe_delayer.WaitForNavigationFinished(); |
+ EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
+ EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); |
+ EXPECT_EQ(url_b, root->current_url()); |
+ EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); |
+ |
+ // Check the PageState of the previous entry to ensure it isn't corrupted. |
+ NavigationEntry* entry = controller.GetEntryAtIndex(1); |
+ EXPECT_EQ(url_a, entry->GetURL()); |
+ ExplodedPageState exploded_state; |
+ EXPECT_TRUE( |
+ DecodePageState(entry->GetPageState().ToEncodedData(), &exploded_state)); |
+ EXPECT_EQ(url_a, GURL(exploded_state.top.url_string.string())); |
+ EXPECT_EQ(frame_url_a2, |
+ GURL(exploded_state.top.children.at(0).url_string.string())); |
+} |
+ |
} // namespace content |