Chromium Code Reviews| 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" |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 #include "content/public/test/test_navigation_observer.h" | 37 #include "content/public/test/test_navigation_observer.h" |
| 38 #include "content/public/test/test_utils.h" | 38 #include "content/public/test/test_utils.h" |
| 39 #include "content/shell/browser/shell.h" | 39 #include "content/shell/browser/shell.h" |
| 40 #include "content/shell/common/shell_switches.h" | 40 #include "content/shell/common/shell_switches.h" |
| 41 #include "content/test/content_browser_test_utils_internal.h" | 41 #include "content/test/content_browser_test_utils_internal.h" |
| 42 #include "content/test/test_frame_navigation_observer.h" | 42 #include "content/test/test_frame_navigation_observer.h" |
| 43 #include "net/dns/mock_host_resolver.h" | 43 #include "net/dns/mock_host_resolver.h" |
| 44 #include "net/test/embedded_test_server/embedded_test_server.h" | 44 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 45 #include "net/test/url_request/url_request_failed_job.h" | 45 #include "net/test/url_request/url_request_failed_job.h" |
| 46 | 46 |
| 47 namespace { | |
| 48 | |
| 49 static std::string kAddNamedFrameScript = | |
| 50 "var f = document.createElement('iframe');" | |
| 51 "f.name = 'foo-frame-name';" | |
| 52 "document.body.appendChild(f);"; | |
| 53 static std::string kAddFrameScript = | |
| 54 "var f = document.createElement('iframe');" | |
| 55 "document.body.appendChild(f);"; | |
| 56 static std::string kRemoveFrameScript = | |
| 57 "var f = document.querySelector('iframe');" | |
| 58 "f.parentNode.removeChild(f);"; | |
| 59 | |
| 60 } // namespace | |
| 61 | |
| 47 namespace content { | 62 namespace content { |
| 48 | 63 |
| 49 class NavigationControllerBrowserTest : public ContentBrowserTest { | 64 class NavigationControllerBrowserTest : public ContentBrowserTest { |
| 50 protected: | 65 protected: |
| 51 void SetUpOnMainThread() override { | 66 void SetUpOnMainThread() override { |
| 52 host_resolver()->AddRule("*", "127.0.0.1"); | 67 host_resolver()->AddRule("*", "127.0.0.1"); |
| 53 ASSERT_TRUE(embedded_test_server()->Start()); | 68 ASSERT_TRUE(embedded_test_server()->Start()); |
| 54 } | 69 } |
| 55 }; | 70 }; |
| 56 | 71 |
| (...skipping 5362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5419 // the body of the page. | 5434 // the body of the page. |
| 5420 std::string body; | 5435 std::string body; |
| 5421 EXPECT_TRUE(ExecuteScriptAndExtractString( | 5436 EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 5422 shell()->web_contents(), | 5437 shell()->web_contents(), |
| 5423 "window.domAutomationController.send(" | 5438 "window.domAutomationController.send(" |
| 5424 "document.getElementsByTagName('pre')[0].innerText);", | 5439 "document.getElementsByTagName('pre')[0].innerText);", |
| 5425 &body)); | 5440 &body)); |
| 5426 EXPECT_EQ("text=value\n", body); | 5441 EXPECT_EQ("text=value\n", body); |
| 5427 } | 5442 } |
| 5428 | 5443 |
| 5444 // Tests that inserting a named subframe into the FrameTree clears any | |
| 5445 // previously existing FrameNavigationEntry objects for the same name. | |
| 5446 // See https://crbug.com/628677. | |
| 5447 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, | |
| 5448 EnsureFrameNavigationEntriesClearedOnMismatch) { | |
| 5449 WebContentsImpl* web_contents = | |
| 5450 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
| 5451 NavigationControllerImpl& controller = web_contents->GetController(); | |
| 5452 FrameTreeNode* root = web_contents->GetFrameTree()->root(); | |
| 5453 | |
| 5454 // Start by navigating to a page with complex frame hierarchy. | |
| 5455 GURL start_url(embedded_test_server()->GetURL("/frame_tree/top.html")); | |
| 5456 EXPECT_TRUE(NavigateToURL(shell(), start_url)); | |
| 5457 EXPECT_EQ(3U, root->child_count()); | |
| 5458 EXPECT_EQ(2U, root->child_at(0)->child_count()); | |
| 5459 | |
| 5460 NavigationEntryImpl* entry = controller.GetLastCommittedEntry(); | |
| 5461 | |
| 5462 // Verify only the parts of the NavigationEntry affected by this test. | |
| 5463 { | |
| 5464 // * Main frame has 3 subframes. | |
| 5465 FrameNavigationEntry* root_entry = entry->GetFrameEntry(root); | |
| 5466 EXPECT_NE(nullptr, root_entry); | |
| 5467 EXPECT_EQ("", root_entry->frame_unique_name()); | |
| 5468 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5469 EXPECT_EQ(3U, entry->root_node()->children.size()); | |
| 5470 | |
| 5471 // * The first child of the main frame is named and has two more children. | |
| 5472 FrameTreeNode* frame = root->child_at(0); | |
| 5473 FrameNavigationEntry* frame_entry = entry->GetFrameEntry(frame); | |
| 5474 EXPECT_NE(nullptr, frame_entry); | |
| 5475 EXPECT_EQ("1-1-name", frame_entry->frame_unique_name()); | |
| 5476 EXPECT_EQ(2U, entry->root_node()->children[0]->children.size()); | |
| 5477 } | |
| 5478 } | |
| 5479 | |
| 5480 // Removing the first child of the main frame should remove the corresponding | |
| 5481 // FrameTreeNode. | |
| 5482 EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript)); | |
| 5483 EXPECT_EQ(2U, root->child_count()); | |
| 5484 | |
| 5485 // However, the FrameNavigationEntry objects for the frame that was removed | |
| 5486 // should still be around. | |
| 5487 { | |
| 5488 FrameNavigationEntry* root_entry = entry->GetFrameEntry(root); | |
| 5489 EXPECT_NE(nullptr, root_entry); | |
| 5490 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5491 EXPECT_EQ(3U, entry->root_node()->children.size()); | |
| 5492 EXPECT_EQ(2U, entry->root_node()->children[0]->children.size()); | |
| 5493 } | |
| 5494 } | |
| 5495 | |
| 5496 // Now, insert a frame with the same name as the previously removed one | |
| 5497 // at a different layer of the frame tree. | |
| 5498 FrameTreeNode* subframe = root->child_at(1)->child_at(1)->child_at(0); | |
| 5499 EXPECT_EQ(2U, root->child_at(1)->child_count()); | |
| 5500 EXPECT_EQ(0U, subframe->child_count()); | |
| 5501 std::string add_matching_name_frame_script = | |
| 5502 "var f = document.createElement('iframe');" | |
| 5503 "f.name = '1-1-name';" | |
| 5504 "document.body.appendChild(f);"; | |
| 5505 EXPECT_TRUE(ExecuteScript(subframe, add_matching_name_frame_script)); | |
| 5506 EXPECT_EQ(1U, subframe->child_count()); | |
| 5507 | |
| 5508 // Verify that the FrameNavigationEntry for the original frame is now gone. | |
| 5509 { | |
| 5510 FrameNavigationEntry* root_entry = entry->GetFrameEntry(root); | |
| 5511 EXPECT_NE(nullptr, root_entry); | |
| 5512 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5513 EXPECT_EQ(2U, entry->root_node()->children.size()); | |
| 5514 } | |
| 5515 } | |
| 5516 } | |
| 5517 | |
| 5518 // Tests that sending a PageState update from a named subframe does not get | |
| 5519 // incorrectly set on previously existing FrameNavigationEntry for the same | |
| 5520 // name. It is similar to EnsureFrameNavigationEntriesClearedOnMismatch, but | |
| 5521 // doesn't navigate the iframes to real URLs when added to the DOM. | |
| 5522 // See https://crbug.com/628677. | |
| 5523 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, | |
| 5524 EnsureFrameNavigationEntriesClearedOnMismatchNoSrc) { | |
| 5525 WebContentsImpl* web_contents = | |
| 5526 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
| 5527 FrameTreeNode* root = web_contents->GetFrameTree()->root(); | |
| 5528 | |
| 5529 GURL start_url(embedded_test_server()->GetURL("/title1.html")); | |
| 5530 EXPECT_TRUE(NavigateToURL(shell(), start_url)); | |
| 5531 NavigationEntryImpl* nav_entry = | |
| 5532 web_contents->GetController().GetLastCommittedEntry(); | |
| 5533 | |
| 5534 EXPECT_TRUE(ExecuteScript(root, kAddNamedFrameScript)); | |
| 5535 EXPECT_EQ(1U, root->child_count()); | |
| 5536 EXPECT_EQ("foo-frame-name", root->child_at(0)->frame_name()); | |
| 5537 | |
| 5538 EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript)); | |
| 5539 EXPECT_EQ(0U, root->child_count()); | |
| 5540 | |
| 5541 // When a frame is removed from the page, the corresponding | |
| 5542 // FrameNavigationEntry is not removed. This is done intentionally to support | |
| 5543 // back-forward navigations in subframes and more intuitive UX on tab restore. | |
| 5544 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5545 EXPECT_EQ(1U, nav_entry->root_node()->children.size()); | |
| 5546 FrameNavigationEntry* frame_entry = | |
| 5547 nav_entry->root_node()->children[0]->frame_entry.get(); | |
| 5548 EXPECT_EQ("foo-frame-name", frame_entry->frame_unique_name()); | |
| 5549 } | |
| 5550 | |
| 5551 EXPECT_TRUE(ExecuteScript(root, kAddFrameScript)); | |
| 5552 EXPECT_EQ(1U, root->child_count()); | |
| 5553 EXPECT_NE("foo-frame-name", root->child_at(0)->frame_name()); | |
| 5554 | |
| 5555 // Add a nested frame with the previously used name. | |
| 5556 EXPECT_TRUE(ExecuteScript(root->child_at(0), kAddNamedFrameScript)); | |
| 5557 EXPECT_EQ(1U, root->child_at(0)->child_count()); | |
| 5558 EXPECT_EQ("foo-frame-name", root->child_at(0)->child_at(0)->frame_name()); | |
| 5559 | |
| 5560 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5561 EXPECT_EQ(1U, nav_entry->root_node()->children.size()); | |
| 5562 | |
| 5563 NavigationEntryImpl::TreeNode* tree_node = | |
| 5564 nav_entry->root_node()->children[0]; | |
| 5565 EXPECT_EQ(1U, tree_node->children.size()); | |
| 5566 | |
| 5567 tree_node = tree_node->children[0]; | |
| 5568 EXPECT_EQ(0U, tree_node->children.size()); | |
| 5569 EXPECT_EQ("foo-frame-name", tree_node->frame_entry->frame_unique_name()); | |
| 5570 } | |
| 5571 | |
| 5572 EXPECT_TRUE(ExecuteScript(root->child_at(0), kRemoveFrameScript)); | |
| 5573 EXPECT_EQ(0U, root->child_at(0)->child_count()); | |
| 5574 } | |
| 5575 | |
| 5576 // This test ensures that the comparison of tree position between a | |
| 5577 // FrameTreeNode and FrameNavigationEntry works correctly for matching | |
| 5578 // first-level frames. | |
| 5579 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, | |
| 5580 EnsureFirstLevelFrameNavigationEntriesMatch) { | |
| 5581 WebContentsImpl* web_contents = | |
| 5582 static_cast<WebContentsImpl*>(shell()->web_contents()); | |
| 5583 FrameTreeNode* root = web_contents->GetFrameTree()->root(); | |
| 5584 FrameTreeNode* node = root; | |
|
Charlie Reis
2016/08/01 23:32:12
nit: No need for this.
| |
| 5585 NavigationEntryImpl::TreeNode* tree_node = nullptr; | |
| 5586 | |
| 5587 GURL start_url(embedded_test_server()->GetURL("/title1.html")); | |
| 5588 EXPECT_TRUE(NavigateToURL(shell(), start_url)); | |
| 5589 NavigationEntryImpl* nav_entry = | |
| 5590 web_contents->GetController().GetLastCommittedEntry(); | |
| 5591 | |
| 5592 // Add, then remove a named frame. It will create a FrameNavigationEntry | |
| 5593 // for the name and leave it around. | |
| 5594 EXPECT_TRUE(ExecuteScript(root, kAddNamedFrameScript)); | |
| 5595 EXPECT_EQ(1U, root->child_count()); | |
| 5596 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5597 EXPECT_EQ(1U, nav_entry->root_node()->children.size()); | |
| 5598 tree_node = nav_entry->root_node()->children[0]; | |
| 5599 } | |
| 5600 | |
| 5601 EXPECT_TRUE(ExecuteScript(root, kRemoveFrameScript)); | |
| 5602 EXPECT_EQ(0U, root->child_count()); | |
| 5603 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) | |
| 5604 EXPECT_EQ(1U, nav_entry->root_node()->children.size()); | |
| 5605 | |
| 5606 // Add another frame with the same name as before. The matching logic | |
| 5607 // should consider them the same and result in the FrameNavigationEntry | |
| 5608 // being reused. | |
| 5609 EXPECT_TRUE(ExecuteScript(root, kAddNamedFrameScript)); | |
| 5610 EXPECT_EQ(1U, root->child_count()); | |
| 5611 if (SiteIsolationPolicy::UseSubframeNavigationEntries()) { | |
| 5612 EXPECT_EQ(1U, nav_entry->root_node()->children.size()); | |
| 5613 EXPECT_EQ(tree_node, nav_entry->root_node()->children[0]); | |
| 5614 } | |
| 5615 | |
| 5616 EXPECT_TRUE(ExecuteScript(node, kRemoveFrameScript)); | |
| 5617 EXPECT_EQ(0U, node->child_count()); | |
| 5618 } | |
| 5619 | |
| 5429 } // namespace content | 5620 } // namespace content |
| OLD | NEW |