Home | History | Annotate | Download | only in frame_host
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/frame_host/navigator_impl.h"
      6 
      7 #include "base/command_line.h"
      8 #include "content/browser/frame_host/frame_tree.h"
      9 #include "content/browser/frame_host/frame_tree_node.h"
     10 #include "content/browser/frame_host/navigation_controller_impl.h"
     11 #include "content/browser/frame_host/navigation_entry_impl.h"
     12 #include "content/browser/frame_host/navigator_delegate.h"
     13 #include "content/browser/frame_host/render_frame_host_impl.h"
     14 #include "content/browser/renderer_host/render_view_host_impl.h"
     15 #include "content/browser/site_instance_impl.h"
     16 #include "content/browser/webui/web_ui_controller_factory_registry.h"
     17 #include "content/browser/webui/web_ui_impl.h"
     18 #include "content/common/frame_messages.h"
     19 #include "content/common/view_messages.h"
     20 #include "content/public/browser/browser_context.h"
     21 #include "content/public/browser/content_browser_client.h"
     22 #include "content/public/browser/global_request_id.h"
     23 #include "content/public/browser/invalidate_type.h"
     24 #include "content/public/browser/navigation_controller.h"
     25 #include "content/public/browser/navigation_details.h"
     26 #include "content/public/browser/page_navigator.h"
     27 #include "content/public/browser/render_view_host.h"
     28 #include "content/public/common/bindings_policy.h"
     29 #include "content/public/common/content_client.h"
     30 #include "content/public/common/content_switches.h"
     31 #include "content/public/common/url_constants.h"
     32 #include "content/public/common/url_utils.h"
     33 
     34 namespace content {
     35 
     36 namespace {
     37 
     38 FrameMsg_Navigate_Type::Value GetNavigationType(
     39     BrowserContext* browser_context, const NavigationEntryImpl& entry,
     40     NavigationController::ReloadType reload_type) {
     41   switch (reload_type) {
     42     case NavigationControllerImpl::RELOAD:
     43       return FrameMsg_Navigate_Type::RELOAD;
     44     case NavigationControllerImpl::RELOAD_IGNORING_CACHE:
     45       return FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE;
     46     case NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL:
     47       return FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
     48     case NavigationControllerImpl::NO_RELOAD:
     49       break;  // Fall through to rest of function.
     50   }
     51 
     52   // |RenderViewImpl::PopulateStateFromPendingNavigationParams| differentiates
     53   // between |RESTORE_WITH_POST| and |RESTORE|.
     54   if (entry.restore_type() ==
     55       NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY) {
     56     if (entry.GetHasPostData())
     57       return FrameMsg_Navigate_Type::RESTORE_WITH_POST;
     58     return FrameMsg_Navigate_Type::RESTORE;
     59   }
     60 
     61   return FrameMsg_Navigate_Type::NORMAL;
     62 }
     63 
     64 void MakeNavigateParams(const NavigationEntryImpl& entry,
     65                         const NavigationControllerImpl& controller,
     66                         NavigationController::ReloadType reload_type,
     67                         FrameMsg_Navigate_Params* params) {
     68   params->page_id = entry.GetPageID();
     69   params->should_clear_history_list = entry.should_clear_history_list();
     70   params->should_replace_current_entry = entry.should_replace_entry();
     71   if (entry.should_clear_history_list()) {
     72     // Set the history list related parameters to the same values a
     73     // NavigationController would return before its first navigation. This will
     74     // fully clear the RenderView's view of the session history.
     75     params->pending_history_list_offset = -1;
     76     params->current_history_list_offset = -1;
     77     params->current_history_list_length = 0;
     78   } else {
     79     params->pending_history_list_offset = controller.GetIndexOfEntry(&entry);
     80     params->current_history_list_offset =
     81         controller.GetLastCommittedEntryIndex();
     82     params->current_history_list_length = controller.GetEntryCount();
     83   }
     84   params->url = entry.GetURL();
     85   if (!entry.GetBaseURLForDataURL().is_empty()) {
     86     params->base_url_for_data_url = entry.GetBaseURLForDataURL();
     87     params->history_url_for_data_url = entry.GetVirtualURL();
     88   }
     89   params->referrer = entry.GetReferrer();
     90   params->transition = entry.GetTransitionType();
     91   params->page_state = entry.GetPageState();
     92   params->navigation_type =
     93       GetNavigationType(controller.GetBrowserContext(), entry, reload_type);
     94   params->request_time = base::Time::Now();
     95   params->extra_headers = entry.extra_headers();
     96   params->transferred_request_child_id =
     97       entry.transferred_global_request_id().child_id;
     98   params->transferred_request_request_id =
     99       entry.transferred_global_request_id().request_id;
    100   params->is_overriding_user_agent = entry.GetIsOverridingUserAgent();
    101   // Avoid downloading when in view-source mode.
    102   params->allow_download = !entry.IsViewSourceMode();
    103   params->is_post = entry.GetHasPostData();
    104   if (entry.GetBrowserInitiatedPostData()) {
    105     params->browser_initiated_post_data.assign(
    106         entry.GetBrowserInitiatedPostData()->front(),
    107         entry.GetBrowserInitiatedPostData()->front() +
    108             entry.GetBrowserInitiatedPostData()->size());
    109   }
    110 
    111   // Set the redirect chain to the navigation's redirects, unless we are
    112   // returning to a completed navigation (whose previous redirects don't apply).
    113   if (PageTransitionIsNewNavigation(params->transition)) {
    114     params->redirects = entry.GetRedirectChain();
    115   } else {
    116     params->redirects.clear();
    117   }
    118 
    119   params->can_load_local_resources = entry.GetCanLoadLocalResources();
    120   params->frame_to_navigate = entry.GetFrameToNavigate();
    121 }
    122 
    123 RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) {
    124   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess))
    125     return rfh->frame_tree_node()->render_manager();
    126 
    127   return rfh->frame_tree_node()->frame_tree()->root()->render_manager();
    128 }
    129 
    130 }  // namespace
    131 
    132 
    133 NavigatorImpl::NavigatorImpl(
    134     NavigationControllerImpl* navigation_controller,
    135     NavigatorDelegate* delegate)
    136     : controller_(navigation_controller),
    137       delegate_(delegate) {
    138 }
    139 
    140 NavigationController* NavigatorImpl::GetController() {
    141   return controller_;
    142 }
    143 
    144 void NavigatorImpl::DidStartProvisionalLoad(
    145     RenderFrameHostImpl* render_frame_host,
    146     int parent_routing_id,
    147     const GURL& url) {
    148   bool is_error_page = (url.spec() == kUnreachableWebDataURL);
    149   bool is_iframe_srcdoc = (url.spec() == kAboutSrcDocURL);
    150   GURL validated_url(url);
    151   RenderProcessHost* render_process_host = render_frame_host->GetProcess();
    152   render_process_host->FilterURL(false, &validated_url);
    153 
    154   bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
    155   NavigationEntryImpl* pending_entry =
    156       NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry());
    157   if (is_main_frame) {
    158     // If there is no browser-initiated pending entry for this navigation and it
    159     // is not for the error URL, create a pending entry using the current
    160     // SiteInstance, and ensure the address bar updates accordingly.  We don't
    161     // know the referrer or extra headers at this point, but the referrer will
    162     // be set properly upon commit.
    163     bool has_browser_initiated_pending_entry = pending_entry &&
    164         !pending_entry->is_renderer_initiated();
    165     if (!has_browser_initiated_pending_entry && !is_error_page) {
    166       NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
    167           controller_->CreateNavigationEntry(validated_url,
    168                                              content::Referrer(),
    169                                              content::PAGE_TRANSITION_LINK,
    170                                              true /* is_renderer_initiated */,
    171                                              std::string(),
    172                                              controller_->GetBrowserContext()));
    173       entry->set_site_instance(
    174           static_cast<SiteInstanceImpl*>(
    175               render_frame_host->render_view_host()->GetSiteInstance()));
    176       // TODO(creis): If there's a pending entry already, find a safe way to
    177       // update it instead of replacing it and copying over things like this.
    178       if (pending_entry) {
    179         entry->set_transferred_global_request_id(
    180             pending_entry->transferred_global_request_id());
    181         entry->set_should_replace_entry(pending_entry->should_replace_entry());
    182         entry->SetRedirectChain(pending_entry->GetRedirectChain());
    183       }
    184       controller_->SetPendingEntry(entry);
    185       if (delegate_)
    186         delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
    187     }
    188   }
    189 
    190   if (delegate_) {
    191     // Notify the observer about the start of the provisional load.
    192     delegate_->DidStartProvisionalLoad(
    193         render_frame_host, parent_routing_id,
    194         validated_url, is_error_page, is_iframe_srcdoc);
    195   }
    196 }
    197 
    198 
    199 void NavigatorImpl::DidFailProvisionalLoadWithError(
    200     RenderFrameHostImpl* render_frame_host,
    201     const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
    202   VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec()
    203           << ", error_code: " << params.error_code
    204           << ", error_description: " << params.error_description
    205           << ", showing_repost_interstitial: " <<
    206             params.showing_repost_interstitial
    207           << ", frame_id: " << render_frame_host->GetRoutingID();
    208   GURL validated_url(params.url);
    209   RenderProcessHost* render_process_host = render_frame_host->GetProcess();
    210   render_process_host->FilterURL(false, &validated_url);
    211 
    212   if (net::ERR_ABORTED == params.error_code) {
    213     // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials.
    214     // This means that the interstitial won't be torn down properly, which is
    215     // bad. But if we have an interstitial, go back to another tab type, and
    216     // then load the same interstitial again, we could end up getting the first
    217     // interstitial's "failed" message (as a result of the cancel) when we're on
    218     // the second one. We can't tell this apart, so we think we're tearing down
    219     // the current page which will cause a crash later on.
    220     //
    221     // http://code.google.com/p/chromium/issues/detail?id=2855
    222     // Because this will not tear down the interstitial properly, if "back" is
    223     // back to another tab type, the interstitial will still be somewhat alive
    224     // in the previous tab type. If you navigate somewhere that activates the
    225     // tab with the interstitial again, you'll see a flash before the new load
    226     // commits of the interstitial page.
    227     FrameTreeNode* root =
    228         render_frame_host->frame_tree_node()->frame_tree()->root();
    229     if (root->render_manager()->interstitial_page() != NULL) {
    230       LOG(WARNING) << "Discarding message during interstitial.";
    231       return;
    232     }
    233 
    234     // We used to cancel the pending renderer here for cross-site downloads.
    235     // However, it's not safe to do that because the download logic repeatedly
    236     // looks for this WebContents based on a render ID.  Instead, we just
    237     // leave the pending renderer around until the next navigation event
    238     // (Navigate, DidNavigate, etc), which will clean it up properly.
    239     //
    240     // TODO(creis): Find a way to cancel any pending RFH here.
    241   }
    242 
    243   // We usually clear the pending entry when it fails, so that an arbitrary URL
    244   // isn't left visible above a committed page.  This must be enforced when
    245   // the pending entry isn't visible (e.g., renderer-initiated navigations) to
    246   // prevent URL spoofs for in-page navigations that don't go through
    247   // DidStartProvisionalLoadForFrame.
    248   //
    249   // However, we do preserve the pending entry in some cases, such as on the
    250   // initial navigation of an unmodified blank tab.  We also allow the delegate
    251   // to say when it's safe to leave aborted URLs in the omnibox, to let the user
    252   // edit the URL and try again.  This may be useful in cases that the committed
    253   // page cannot be attacker-controlled.  In these cases, we still allow the
    254   // view to clear the pending entry and typed URL if the user requests
    255   // (e.g., hitting Escape with focus in the address bar).
    256   //
    257   // Note: don't touch the transient entry, since an interstitial may exist.
    258   bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() ||
    259       delegate_->ShouldPreserveAbortedURLs();
    260   if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() ||
    261       !should_preserve_entry) {
    262     controller_->DiscardPendingEntry();
    263 
    264     // Also force the UI to refresh.
    265     controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
    266   }
    267 
    268   if (delegate_)
    269     delegate_->DidFailProvisionalLoadWithError(render_frame_host, params);
    270 }
    271 
    272 void NavigatorImpl::DidFailLoadWithError(
    273     RenderFrameHostImpl* render_frame_host,
    274     const GURL& url,
    275     int error_code,
    276     const base::string16& error_description) {
    277   if (delegate_) {
    278     delegate_->DidFailLoadWithError(
    279         render_frame_host, url, error_code,
    280         error_description);
    281   }
    282 }
    283 
    284 void NavigatorImpl::DidRedirectProvisionalLoad(
    285     RenderFrameHostImpl* render_frame_host,
    286     int32 page_id,
    287     const GURL& source_url,
    288     const GURL& target_url) {
    289   // TODO(creis): Remove this method and have the pre-rendering code listen to
    290   // WebContentsObserver::DidGetRedirectForResourceRequest instead.
    291   // See http://crbug.com/78512.
    292   GURL validated_source_url(source_url);
    293   GURL validated_target_url(target_url);
    294   RenderProcessHost* render_process_host = render_frame_host->GetProcess();
    295   render_process_host->FilterURL(false, &validated_source_url);
    296   render_process_host->FilterURL(false, &validated_target_url);
    297   NavigationEntry* entry;
    298   if (page_id == -1) {
    299     entry = controller_->GetPendingEntry();
    300   } else {
    301     entry = controller_->GetEntryWithPageID(
    302         render_frame_host->GetSiteInstance(), page_id);
    303   }
    304   if (!entry || entry->GetURL() != validated_source_url)
    305     return;
    306 
    307   if (delegate_) {
    308     delegate_->DidRedirectProvisionalLoad(
    309         render_frame_host, validated_target_url);
    310   }
    311 }
    312 
    313 bool NavigatorImpl::NavigateToEntry(
    314     RenderFrameHostImpl* render_frame_host,
    315     const NavigationEntryImpl& entry,
    316     NavigationController::ReloadType reload_type) {
    317   TRACE_EVENT0("browser", "NavigatorImpl::NavigateToEntry");
    318 
    319   // The renderer will reject IPC messages with URLs longer than
    320   // this limit, so don't attempt to navigate with a longer URL.
    321   if (entry.GetURL().spec().size() > GetMaxURLChars()) {
    322     LOG(WARNING) << "Refusing to load URL as it exceeds " << GetMaxURLChars()
    323                  << " characters.";
    324     return false;
    325   }
    326 
    327   RenderFrameHostManager* manager =
    328       render_frame_host->frame_tree_node()->render_manager();
    329   RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry);
    330   if (!dest_render_frame_host)
    331     return false;  // Unable to create the desired RenderFrameHost.
    332 
    333   // Make sure no code called via RFHM::Navigate clears the pending entry.
    334   CHECK_EQ(controller_->GetPendingEntry(), &entry);
    335 
    336   // For security, we should never send non-Web-UI URLs to a Web UI renderer.
    337   // Double check that here.
    338   int enabled_bindings =
    339       dest_render_frame_host->render_view_host()->GetEnabledBindings();
    340   bool is_allowed_in_web_ui_renderer =
    341       WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
    342           controller_->GetBrowserContext(), entry.GetURL());
    343   if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) &&
    344       !is_allowed_in_web_ui_renderer) {
    345     // Log the URL to help us diagnose any future failures of this CHECK.
    346     GetContentClient()->SetActiveURL(entry.GetURL());
    347     CHECK(0);
    348   }
    349 
    350   // Notify observers that we will navigate in this RenderFrame.
    351   if (delegate_)
    352     delegate_->AboutToNavigateRenderFrame(dest_render_frame_host);
    353 
    354   // Used for page load time metrics.
    355   current_load_start_ = base::TimeTicks::Now();
    356 
    357   // Navigate in the desired RenderFrameHost.
    358   FrameMsg_Navigate_Params navigate_params;
    359   MakeNavigateParams(entry, *controller_, reload_type, &navigate_params);
    360   dest_render_frame_host->Navigate(navigate_params);
    361 
    362   // Make sure no code called via RFH::Navigate clears the pending entry.
    363   CHECK_EQ(controller_->GetPendingEntry(), &entry);
    364 
    365   if (entry.GetPageID() == -1) {
    366     // HACK!!  This code suppresses javascript: URLs from being added to
    367     // session history, which is what we want to do for javascript: URLs that
    368     // do not generate content.  What we really need is a message from the
    369     // renderer telling us that a new page was not created.  The same message
    370     // could be used for mailto: URLs and the like.
    371     if (entry.GetURL().SchemeIs(url::kJavaScriptScheme))
    372       return false;
    373   }
    374 
    375   // Notify observers about navigation.
    376   if (delegate_) {
    377     delegate_->DidStartNavigationToPendingEntry(render_frame_host,
    378                                                 entry.GetURL(),
    379                                                 reload_type);
    380   }
    381 
    382   return true;
    383 }
    384 
    385 bool NavigatorImpl::NavigateToPendingEntry(
    386     RenderFrameHostImpl* render_frame_host,
    387     NavigationController::ReloadType reload_type) {
    388   return NavigateToEntry(
    389       render_frame_host,
    390       *NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()),
    391       reload_type);
    392 }
    393 
    394 base::TimeTicks NavigatorImpl::GetCurrentLoadStart() {
    395   return current_load_start_;
    396 }
    397 
    398 void NavigatorImpl::DidNavigate(
    399     RenderFrameHostImpl* render_frame_host,
    400     const FrameHostMsg_DidCommitProvisionalLoad_Params& input_params) {
    401   FrameHostMsg_DidCommitProvisionalLoad_Params params(input_params);
    402   FrameTree* frame_tree = render_frame_host->frame_tree_node()->frame_tree();
    403   bool use_site_per_process =
    404       CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess);
    405 
    406   if (use_site_per_process) {
    407     // TODO(creis): Until we mirror the frame tree in the subframe's process,
    408     // cross-process subframe navigations happen in a renderer's main frame.
    409     // Correct the transition type here if we know it is for a subframe.
    410     NavigationEntryImpl* pending_entry =
    411         NavigationEntryImpl::FromNavigationEntry(
    412             controller_->GetPendingEntry());
    413     if (!render_frame_host->frame_tree_node()->IsMainFrame() &&
    414         pending_entry &&
    415         pending_entry->frame_tree_node_id() ==
    416             render_frame_host->frame_tree_node()->frame_tree_node_id()) {
    417       params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
    418     }
    419   }
    420 
    421   if (PageTransitionIsMainFrame(params.transition)) {
    422     if (delegate_) {
    423       // When overscroll navigation gesture is enabled, a screenshot of the page
    424       // in its current state is taken so that it can be used during the
    425       // nav-gesture. It is necessary to take the screenshot here, before
    426       // calling RenderFrameHostManager::DidNavigateMainFrame, because that can
    427       // change WebContents::GetRenderViewHost to return the new host, instead
    428       // of the one that may have just been swapped out.
    429       if (delegate_->CanOverscrollContent()) {
    430         // Don't take screenshots if we are staying on the same page. We want
    431         // in-page navigations to be super fast, and taking a screenshot
    432         // currently blocks GPU for a longer time than we are willing to
    433         // tolerate in this use case.
    434         if (!params.was_within_same_page)
    435           controller_->TakeScreenshot();
    436       }
    437 
    438       // Run tasks that must execute just before the commit.
    439       delegate_->DidNavigateMainFramePreCommit(params);
    440     }
    441 
    442     if (!use_site_per_process)
    443       frame_tree->root()->render_manager()->DidNavigateFrame(render_frame_host);
    444   }
    445 
    446   // When using --site-per-process, we notify the RFHM for all navigations,
    447   // not just main frame navigations.
    448   if (use_site_per_process) {
    449     FrameTreeNode* frame = render_frame_host->frame_tree_node();
    450     frame->render_manager()->DidNavigateFrame(render_frame_host);
    451   }
    452 
    453   // Update the site of the SiteInstance if it doesn't have one yet, unless
    454   // assigning a site is not necessary for this URL.  In that case, the
    455   // SiteInstance can still be considered unused until a navigation to a real
    456   // page.
    457   SiteInstanceImpl* site_instance =
    458       static_cast<SiteInstanceImpl*>(render_frame_host->GetSiteInstance());
    459   if (!site_instance->HasSite() &&
    460       ShouldAssignSiteForURL(params.url)) {
    461     site_instance->SetSite(params.url);
    462   }
    463 
    464   // Need to update MIME type here because it's referred to in
    465   // UpdateNavigationCommands() called by RendererDidNavigate() to
    466   // determine whether or not to enable the encoding menu.
    467   // It's updated only for the main frame. For a subframe,
    468   // RenderView::UpdateURL does not set params.contents_mime_type.
    469   // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
    470   // TODO(jungshik): Add a test for the encoding menu to avoid
    471   // regressing it again.
    472   // TODO(nasko): Verify the correctness of the above comment, since some of the
    473   // code doesn't exist anymore. Also, move this code in the
    474   // PageTransitionIsMainFrame code block above.
    475   if (PageTransitionIsMainFrame(params.transition) && delegate_)
    476     delegate_->SetMainFrameMimeType(params.contents_mime_type);
    477 
    478   LoadCommittedDetails details;
    479   bool did_navigate = controller_->RendererDidNavigate(render_frame_host,
    480                                                        params, &details);
    481 
    482   // For now, keep track of each frame's URL in its FrameTreeNode.  This lets
    483   // us estimate our process count for implementing OOP iframes.
    484   // TODO(creis): Remove this when we track which pages commit in each frame.
    485   render_frame_host->frame_tree_node()->set_current_url(params.url);
    486 
    487   // Send notification about committed provisional loads. This notification is
    488   // different from the NAV_ENTRY_COMMITTED notification which doesn't include
    489   // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
    490   if (details.type != NAVIGATION_TYPE_NAV_IGNORE && delegate_) {
    491     // For AUTO_SUBFRAME navigations, an event for the main frame is generated
    492     // that is not recorded in the navigation history. For the purpose of
    493     // tracking navigation events, we treat this event as a sub frame navigation
    494     // event.
    495     bool is_main_frame = did_navigate ? details.is_main_frame : false;
    496     PageTransition transition_type = params.transition;
    497     // Whether or not a page transition was triggered by going backward or
    498     // forward in the history is only stored in the navigation controller's
    499     // entry list.
    500     if (did_navigate &&
    501         (controller_->GetLastCommittedEntry()->GetTransitionType() &
    502             PAGE_TRANSITION_FORWARD_BACK)) {
    503       transition_type = PageTransitionFromInt(
    504           params.transition | PAGE_TRANSITION_FORWARD_BACK);
    505     }
    506 
    507     delegate_->DidCommitProvisionalLoad(render_frame_host,
    508                                         params.frame_unique_name,
    509                                         is_main_frame,
    510                                         params.url,
    511                                         transition_type);
    512   }
    513 
    514   if (!did_navigate)
    515     return;  // No navigation happened.
    516 
    517   // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
    518   // for the appropriate notification (best) or you can add it to
    519   // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
    520   // necessary, please).
    521 
    522   // Run post-commit tasks.
    523   if (delegate_) {
    524     if (details.is_main_frame)
    525       delegate_->DidNavigateMainFramePostCommit(details, params);
    526 
    527     delegate_->DidNavigateAnyFramePostCommit(
    528         render_frame_host, details, params);
    529   }
    530 }
    531 
    532 bool NavigatorImpl::ShouldAssignSiteForURL(const GURL& url) {
    533   // about:blank should not "use up" a new SiteInstance.  The SiteInstance can
    534   // still be used for a normal web site.
    535   if (url == GURL(url::kAboutBlankURL))
    536     return false;
    537 
    538   // The embedder will then have the opportunity to determine if the URL
    539   // should "use up" the SiteInstance.
    540   return GetContentClient()->browser()->ShouldAssignSiteForURL(url);
    541 }
    542 
    543 void NavigatorImpl::RequestOpenURL(
    544     RenderFrameHostImpl* render_frame_host,
    545     const GURL& url,
    546     const Referrer& referrer,
    547     WindowOpenDisposition disposition,
    548     bool should_replace_current_entry,
    549     bool user_gesture) {
    550   SiteInstance* current_site_instance =
    551       GetRenderManager(render_frame_host)->current_frame_host()->
    552           GetSiteInstance();
    553   // If this came from a swapped out RenderViewHost, we only allow the request
    554   // if we are still in the same BrowsingInstance.
    555   if (render_frame_host->render_view_host()->IsSwappedOut() &&
    556       !render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
    557           current_site_instance)) {
    558     return;
    559   }
    560 
    561   // Delegate to RequestTransferURL because this is just the generic
    562   // case where |old_request_id| is empty.
    563   // TODO(creis): Pass the redirect_chain into this method to support client
    564   // redirects.  http://crbug.com/311721.
    565   std::vector<GURL> redirect_chain;
    566   RequestTransferURL(
    567       render_frame_host, url, redirect_chain, referrer, PAGE_TRANSITION_LINK,
    568       disposition, GlobalRequestID(),
    569       should_replace_current_entry, user_gesture);
    570 }
    571 
    572 void NavigatorImpl::RequestTransferURL(
    573     RenderFrameHostImpl* render_frame_host,
    574     const GURL& url,
    575     const std::vector<GURL>& redirect_chain,
    576     const Referrer& referrer,
    577     PageTransition page_transition,
    578     WindowOpenDisposition disposition,
    579     const GlobalRequestID& transferred_global_request_id,
    580     bool should_replace_current_entry,
    581     bool user_gesture) {
    582   GURL dest_url(url);
    583   SiteInstance* current_site_instance =
    584       GetRenderManager(render_frame_host)->current_frame_host()->
    585           GetSiteInstance();
    586   if (!GetContentClient()->browser()->ShouldAllowOpenURL(
    587           current_site_instance, url)) {
    588     dest_url = GURL(url::kAboutBlankURL);
    589   }
    590 
    591   int64 frame_tree_node_id = -1;
    592   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) {
    593     frame_tree_node_id =
    594         render_frame_host->frame_tree_node()->frame_tree_node_id();
    595   }
    596   OpenURLParams params(
    597       dest_url, referrer, frame_tree_node_id, disposition, page_transition,
    598       true /* is_renderer_initiated */);
    599   if (redirect_chain.size() > 0)
    600     params.redirect_chain = redirect_chain;
    601   params.transferred_global_request_id = transferred_global_request_id;
    602   params.should_replace_current_entry = should_replace_current_entry;
    603   params.user_gesture = user_gesture;
    604 
    605   if (GetRenderManager(render_frame_host)->web_ui()) {
    606     // Web UI pages sometimes want to override the page transition type for
    607     // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for
    608     // automatically generated suggestions).  We don't override other types
    609     // like TYPED because they have different implications (e.g., autocomplete).
    610     if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK))
    611       params.transition =
    612           GetRenderManager(render_frame_host)->web_ui()->
    613               GetLinkTransitionType();
    614 
    615     // Note also that we hide the referrer for Web UI pages. We don't really
    616     // want web sites to see a referrer of "chrome://blah" (and some
    617     // chrome: URLs might have search terms or other stuff we don't want to
    618     // send to the site), so we send no referrer.
    619     params.referrer = Referrer();
    620 
    621     // Navigations in Web UI pages count as browser-initiated navigations.
    622     params.is_renderer_initiated = false;
    623   }
    624 
    625   if (delegate_)
    626     delegate_->RequestOpenURL(render_frame_host, params);
    627 }
    628 
    629 }  // namespace content
    630