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