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