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
57using content::GlobalRequestID;
58using content::NavigationController;
59using content::WebContents;
60
61class BrowserNavigatorWebContentsAdoption {
62 public:
63  static void AttachTabHelpers(content::WebContents* contents) {
64    TabHelpers::AttachTabHelpers(contents);
65  }
66};
67
68namespace {
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.
73bool 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.
80Browser* 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.
94bool 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.
125Browser* 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.
207void 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.
248Profile* 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
257void 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.
289class 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.
312class 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
339content::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.
375bool 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
389chrome::HostDesktopType GetHostDesktop(Browser* browser) {
390  if (browser)
391    return browser->host_desktop_type();
392  return chrome::GetActiveDesktop();
393}
394
395}  // namespace
396
397namespace chrome {
398
399NavigateParams::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
424NavigateParams::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
447NavigateParams::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
472NavigateParams::~NavigateParams() {}
473
474void 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
491void 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
714bool 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