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