Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 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 "chrome/browser/ui/browser_navigator.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/command_line.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/browser/browser_about_handler.h"
     14 #include "chrome/browser/chrome_notification_types.h"
     15 #include "chrome/browser/extensions/extension_service.h"
     16 #include "chrome/browser/extensions/tab_helper.h"
     17 #include "chrome/browser/google/google_url_tracker.h"
     18 #include "chrome/browser/prefs/incognito_mode_prefs.h"
     19 #include "chrome/browser/prerender/prerender_manager.h"
     20 #include "chrome/browser/prerender/prerender_manager_factory.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/tab_contents/tab_util.h"
     23 #include "chrome/browser/ui/browser.h"
     24 #include "chrome/browser/ui/browser_finder.h"
     25 #include "chrome/browser/ui/browser_instant_controller.h"
     26 #include "chrome/browser/ui/browser_tab_contents.h"
     27 #include "chrome/browser/ui/browser_window.h"
     28 #include "chrome/browser/ui/host_desktop.h"
     29 #include "chrome/browser/ui/omnibox/location_bar.h"
     30 #include "chrome/browser/ui/singleton_tabs.h"
     31 #include "chrome/browser/ui/status_bubble.h"
     32 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     33 #include "chrome/browser/web_applications/web_app.h"
     34 #include "chrome/common/extensions/extension.h"
     35 #include "chrome/common/pref_names.h"
     36 #include "chrome/common/url_constants.h"
     37 #include "content/public/browser/browser_url_handler.h"
     38 #include "content/public/browser/notification_service.h"
     39 #include "content/public/browser/render_view_host.h"
     40 #include "content/public/browser/web_contents.h"
     41 #include "content/public/browser/web_contents_view.h"
     42 
     43 #if defined(USE_AURA)
     44 #include "ui/aura/window.h"
     45 #endif
     46 
     47 using content::GlobalRequestID;
     48 using content::NavigationController;
     49 using content::WebContents;
     50 
     51 class BrowserNavigatorWebContentsAdoption {
     52  public:
     53   static void AttachTabHelpers(content::WebContents* contents) {
     54     BrowserTabContents::AttachTabHelpers(contents);
     55   }
     56 };
     57 
     58 namespace {
     59 
     60 // Returns true if the specified Browser can open tabs. Not all Browsers support
     61 // multiple tabs, such as app frames and popups. This function returns false for
     62 // those types of Browser.
     63 bool WindowCanOpenTabs(Browser* browser) {
     64   return browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
     65       browser->tab_strip_model()->empty();
     66 }
     67 
     68 // Finds an existing Browser compatible with |profile|, making a new one if no
     69 // such Browser is located.
     70 Browser* GetOrCreateBrowser(Profile* profile,
     71                             chrome::HostDesktopType host_desktop_type) {
     72   Browser* browser = chrome::FindTabbedBrowser(profile, false,
     73                                                host_desktop_type);
     74   return browser ? browser : new Browser(
     75       Browser::CreateParams(profile, host_desktop_type));
     76 }
     77 
     78 // Change some of the navigation parameters based on the particular URL.
     79 // Currently this applies to some chrome:// pages which we always want to open
     80 // in a non-incognito window. Note that even though a ChromeOS guest session is
     81 // technically an incognito window, these URLs are allowed.
     82 // Returns true on success. Otherwise, if changing params leads the browser into
     83 // an erroneous state, returns false.
     84 bool AdjustNavigateParamsForURL(chrome::NavigateParams* params) {
     85   if (params->target_contents != NULL ||
     86       chrome::IsURLAllowedInIncognito(params->url,
     87                                       params->initiating_profile) ||
     88       params->initiating_profile->IsGuestSession()) {
     89     return true;
     90   }
     91 
     92   Profile* profile = params->initiating_profile;
     93 
     94   if (profile->IsOffTheRecord() || params->disposition == OFF_THE_RECORD) {
     95     profile = profile->GetOriginalProfile();
     96 
     97     // If incognito is forced, we punt.
     98     PrefService* prefs = profile->GetPrefs();
     99     if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
    100             IncognitoModePrefs::FORCED) {
    101       return false;
    102     }
    103 
    104     params->disposition = SINGLETON_TAB;
    105     params->browser =
    106         chrome::FindOrCreateTabbedBrowser(profile, params->host_desktop_type);
    107     params->window_action = chrome::NavigateParams::SHOW_WINDOW;
    108   }
    109 
    110   return true;
    111 }
    112 
    113 // Returns a Browser that can host the navigation or tab addition specified in
    114 // |params|. This might just return the same Browser specified in |params|, or
    115 // some other if that Browser is deemed incompatible.
    116 Browser* GetBrowserForDisposition(chrome::NavigateParams* params) {
    117   // If no source WebContents was specified, we use the selected one from
    118   // the target browser. This must happen first, before
    119   // GetBrowserForDisposition() has a chance to replace |params->browser| with
    120   // another one.
    121   if (!params->source_contents && params->browser) {
    122     params->source_contents =
    123         params->browser->tab_strip_model()->GetActiveWebContents();
    124   }
    125 
    126   Profile* profile = params->initiating_profile;
    127 
    128   switch (params->disposition) {
    129     case CURRENT_TAB:
    130       if (params->browser)
    131         return params->browser;
    132       // Find a compatible window and re-execute this command in it. Otherwise
    133       // re-run with NEW_WINDOW.
    134       return GetOrCreateBrowser(profile, params->host_desktop_type);
    135     case SINGLETON_TAB:
    136     case NEW_FOREGROUND_TAB:
    137     case NEW_BACKGROUND_TAB:
    138       // See if we can open the tab in the window this navigator is bound to.
    139       if (params->browser && WindowCanOpenTabs(params->browser))
    140         return params->browser;
    141       // Find a compatible window and re-execute this command in it. Otherwise
    142       // re-run with NEW_WINDOW.
    143       return GetOrCreateBrowser(profile, params->host_desktop_type);
    144     case NEW_POPUP: {
    145       // Make a new popup window.
    146       // Coerce app-style if |source| represents an app.
    147       std::string app_name;
    148       if (!params->extension_app_id.empty()) {
    149         app_name = web_app::GenerateApplicationNameFromExtensionId(
    150             params->extension_app_id);
    151       } else if (params->browser && !params->browser->app_name().empty()) {
    152         app_name = params->browser->app_name();
    153       } else if (params->source_contents) {
    154         extensions::TabHelper* extensions_tab_helper =
    155             extensions::TabHelper::FromWebContents(params->source_contents);
    156         if (extensions_tab_helper && extensions_tab_helper->is_app()) {
    157           app_name = web_app::GenerateApplicationNameFromExtensionId(
    158               extensions_tab_helper->extension_app()->id());
    159         }
    160       }
    161       if (app_name.empty()) {
    162         Browser::CreateParams browser_params(
    163             Browser::TYPE_POPUP, profile, params->host_desktop_type);
    164         browser_params.initial_bounds = params->window_bounds;
    165         return new Browser(browser_params);
    166       }
    167 
    168       return new Browser(Browser::CreateParams::CreateForApp(
    169           Browser::TYPE_POPUP, app_name, params->window_bounds, profile,
    170           params->host_desktop_type));
    171     }
    172     case NEW_WINDOW: {
    173       // Make a new normal browser window.
    174       return new Browser(Browser::CreateParams(profile,
    175                                                params->host_desktop_type));
    176     }
    177     case OFF_THE_RECORD:
    178       // Make or find an incognito window.
    179       return GetOrCreateBrowser(profile->GetOffTheRecordProfile(),
    180                                 params->host_desktop_type);
    181     // The following types all result in no navigation.
    182     case SUPPRESS_OPEN:
    183     case SAVE_TO_DISK:
    184     case IGNORE_ACTION:
    185       return NULL;
    186     default:
    187       NOTREACHED();
    188   }
    189   return NULL;
    190 }
    191 
    192 // Fix disposition and other parameter values depending on prevailing
    193 // conditions.
    194 void NormalizeDisposition(chrome::NavigateParams* params) {
    195   // Calculate the WindowOpenDisposition if necessary.
    196   if (params->browser->tab_strip_model()->empty() &&
    197       (params->disposition == NEW_BACKGROUND_TAB ||
    198        params->disposition == CURRENT_TAB ||
    199        params->disposition == SINGLETON_TAB)) {
    200     params->disposition = NEW_FOREGROUND_TAB;
    201   }
    202   if (params->browser->profile()->IsOffTheRecord() &&
    203       params->disposition == OFF_THE_RECORD) {
    204     params->disposition = NEW_FOREGROUND_TAB;
    205   }
    206   if (!params->source_contents && params->disposition == CURRENT_TAB)
    207     params->disposition = NEW_FOREGROUND_TAB;
    208 
    209   switch (params->disposition) {
    210     case NEW_BACKGROUND_TAB:
    211       // Disposition trumps add types. ADD_ACTIVE is a default, so we need to
    212       // remove it if disposition implies the tab is going to open in the
    213       // background.
    214       params->tabstrip_add_types &= ~TabStripModel::ADD_ACTIVE;
    215       break;
    216 
    217     case NEW_WINDOW:
    218     case NEW_POPUP:
    219       // Code that wants to open a new window typically expects it to be shown
    220       // automatically.
    221       if (params->window_action == chrome::NavigateParams::NO_ACTION)
    222         params->window_action = chrome::NavigateParams::SHOW_WINDOW;
    223       // Fall-through.
    224     case NEW_FOREGROUND_TAB:
    225     case SINGLETON_TAB:
    226       params->tabstrip_add_types |= TabStripModel::ADD_ACTIVE;
    227       break;
    228 
    229     default:
    230       break;
    231   }
    232 }
    233 
    234 // Obtain the profile used by the code that originated the Navigate() request.
    235 Profile* GetSourceProfile(chrome::NavigateParams* params) {
    236   if (params->source_contents) {
    237     return Profile::FromBrowserContext(
    238         params->source_contents->GetBrowserContext());
    239   }
    240 
    241   return params->initiating_profile;
    242 }
    243 
    244 void LoadURLInContents(WebContents* target_contents,
    245                        const GURL& url,
    246                        chrome::NavigateParams* params) {
    247   NavigationController::LoadURLParams load_url_params(url);
    248   load_url_params.referrer = params->referrer;
    249   load_url_params.transition_type = params->transition;
    250   load_url_params.extra_headers = params->extra_headers;
    251   load_url_params.should_replace_current_entry =
    252       params->should_replace_current_entry;
    253 
    254   if (params->transferred_global_request_id != GlobalRequestID()) {
    255     load_url_params.is_renderer_initiated = params->is_renderer_initiated;
    256     load_url_params.transferred_global_request_id =
    257         params->transferred_global_request_id;
    258   } else if (params->is_renderer_initiated) {
    259     load_url_params.is_renderer_initiated = true;
    260   }
    261 
    262   // Only allows the browser-initiated navigation to use POST.
    263   if (params->uses_post && !params->is_renderer_initiated) {
    264     load_url_params.load_type =
    265         NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
    266     load_url_params.browser_initiated_post_data =
    267         params->browser_initiated_post_data;
    268   }
    269   target_contents->GetController().LoadURLWithParams(load_url_params);
    270 }
    271 
    272 // This class makes sure the Browser object held in |params| is made visible
    273 // by the time it goes out of scope, provided |params| wants it to be shown.
    274 class ScopedBrowserDisplayer {
    275  public:
    276   explicit ScopedBrowserDisplayer(chrome::NavigateParams* params)
    277       : params_(params) {
    278   }
    279   ~ScopedBrowserDisplayer() {
    280     if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW_INACTIVE)
    281       params_->browser->window()->ShowInactive();
    282     else if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW)
    283       params_->browser->window()->Show();
    284   }
    285  private:
    286   chrome::NavigateParams* params_;
    287   DISALLOW_COPY_AND_ASSIGN(ScopedBrowserDisplayer);
    288 };
    289 
    290 // This class manages the lifetime of a WebContents created by the
    291 // Navigate() function. When Navigate() creates a WebContents for a URL,
    292 // an instance of this class takes ownership of it via TakeOwnership() until the
    293 // WebContents is added to a tab strip at which time ownership is
    294 // relinquished via ReleaseOwnership(). If this object goes out of scope without
    295 // being added to a tab strip, the created WebContents is deleted to
    296 // avoid a leak and the params->target_contents field is set to NULL.
    297 class ScopedTargetContentsOwner {
    298  public:
    299   explicit ScopedTargetContentsOwner(chrome::NavigateParams* params)
    300       : params_(params) {
    301   }
    302   ~ScopedTargetContentsOwner() {
    303     if (target_contents_owner_.get())
    304       params_->target_contents = NULL;
    305   }
    306 
    307   // Assumes ownership of |params_|' target_contents until ReleaseOwnership
    308   // is called.
    309   void TakeOwnership() {
    310     target_contents_owner_.reset(params_->target_contents);
    311   }
    312 
    313   // Relinquishes ownership of |params_|' target_contents.
    314   WebContents* ReleaseOwnership() {
    315     return target_contents_owner_.release();
    316   }
    317 
    318  private:
    319   chrome::NavigateParams* params_;
    320   scoped_ptr<WebContents> target_contents_owner_;
    321   DISALLOW_COPY_AND_ASSIGN(ScopedTargetContentsOwner);
    322 };
    323 
    324 content::WebContents* CreateTargetContents(const chrome::NavigateParams& params,
    325                                            const GURL& url) {
    326   WebContents::CreateParams create_params(
    327       params.browser->profile(),
    328       tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url));
    329   if (params.source_contents) {
    330     create_params.initial_size =
    331         params.source_contents->GetView()->GetContainerSize();
    332     if (params.should_set_opener)
    333       create_params.opener = params.source_contents;
    334   }
    335 #if defined(USE_AURA)
    336   if (params.browser->window() &&
    337       params.browser->window()->GetNativeWindow()) {
    338     create_params.context =
    339         params.browser->window()->GetNativeWindow();
    340   }
    341 #endif
    342 
    343   WebContents* target_contents = WebContents::Create(create_params);
    344 
    345   // New tabs can have WebUI URLs that will make calls back to arbitrary
    346   // tab helpers, so the entire set of tab helpers needs to be set up
    347   // immediately.
    348   BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents);
    349   extensions::TabHelper::FromWebContents(target_contents)->
    350       SetExtensionAppById(params.extension_app_id);
    351   // TODO(sky): Figure out why this is needed. Without it we seem to get
    352   // failures in startup tests.
    353   // By default, content believes it is not hidden.  When adding contents
    354   // in the background, tell it that it's hidden.
    355   if ((params.tabstrip_add_types & TabStripModel::ADD_ACTIVE) == 0) {
    356     // TabStripModel::AddWebContents invokes WasHidden if not foreground.
    357     target_contents->WasHidden();
    358   }
    359   return target_contents;
    360 }
    361 
    362 // If a prerendered page exists for |url|, replace the page at |target_contents|
    363 // with it.
    364 bool SwapInPrerender(WebContents* target_contents, const GURL& url) {
    365   prerender::PrerenderManager* prerender_manager =
    366       prerender::PrerenderManagerFactory::GetForProfile(
    367           Profile::FromBrowserContext(target_contents->GetBrowserContext()));
    368   return prerender_manager &&
    369       prerender_manager->MaybeUsePrerenderedPage(target_contents, url);
    370 }
    371 
    372 bool SwapInInstantNTP(chrome::NavigateParams* params,
    373                       const GURL& url,
    374                       content::WebContents* source_contents) {
    375   BrowserInstantController* instant = params->browser->instant_controller();
    376   return instant && instant->MaybeSwapInInstantNTPContents(
    377       url, source_contents, &params->target_contents);
    378 }
    379 
    380 chrome::HostDesktopType GetHostDesktop(Browser* browser) {
    381   if (browser)
    382     return browser->host_desktop_type();
    383   return chrome::GetActiveDesktop();
    384 }
    385 
    386 }  // namespace
    387 
    388 namespace chrome {
    389 
    390 NavigateParams::NavigateParams(Browser* a_browser,
    391                                const GURL& a_url,
    392                                content::PageTransition a_transition)
    393     : url(a_url),
    394       uses_post(false),
    395       target_contents(NULL),
    396       source_contents(NULL),
    397       disposition(CURRENT_TAB),
    398       transition(a_transition),
    399       is_renderer_initiated(false),
    400       tabstrip_index(-1),
    401       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    402       window_action(NO_ACTION),
    403       user_gesture(true),
    404       path_behavior(RESPECT),
    405       ref_behavior(IGNORE_REF),
    406       browser(a_browser),
    407       initiating_profile(NULL),
    408       host_desktop_type(GetHostDesktop(a_browser)),
    409       should_replace_current_entry(false),
    410       should_set_opener(false) {
    411 }
    412 
    413 NavigateParams::NavigateParams(Browser* a_browser,
    414                                WebContents* a_target_contents)
    415     : uses_post(false),
    416       target_contents(a_target_contents),
    417       source_contents(NULL),
    418       disposition(CURRENT_TAB),
    419       transition(content::PAGE_TRANSITION_LINK),
    420       is_renderer_initiated(false),
    421       tabstrip_index(-1),
    422       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    423       window_action(NO_ACTION),
    424       user_gesture(true),
    425       path_behavior(RESPECT),
    426       ref_behavior(IGNORE_REF),
    427       browser(a_browser),
    428       initiating_profile(NULL),
    429       host_desktop_type(GetHostDesktop(a_browser)),
    430       should_replace_current_entry(false),
    431       should_set_opener(false) {
    432 }
    433 
    434 NavigateParams::NavigateParams(Profile* a_profile,
    435                                const GURL& a_url,
    436                                content::PageTransition a_transition)
    437     : url(a_url),
    438       uses_post(false),
    439       target_contents(NULL),
    440       source_contents(NULL),
    441       disposition(NEW_FOREGROUND_TAB),
    442       transition(a_transition),
    443       is_renderer_initiated(false),
    444       tabstrip_index(-1),
    445       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    446       window_action(SHOW_WINDOW),
    447       user_gesture(true),
    448       path_behavior(RESPECT),
    449       ref_behavior(IGNORE_REF),
    450       browser(NULL),
    451       initiating_profile(a_profile),
    452       host_desktop_type(chrome::GetActiveDesktop()),
    453       should_replace_current_entry(false),
    454       should_set_opener(false) {
    455 }
    456 
    457 NavigateParams::~NavigateParams() {}
    458 
    459 void FillNavigateParamsFromOpenURLParams(chrome::NavigateParams* nav_params,
    460                                          const content::OpenURLParams& params) {
    461   nav_params->referrer = params.referrer;
    462   nav_params->extra_headers = params.extra_headers;
    463   nav_params->disposition = params.disposition;
    464   nav_params->override_encoding = params.override_encoding;
    465   nav_params->is_renderer_initiated = params.is_renderer_initiated;
    466   nav_params->transferred_global_request_id =
    467       params.transferred_global_request_id;
    468   nav_params->should_replace_current_entry =
    469       params.should_replace_current_entry;
    470   nav_params->uses_post = params.uses_post;
    471   nav_params->browser_initiated_post_data = params.browser_initiated_post_data;
    472 }
    473 
    474 void Navigate(NavigateParams* params) {
    475   Browser* source_browser = params->browser;
    476   if (source_browser)
    477     params->initiating_profile = source_browser->profile();
    478   DCHECK(params->initiating_profile);
    479 
    480   if (!AdjustNavigateParamsForURL(params))
    481     return;
    482 
    483   ExtensionService* service = params->initiating_profile->GetExtensionService();
    484   if (service)
    485     service->ShouldBlockUrlInBrowserTab(&params->url);
    486 
    487   // The browser window may want to adjust the disposition.
    488   if (params->disposition == NEW_POPUP &&
    489       source_browser &&
    490       source_browser->window()) {
    491     params->disposition =
    492         source_browser->window()->GetDispositionForPopupBounds(
    493             params->window_bounds);
    494   }
    495 
    496   params->browser = GetBrowserForDisposition(params);
    497   if (!params->browser)
    498     return;
    499 
    500   // Navigate() must not return early after this point.
    501 
    502   if (GetSourceProfile(params) != params->browser->profile()) {
    503     // A tab is being opened from a link from a different profile, we must reset
    504     // source information that may cause state to be shared.
    505     params->source_contents = NULL;
    506     params->referrer = content::Referrer();
    507   }
    508 
    509   // Make sure the Browser is shown if params call for it.
    510   ScopedBrowserDisplayer displayer(params);
    511 
    512   // Makes sure any WebContents created by this function is destroyed if
    513   // not properly added to a tab strip.
    514   ScopedTargetContentsOwner target_contents_owner(params);
    515 
    516   // Some dispositions need coercion to base types.
    517   NormalizeDisposition(params);
    518 
    519   // If a new window has been created, it needs to be displayed.
    520   if (params->window_action == NavigateParams::NO_ACTION &&
    521       source_browser != params->browser &&
    522       params->browser->tab_strip_model()->empty()) {
    523     params->window_action = NavigateParams::SHOW_WINDOW;
    524   }
    525 
    526   // If we create a popup window from a non user-gesture, don't activate it.
    527   if (params->window_action == NavigateParams::SHOW_WINDOW &&
    528       params->disposition == NEW_POPUP &&
    529       params->user_gesture == false) {
    530     params->window_action = NavigateParams::SHOW_WINDOW_INACTIVE;
    531   }
    532 
    533   // Determine if the navigation was user initiated. If it was, we need to
    534   // inform the target WebContents, and we may need to update the UI.
    535   content::PageTransition base_transition =
    536       content::PageTransitionStripQualifier(params->transition);
    537   bool user_initiated =
    538       params->transition & content::PAGE_TRANSITION_FROM_ADDRESS_BAR ||
    539       base_transition == content::PAGE_TRANSITION_TYPED ||
    540       base_transition == content::PAGE_TRANSITION_AUTO_BOOKMARK ||
    541       base_transition == content::PAGE_TRANSITION_GENERATED ||
    542       base_transition == content::PAGE_TRANSITION_AUTO_TOPLEVEL ||
    543       base_transition == content::PAGE_TRANSITION_RELOAD ||
    544       base_transition == content::PAGE_TRANSITION_KEYWORD;
    545 
    546   // Check if this is a singleton tab that already exists
    547   int singleton_index = chrome::GetIndexOfSingletonTab(params);
    548 
    549   // Did we use Instant's NTP contents?
    550   bool swapped_in_instant = false;
    551 
    552   // If no target WebContents was specified, we need to construct one if
    553   // we are supposed to target a new tab; unless it's a singleton that already
    554   // exists.
    555   if (!params->target_contents && singleton_index < 0) {
    556     GURL url;
    557     if (params->url.is_empty()) {
    558       url = params->browser->profile()->GetHomePage();
    559       params->transition = content::PageTransitionFromInt(
    560           params->transition | content::PAGE_TRANSITION_HOME_PAGE);
    561     } else {
    562       url = params->url;
    563     }
    564 
    565     if (params->disposition != CURRENT_TAB) {
    566       swapped_in_instant = SwapInInstantNTP(params, url, NULL);
    567       if (!swapped_in_instant)
    568         params->target_contents = CreateTargetContents(*params, url);
    569 
    570       // This function takes ownership of |params->target_contents| until it
    571       // is added to a TabStripModel.
    572       target_contents_owner.TakeOwnership();
    573     } else {
    574       // ... otherwise if we're loading in the current tab, the target is the
    575       // same as the source.
    576       DCHECK(params->source_contents);
    577       swapped_in_instant = SwapInInstantNTP(params, url,
    578                                             params->source_contents);
    579       if (!swapped_in_instant)
    580         params->target_contents = params->source_contents;
    581       DCHECK(params->target_contents);
    582     }
    583 
    584     if (user_initiated)
    585       params->target_contents->UserGestureDone();
    586 
    587     if (!swapped_in_instant) {
    588       if (SwapInPrerender(params->target_contents, url))
    589         return;
    590 
    591       // Try to handle non-navigational URLs that popup dialogs and such, these
    592       // should not actually navigate.
    593       if (!HandleNonNavigationAboutURL(url)) {
    594         // Perform the actual navigation, tracking whether it came from the
    595         // renderer.
    596 
    597         LoadURLInContents(params->target_contents, url, params);
    598       }
    599     }
    600   } else {
    601     // |target_contents| was specified non-NULL, and so we assume it has already
    602     // been navigated appropriately. We need to do nothing more other than
    603     // add it to the appropriate tabstrip.
    604   }
    605 
    606   // If the user navigated from the omnibox, and the selected tab is going to
    607   // lose focus, then make sure the focus for the source tab goes away from the
    608   // omnibox.
    609   if (params->source_contents &&
    610       (params->disposition == NEW_FOREGROUND_TAB ||
    611        params->disposition == NEW_WINDOW) &&
    612       (params->tabstrip_add_types & TabStripModel::ADD_INHERIT_OPENER))
    613     params->source_contents->GetView()->Focus();
    614 
    615   if (params->source_contents == params->target_contents ||
    616       (swapped_in_instant && params->disposition == CURRENT_TAB)) {
    617     // The navigation occurred in the source tab.
    618     params->browser->UpdateUIForNavigationInTab(params->target_contents,
    619                                                 params->transition,
    620                                                 user_initiated);
    621   } else if (singleton_index == -1) {
    622     // If some non-default value is set for the index, we should tell the
    623     // TabStripModel to respect it.
    624     if (params->tabstrip_index != -1)
    625       params->tabstrip_add_types |= TabStripModel::ADD_FORCE_INDEX;
    626 
    627     // The navigation should insert a new tab into the target Browser.
    628     params->browser->tab_strip_model()->AddWebContents(
    629         params->target_contents,
    630         params->tabstrip_index,
    631         params->transition,
    632         params->tabstrip_add_types);
    633     // Now that the |params->target_contents| is safely owned by the target
    634     // Browser's TabStripModel, we can release ownership.
    635     target_contents_owner.ReleaseOwnership();
    636   }
    637 
    638   if (singleton_index >= 0) {
    639     WebContents* target =
    640         params->browser->tab_strip_model()->GetWebContentsAt(singleton_index);
    641 
    642     if (target->IsCrashed()) {
    643       target->GetController().Reload(true);
    644     } else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE &&
    645         target->GetURL() != params->url) {
    646       LoadURLInContents(target, params->url, params);
    647     }
    648 
    649     // If the singleton tab isn't already selected, select it.
    650     if (params->source_contents != params->target_contents) {
    651       params->browser->tab_strip_model()->ActivateTabAt(singleton_index,
    652                                                         user_initiated);
    653     }
    654   }
    655 
    656   if (params->disposition != CURRENT_TAB) {
    657     content::NotificationService::current()->Notify(
    658         chrome::NOTIFICATION_TAB_ADDED,
    659         content::Source<content::WebContentsDelegate>(params->browser),
    660         content::Details<WebContents>(params->target_contents));
    661   }
    662 }
    663 
    664 bool IsURLAllowedInIncognito(const GURL& url,
    665                              content::BrowserContext* browser_context) {
    666   if (url.scheme() == content::kViewSourceScheme) {
    667     // A view-source URL is allowed in incognito mode only if the URL itself
    668     // is allowed in incognito mode. Remove the "view-source:" from the start
    669     // of the URL and validate the rest.
    670     std::string stripped_spec = url.spec();
    671     DCHECK_GT(stripped_spec.size(), strlen(content::kViewSourceScheme));
    672     stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
    673     GURL stripped_url(stripped_spec);
    674     return stripped_url.is_valid() &&
    675         IsURLAllowedInIncognito(stripped_url, browser_context);
    676   }
    677   // Most URLs are allowed in incognito; the following are exceptions.
    678   // chrome://extensions is on the list because it redirects to
    679   // chrome://settings.
    680   if (url.scheme() == chrome::kChromeUIScheme &&
    681       (url.host() == chrome::kChromeUISettingsHost ||
    682        url.host() == chrome::kChromeUISettingsFrameHost ||
    683        url.host() == chrome::kChromeUIExtensionsHost ||
    684        url.host() == chrome::kChromeUIBookmarksHost ||
    685        url.host() == chrome::kChromeUIUberHost)) {
    686     return false;
    687   }
    688 
    689   GURL rewritten_url = url;
    690   bool reverse_on_redirect = false;
    691   content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary(
    692       &rewritten_url, browser_context, &reverse_on_redirect);
    693 
    694   // Some URLs are mapped to uber subpages. Do not allow them in incognito.
    695   return !(rewritten_url.scheme() == chrome::kChromeUIScheme &&
    696            rewritten_url.host() == chrome::kChromeUIUberHost);
    697 }
    698 
    699 }  // namespace chrome
    700