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/omnibox/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 53 using content::GlobalRequestID; 54 using content::NavigationController; 55 using content::WebContents; 56 57 class BrowserNavigatorWebContentsAdoption { 58 public: 59 static void AttachTabHelpers(content::WebContents* contents) { 60 TabHelpers::AttachTabHelpers(contents); 61 } 62 }; 63 64 namespace { 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. 69 bool 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. 76 Browser* 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. 90 bool 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. 121 Browser* 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. 203 void 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. 244 Profile* 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 253 void 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. 285 class 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. 308 class 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 335 content::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. 371 bool 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 385 chrome::HostDesktopType GetHostDesktop(Browser* browser) { 386 if (browser) 387 return browser->host_desktop_type(); 388 return chrome::GetActiveDesktop(); 389 } 390 391 } // namespace 392 393 namespace chrome { 394 395 NavigateParams::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 420 NavigateParams::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 443 NavigateParams::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 468 NavigateParams::~NavigateParams() {} 469 470 void 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 487 void 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 708 bool 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