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
47using content::GlobalRequestID;
48using content::NavigationController;
49using content::WebContents;
50
51class BrowserNavigatorWebContentsAdoption {
52 public:
53  static void AttachTabHelpers(content::WebContents* contents) {
54    BrowserTabContents::AttachTabHelpers(contents);
55  }
56};
57
58namespace {
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.
63bool 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.
70Browser* 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.
84bool 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.
116Browser* 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.
194void 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.
235Profile* 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
244void 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.
274class 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.
297class 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
324content::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.
364bool 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
372bool 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
380chrome::HostDesktopType GetHostDesktop(Browser* browser) {
381  if (browser)
382    return browser->host_desktop_type();
383  return chrome::GetActiveDesktop();
384}
385
386}  // namespace
387
388namespace chrome {
389
390NavigateParams::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
413NavigateParams::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
434NavigateParams::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
457NavigateParams::~NavigateParams() {}
458
459void 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
474void 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
664bool 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