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