OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/frame_host/navigation_controller_impl.h" | 5 #include "content/browser/frame_host/navigation_controller_impl.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/macros.h" | 12 #include "base/macros.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
15 #include "content/browser/frame_host/frame_navigation_entry.h" | 15 #include "content/browser/frame_host/frame_navigation_entry.h" |
16 #include "content/browser/frame_host/frame_tree.h" | 16 #include "content/browser/frame_host/frame_tree.h" |
17 #include "content/browser/frame_host/navigation_entry_impl.h" | 17 #include "content/browser/frame_host/navigation_entry_impl.h" |
18 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 18 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
19 #include "content/browser/web_contents/web_contents_impl.h" | 19 #include "content/browser/web_contents/web_contents_impl.h" |
| 20 #include "content/common/page_state_serialization.h" |
20 #include "content/common/site_isolation_policy.h" | 21 #include "content/common/site_isolation_policy.h" |
21 #include "content/public/browser/navigation_handle.h" | 22 #include "content/public/browser/navigation_handle.h" |
22 #include "content/public/browser/render_view_host.h" | 23 #include "content/public/browser/render_view_host.h" |
23 #include "content/public/browser/resource_controller.h" | 24 #include "content/public/browser/resource_controller.h" |
24 #include "content/public/browser/resource_dispatcher_host.h" | 25 #include "content/public/browser/resource_dispatcher_host.h" |
25 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 26 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
26 #include "content/public/browser/resource_throttle.h" | 27 #include "content/public/browser/resource_throttle.h" |
27 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
28 #include "content/public/browser/web_contents_observer.h" | 29 #include "content/public/browser/web_contents_observer.h" |
29 #include "content/public/common/bindings_policy.h" | 30 #include "content/public/common/bindings_policy.h" |
(...skipping 3483 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3513 controller.GoToOffset(-2); | 3514 controller.GoToOffset(-2); |
3514 observer.Wait(); | 3515 observer.Wait(); |
3515 | 3516 |
3516 EXPECT_EQ(3, controller.GetEntryCount()); | 3517 EXPECT_EQ(3, controller.GetEntryCount()); |
3517 EXPECT_EQ(3, RendererHistoryLength(shell())); | 3518 EXPECT_EQ(3, RendererHistoryLength(shell())); |
3518 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); | 3519 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); |
3519 | 3520 |
3520 EXPECT_EQ(frame_url_1, frame->current_url()); | 3521 EXPECT_EQ(frame_url_1, frame->current_url()); |
3521 } | 3522 } |
3522 | 3523 |
| 3524 // Ensure that we do not corrupt a NavigationEntry's PageState if a subframe |
| 3525 // forward navigation commits after we've already started another forward |
| 3526 // navigation in the main frame. See https://crbug.com/597322. |
| 3527 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| 3528 ForwardInSubframeWithPendingForward) { |
| 3529 // Navigate to a page with an iframe. |
| 3530 GURL url_a(embedded_test_server()->GetURL( |
| 3531 "/navigation_controller/page_with_data_iframe.html")); |
| 3532 GURL frame_url_a1("data:text/html,Subframe"); |
| 3533 EXPECT_TRUE(NavigateToURL(shell(), url_a)); |
| 3534 |
| 3535 NavigationController& controller = shell()->web_contents()->GetController(); |
| 3536 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 3537 ->GetFrameTree() |
| 3538 ->root(); |
| 3539 ASSERT_EQ(1U, root->child_count()); |
| 3540 EXPECT_EQ(url_a, root->current_url()); |
| 3541 FrameTreeNode* frame = root->child_at(0); |
| 3542 EXPECT_EQ(frame_url_a1, frame->current_url()); |
| 3543 |
| 3544 // Navigate the iframe to a second page. |
| 3545 GURL frame_url_a2 = embedded_test_server()->GetURL( |
| 3546 "/navigation_controller/simple_page_1.html"); |
| 3547 NavigateFrameToURL(frame, frame_url_a2); |
| 3548 |
| 3549 EXPECT_EQ(2, controller.GetEntryCount()); |
| 3550 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
| 3551 EXPECT_EQ(url_a, root->current_url()); |
| 3552 EXPECT_EQ(frame_url_a2, frame->current_url()); |
| 3553 |
| 3554 // Navigate the top-level frame to another page with an iframe. |
| 3555 GURL url_b(embedded_test_server()->GetURL( |
| 3556 "/navigation_controller/page_with_iframe.html")); |
| 3557 GURL frame_url_b1(url::kAboutBlankURL); |
| 3558 EXPECT_TRUE(NavigateToURL(shell(), url_b)); |
| 3559 EXPECT_EQ(3, controller.GetEntryCount()); |
| 3560 EXPECT_EQ(url_b, root->current_url()); |
| 3561 EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); |
| 3562 |
| 3563 // Go back two entries. The original frame URL should be back. |
| 3564 ASSERT_TRUE(controller.CanGoToOffset(-2)); |
| 3565 controller.GoToOffset(-2); |
| 3566 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 3567 |
| 3568 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); |
| 3569 EXPECT_EQ(url_a, root->current_url()); |
| 3570 EXPECT_EQ(frame_url_a1, root->child_at(0)->current_url()); |
| 3571 |
| 3572 // Go forward two times in a row, being careful that the subframe commits |
| 3573 // after the second forward navigation begins but before the main frame |
| 3574 // commits. |
| 3575 TestNavigationManager subframe_delayer(shell()->web_contents(), frame_url_a2); |
| 3576 TestNavigationManager mainframe_delayer(shell()->web_contents(), url_b); |
| 3577 controller.GoForward(); |
| 3578 subframe_delayer.WaitForWillStartRequest(); |
| 3579 controller.GoForward(); |
| 3580 mainframe_delayer.WaitForWillStartRequest(); |
| 3581 EXPECT_EQ(2, controller.GetPendingEntryIndex()); |
| 3582 |
| 3583 // Let the subframe commit. |
| 3584 subframe_delayer.ResumeNavigation(); |
| 3585 subframe_delayer.WaitForNavigationFinished(); |
| 3586 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
| 3587 EXPECT_EQ(url_a, root->current_url()); |
| 3588 EXPECT_EQ(frame_url_a2, root->child_at(0)->current_url()); |
| 3589 |
| 3590 // Let the main frame commit. |
| 3591 mainframe_delayer.ResumeNavigation(); |
| 3592 mainframe_delayer.WaitForNavigationFinished(); |
| 3593 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 3594 EXPECT_EQ(2, controller.GetLastCommittedEntryIndex()); |
| 3595 EXPECT_EQ(url_b, root->current_url()); |
| 3596 EXPECT_EQ(frame_url_b1, root->child_at(0)->current_url()); |
| 3597 |
| 3598 // Check the PageState of the previous entry to ensure it isn't corrupted. |
| 3599 NavigationEntry* entry = controller.GetEntryAtIndex(1); |
| 3600 EXPECT_EQ(url_a, entry->GetURL()); |
| 3601 ExplodedPageState exploded_state; |
| 3602 EXPECT_TRUE( |
| 3603 DecodePageState(entry->GetPageState().ToEncodedData(), &exploded_state)); |
| 3604 EXPECT_EQ(url_a, GURL(exploded_state.top.url_string.string())); |
| 3605 EXPECT_EQ(frame_url_a2, |
| 3606 GURL(exploded_state.top.children.at(0).url_string.string())); |
| 3607 } |
| 3608 |
| 3609 // Ensure that forward navigations in cloned tabs can commit if they redirect to |
| 3610 // a different site than before. This causes the navigation's item sequence |
| 3611 // number to change, meaning that we can't use it for determining whether the |
| 3612 // commit matches the history item. See https://crbug.com/600238. |
| 3613 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| 3614 ForwardRedirectWithNoCommittedEntry) { |
| 3615 NavigationController& controller = shell()->web_contents()->GetController(); |
| 3616 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 3617 ->GetFrameTree() |
| 3618 ->root(); |
| 3619 |
| 3620 // Put 2 pages in history. |
| 3621 GURL url_1(embedded_test_server()->GetURL( |
| 3622 "/navigation_controller/simple_page_1.html")); |
| 3623 EXPECT_TRUE(NavigateToURL(shell(), url_1)); |
| 3624 |
| 3625 GURL url_2(embedded_test_server()->GetURL( |
| 3626 "/navigation_controller/simple_page_2.html")); |
| 3627 EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 3628 |
| 3629 EXPECT_EQ(url_2, root->current_url()); |
| 3630 EXPECT_EQ(2, controller.GetEntryCount()); |
| 3631 EXPECT_EQ(1, controller.GetLastCommittedEntryIndex()); |
| 3632 |
| 3633 // Do a replaceState to a URL that will redirect when we come back to it via |
| 3634 // session history. |
| 3635 GURL url_3(embedded_test_server()->GetURL( |
| 3636 "foo.com", "/navigation_controller/page_with_links.html")); |
| 3637 { |
| 3638 TestNavigationObserver observer(shell()->web_contents()); |
| 3639 std::string script = |
| 3640 "history.replaceState({}, '', '/server-redirect?" + url_3.spec() + "')"; |
| 3641 EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| 3642 observer.Wait(); |
| 3643 } |
| 3644 |
| 3645 // Go back. |
| 3646 controller.GoBack(); |
| 3647 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 3648 EXPECT_EQ(0, controller.GetLastCommittedEntryIndex()); |
| 3649 EXPECT_EQ(url_1, root->current_url()); |
| 3650 |
| 3651 // Clone the tab without navigating it. |
| 3652 std::unique_ptr<WebContentsImpl> new_tab( |
| 3653 static_cast<WebContentsImpl*>(shell()->web_contents()->Clone())); |
| 3654 NavigationController& new_controller = new_tab->GetController(); |
| 3655 FrameTreeNode* new_root = new_tab->GetFrameTree()->root(); |
| 3656 EXPECT_TRUE(new_controller.IsInitialNavigation()); |
| 3657 EXPECT_TRUE(new_controller.NeedsReload()); |
| 3658 |
| 3659 // Go forward in the new tab. |
| 3660 { |
| 3661 TestNavigationObserver observer(new_tab.get()); |
| 3662 new_controller.GoForward(); |
| 3663 observer.Wait(); |
| 3664 } |
| 3665 EXPECT_TRUE(new_root->current_frame_host()->IsRenderFrameLive()); |
| 3666 EXPECT_EQ(url_3, new_root->current_url()); |
| 3667 } |
| 3668 |
3523 } // namespace content | 3669 } // namespace content |
OLD | NEW |