| Index: content/browser/frame_host/render_frame_host_manager.cc
|
| diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
|
| index 9973a8657557899523f41b4e45c838445fc7a3ce..12869aacf5fa7ac456503cc8f5a35ce877cfd76e 100644
|
| --- a/content/browser/frame_host/render_frame_host_manager.cc
|
| +++ b/content/browser/frame_host/render_frame_host_manager.cc
|
| @@ -15,6 +15,7 @@
|
| #include "content/browser/frame_host/cross_site_transferring_request.h"
|
| #include "content/browser/frame_host/debug_urls.h"
|
| #include "content/browser/frame_host/interstitial_page_impl.h"
|
| +#include "content/browser/frame_host/navigation_commit_info.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_request.h"
|
| @@ -39,9 +40,39 @@
|
| #include "content/public/browser/web_ui_controller.h"
|
| #include "content/public/common/content_switches.h"
|
| #include "content/public/common/url_constants.h"
|
| +#include "net/base/load_flags.h"
|
|
|
| namespace content {
|
|
|
| +namespace {
|
| +
|
| +FrameHostMsg_BeginNavigation_Params BeginNavigationFromNavigate(
|
| + const FrameMsg_Navigate_Params& navigate_params) {
|
| + FrameHostMsg_BeginNavigation_Params begin_navigation_params;
|
| + begin_navigation_params.method = navigate_params.is_post ?
|
| + "POST" : "GET";
|
| + begin_navigation_params.url = navigate_params.url;
|
| + begin_navigation_params.referrer = navigate_params.referrer.url;
|
| + begin_navigation_params.referrer_policy = navigate_params.referrer.policy;
|
| +
|
| + // TODO(clamy): This should be modified to take into account caching policy
|
| + // requirements (eg for POST reloads).
|
| + begin_navigation_params.load_flags =
|
| + net::LOAD_NORMAL | net::LOAD_ENABLE_LOAD_TIMING;
|
| +
|
| + // TODO(clamy): Post data from the browser should be put in the request body.
|
| +
|
| + begin_navigation_params.has_user_gesture = false;
|
| + begin_navigation_params.transition_type = navigate_params.transition;
|
| + begin_navigation_params.should_replace_current_entry =
|
| + navigate_params.should_replace_current_entry;
|
| + begin_navigation_params.allow_download =
|
| + navigate_params.allow_download;
|
| + return begin_navigation_params;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| RenderFrameHostManager::PendingNavigationParams::PendingNavigationParams(
|
| const GlobalRequestID& global_request_id,
|
| scoped_ptr<CrossSiteTransferringRequest> cross_site_transferring_request,
|
| @@ -180,43 +211,9 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
|
| if (!dest_render_frame_host)
|
| return NULL; // We weren't able to create a pending render frame host.
|
|
|
| - // If the current render_frame_host_ isn't live, we should create it so
|
| - // that we don't show a sad tab while the dest_render_frame_host fetches
|
| - // its first page. (Bug 1145340)
|
| - if (dest_render_frame_host != render_frame_host_ &&
|
| - !render_frame_host_->render_view_host()->IsRenderViewLive()) {
|
| - // Note: we don't call InitRenderView here because we are navigating away
|
| - // soon anyway, and we don't have the NavigationEntry for this host.
|
| - delegate_->CreateRenderViewForRenderManager(
|
| - render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
|
| - MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
|
| - }
|
| -
|
| - // If the renderer crashed, then try to create a new one to satisfy this
|
| - // navigation request.
|
| - if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
|
| - // Recreate the opener chain.
|
| - int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
|
| - dest_render_frame_host->GetSiteInstance());
|
| - if (!InitRenderView(dest_render_frame_host->render_view_host(),
|
| - opener_route_id,
|
| - MSG_ROUTING_NONE,
|
| - frame_tree_node_->IsMainFrame()))
|
| - return NULL;
|
| -
|
| - // Now that we've created a new renderer, be sure to hide it if it isn't
|
| - // our primary one. Otherwise, we might crash if we try to call Show()
|
| - // on it later.
|
| - if (dest_render_frame_host != render_frame_host_ &&
|
| - dest_render_frame_host->render_view_host()->GetView()) {
|
| - dest_render_frame_host->render_view_host()->GetView()->Hide();
|
| - } else {
|
| - // Notify here as we won't be calling CommitPending (which does the
|
| - // notify).
|
| - delegate_->NotifySwappedFromRenderManager(
|
| - NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
|
| - }
|
| - }
|
| + // Initialize the destination RFH and the current RFH if they are not live.
|
| + if (!InitRenderFrameHostsBeforeNavigation(dest_render_frame_host))
|
| + return NULL;
|
|
|
| // If entry includes the request ID of a request that is being transferred,
|
| // the destination render frame will take ownership, so release ownership of
|
| @@ -230,6 +227,20 @@ RenderFrameHostImpl* RenderFrameHostManager::Navigate(
|
| return dest_render_frame_host;
|
| }
|
|
|
| +bool RenderFrameHostManager::RequestNavigation(
|
| + const NavigationEntryImpl& entry,
|
| + const FrameMsg_Navigate_Params& navigate_params) {
|
| + // TODO(clamy): replace RenderViewHost::IsRenderViewLive by
|
| + // RenderFrameHost::IsLive.
|
| + if (render_frame_host_->render_view_host()->IsRenderViewLive())
|
| + // TODO(clamy): send a RequestNavigation IPC.
|
| + return true;
|
| +
|
| + // The navigation request is sent directly to the IO thread.
|
| + OnBeginNavigation(BeginNavigationFromNavigate(navigate_params));
|
| + return true;
|
| +}
|
| +
|
| void RenderFrameHostManager::Stop() {
|
| render_frame_host_->render_view_host()->Stop();
|
|
|
| @@ -585,8 +596,73 @@ void RenderFrameHostManager::OnBeginNavigation(
|
| navigation_request_.reset(
|
| new NavigationRequest(info, frame_tree_node_->frame_tree_node_id()));
|
| navigation_request_->BeginNavigation(params.request_body);
|
| - // TODO(clamy): If we have no live RenderFrameHost to handle the request (eg
|
| - // cross-site navigation) spawn one speculatively here and keep track of it.
|
| +
|
| + // Create a new RFH for the navigation if necessary.
|
| + RenderFrameHostImpl* dest_render_frame_host = render_frame_host_.get();
|
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
|
| + SiteInstance* new_instance = GetSiteInstanceForNavigation(
|
| + *NavigationEntryImpl::FromNavigationEntry(
|
| + frame_tree_node_->navigator()->GetController()->GetPendingEntry()));
|
| + if (current_instance != new_instance) {
|
| + dest_render_frame_host = CreateRenderFrameHostForCrossSite(
|
| + current_instance, new_instance, true);
|
| + DCHECK(dest_render_frame_host);
|
| + }
|
| + InitRenderFrameHostsBeforeNavigation(dest_render_frame_host);
|
| +}
|
| +
|
| +void RenderFrameHostManager::CommitNavigation(
|
| + const NavigationCommitInfo& info) {
|
| + // Update the pending NavigationEntry for commit.
|
| + // TODO(clamy): Check if some more state should be updated at that point.
|
| + NavigationEntry* entry =
|
| + frame_tree_node_->navigator()->GetController()->GetPendingEntry();
|
| + entry->SetURL(info.navigation_url);
|
| +
|
| + // Pick the right RenderFrameHost to commit the navigation. If the current RFH
|
| + // is not suitable, a RFH may have been spawned speculatively to handle the
|
| + // navigation. If there is none, or if it is not suitable, a new RFH needs to
|
| + // be created.
|
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
|
| + SiteInstance* speculative_instance = speculative_render_frame_host_.get() ?
|
| + speculative_render_frame_host_->GetSiteInstance() : NULL;
|
| + DCHECK(current_instance != speculative_instance);
|
| +
|
| + SiteInstance* new_instance = GetSiteInstanceForNavigation(
|
| + *NavigationEntryImpl::FromNavigationEntry(entry));
|
| + RenderFrameHostImpl* rfh_to_navigate = NULL;
|
| + DCHECK(!pending_render_frame_host_.get());
|
| +
|
| + if (current_instance == new_instance)
|
| + rfh_to_navigate = render_frame_host_.get();
|
| +
|
| + if (speculative_instance) {
|
| + if (speculative_instance == new_instance) {
|
| + rfh_to_navigate = speculative_render_frame_host_.get();
|
| + } else {
|
| + speculative_render_frame_host_.reset();
|
| + }
|
| + }
|
| +
|
| + if (!rfh_to_navigate) {
|
| + rfh_to_navigate = CreateRenderFrameHostForCrossSite(
|
| + current_instance, new_instance, true);
|
| + DCHECK(rfh_to_navigate);
|
| + }
|
| +
|
| + // A WebUI renderer should never display a non WebUI url.
|
| + frame_tree_node_->navigator()->CheckWebUIRendererDoesNotDisplayNormalURL(
|
| + rfh_to_navigate, info.navigation_url);
|
| +
|
| + // TODO(clamy): the rfh_to_navigate should now send a commit IPC to the
|
| + // renderer.
|
| + // TODO(clamy): If the current RFH is not reused, then it should be swapped
|
| + // out, and asked to run its unload handler.
|
| + if (rfh_to_navigate != render_frame_host_.get())
|
| + SetRenderFrameHost(speculative_render_frame_host_.Pass());
|
| + DCHECK(!speculative_render_frame_host_.get());
|
| +
|
| + navigation_request_.reset();
|
| }
|
|
|
| void RenderFrameHostManager::Observe(
|
| @@ -900,6 +976,34 @@ SiteInstance* RenderFrameHostManager::GetSiteInstanceForEntry(
|
| return current_instance->GetRelatedSiteInstance(dest_url);
|
| }
|
|
|
| +RenderFrameHostImpl* RenderFrameHostManager::CreateRenderFrameHostForCrossSite(
|
| + SiteInstance* old_instance,
|
| + SiteInstance* new_instance,
|
| + bool is_speculative) {
|
| + // Ensure that we have created RFHs for the new RFH's opener chain if
|
| + // we are staying in the same BrowsingInstance. This allows the pending RFH
|
| + // to send cross-process script calls to its opener(s).
|
| + int opener_route_id = MSG_ROUTING_NONE;
|
| + if (new_instance->IsRelatedSiteInstance(old_instance)) {
|
| + opener_route_id =
|
| + delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
|
| + }
|
| +
|
| + // Create a non-swapped-out speculative RFH with the given opener.
|
| + int route_id = CreateRenderFrame(new_instance, opener_route_id, false,
|
| + delegate_->IsHidden(), is_speculative);
|
| + if (route_id == MSG_ROUTING_NONE) {
|
| + if (is_speculative)
|
| + speculative_render_frame_host_.reset();
|
| + else
|
| + pending_render_frame_host_.reset();
|
| + return NULL;
|
| + }
|
| + if (is_speculative)
|
| + return speculative_render_frame_host_.get();
|
| + return pending_render_frame_host_.get();
|
| +}
|
| +
|
| scoped_ptr<RenderFrameHostImpl> RenderFrameHostManager::CreateRenderFrameHost(
|
| SiteInstance* site_instance,
|
| int view_routing_id,
|
| @@ -944,9 +1048,11 @@ int RenderFrameHostManager::CreateRenderFrame(
|
| SiteInstance* instance,
|
| int opener_route_id,
|
| bool swapped_out,
|
| - bool hidden) {
|
| + bool hidden,
|
| + bool is_speculative) {
|
| CHECK(instance);
|
| DCHECK(!swapped_out || hidden); // Swapped out views should always be hidden.
|
| + DCHECK(!(swapped_out && is_speculative));
|
|
|
| scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
|
| RenderFrameHostImpl* frame_to_announce = NULL;
|
| @@ -1020,8 +1126,12 @@ int RenderFrameHostManager::CreateRenderFrame(
|
| }
|
|
|
| // Use this as our new pending RFH if it isn't swapped out.
|
| - if (!swapped_out)
|
| - pending_render_frame_host_ = new_render_frame_host.Pass();
|
| + if (!swapped_out) {
|
| + if (is_speculative)
|
| + speculative_render_frame_host_ = new_render_frame_host.Pass();
|
| + else
|
| + pending_render_frame_host_ = new_render_frame_host.Pass();
|
| + }
|
|
|
| // If a brand new RFH was created, announce it to observers.
|
| if (frame_to_announce)
|
| @@ -1058,6 +1168,77 @@ bool RenderFrameHostManager::InitRenderView(RenderViewHost* render_view_host,
|
| render_view_host, opener_route_id, proxy_routing_id, for_main_frame);
|
| }
|
|
|
| +bool RenderFrameHostManager::InitRenderFrameHostsBeforeNavigation(
|
| + RenderFrameHostImpl* dest_render_frame_host) {
|
| + // If the current render_frame_host_ isn't live, we should create it so
|
| + // that we don't show a sad tab while the dest_render_frame_host fetches
|
| + // its first page. (crbug.com/1145340)
|
| + if (dest_render_frame_host != render_frame_host_ &&
|
| + !render_frame_host_->render_view_host()->IsRenderViewLive()) {
|
| + // Note: we don't call InitRenderView here because we are navigating away
|
| + // soon anyway, and we don't have the NavigationEntry for this host.
|
| + delegate_->CreateRenderViewForRenderManager(
|
| + render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
|
| + MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
|
| + }
|
| +
|
| + // If the renderer crashed, then try to create a new one to satisfy this
|
| + // navigation request.
|
| + if (!dest_render_frame_host->render_view_host()->IsRenderViewLive()) {
|
| + // Recreate the opener chain.
|
| + int opener_route_id = delegate_->CreateOpenerRenderViewsForRenderManager(
|
| + dest_render_frame_host->GetSiteInstance());
|
| + if (!InitRenderView(dest_render_frame_host->render_view_host(),
|
| + opener_route_id,
|
| + MSG_ROUTING_NONE,
|
| + frame_tree_node_->IsMainFrame()))
|
| + return false;
|
| +
|
| + // Now that we've created a new renderer, be sure to hide it if it isn't
|
| + // our primary one. Otherwise, we might crash if we try to call Show()
|
| + // on it later.
|
| + if (dest_render_frame_host != render_frame_host_ &&
|
| + dest_render_frame_host->render_view_host()->GetView()) {
|
| + dest_render_frame_host->render_view_host()->GetView()->Hide();
|
| + } else {
|
| + // Notify here as we won't be calling CommitPending (which does the
|
| + // notify).
|
| + delegate_->NotifySwappedFromRenderManager(
|
| + NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +SiteInstance* RenderFrameHostManager::GetSiteInstanceForNavigation(
|
| + const NavigationEntryImpl& entry) {
|
| + SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
|
| + SiteInstance* new_instance = current_instance;
|
| +
|
| + // We do not currently swap processes for navigations in webview tag guests.
|
| + bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
|
| +
|
| + // Determine if we need a new BrowsingInstance for this entry. If true, this
|
| + // implies that it will get a new SiteInstance (and likely process), and that
|
| + // other tabs in the current BrowsingInstance will be unable to script it.
|
| + // This is used for cases that require a process swap even in the
|
| + // process-per-tab model, such as WebUI pages.
|
| + const NavigationEntry* current_entry =
|
| + delegate_->GetLastCommittedNavigationEntryForRenderManager();
|
| + bool force_swap = !is_guest_scheme &&
|
| + ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
|
| + if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
|
| + new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
|
| +
|
| + // If force_swap is true, we must use a different SiteInstance. If we didn't,
|
| + // we would have two RenderFrameHosts in the same SiteInstance and the same
|
| + // frame, resulting in page_id conflicts for their NavigationEntries.
|
| + if (force_swap)
|
| + CHECK_NE(new_instance, current_instance);
|
| +
|
| + return new_instance;
|
| +}
|
| +
|
| void RenderFrameHostManager::CommitPending() {
|
| // First check whether we're going to want to focus the location bar after
|
| // this commit. We do this now because the navigation hasn't formally
|
| @@ -1266,28 +1447,9 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
|
| // before the end of this method, so we don't have to worry about their ref
|
| // counts dropping to zero.
|
| SiteInstance* current_instance = render_frame_host_->GetSiteInstance();
|
| - SiteInstance* new_instance = current_instance;
|
| -
|
| - // We do not currently swap processes for navigations in webview tag guests.
|
| - bool is_guest_scheme = current_instance->GetSiteURL().SchemeIs(kGuestScheme);
|
| -
|
| - // Determine if we need a new BrowsingInstance for this entry. If true, this
|
| - // implies that it will get a new SiteInstance (and likely process), and that
|
| - // other tabs in the current BrowsingInstance will be unable to script it.
|
| - // This is used for cases that require a process swap even in the
|
| - // process-per-tab model, such as WebUI pages.
|
| + SiteInstance* new_instance = GetSiteInstanceForNavigation(entry);
|
| const NavigationEntry* current_entry =
|
| delegate_->GetLastCommittedNavigationEntryForRenderManager();
|
| - bool force_swap = !is_guest_scheme &&
|
| - ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
|
| - if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
|
| - new_instance = GetSiteInstanceForEntry(entry, current_instance, force_swap);
|
| -
|
| - // If force_swap is true, we must use a different SiteInstance. If we didn't,
|
| - // we would have two RenderFrameHosts in the same SiteInstance and the same
|
| - // frame, resulting in page_id conflicts for their NavigationEntries.
|
| - if (force_swap)
|
| - CHECK_NE(new_instance, current_instance);
|
|
|
| if (new_instance != current_instance) {
|
| // New SiteInstance: create a pending RFH to navigate.
|
| @@ -1301,21 +1463,10 @@ RenderFrameHostImpl* RenderFrameHostManager::UpdateStateForNavigate(
|
| // not have its bindings set appropriately.
|
| SetPendingWebUI(entry);
|
|
|
| - // Ensure that we have created RFHs for the new RFH's opener chain if
|
| - // we are staying in the same BrowsingInstance. This allows the pending RFH
|
| - // to send cross-process script calls to its opener(s).
|
| - int opener_route_id = MSG_ROUTING_NONE;
|
| - if (new_instance->IsRelatedSiteInstance(current_instance)) {
|
| - opener_route_id =
|
| - delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
|
| - }
|
| -
|
| - // Create a non-swapped-out pending RFH with the given opener and navigate
|
| - // it.
|
| - int route_id = CreateRenderFrame(new_instance, opener_route_id, false,
|
| - delegate_->IsHidden());
|
| - if (route_id == MSG_ROUTING_NONE)
|
| + if (!CreateRenderFrameHostForCrossSite(
|
| + current_instance, new_instance, false)) {
|
| return NULL;
|
| + }
|
|
|
| // Check if our current RFH is live before we set up a transition.
|
| if (!render_frame_host_->render_view_host()->IsRenderViewLive()) {
|
|
|