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/extension_service.h" 16 #include "chrome/browser/extensions/tab_helper.h" 17 #include "chrome/browser/google/google_url_tracker.h" 18 #include "chrome/browser/prefs/incognito_mode_prefs.h" 19 #include "chrome/browser/prerender/prerender_manager.h" 20 #include "chrome/browser/prerender/prerender_manager_factory.h" 21 #include "chrome/browser/prerender/prerender_util.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/tab_contents/tab_util.h" 24 #include "chrome/browser/ui/browser.h" 25 #include "chrome/browser/ui/browser_finder.h" 26 #include "chrome/browser/ui/browser_instant_controller.h" 27 #include "chrome/browser/ui/browser_tab_contents.h" 28 #include "chrome/browser/ui/browser_window.h" 29 #include "chrome/browser/ui/host_desktop.h" 30 #include "chrome/browser/ui/omnibox/location_bar.h" 31 #include "chrome/browser/ui/search/instant_search_prerenderer.h" 32 #include "chrome/browser/ui/singleton_tabs.h" 33 #include "chrome/browser/ui/status_bubble.h" 34 #include "chrome/browser/ui/tabs/tab_strip_model.h" 35 #include "chrome/browser/web_applications/web_app.h" 36 #include "chrome/common/pref_names.h" 37 #include "chrome/common/url_constants.h" 38 #include "content/public/browser/browser_url_handler.h" 39 #include "content/public/browser/navigation_entry.h" 40 #include "content/public/browser/notification_service.h" 41 #include "content/public/browser/render_view_host.h" 42 #include "content/public/browser/web_contents.h" 43 #include "content/public/browser/web_contents_view.h" 44 #include "extensions/common/extension.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 BrowserTabContents::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.initial_bounds = params->window_bounds; 170 return new Browser(browser_params); 171 } 172 173 return new Browser(Browser::CreateParams::CreateForApp( 174 Browser::TYPE_POPUP, app_name, params->window_bounds, profile, 175 params->host_desktop_type)); 176 } 177 case NEW_WINDOW: { 178 // Make a new normal browser window. 179 return new Browser(Browser::CreateParams(profile, 180 params->host_desktop_type)); 181 } 182 case OFF_THE_RECORD: 183 // Make or find an incognito window. 184 return GetOrCreateBrowser(profile->GetOffTheRecordProfile(), 185 params->host_desktop_type); 186 // The following types all result in no navigation. 187 case SUPPRESS_OPEN: 188 case SAVE_TO_DISK: 189 case IGNORE_ACTION: 190 return NULL; 191 default: 192 NOTREACHED(); 193 } 194 return NULL; 195 } 196 197 // Fix disposition and other parameter values depending on prevailing 198 // conditions. 199 void NormalizeDisposition(chrome::NavigateParams* params) { 200 // Calculate the WindowOpenDisposition if necessary. 201 if (params->browser->tab_strip_model()->empty() && 202 (params->disposition == NEW_BACKGROUND_TAB || 203 params->disposition == CURRENT_TAB || 204 params->disposition == SINGLETON_TAB)) { 205 params->disposition = NEW_FOREGROUND_TAB; 206 } 207 if (params->browser->profile()->IsOffTheRecord() && 208 params->disposition == OFF_THE_RECORD) { 209 params->disposition = NEW_FOREGROUND_TAB; 210 } 211 if (!params->source_contents && params->disposition == CURRENT_TAB) 212 params->disposition = NEW_FOREGROUND_TAB; 213 214 switch (params->disposition) { 215 case NEW_BACKGROUND_TAB: 216 // Disposition trumps add types. ADD_ACTIVE is a default, so we need to 217 // remove it if disposition implies the tab is going to open in the 218 // background. 219 params->tabstrip_add_types &= ~TabStripModel::ADD_ACTIVE; 220 break; 221 222 case NEW_WINDOW: 223 case NEW_POPUP: 224 // Code that wants to open a new window typically expects it to be shown 225 // automatically. 226 if (params->window_action == chrome::NavigateParams::NO_ACTION) 227 params->window_action = chrome::NavigateParams::SHOW_WINDOW; 228 // Fall-through. 229 case NEW_FOREGROUND_TAB: 230 case SINGLETON_TAB: 231 params->tabstrip_add_types |= TabStripModel::ADD_ACTIVE; 232 break; 233 234 default: 235 break; 236 } 237 } 238 239 // Obtain the profile used by the code that originated the Navigate() request. 240 Profile* GetSourceProfile(chrome::NavigateParams* params) { 241 if (params->source_contents) { 242 return Profile::FromBrowserContext( 243 params->source_contents->GetBrowserContext()); 244 } 245 246 return params->initiating_profile; 247 } 248 249 void LoadURLInContents(WebContents* target_contents, 250 const GURL& url, 251 chrome::NavigateParams* params) { 252 NavigationController::LoadURLParams load_url_params(url); 253 load_url_params.referrer = params->referrer; 254 load_url_params.frame_tree_node_id = params->frame_tree_node_id; 255 load_url_params.redirect_chain = params->redirect_chain; 256 load_url_params.transition_type = params->transition; 257 load_url_params.extra_headers = params->extra_headers; 258 load_url_params.should_replace_current_entry = 259 params->should_replace_current_entry; 260 261 if (params->transferred_global_request_id != GlobalRequestID()) { 262 load_url_params.is_renderer_initiated = params->is_renderer_initiated; 263 load_url_params.transferred_global_request_id = 264 params->transferred_global_request_id; 265 } else if (params->is_renderer_initiated) { 266 load_url_params.is_renderer_initiated = true; 267 } 268 269 // Only allows the browser-initiated navigation to use POST. 270 if (params->uses_post && !params->is_renderer_initiated) { 271 load_url_params.load_type = 272 NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST; 273 load_url_params.browser_initiated_post_data = 274 params->browser_initiated_post_data; 275 } 276 target_contents->GetController().LoadURLWithParams(load_url_params); 277 } 278 279 // This class makes sure the Browser object held in |params| is made visible 280 // by the time it goes out of scope, provided |params| wants it to be shown. 281 class ScopedBrowserShower { 282 public: 283 explicit ScopedBrowserShower(chrome::NavigateParams* params) 284 : params_(params) { 285 } 286 ~ScopedBrowserShower() { 287 if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW_INACTIVE) 288 params_->browser->window()->ShowInactive(); 289 else if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW) 290 params_->browser->window()->Show(); 291 } 292 private: 293 chrome::NavigateParams* params_; 294 DISALLOW_COPY_AND_ASSIGN(ScopedBrowserShower); 295 }; 296 297 // This class manages the lifetime of a WebContents created by the 298 // Navigate() function. When Navigate() creates a WebContents for a URL, 299 // an instance of this class takes ownership of it via TakeOwnership() until the 300 // WebContents is added to a tab strip at which time ownership is 301 // relinquished via ReleaseOwnership(). If this object goes out of scope without 302 // being added to a tab strip, the created WebContents is deleted to 303 // avoid a leak and the params->target_contents field is set to NULL. 304 class ScopedTargetContentsOwner { 305 public: 306 explicit ScopedTargetContentsOwner(chrome::NavigateParams* params) 307 : params_(params) { 308 } 309 ~ScopedTargetContentsOwner() { 310 if (target_contents_owner_.get()) 311 params_->target_contents = NULL; 312 } 313 314 // Assumes ownership of |params_|' target_contents until ReleaseOwnership 315 // is called. 316 void TakeOwnership() { 317 target_contents_owner_.reset(params_->target_contents); 318 } 319 320 // Relinquishes ownership of |params_|' target_contents. 321 WebContents* ReleaseOwnership() { 322 return target_contents_owner_.release(); 323 } 324 325 private: 326 chrome::NavigateParams* params_; 327 scoped_ptr<WebContents> target_contents_owner_; 328 DISALLOW_COPY_AND_ASSIGN(ScopedTargetContentsOwner); 329 }; 330 331 content::WebContents* CreateTargetContents(const chrome::NavigateParams& params, 332 const GURL& url) { 333 WebContents::CreateParams create_params( 334 params.browser->profile(), 335 tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url)); 336 if (params.source_contents) { 337 create_params.initial_size = 338 params.source_contents->GetView()->GetContainerSize(); 339 if (params.should_set_opener) 340 create_params.opener = params.source_contents; 341 } 342 if (params.disposition == NEW_BACKGROUND_TAB) 343 create_params.initially_hidden = true; 344 345 #if defined(USE_AURA) 346 if (params.browser->window() && 347 params.browser->window()->GetNativeWindow()) { 348 create_params.context = 349 params.browser->window()->GetNativeWindow(); 350 } 351 #endif 352 353 WebContents* target_contents = WebContents::Create(create_params); 354 355 // New tabs can have WebUI URLs that will make calls back to arbitrary 356 // tab helpers, so the entire set of tab helpers needs to be set up 357 // immediately. 358 BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents); 359 extensions::TabHelper::FromWebContents(target_contents)-> 360 SetExtensionAppById(params.extension_app_id); 361 return target_contents; 362 } 363 364 // If a prerendered page exists for |url|, replace the page at 365 // |params->target_contents| with it and update to point to the swapped-in 366 // WebContents. 367 bool SwapInPrerender(const GURL& url, chrome::NavigateParams* params) { 368 Profile* profile = 369 Profile::FromBrowserContext(params->target_contents->GetBrowserContext()); 370 InstantSearchPrerenderer* prerenderer = 371 InstantSearchPrerenderer::GetForProfile(profile); 372 if (prerenderer && prerenderer->UsePrerenderedPage(url, params)) 373 return true; 374 375 prerender::PrerenderManager* prerender_manager = 376 prerender::PrerenderManagerFactory::GetForProfile(profile); 377 return prerender_manager && 378 prerender_manager->MaybeUsePrerenderedPage(url, params); 379 } 380 381 bool SwapInInstantNTP(chrome::NavigateParams* params, 382 const GURL& url, 383 content::WebContents* source_contents) { 384 BrowserInstantController* instant = params->browser->instant_controller(); 385 return instant && instant->MaybeSwapInInstantNTPContents( 386 url, source_contents, ¶ms->target_contents); 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 content::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 transition(a_transition), 409 is_renderer_initiated(false), 410 tabstrip_index(-1), 411 tabstrip_add_types(TabStripModel::ADD_ACTIVE), 412 window_action(NO_ACTION), 413 user_gesture(true), 414 path_behavior(RESPECT), 415 ref_behavior(IGNORE_REF), 416 browser(a_browser), 417 initiating_profile(NULL), 418 host_desktop_type(GetHostDesktop(a_browser)), 419 should_replace_current_entry(false), 420 should_set_opener(false) { 421 } 422 423 NavigateParams::NavigateParams(Browser* a_browser, 424 WebContents* a_target_contents) 425 : frame_tree_node_id(-1), 426 uses_post(false), 427 target_contents(a_target_contents), 428 source_contents(NULL), 429 disposition(CURRENT_TAB), 430 transition(content::PAGE_TRANSITION_LINK), 431 is_renderer_initiated(false), 432 tabstrip_index(-1), 433 tabstrip_add_types(TabStripModel::ADD_ACTIVE), 434 window_action(NO_ACTION), 435 user_gesture(true), 436 path_behavior(RESPECT), 437 ref_behavior(IGNORE_REF), 438 browser(a_browser), 439 initiating_profile(NULL), 440 host_desktop_type(GetHostDesktop(a_browser)), 441 should_replace_current_entry(false), 442 should_set_opener(false) { 443 } 444 445 NavigateParams::NavigateParams(Profile* a_profile, 446 const GURL& a_url, 447 content::PageTransition a_transition) 448 : url(a_url), 449 frame_tree_node_id(-1), 450 uses_post(false), 451 target_contents(NULL), 452 source_contents(NULL), 453 disposition(NEW_FOREGROUND_TAB), 454 transition(a_transition), 455 is_renderer_initiated(false), 456 tabstrip_index(-1), 457 tabstrip_add_types(TabStripModel::ADD_ACTIVE), 458 window_action(SHOW_WINDOW), 459 user_gesture(true), 460 path_behavior(RESPECT), 461 ref_behavior(IGNORE_REF), 462 browser(NULL), 463 initiating_profile(a_profile), 464 host_desktop_type(chrome::GetActiveDesktop()), 465 should_replace_current_entry(false), 466 should_set_opener(false) { 467 } 468 469 NavigateParams::~NavigateParams() {} 470 471 void FillNavigateParamsFromOpenURLParams(chrome::NavigateParams* nav_params, 472 const content::OpenURLParams& params) { 473 nav_params->referrer = params.referrer; 474 nav_params->frame_tree_node_id = params.frame_tree_node_id; 475 nav_params->redirect_chain = params.redirect_chain; 476 nav_params->extra_headers = params.extra_headers; 477 nav_params->disposition = params.disposition; 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 ExtensionService* service = params->initiating_profile->GetExtensionService(); 497 if (service) 498 service->ShouldBlockUrlInBrowserTab(¶ms->url); 499 500 // The browser window may want to adjust the disposition. 501 if (params->disposition == NEW_POPUP && 502 source_browser && 503 source_browser->window()) { 504 params->disposition = 505 source_browser->window()->GetDispositionForPopupBounds( 506 params->window_bounds); 507 } 508 509 params->browser = GetBrowserForDisposition(params); 510 if (!params->browser) 511 return; 512 513 #if defined(USE_ASH) 514 if (source_browser && source_browser != params->browser) { 515 // When the newly created browser was spawned by a browser which visits 516 // another user's desktop, it should be shown on the same desktop as the 517 // originating one. (This is part of the desktop separation per profile). 518 MultiUserWindowManager* manager = MultiUserWindowManager::GetInstance(); 519 // Some unit tests have no manager instantiated. 520 if (manager) { 521 aura::Window* src_window = source_browser->window()->GetNativeWindow(); 522 aura::Window* new_window = params->browser->window()->GetNativeWindow(); 523 const std::string& src_user = 524 manager->GetUserPresentingWindow(src_window); 525 if (src_user != manager->GetUserPresentingWindow(new_window)) { 526 // Once the window gets presented, it should be shown on the same 527 // desktop as the desktop of the creating browser. Note that this 528 // command will not show the window if it wasn't shown yet by the 529 // browser creation. 530 manager->ShowWindowForUser(new_window, src_user); 531 } 532 } 533 } 534 #endif 535 536 // Navigate() must not return early after this point. 537 538 if (GetSourceProfile(params) != params->browser->profile()) { 539 // A tab is being opened from a link from a different profile, we must reset 540 // source information that may cause state to be shared. 541 params->source_contents = NULL; 542 params->referrer = content::Referrer(); 543 } 544 545 // Make sure the Browser is shown if params call for it. 546 ScopedBrowserShower shower(params); 547 548 // Makes sure any WebContents created by this function is destroyed if 549 // not properly added to a tab strip. 550 ScopedTargetContentsOwner target_contents_owner(params); 551 552 // Some dispositions need coercion to base types. 553 NormalizeDisposition(params); 554 555 // If a new window has been created, it needs to be shown. 556 if (params->window_action == NavigateParams::NO_ACTION && 557 source_browser != params->browser && 558 params->browser->tab_strip_model()->empty()) { 559 params->window_action = NavigateParams::SHOW_WINDOW; 560 } 561 562 // If we create a popup window from a non user-gesture, don't activate it. 563 if (params->window_action == NavigateParams::SHOW_WINDOW && 564 params->disposition == NEW_POPUP && 565 params->user_gesture == false) { 566 params->window_action = NavigateParams::SHOW_WINDOW_INACTIVE; 567 } 568 569 // Determine if the navigation was user initiated. If it was, we need to 570 // inform the target WebContents, and we may need to update the UI. 571 content::PageTransition base_transition = 572 content::PageTransitionStripQualifier(params->transition); 573 bool user_initiated = 574 params->transition & content::PAGE_TRANSITION_FROM_ADDRESS_BAR || 575 base_transition == content::PAGE_TRANSITION_TYPED || 576 base_transition == content::PAGE_TRANSITION_AUTO_BOOKMARK || 577 base_transition == content::PAGE_TRANSITION_GENERATED || 578 base_transition == content::PAGE_TRANSITION_AUTO_TOPLEVEL || 579 base_transition == content::PAGE_TRANSITION_RELOAD || 580 base_transition == content::PAGE_TRANSITION_KEYWORD; 581 582 // Check if this is a singleton tab that already exists 583 int singleton_index = chrome::GetIndexOfSingletonTab(params); 584 585 // Did we use Instant's NTP contents or a prerender? 586 bool swapped_in = false; 587 588 // If no target WebContents was specified, we need to construct one if 589 // we are supposed to target a new tab; unless it's a singleton that already 590 // exists. 591 if (!params->target_contents && singleton_index < 0) { 592 GURL url; 593 if (params->url.is_empty()) { 594 url = params->browser->profile()->GetHomePage(); 595 params->transition = content::PageTransitionFromInt( 596 params->transition | content::PAGE_TRANSITION_HOME_PAGE); 597 } else { 598 url = params->url; 599 } 600 601 if (params->disposition != CURRENT_TAB) { 602 swapped_in = SwapInInstantNTP(params, url, NULL); 603 if (!swapped_in) 604 params->target_contents = CreateTargetContents(*params, url); 605 606 // This function takes ownership of |params->target_contents| until it 607 // is added to a TabStripModel. 608 target_contents_owner.TakeOwnership(); 609 } else { 610 // ... otherwise if we're loading in the current tab, the target is the 611 // same as the source. 612 DCHECK(params->source_contents); 613 swapped_in = SwapInInstantNTP(params, url, params->source_contents); 614 if (!swapped_in) 615 params->target_contents = params->source_contents; 616 DCHECK(params->target_contents); 617 // Prerender expects |params->target_contents| to be attached to a browser 618 // window, so only call for CURRENT_TAB navigations. (Others are currently 619 // unsupported because of session storage namespaces anyway.) 620 // Notice that this includes middle-clicking, since middle clicking 621 // translates into a chrome::Navigate call with no URL followed by a 622 // CURRENT_TAB navigation. 623 // TODO(tburkard): We can actually swap in in non-CURRENT_TAB cases, as 624 // long as the WebContents we swap into is part of a TabStrip model. 625 // Therefore, we should swap in regardless of CURRENT_TAB, and instead, 626 // check in the swapin function whether the WebContents is not in a 627 // TabStrip model, in which case we must not swap in. 628 if (!swapped_in) 629 swapped_in = SwapInPrerender(url, params); 630 } 631 632 if (user_initiated) 633 params->target_contents->UserGestureDone(); 634 635 if (!swapped_in) { 636 // Try to handle non-navigational URLs that popup dialogs and such, these 637 // should not actually navigate. 638 if (!HandleNonNavigationAboutURL(url)) { 639 // Perform the actual navigation, tracking whether it came from the 640 // renderer. 641 642 LoadURLInContents(params->target_contents, url, params); 643 // For prerender bookkeeping purposes, record that this pending navigate 644 // originated from chrome::Navigate. 645 content::NavigationEntry* entry = 646 params->target_contents->GetController().GetPendingEntry(); 647 if (entry) 648 entry->SetExtraData(prerender::kChromeNavigateExtraDataKey, 649 base::string16()); 650 } 651 } 652 } else { 653 // |target_contents| was specified non-NULL, and so we assume it has already 654 // been navigated appropriately. We need to do nothing more other than 655 // add it to the appropriate tabstrip. 656 } 657 658 // If the user navigated from the omnibox, and the selected tab is going to 659 // lose focus, then make sure the focus for the source tab goes away from the 660 // omnibox. 661 if (params->source_contents && 662 (params->disposition == NEW_FOREGROUND_TAB || 663 params->disposition == NEW_WINDOW) && 664 (params->tabstrip_add_types & TabStripModel::ADD_INHERIT_OPENER)) 665 params->source_contents->GetView()->Focus(); 666 667 if (params->source_contents == params->target_contents || 668 (swapped_in && params->disposition == CURRENT_TAB)) { 669 // The navigation occurred in the source tab. 670 params->browser->UpdateUIForNavigationInTab(params->target_contents, 671 params->transition, 672 user_initiated); 673 } else if (singleton_index == -1) { 674 // If some non-default value is set for the index, we should tell the 675 // TabStripModel to respect it. 676 if (params->tabstrip_index != -1) 677 params->tabstrip_add_types |= TabStripModel::ADD_FORCE_INDEX; 678 679 // The navigation should insert a new tab into the target Browser. 680 params->browser->tab_strip_model()->AddWebContents( 681 params->target_contents, 682 params->tabstrip_index, 683 params->transition, 684 params->tabstrip_add_types); 685 // Now that the |params->target_contents| is safely owned by the target 686 // Browser's TabStripModel, we can release ownership. 687 target_contents_owner.ReleaseOwnership(); 688 } 689 690 if (singleton_index >= 0) { 691 WebContents* target = 692 params->browser->tab_strip_model()->GetWebContentsAt(singleton_index); 693 694 if (target->IsCrashed()) { 695 target->GetController().Reload(true); 696 } else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE && 697 target->GetURL() != params->url) { 698 LoadURLInContents(target, params->url, params); 699 // For prerender bookkeeping purposes, record that this pending navigate 700 // originated from chrome::Navigate. 701 content::NavigationEntry* entry = 702 target->GetController().GetPendingEntry(); 703 if (entry) 704 entry->SetExtraData(prerender::kChromeNavigateExtraDataKey, 705 base::string16()); 706 } 707 708 // If the singleton tab isn't already selected, select it. 709 if (params->source_contents != params->target_contents) { 710 params->browser->tab_strip_model()->ActivateTabAt(singleton_index, 711 user_initiated); 712 } 713 } 714 715 if (params->disposition != CURRENT_TAB) { 716 content::NotificationService::current()->Notify( 717 chrome::NOTIFICATION_TAB_ADDED, 718 content::Source<content::WebContentsDelegate>(params->browser), 719 content::Details<WebContents>(params->target_contents)); 720 } 721 } 722 723 bool IsURLAllowedInIncognito(const GURL& url, 724 content::BrowserContext* browser_context) { 725 if (url.scheme() == content::kViewSourceScheme) { 726 // A view-source URL is allowed in incognito mode only if the URL itself 727 // is allowed in incognito mode. Remove the "view-source:" from the start 728 // of the URL and validate the rest. 729 std::string stripped_spec = url.spec(); 730 DCHECK_GT(stripped_spec.size(), strlen(content::kViewSourceScheme)); 731 stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1); 732 GURL stripped_url(stripped_spec); 733 return stripped_url.is_valid() && 734 IsURLAllowedInIncognito(stripped_url, browser_context); 735 } 736 // Most URLs are allowed in incognito; the following are exceptions. 737 // chrome://extensions is on the list because it redirects to 738 // chrome://settings. 739 if (url.scheme() == chrome::kChromeUIScheme && 740 (url.host() == chrome::kChromeUISettingsHost || 741 url.host() == chrome::kChromeUISettingsFrameHost || 742 url.host() == chrome::kChromeUIExtensionsHost || 743 url.host() == chrome::kChromeUIBookmarksHost || 744 #if defined(ENABLE_ENHANCED_BOOKMARKS) 745 url.host() == chrome::kChromeUIEnhancedBookmarksHost || 746 #endif 747 url.host() == chrome::kChromeUIUberHost || 748 url.host() == chrome::kChromeUIThumbnailHost || 749 url.host() == chrome::kChromeUIThumbnailHost2 || 750 url.host() == chrome::kChromeUIThumbnailListHost)) { 751 return false; 752 } 753 754 if (url.scheme() == chrome::kChromeSearchScheme && 755 (url.host() == chrome::kChromeUIThumbnailHost || 756 url.host() == chrome::kChromeUIThumbnailHost2 || 757 url.host() == chrome::kChromeUIThumbnailListHost)) { 758 return false; 759 } 760 761 GURL rewritten_url = url; 762 bool reverse_on_redirect = false; 763 content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary( 764 &rewritten_url, browser_context, &reverse_on_redirect); 765 766 // Some URLs are mapped to uber subpages. Do not allow them in incognito. 767 return !(rewritten_url.scheme() == chrome::kChromeUIScheme && 768 rewritten_url.host() == chrome::kChromeUIUberHost); 769 } 770 771 } // namespace chrome 772