| Index: content/browser/frame_host/render_view_host_manager.cc
|
| diff --git a/content/browser/frame_host/render_view_host_manager.cc b/content/browser/frame_host/render_view_host_manager.cc
|
| index 71c39282a6444bee1116ffc1c10be11c04b01171..e46124b2cc653d5e6e28b015c47ca8f8e2cf2634 100644
|
| --- a/content/browser/frame_host/render_view_host_manager.cc
|
| +++ b/content/browser/frame_host/render_view_host_manager.cc
|
| @@ -9,6 +9,7 @@
|
| #include "base/command_line.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/logging.h"
|
| +#include "content/browser/child_process_security_policy_impl.h"
|
| #include "content/browser/devtools/render_view_devtools_agent_host.h"
|
| #include "content/browser/frame_host/interstitial_page_impl.h"
|
| #include "content/browser/frame_host/navigation_controller_impl.h"
|
| @@ -491,8 +492,8 @@ bool RenderViewHostManager::ShouldTransitionCrossSite() {
|
| !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab);
|
| }
|
|
|
| -bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
|
| - const NavigationEntry* curr_entry,
|
| +bool RenderViewHostManager::ShouldSwapBrowsingInstancesForNavigation(
|
| + const NavigationEntry* current_entry,
|
| const NavigationEntryImpl* new_entry) const {
|
| DCHECK(new_entry);
|
|
|
| @@ -501,16 +502,18 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
|
| return false;
|
|
|
| // Check for reasons to swap processes even if we are in a process model that
|
| - // doesn't usually swap (e.g., process-per-tab).
|
| + // doesn't usually swap (e.g., process-per-tab). Any time we return true,
|
| + // the new_entry will be rendered in a new SiteInstance AND BrowsingInstance.
|
|
|
| // We use the effective URL here, since that's what is used in the
|
| // SiteInstance's site and when we later call IsSameWebSite. If there is no
|
| - // curr_entry, check the current SiteInstance's site, which might already be
|
| - // committed to a Web UI URL (such as the NTP).
|
| + // current_entry, check the current SiteInstance's site, which might already
|
| + // be committed to a Web UI URL (such as the NTP).
|
| BrowserContext* browser_context =
|
| delegate_->GetControllerForRenderManager().GetBrowserContext();
|
| - const GURL& current_url = (curr_entry) ?
|
| - SiteInstanceImpl::GetEffectiveURL(browser_context, curr_entry->GetURL()) :
|
| + const GURL& current_url = (current_entry) ?
|
| + SiteInstanceImpl::GetEffectiveURL(browser_context,
|
| + current_entry->GetURL()) :
|
| render_view_host_->GetSiteInstance()->GetSiteURL();
|
| const GURL& new_url = SiteInstanceImpl::GetEffectiveURL(browser_context,
|
| new_entry->GetURL());
|
| @@ -519,14 +522,14 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
|
| // page and one isn't.
|
| if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
|
| browser_context, current_url)) {
|
| - // Force swap if it's not an acceptable URL for Web UI.
|
| + // If so, force a swap if destination is not an acceptable URL for Web UI.
|
| // Here, data URLs are never allowed.
|
| if (!WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
|
| browser_context, new_url, false)) {
|
| return true;
|
| }
|
| } else {
|
| - // Force swap if it's a Web UI URL.
|
| + // Force a swap if it's a Web UI URL.
|
| if (WebUIControllerFactoryRegistry::GetInstance()->UseWebUIForURL(
|
| browser_context, new_url)) {
|
| return true;
|
| @@ -534,40 +537,38 @@ bool RenderViewHostManager::ShouldSwapProcessesForNavigation(
|
| }
|
|
|
| // Check with the content client as well. Important to pass current_url here,
|
| - // which uses the SiteInstance's site if there is no curr_entry.
|
| - if (GetContentClient()->browser()->ShouldSwapProcessesForNavigation(
|
| + // which uses the SiteInstance's site if there is no current_entry.
|
| + if (GetContentClient()->browser()->ShouldSwapBrowsingInstancesForNavigation(
|
| render_view_host_->GetSiteInstance(), current_url, new_url)) {
|
| return true;
|
| }
|
|
|
| - if (!curr_entry)
|
| - return false;
|
| -
|
| // We can't switch a RenderView between view source and non-view source mode
|
| // without screwing up the session history sometimes (when navigating between
|
| - // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat
|
| - // it as a new navigation). So require a view switch.
|
| - if (curr_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
|
| + // "view-source:http://foo.com/" and "http://foo.com/", Blink doesn't treat
|
| + // it as a new navigation). So require a BrowsingInstance switch.
|
| + if (current_entry &&
|
| + current_entry->IsViewSourceMode() != new_entry->IsViewSourceMode())
|
| return true;
|
|
|
| return false;
|
| }
|
|
|
| bool RenderViewHostManager::ShouldReuseWebUI(
|
| - const NavigationEntry* curr_entry,
|
| + const NavigationEntry* current_entry,
|
| const NavigationEntryImpl* new_entry) const {
|
| NavigationControllerImpl& controller =
|
| delegate_->GetControllerForRenderManager();
|
| - return curr_entry && web_ui_.get() &&
|
| + return current_entry && web_ui_.get() &&
|
| (WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
|
| - controller.GetBrowserContext(), curr_entry->GetURL()) ==
|
| + controller.GetBrowserContext(), current_entry->GetURL()) ==
|
| WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
|
| controller.GetBrowserContext(), new_entry->GetURL()));
|
| }
|
|
|
| SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| const NavigationEntryImpl& entry,
|
| - SiteInstance* curr_instance,
|
| + SiteInstance* current_instance,
|
| bool force_browsing_instance_swap) {
|
| // Determine which SiteInstance to use for navigating to |entry|.
|
| const GURL& dest_url = entry.GetURL();
|
| @@ -600,23 +601,23 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerSite) &&
|
| PageTransitionCoreTypeIs(entry.GetTransitionType(),
|
| PAGE_TRANSITION_GENERATED)) {
|
| - return curr_instance;
|
| + return current_instance;
|
| }
|
|
|
| - SiteInstanceImpl* curr_site_instance =
|
| - static_cast<SiteInstanceImpl*>(curr_instance);
|
| + SiteInstanceImpl* current_site_instance =
|
| + static_cast<SiteInstanceImpl*>(current_instance);
|
|
|
| // If we haven't used our SiteInstance (and thus RVH) yet, then we can use it
|
| // for this entry. We won't commit the SiteInstance to this site until the
|
| // navigation commits (in DidNavigate), unless the navigation entry was
|
| // restored or it's a Web UI as described below.
|
| - if (!curr_site_instance->HasSite()) {
|
| + if (!current_site_instance->HasSite()) {
|
| // If we've already created a SiteInstance for our destination, we don't
|
| // want to use this unused SiteInstance; use the existing one. (We don't
|
| - // do this check if the curr_instance has a site, because for now, we want
|
| - // to compare against the current URL and not the SiteInstance's site. In
|
| - // this case, there is no current URL, so comparing against the site is ok.
|
| - // See additional comments below.)
|
| + // do this check if the current_instance has a site, because for now, we
|
| + // want to compare against the current URL and not the SiteInstance's site.
|
| + // In this case, there is no current URL, so comparing against the site is
|
| + // ok. See additional comments below.)
|
| //
|
| // Also, if the URL should use process-per-site mode and there is an
|
| // existing process for the site, we should use it. We can call
|
| @@ -625,17 +626,17 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| bool use_process_per_site =
|
| RenderProcessHost::ShouldUseProcessPerSite(browser_context, dest_url) &&
|
| RenderProcessHostImpl::GetProcessHostForSite(browser_context, dest_url);
|
| - if (curr_site_instance->HasRelatedSiteInstance(dest_url) ||
|
| + if (current_site_instance->HasRelatedSiteInstance(dest_url) ||
|
| use_process_per_site) {
|
| - return curr_site_instance->GetRelatedSiteInstance(dest_url);
|
| + return current_site_instance->GetRelatedSiteInstance(dest_url);
|
| }
|
|
|
| // For extensions, Web UI URLs (such as the new tab page), and apps we do
|
| - // not want to use the curr_instance if it has no site, since it will have a
|
| - // RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance for this
|
| - // URL instead (with the correct process type).
|
| - if (curr_site_instance->HasWrongProcessForURL(dest_url))
|
| - return curr_site_instance->GetRelatedSiteInstance(dest_url);
|
| + // not want to use the current_instance if it has no site, since it will
|
| + // have a RenderProcessHost of PRIV_NORMAL. Create a new SiteInstance for
|
| + // this URL instead (with the correct process type).
|
| + if (current_site_instance->HasWrongProcessForURL(dest_url))
|
| + return current_site_instance->GetRelatedSiteInstance(dest_url);
|
|
|
| // View-source URLs must use a new SiteInstance and BrowsingInstance.
|
| // TODO(nasko): This is the same condition as later in the function. This
|
| @@ -660,28 +661,28 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| // we need to set the site first, otherwise after a restore none of the
|
| // pages would share renderers in process-per-site.
|
| if (entry.restore_type() != NavigationEntryImpl::RESTORE_NONE)
|
| - curr_site_instance->SetSite(dest_url);
|
| + current_site_instance->SetSite(dest_url);
|
|
|
| - return curr_site_instance;
|
| + return current_site_instance;
|
| }
|
|
|
| - // Otherwise, only create a new SiteInstance for cross-site navigation.
|
| + // Otherwise, only create a new SiteInstance for a cross-site navigation.
|
|
|
| // TODO(creis): Once we intercept links and script-based navigations, we
|
| // will be able to enforce that all entries in a SiteInstance actually have
|
| // the same site, and it will be safe to compare the URL against the
|
| // SiteInstance's site, as follows:
|
| - // const GURL& current_url = curr_instance->site();
|
| + // const GURL& current_url = current_instance->site();
|
| // For now, though, we're in a hybrid model where you only switch
|
| // SiteInstances if you type in a cross-site URL. This means we have to
|
| // compare the entry's URL to the last committed entry's URL.
|
| - NavigationEntry* curr_entry = controller.GetLastCommittedEntry();
|
| + NavigationEntry* current_entry = controller.GetLastCommittedEntry();
|
| if (interstitial_page_) {
|
| // The interstitial is currently the last committed entry, but we want to
|
| // compare against the last non-interstitial entry.
|
| - curr_entry = controller.GetEntryAtOffset(-1);
|
| + current_entry = controller.GetEntryAtOffset(-1);
|
| }
|
| - // If there is no last non-interstitial entry (and curr_instance already
|
| + // If there is no last non-interstitial entry (and current_instance already
|
| // has a site), then we must have been opened from another tab. We want
|
| // to compare against the URL of the page that opened us, but we can't
|
| // get to it directly. The best we can do is check against the site of
|
| @@ -691,14 +692,14 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| // to open a new tab to an interstitial-inducing URL, and then navigates
|
| // the page to a different same-site URL. (This seems very unlikely in
|
| // practice.)
|
| - const GURL& current_url = (curr_entry) ? curr_entry->GetURL() :
|
| - curr_instance->GetSiteURL();
|
| + const GURL& current_url = (current_entry) ? current_entry->GetURL() :
|
| + current_instance->GetSiteURL();
|
|
|
| // View-source URLs must use a new SiteInstance and BrowsingInstance.
|
| // TODO(creis): Refactor this method so this duplicated code isn't needed.
|
| // See http://crbug.com/123007.
|
| - if (curr_entry &&
|
| - curr_entry->IsViewSourceMode() != entry.IsViewSourceMode()) {
|
| + if (current_entry &&
|
| + current_entry->IsViewSourceMode() != entry.IsViewSourceMode()) {
|
| return SiteInstance::CreateForURL(browser_context, dest_url);
|
| }
|
|
|
| @@ -706,9 +707,8 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| // process type is correct. (The URL may have been installed as an app since
|
| // the last time we visited it.)
|
| if (SiteInstance::IsSameWebSite(browser_context, current_url, dest_url) &&
|
| - !static_cast<SiteInstanceImpl*>(curr_instance)->HasWrongProcessForURL(
|
| - dest_url)) {
|
| - return curr_instance;
|
| + !current_site_instance->HasWrongProcessForURL(dest_url)) {
|
| + return current_instance;
|
| }
|
|
|
| // Start the new renderer in a new SiteInstance, but in the current
|
| @@ -716,7 +716,7 @@ SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry(
|
| // SiteInstance to a RenderViewHost (if it is different than our current
|
| // SiteInstance), so that it is ref counted. This will happen in
|
| // CreateRenderView.
|
| - return curr_instance->GetRelatedSiteInstance(dest_url);
|
| + return current_instance->GetRelatedSiteInstance(dest_url);
|
| }
|
|
|
| int RenderViewHostManager::CreateRenderView(
|
| @@ -779,8 +779,14 @@ bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host,
|
| int opener_route_id) {
|
| // If the pending navigation is to a WebUI and the RenderView is not in a
|
| // guest process, tell the RenderView about any bindings it will need enabled.
|
| - if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest())
|
| + if (pending_web_ui() && !render_view_host->GetProcess()->IsGuest()) {
|
| render_view_host->AllowBindings(pending_web_ui()->GetBindings());
|
| + } else {
|
| + // Ensure that we don't create an unprivileged RenderView in a WebUI-enabled
|
| + // process.
|
| + CHECK(!ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
|
| + render_view_host->GetProcess()->GetID()));
|
| + }
|
|
|
| return delegate_->CreateRenderViewForRenderManager(render_view_host,
|
| opener_route_id);
|
| @@ -911,38 +917,43 @@ void RenderViewHostManager::ShutdownRenderViewHostsInSiteInstance(
|
|
|
| RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
|
| const NavigationEntryImpl& entry) {
|
| - // If we are cross-navigating, then we want to get back to normal and navigate
|
| - // as usual.
|
| + // If we are currently navigating cross-process, we want to get back to normal
|
| + // and then navigate as usual.
|
| if (cross_navigation_pending_) {
|
| if (pending_render_view_host_)
|
| CancelPending();
|
| cross_navigation_pending_ = false;
|
| }
|
|
|
| - // render_view_host_ will not be deleted before the end of this method, so we
|
| - // don't have to worry about this SiteInstance's ref count dropping to zero.
|
| - SiteInstance* curr_instance = render_view_host_->GetSiteInstance();
|
| -
|
| - // Determine if we need a new SiteInstance for this entry.
|
| - // Again, new_instance won't be deleted before the end of this method, so it
|
| - // is safe to use a normal pointer here.
|
| - SiteInstance* new_instance = curr_instance;
|
| - const NavigationEntry* curr_entry =
|
| + // render_view_host_'s SiteInstance and new_instance will not be deleted
|
| + // before the end of this method, so we don't have to worry about their ref
|
| + // counts dropping to zero.
|
| + SiteInstance* current_instance = render_view_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 BrosingInstance will be unalbe 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 is_guest_scheme = curr_instance->GetSiteURL().SchemeIs(kGuestScheme);
|
| bool force_swap = !is_guest_scheme &&
|
| - ShouldSwapProcessesForNavigation(curr_entry, &entry);
|
| + ShouldSwapBrowsingInstancesForNavigation(current_entry, &entry);
|
| if (!is_guest_scheme && (ShouldTransitionCrossSite() || force_swap))
|
| - new_instance = GetSiteInstanceForEntry(entry, curr_instance, 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 RenderViewHosts in the same SiteInstance and the same
|
| // tab, resulting in page_id conflicts for their NavigationEntries.
|
| if (force_swap)
|
| - CHECK_NE(new_instance, curr_instance);
|
| + CHECK_NE(new_instance, current_instance);
|
|
|
| - if (new_instance != curr_instance) {
|
| - // New SiteInstance.
|
| + if (new_instance != current_instance) {
|
| + // New SiteInstance: create a pending RVH to navigate.
|
| DCHECK(!cross_navigation_pending_);
|
|
|
| // This will possibly create (set to NULL) a Web UI object for the pending
|
| @@ -957,7 +968,7 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
|
| // we are staying in the same BrowsingInstance. This allows the pending RVH
|
| // to send cross-process script calls to its opener(s).
|
| int opener_route_id = MSG_ROUTING_NONE;
|
| - if (new_instance->IsRelatedSiteInstance(curr_instance)) {
|
| + if (new_instance->IsRelatedSiteInstance(current_instance)) {
|
| opener_route_id =
|
| delegate_->CreateOpenerRenderViewsForRenderManager(new_instance);
|
| }
|
| @@ -1028,32 +1039,31 @@ RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate(
|
| render_view_host_->FirePageBeforeUnload(true);
|
|
|
| return pending_render_view_host_;
|
| + }
|
| +
|
| + // Otherwise the same SiteInstance can be used. Navigate render_view_host_.
|
| + DCHECK(!cross_navigation_pending_);
|
| + if (ShouldReuseWebUI(current_entry, &entry)) {
|
| + pending_web_ui_.reset();
|
| + pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
|
| } else {
|
| - if (ShouldReuseWebUI(curr_entry, &entry)) {
|
| - pending_web_ui_.reset();
|
| - pending_and_current_web_ui_ = web_ui_->AsWeakPtr();
|
| - } else {
|
| - SetPendingWebUI(entry);
|
| + SetPendingWebUI(entry);
|
|
|
| - // Make sure the new RenderViewHost has the right bindings.
|
| - if (pending_web_ui() && !render_view_host_->GetProcess()->IsGuest())
|
| - render_view_host_->AllowBindings(pending_web_ui()->GetBindings());
|
| - }
|
| + // Make sure the new RenderViewHost has the right bindings.
|
| + if (pending_web_ui() && !render_view_host_->GetProcess()->IsGuest())
|
| + render_view_host_->AllowBindings(pending_web_ui()->GetBindings());
|
| + }
|
|
|
| - if (pending_web_ui() && render_view_host_->IsRenderViewLive())
|
| - pending_web_ui()->GetController()->RenderViewReused(render_view_host_);
|
| + if (pending_web_ui() && render_view_host_->IsRenderViewLive())
|
| + pending_web_ui()->GetController()->RenderViewReused(render_view_host_);
|
|
|
| - // The renderer can exit view source mode when any error or cancellation
|
| - // happen. We must overwrite to recover the mode.
|
| - if (entry.IsViewSourceMode()) {
|
| - render_view_host_->Send(
|
| - new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID()));
|
| - }
|
| + // The renderer can exit view source mode when any error or cancellation
|
| + // happen. We must overwrite to recover the mode.
|
| + if (entry.IsViewSourceMode()) {
|
| + render_view_host_->Send(
|
| + new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID()));
|
| }
|
|
|
| - // Same SiteInstance can be used. Navigate render_view_host_ if we are not
|
| - // cross navigating.
|
| - DCHECK(!cross_navigation_pending_);
|
| return render_view_host_;
|
| }
|
|
|
|
|