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