Commit 625a0c7d authored by creis's avatar creis Committed by Commit bot

OOPIF: Create subframe FrameNavigationEntries for AUTO_SUBFRAME navigations.

Only takes effect in --site-per-process mode.  Just the first phase of
adding frame entries; won't handle nested iframes or history navigations
yet.

BUG=236848
TEST=New unit and browser tests pass in --site-per-process mode.

Review URL: https://codereview.chromium.org/1029893002

Cr-Commit-Position: refs/heads/master@{#322088}
parent 7aba6ac8
...@@ -1297,6 +1297,18 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe( ...@@ -1297,6 +1297,18 @@ bool NavigationControllerImpl::RendererDidNavigateAutoSubframe(
return true; return true;
} }
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
// This may be a "new auto" case where we add a new FrameNavigationEntry, or
// it may be a "history auto" case where we update an existing one.
int64 frame_tree_node_id = rfh->frame_tree_node()->frame_tree_node_id();
NavigationEntryImpl* last_committed = GetLastCommittedEntry();
last_committed->AddOrUpdateFrameEntry(frame_tree_node_id,
rfh->GetSiteInstance(),
params.url,
params.referrer);
}
// We do not need to discard the pending entry in this case, since we will // We do not need to discard the pending entry in this case, since we will
// not generate commit notifications for this auto-subframe navigation. // not generate commit notifications for this auto-subframe navigation.
return false; return false;
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "content/browser/frame_host/frame_navigation_entry.h"
#include "content/browser/frame_host/frame_tree.h" #include "content/browser/frame_host/frame_tree.h"
#include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h"
...@@ -12,6 +14,7 @@ ...@@ -12,6 +14,7 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/common/bindings_policy.h" #include "content/public/common/bindings_policy.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h" #include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
...@@ -853,4 +856,55 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ...@@ -853,4 +856,55 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
} }
} }
// Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
// commits.
// TODO(creis): Test cross-site and nested iframes.
// TODO(creis): Test updating entries for history auto subframe navigations.
IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
FrameNavigationEntry_AutoSubframe) {
GURL main_url(embedded_test_server()->GetURL(
"/navigation_controller/simple_page_1.html"));
NavigateToURL(shell(), main_url);
const NavigationControllerImpl& controller =
static_cast<const NavigationControllerImpl&>(
shell()->web_contents()->GetController());
FrameTreeNode* root =
static_cast<WebContentsImpl*>(shell()->web_contents())->
GetFrameTree()->root();
// Create an iframe.
GURL frame_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 = '" + frame_url.spec() + "';"
"document.body.appendChild(iframe);";
EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
capturer.Wait();
EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
}
// Check last committed NavigationEntry.
EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(main_url, entry->GetURL());
FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(main_url, root_entry->url());
// Verify subframe entries if we're in --site-per-process mode.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
// The entry should now have a subframe FrameNavigationEntry.
ASSERT_EQ(1U, entry->root_node()->children.size());
FrameNavigationEntry* frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(frame_url, frame_entry->url());
} else {
// There are no subframe FrameNavigationEntries by default.
EXPECT_EQ(0U, entry->root_node()->children.size());
}
}
} // namespace content } // namespace content
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/browser/frame_host/cross_site_transferring_request.h" #include "content/browser/frame_host/cross_site_transferring_request.h"
#include "content/browser/frame_host/frame_navigation_entry.h"
#include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/navigation_controller_impl.h"
#include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/frame_host/navigation_entry_screenshot_manager.h" #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
...@@ -1966,34 +1967,103 @@ TEST_F(NavigationControllerTest, NewSubframe) { ...@@ -1966,34 +1967,103 @@ TEST_F(NavigationControllerTest, NewSubframe) {
// Auto subframes are ones the page loads automatically like ads. They should // Auto subframes are ones the page loads automatically like ads. They should
// not create new navigation entries. // not create new navigation entries.
// TODO(creis): Test cross-site and nested iframes.
// TODO(creis): Test updating entries for history auto subframe navigations.
TEST_F(NavigationControllerTest, AutoSubframe) { TEST_F(NavigationControllerTest, AutoSubframe) {
NavigationControllerImpl& controller = controller_impl(); NavigationControllerImpl& controller = controller_impl();
TestNotificationTracker notifications; TestNotificationTracker notifications;
RegisterForAllNavNotifications(&notifications, &controller); RegisterForAllNavNotifications(&notifications, &controller);
const GURL url1("http://foo1"); const GURL url1("http://foo/1");
main_test_rfh()->SendNavigate(0, url1); main_test_rfh()->SendNavigate(1, url1);
EXPECT_EQ(1U, navigation_entry_committed_counter_); EXPECT_EQ(1U, navigation_entry_committed_counter_);
navigation_entry_committed_counter_ = 0; navigation_entry_committed_counter_ = 0;
const GURL url2("http://foo2"); // Add a subframe and navigate it.
FrameHostMsg_DidCommitProvisionalLoad_Params params; main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
params.page_id = 0; SandboxFlags::NONE);
params.url = url2; RenderFrameHostImpl* subframe =
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME; contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
params.should_update_history = false; const GURL url2("http://foo/2");
params.gesture = NavigationGestureUser; {
params.is_post = false; FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_state = PageState::CreateFromURL(url2); params.page_id = 1;
params.url = url2;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
params.page_state = PageState::CreateFromURL(url2);
// Navigating should do nothing. // Navigating should do nothing.
LoadCommittedDetails details; LoadCommittedDetails details;
EXPECT_FALSE(controller.RendererDidNavigate(main_test_rfh(), params, EXPECT_FALSE(controller.RendererDidNavigate(subframe, params, &details));
&details)); EXPECT_EQ(0U, notifications.size());
EXPECT_EQ(0U, notifications.size()); }
// There should still be only one entry. // There should still be only one entry.
EXPECT_EQ(1, controller.GetEntryCount()); EXPECT_EQ(1, controller.GetEntryCount());
NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
EXPECT_EQ(url1, entry->GetURL());
EXPECT_EQ(1, entry->GetPageID());
FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
EXPECT_EQ(url1, root_entry->url());
// Verify subframe entries if we're in --site-per-process mode.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
// The entry should now have a subframe FrameNavigationEntry.
ASSERT_EQ(1U, entry->root_node()->children.size());
FrameNavigationEntry* frame_entry =
entry->root_node()->children[0]->frame_entry.get();
EXPECT_EQ(url2, frame_entry->url());
} else {
// There are no subframe FrameNavigationEntries by default.
EXPECT_EQ(0U, entry->root_node()->children.size());
}
// Add a second subframe and navigate.
main_test_rfh()->OnCreateChildFrame(MSG_ROUTING_NONE, std::string(),
SandboxFlags::NONE);
RenderFrameHostImpl* subframe2 =
contents()->GetFrameTree()->root()->child_at(1)->current_frame_host();
const GURL url3("http://foo/3");
{
FrameHostMsg_DidCommitProvisionalLoad_Params params;
params.page_id = 1;
params.url = url3;
params.transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
params.should_update_history = false;
params.gesture = NavigationGestureUser;
params.is_post = false;
params.page_state = PageState::CreateFromURL(url3);
// Navigating should do nothing.
LoadCommittedDetails details;
EXPECT_FALSE(controller.RendererDidNavigate(subframe2, params, &details));
EXPECT_EQ(0U, notifications.size());
}
// There should still be only one entry, mostly unchanged.
EXPECT_EQ(1, controller.GetEntryCount());
EXPECT_EQ(entry, controller.GetLastCommittedEntry());
EXPECT_EQ(url1, entry->GetURL());
EXPECT_EQ(1, entry->GetPageID());
EXPECT_EQ(root_entry, entry->root_node()->frame_entry.get());
EXPECT_EQ(url1, root_entry->url());
// Verify subframe entries if we're in --site-per-process mode.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSitePerProcess)) {
// The entry should now have 2 subframe FrameNavigationEntries.
ASSERT_EQ(2U, entry->root_node()->children.size());
FrameNavigationEntry* new_frame_entry =
entry->root_node()->children[1]->frame_entry.get();
EXPECT_EQ(url3, new_frame_entry->url());
} else {
// There are no subframe FrameNavigationEntries by default.
EXPECT_EQ(0U, entry->root_node()->children.size());
}
} }
// Tests navigation and then going back to a subframe navigation. // Tests navigation and then going back to a subframe navigation.
......
...@@ -471,6 +471,18 @@ void NavigationEntryImpl::ResetForCommit() { ...@@ -471,6 +471,18 @@ void NavigationEntryImpl::ResetForCommit() {
#endif #endif
} }
void NavigationEntryImpl::AddOrUpdateFrameEntry(int64 frame_tree_node_id,
SiteInstanceImpl* site_instance,
const GURL& url,
const Referrer& referrer) {
// TODO(creis): Walk tree to find the node to update.
// TODO(creis): Only create a new entry if one doesn't exist yet.
FrameNavigationEntry* frame_entry =
new FrameNavigationEntry(site_instance, url, referrer);
root_node()->children.push_back(
new NavigationEntryImpl::TreeNode(frame_entry));
}
void NavigationEntryImpl::SetScreenshotPNGData( void NavigationEntryImpl::SetScreenshotPNGData(
scoped_refptr<base::RefCountedBytes> png_data) { scoped_refptr<base::RefCountedBytes> png_data) {
screenshot_ = png_data; screenshot_ = png_data;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/browser/frame_host/frame_navigation_entry.h" #include "content/browser/frame_host/frame_navigation_entry.h"
#include "content/browser/site_instance_impl.h" #include "content/browser/site_instance_impl.h"
...@@ -42,6 +43,9 @@ class CONTENT_EXPORT NavigationEntryImpl ...@@ -42,6 +43,9 @@ class CONTENT_EXPORT NavigationEntryImpl
// Ref counted pointer that keeps the FrameNavigationEntry alive as long as // Ref counted pointer that keeps the FrameNavigationEntry alive as long as
// it is needed by this node's NavigationEntry. // it is needed by this node's NavigationEntry.
scoped_refptr<FrameNavigationEntry> frame_entry; scoped_refptr<FrameNavigationEntry> frame_entry;
// List of child TreeNodes, which will be deleted when this node is.
ScopedVector<TreeNode> children;
}; };
static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry); static NavigationEntryImpl* FromNavigationEntry(NavigationEntry* entry);
...@@ -137,6 +141,24 @@ class CONTENT_EXPORT NavigationEntryImpl ...@@ -137,6 +141,24 @@ class CONTENT_EXPORT NavigationEntryImpl
// pieces of non-persisted state, as documented on the members below. // pieces of non-persisted state, as documented on the members below.
void ResetForCommit(); void ResetForCommit();
// Exposes the tree of FrameNavigationEntries that make up this joint session
// history item.
// In default Chrome, this tree only has a root node with an unshared
// FrameNavigationEntry. Subframes are only added to the tree if the
// --site-per-process flag is passed.
TreeNode* root_node() const {
return frame_tree_.get();
}
// Finds the TreeNode associated with |frame_tree_node_id| to add or update
// its FrameNavigationEntry. A new FrameNavigationEntry is added if none
// exists, or else the existing one (which might be shared with other
// NavigationEntries) is updated with the given parameters.
void AddOrUpdateFrameEntry(int64 frame_tree_node_id,
SiteInstanceImpl* site_instance,
const GURL& url,
const Referrer& referrer);
void set_unique_id(int unique_id) { void set_unique_id(int unique_id) {
unique_id_ = unique_id; unique_id_ = unique_id;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment