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