navigator_impl.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2013 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 "content/browser/frame_host/navigator_impl.h" 6 7#include "base/command_line.h" 8#include "base/time/time.h" 9#include "content/browser/frame_host/frame_tree.h" 10#include "content/browser/frame_host/frame_tree_node.h" 11#include "content/browser/frame_host/navigation_controller_impl.h" 12#include "content/browser/frame_host/navigation_entry_impl.h" 13#include "content/browser/frame_host/navigator_delegate.h" 14#include "content/browser/frame_host/render_frame_host_impl.h" 15#include "content/browser/renderer_host/render_view_host_impl.h" 16#include "content/browser/site_instance_impl.h" 17#include "content/browser/webui/web_ui_controller_factory_registry.h" 18#include "content/browser/webui/web_ui_impl.h" 19#include "content/common/frame_messages.h" 20#include "content/common/view_messages.h" 21#include "content/public/browser/browser_context.h" 22#include "content/public/browser/content_browser_client.h" 23#include "content/public/browser/global_request_id.h" 24#include "content/public/browser/invalidate_type.h" 25#include "content/public/browser/navigation_controller.h" 26#include "content/public/browser/navigation_details.h" 27#include "content/public/browser/page_navigator.h" 28#include "content/public/browser/render_view_host.h" 29#include "content/public/common/bindings_policy.h" 30#include "content/public/common/content_client.h" 31#include "content/public/common/content_switches.h" 32#include "content/public/common/url_constants.h" 33#include "content/public/common/url_utils.h" 34 35namespace content { 36 37namespace { 38 39FrameMsg_Navigate_Type::Value GetNavigationType( 40 BrowserContext* browser_context, const NavigationEntryImpl& entry, 41 NavigationController::ReloadType reload_type) { 42 switch (reload_type) { 43 case NavigationControllerImpl::RELOAD: 44 return FrameMsg_Navigate_Type::RELOAD; 45 case NavigationControllerImpl::RELOAD_IGNORING_CACHE: 46 return FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE; 47 case NavigationControllerImpl::RELOAD_ORIGINAL_REQUEST_URL: 48 return FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL; 49 case NavigationControllerImpl::NO_RELOAD: 50 break; // Fall through to rest of function. 51 } 52 53 // |RenderViewImpl::PopulateStateFromPendingNavigationParams| differentiates 54 // between |RESTORE_WITH_POST| and |RESTORE|. 55 if (entry.restore_type() == 56 NavigationEntryImpl::RESTORE_LAST_SESSION_EXITED_CLEANLY) { 57 if (entry.GetHasPostData()) 58 return FrameMsg_Navigate_Type::RESTORE_WITH_POST; 59 return FrameMsg_Navigate_Type::RESTORE; 60 } 61 62 return FrameMsg_Navigate_Type::NORMAL; 63} 64 65void MakeNavigateParams(const NavigationEntryImpl& entry, 66 const NavigationControllerImpl& controller, 67 NavigationController::ReloadType reload_type, 68 base::TimeTicks navigation_start, 69 FrameMsg_Navigate_Params* params) { 70 params->page_id = entry.GetPageID(); 71 params->should_clear_history_list = entry.should_clear_history_list(); 72 params->should_replace_current_entry = entry.should_replace_entry(); 73 if (entry.should_clear_history_list()) { 74 // Set the history list related parameters to the same values a 75 // NavigationController would return before its first navigation. This will 76 // fully clear the RenderView's view of the session history. 77 params->pending_history_list_offset = -1; 78 params->current_history_list_offset = -1; 79 params->current_history_list_length = 0; 80 } else { 81 params->pending_history_list_offset = controller.GetIndexOfEntry(&entry); 82 params->current_history_list_offset = 83 controller.GetLastCommittedEntryIndex(); 84 params->current_history_list_length = controller.GetEntryCount(); 85 } 86 params->url = entry.GetURL(); 87 if (!entry.GetBaseURLForDataURL().is_empty()) { 88 params->base_url_for_data_url = entry.GetBaseURLForDataURL(); 89 params->history_url_for_data_url = entry.GetVirtualURL(); 90 } 91 params->referrer = entry.GetReferrer(); 92 params->transition = entry.GetTransitionType(); 93 params->page_state = entry.GetPageState(); 94 params->navigation_type = 95 GetNavigationType(controller.GetBrowserContext(), entry, reload_type); 96 // This is used by the old performance infrastructure to set up DocumentState 97 // associated with the RenderView. 98 // TODO(ppi): make it go away. 99 params->request_time = base::Time::Now(); 100 params->extra_headers = entry.extra_headers(); 101 params->transferred_request_child_id = 102 entry.transferred_global_request_id().child_id; 103 params->transferred_request_request_id = 104 entry.transferred_global_request_id().request_id; 105 params->is_overriding_user_agent = entry.GetIsOverridingUserAgent(); 106 // Avoid downloading when in view-source mode. 107 params->allow_download = !entry.IsViewSourceMode(); 108 params->is_post = entry.GetHasPostData(); 109 if (entry.GetBrowserInitiatedPostData()) { 110 params->browser_initiated_post_data.assign( 111 entry.GetBrowserInitiatedPostData()->front(), 112 entry.GetBrowserInitiatedPostData()->front() + 113 entry.GetBrowserInitiatedPostData()->size()); 114 } 115 116 // Set the redirect chain to the navigation's redirects, unless we are 117 // returning to a completed navigation (whose previous redirects don't apply). 118 if (PageTransitionIsNewNavigation(params->transition)) { 119 params->redirects = entry.GetRedirectChain(); 120 } else { 121 params->redirects.clear(); 122 } 123 124 params->can_load_local_resources = entry.GetCanLoadLocalResources(); 125 params->frame_to_navigate = entry.GetFrameToNavigate(); 126 params->browser_navigation_start = navigation_start; 127} 128 129RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) { 130 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) 131 return rfh->frame_tree_node()->render_manager(); 132 133 return rfh->frame_tree_node()->frame_tree()->root()->render_manager(); 134} 135 136} // namespace 137 138 139NavigatorImpl::NavigatorImpl( 140 NavigationControllerImpl* navigation_controller, 141 NavigatorDelegate* delegate) 142 : controller_(navigation_controller), 143 delegate_(delegate) { 144} 145 146NavigationController* NavigatorImpl::GetController() { 147 return controller_; 148} 149 150void NavigatorImpl::DidStartProvisionalLoad( 151 RenderFrameHostImpl* render_frame_host, 152 const GURL& url) { 153 bool is_error_page = (url.spec() == kUnreachableWebDataURL); 154 bool is_iframe_srcdoc = (url.spec() == kAboutSrcDocURL); 155 GURL validated_url(url); 156 RenderProcessHost* render_process_host = render_frame_host->GetProcess(); 157 render_process_host->FilterURL(false, &validated_url); 158 159 bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame(); 160 NavigationEntryImpl* pending_entry = 161 NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()); 162 if (is_main_frame) { 163 // If there is no browser-initiated pending entry for this navigation and it 164 // is not for the error URL, create a pending entry using the current 165 // SiteInstance, and ensure the address bar updates accordingly. We don't 166 // know the referrer or extra headers at this point, but the referrer will 167 // be set properly upon commit. 168 bool has_browser_initiated_pending_entry = pending_entry && 169 !pending_entry->is_renderer_initiated(); 170 if (!has_browser_initiated_pending_entry && !is_error_page) { 171 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( 172 controller_->CreateNavigationEntry(validated_url, 173 content::Referrer(), 174 content::PAGE_TRANSITION_LINK, 175 true /* is_renderer_initiated */, 176 std::string(), 177 controller_->GetBrowserContext())); 178 entry->set_site_instance( 179 static_cast<SiteInstanceImpl*>( 180 render_frame_host->render_view_host()->GetSiteInstance())); 181 // TODO(creis): If there's a pending entry already, find a safe way to 182 // update it instead of replacing it and copying over things like this. 183 if (pending_entry) { 184 entry->set_transferred_global_request_id( 185 pending_entry->transferred_global_request_id()); 186 entry->set_should_replace_entry(pending_entry->should_replace_entry()); 187 entry->SetRedirectChain(pending_entry->GetRedirectChain()); 188 } 189 controller_->SetPendingEntry(entry); 190 if (delegate_) 191 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); 192 } 193 } 194 195 if (delegate_) { 196 // Notify the observer about the start of the provisional load. 197 delegate_->DidStartProvisionalLoad( 198 render_frame_host, validated_url, is_error_page, is_iframe_srcdoc); 199 } 200} 201 202 203void NavigatorImpl::DidFailProvisionalLoadWithError( 204 RenderFrameHostImpl* render_frame_host, 205 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { 206 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() 207 << ", error_code: " << params.error_code 208 << ", error_description: " << params.error_description 209 << ", showing_repost_interstitial: " << 210 params.showing_repost_interstitial 211 << ", frame_id: " << render_frame_host->GetRoutingID(); 212 GURL validated_url(params.url); 213 RenderProcessHost* render_process_host = render_frame_host->GetProcess(); 214 render_process_host->FilterURL(false, &validated_url); 215 216 if (net::ERR_ABORTED == params.error_code) { 217 // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials. 218 // This means that the interstitial won't be torn down properly, which is 219 // bad. But if we have an interstitial, go back to another tab type, and 220 // then load the same interstitial again, we could end up getting the first 221 // interstitial's "failed" message (as a result of the cancel) when we're on 222 // the second one. We can't tell this apart, so we think we're tearing down 223 // the current page which will cause a crash later on. 224 // 225 // http://code.google.com/p/chromium/issues/detail?id=2855 226 // Because this will not tear down the interstitial properly, if "back" is 227 // back to another tab type, the interstitial will still be somewhat alive 228 // in the previous tab type. If you navigate somewhere that activates the 229 // tab with the interstitial again, you'll see a flash before the new load 230 // commits of the interstitial page. 231 FrameTreeNode* root = 232 render_frame_host->frame_tree_node()->frame_tree()->root(); 233 if (root->render_manager()->interstitial_page() != NULL) { 234 LOG(WARNING) << "Discarding message during interstitial."; 235 return; 236 } 237 238 // We used to cancel the pending renderer here for cross-site downloads. 239 // However, it's not safe to do that because the download logic repeatedly 240 // looks for this WebContents based on a render ID. Instead, we just 241 // leave the pending renderer around until the next navigation event 242 // (Navigate, DidNavigate, etc), which will clean it up properly. 243 // 244 // TODO(creis): Find a way to cancel any pending RFH here. 245 } 246 247 // We usually clear the pending entry when it fails, so that an arbitrary URL 248 // isn't left visible above a committed page. This must be enforced when 249 // the pending entry isn't visible (e.g., renderer-initiated navigations) to 250 // prevent URL spoofs for in-page navigations that don't go through 251 // DidStartProvisionalLoadForFrame. 252 // 253 // However, we do preserve the pending entry in some cases, such as on the 254 // initial navigation of an unmodified blank tab. We also allow the delegate 255 // to say when it's safe to leave aborted URLs in the omnibox, to let the user 256 // edit the URL and try again. This may be useful in cases that the committed 257 // page cannot be attacker-controlled. In these cases, we still allow the 258 // view to clear the pending entry and typed URL if the user requests 259 // (e.g., hitting Escape with focus in the address bar). 260 // 261 // Note: don't touch the transient entry, since an interstitial may exist. 262 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || 263 delegate_->ShouldPreserveAbortedURLs(); 264 if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() || 265 !should_preserve_entry) { 266 controller_->DiscardPendingEntry(); 267 268 // Also force the UI to refresh. 269 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); 270 } 271 272 if (delegate_) 273 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); 274} 275 276void NavigatorImpl::DidFailLoadWithError( 277 RenderFrameHostImpl* render_frame_host, 278 const GURL& url, 279 int error_code, 280 const base::string16& error_description) { 281 if (delegate_) { 282 delegate_->DidFailLoadWithError( 283 render_frame_host, url, error_code, 284 error_description); 285 } 286} 287 288void NavigatorImpl::DidRedirectProvisionalLoad( 289 RenderFrameHostImpl* render_frame_host, 290 int32 page_id, 291 const GURL& source_url, 292 const GURL& target_url) { 293 // TODO(creis): Remove this method and have the pre-rendering code listen to 294 // WebContentsObserver::DidGetRedirectForResourceRequest instead. 295 // See http://crbug.com/78512. 296 GURL validated_source_url(source_url); 297 GURL validated_target_url(target_url); 298 RenderProcessHost* render_process_host = render_frame_host->GetProcess(); 299 render_process_host->FilterURL(false, &validated_source_url); 300 render_process_host->FilterURL(false, &validated_target_url); 301 NavigationEntry* entry; 302 if (page_id == -1) { 303 entry = controller_->GetPendingEntry(); 304 } else { 305 entry = controller_->GetEntryWithPageID( 306 render_frame_host->GetSiteInstance(), page_id); 307 } 308 if (!entry || entry->GetURL() != validated_source_url) 309 return; 310 311 if (delegate_) { 312 delegate_->DidRedirectProvisionalLoad( 313 render_frame_host, validated_target_url); 314 } 315} 316 317bool NavigatorImpl::NavigateToEntry( 318 RenderFrameHostImpl* render_frame_host, 319 const NavigationEntryImpl& entry, 320 NavigationController::ReloadType reload_type) { 321 TRACE_EVENT0("browser", "NavigatorImpl::NavigateToEntry"); 322 323 // The renderer will reject IPC messages with URLs longer than 324 // this limit, so don't attempt to navigate with a longer URL. 325 if (entry.GetURL().spec().size() > GetMaxURLChars()) { 326 LOG(WARNING) << "Refusing to load URL as it exceeds " << GetMaxURLChars() 327 << " characters."; 328 return false; 329 } 330 331 // This will be used to set the Navigation Timing API navigationStart 332 // parameter for browser navigations in new tabs (intents, tabs opened through 333 // "Open link in new tab"). We need to keep it above RFHM::Navigate() call to 334 // capture the time needed for the RenderFrameHost initialization. 335 base::TimeTicks navigation_start = base::TimeTicks::Now(); 336 337 RenderFrameHostManager* manager = 338 render_frame_host->frame_tree_node()->render_manager(); 339 RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry); 340 if (!dest_render_frame_host) 341 return false; // Unable to create the desired RenderFrameHost. 342 343 // Make sure no code called via RFHM::Navigate clears the pending entry. 344 CHECK_EQ(controller_->GetPendingEntry(), &entry); 345 346 // For security, we should never send non-Web-UI URLs to a Web UI renderer. 347 // Double check that here. 348 int enabled_bindings = 349 dest_render_frame_host->render_view_host()->GetEnabledBindings(); 350 bool is_allowed_in_web_ui_renderer = 351 WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI( 352 controller_->GetBrowserContext(), entry.GetURL()); 353 if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) && 354 !is_allowed_in_web_ui_renderer) { 355 // Log the URL to help us diagnose any future failures of this CHECK. 356 GetContentClient()->SetActiveURL(entry.GetURL()); 357 CHECK(0); 358 } 359 360 // Notify observers that we will navigate in this RenderFrame. 361 if (delegate_) 362 delegate_->AboutToNavigateRenderFrame(dest_render_frame_host); 363 364 // WebContents uses this to fill LoadNotificationDetails when the load 365 // completes, so that PerformanceMonitor that listens to the notification can 366 // record the load time. PerformanceMonitor is no longer maintained. 367 // TODO(ppi): make this go away. 368 current_load_start_ = base::TimeTicks::Now(); 369 370 // Navigate in the desired RenderFrameHost. 371 FrameMsg_Navigate_Params navigate_params; 372 MakeNavigateParams(entry, *controller_, reload_type, navigation_start, 373 &navigate_params); 374 dest_render_frame_host->Navigate(navigate_params); 375 376 // Make sure no code called via RFH::Navigate clears the pending entry. 377 CHECK_EQ(controller_->GetPendingEntry(), &entry); 378 379 if (entry.GetPageID() == -1) { 380 // HACK!! This code suppresses javascript: URLs from being added to 381 // session history, which is what we want to do for javascript: URLs that 382 // do not generate content. What we really need is a message from the 383 // renderer telling us that a new page was not created. The same message 384 // could be used for mailto: URLs and the like. 385 if (entry.GetURL().SchemeIs(url::kJavaScriptScheme)) 386 return false; 387 } 388 389 // Notify observers about navigation. 390 if (delegate_) { 391 delegate_->DidStartNavigationToPendingEntry(dest_render_frame_host, 392 entry.GetURL(), 393 reload_type); 394 } 395 396 return true; 397} 398 399bool NavigatorImpl::NavigateToPendingEntry( 400 RenderFrameHostImpl* render_frame_host, 401 NavigationController::ReloadType reload_type) { 402 return NavigateToEntry( 403 render_frame_host, 404 *NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()), 405 reload_type); 406} 407 408base::TimeTicks NavigatorImpl::GetCurrentLoadStart() { 409 return current_load_start_; 410} 411 412void NavigatorImpl::DidNavigate( 413 RenderFrameHostImpl* render_frame_host, 414 const FrameHostMsg_DidCommitProvisionalLoad_Params& input_params) { 415 FrameHostMsg_DidCommitProvisionalLoad_Params params(input_params); 416 FrameTree* frame_tree = render_frame_host->frame_tree_node()->frame_tree(); 417 bool use_site_per_process = 418 CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess); 419 420 if (use_site_per_process) { 421 // TODO(creis): Until we mirror the frame tree in the subframe's process, 422 // cross-process subframe navigations happen in a renderer's main frame. 423 // Correct the transition type here if we know it is for a subframe. 424 NavigationEntryImpl* pending_entry = 425 NavigationEntryImpl::FromNavigationEntry( 426 controller_->GetPendingEntry()); 427 if (!render_frame_host->frame_tree_node()->IsMainFrame() && 428 pending_entry && 429 pending_entry->frame_tree_node_id() == 430 render_frame_host->frame_tree_node()->frame_tree_node_id()) { 431 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME; 432 } 433 } 434 435 if (PageTransitionIsMainFrame(params.transition)) { 436 if (delegate_) { 437 // When overscroll navigation gesture is enabled, a screenshot of the page 438 // in its current state is taken so that it can be used during the 439 // nav-gesture. It is necessary to take the screenshot here, before 440 // calling RenderFrameHostManager::DidNavigateMainFrame, because that can 441 // change WebContents::GetRenderViewHost to return the new host, instead 442 // of the one that may have just been swapped out. 443 if (delegate_->CanOverscrollContent()) { 444 bool page_id_changed; 445 bool url_changed; 446 NavigationEntry* current_entry = controller_->GetLastCommittedEntry(); 447 if (current_entry) { 448 page_id_changed = params.page_id > 0 && 449 params.page_id != current_entry->GetPageID(); 450 url_changed = params.url != current_entry->GetURL(); 451 } else { 452 page_id_changed = params.page_id > 0; 453 url_changed = params.url != GURL::EmptyGURL(); 454 } 455 456 // We only want to take the screenshot if the are navigating to a 457 // different history entry than the current one. So if neither the 458 // page id nor the url changed - don't take the screenshot. 459 if (page_id_changed || url_changed) 460 controller_->TakeScreenshot(); 461 } 462 463 // Run tasks that must execute just before the commit. 464 bool is_navigation_within_page = controller_->IsURLInPageNavigation( 465 params.url, params.was_within_same_page, render_frame_host); 466 delegate_->DidNavigateMainFramePreCommit(is_navigation_within_page); 467 } 468 469 if (!use_site_per_process) 470 frame_tree->root()->render_manager()->DidNavigateFrame(render_frame_host); 471 } 472 473 // When using --site-per-process, we notify the RFHM for all navigations, 474 // not just main frame navigations. 475 if (use_site_per_process) { 476 FrameTreeNode* frame = render_frame_host->frame_tree_node(); 477 frame->render_manager()->DidNavigateFrame(render_frame_host); 478 } 479 480 // Update the site of the SiteInstance if it doesn't have one yet, unless 481 // assigning a site is not necessary for this URL. In that case, the 482 // SiteInstance can still be considered unused until a navigation to a real 483 // page. 484 SiteInstanceImpl* site_instance = 485 static_cast<SiteInstanceImpl*>(render_frame_host->GetSiteInstance()); 486 if (!site_instance->HasSite() && 487 ShouldAssignSiteForURL(params.url)) { 488 site_instance->SetSite(params.url); 489 } 490 491 // Need to update MIME type here because it's referred to in 492 // UpdateNavigationCommands() called by RendererDidNavigate() to 493 // determine whether or not to enable the encoding menu. 494 // It's updated only for the main frame. For a subframe, 495 // RenderView::UpdateURL does not set params.contents_mime_type. 496 // (see http://code.google.com/p/chromium/issues/detail?id=2929 ) 497 // TODO(jungshik): Add a test for the encoding menu to avoid 498 // regressing it again. 499 // TODO(nasko): Verify the correctness of the above comment, since some of the 500 // code doesn't exist anymore. Also, move this code in the 501 // PageTransitionIsMainFrame code block above. 502 if (PageTransitionIsMainFrame(params.transition) && delegate_) 503 delegate_->SetMainFrameMimeType(params.contents_mime_type); 504 505 LoadCommittedDetails details; 506 bool did_navigate = controller_->RendererDidNavigate(render_frame_host, 507 params, &details); 508 509 // For now, keep track of each frame's URL in its FrameTreeNode. This lets 510 // us estimate our process count for implementing OOP iframes. 511 // TODO(creis): Remove this when we track which pages commit in each frame. 512 render_frame_host->frame_tree_node()->set_current_url(params.url); 513 514 // Send notification about committed provisional loads. This notification is 515 // different from the NAV_ENTRY_COMMITTED notification which doesn't include 516 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations. 517 if (details.type != NAVIGATION_TYPE_NAV_IGNORE && delegate_) { 518 DCHECK_EQ(!render_frame_host->GetParent(), 519 did_navigate ? details.is_main_frame : false); 520 PageTransition transition_type = params.transition; 521 // Whether or not a page transition was triggered by going backward or 522 // forward in the history is only stored in the navigation controller's 523 // entry list. 524 if (did_navigate && 525 (controller_->GetLastCommittedEntry()->GetTransitionType() & 526 PAGE_TRANSITION_FORWARD_BACK)) { 527 transition_type = PageTransitionFromInt( 528 params.transition | PAGE_TRANSITION_FORWARD_BACK); 529 } 530 531 delegate_->DidCommitProvisionalLoad(render_frame_host, 532 params.url, 533 transition_type); 534 } 535 536 if (!did_navigate) 537 return; // No navigation happened. 538 539 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen 540 // for the appropriate notification (best) or you can add it to 541 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if 542 // necessary, please). 543 544 // Run post-commit tasks. 545 if (delegate_) { 546 if (details.is_main_frame) 547 delegate_->DidNavigateMainFramePostCommit(details, params); 548 549 delegate_->DidNavigateAnyFramePostCommit( 550 render_frame_host, details, params); 551 } 552} 553 554bool NavigatorImpl::ShouldAssignSiteForURL(const GURL& url) { 555 // about:blank should not "use up" a new SiteInstance. The SiteInstance can 556 // still be used for a normal web site. 557 if (url == GURL(url::kAboutBlankURL)) 558 return false; 559 560 // The embedder will then have the opportunity to determine if the URL 561 // should "use up" the SiteInstance. 562 return GetContentClient()->browser()->ShouldAssignSiteForURL(url); 563} 564 565void NavigatorImpl::RequestOpenURL( 566 RenderFrameHostImpl* render_frame_host, 567 const GURL& url, 568 const Referrer& referrer, 569 WindowOpenDisposition disposition, 570 bool should_replace_current_entry, 571 bool user_gesture) { 572 SiteInstance* current_site_instance = 573 GetRenderManager(render_frame_host)->current_frame_host()-> 574 GetSiteInstance(); 575 // If this came from a swapped out RenderViewHost, we only allow the request 576 // if we are still in the same BrowsingInstance. 577 if (render_frame_host->render_view_host()->IsSwappedOut() && 578 !render_frame_host->GetSiteInstance()->IsRelatedSiteInstance( 579 current_site_instance)) { 580 return; 581 } 582 583 // Delegate to RequestTransferURL because this is just the generic 584 // case where |old_request_id| is empty. 585 // TODO(creis): Pass the redirect_chain into this method to support client 586 // redirects. http://crbug.com/311721. 587 std::vector<GURL> redirect_chain; 588 RequestTransferURL( 589 render_frame_host, url, redirect_chain, referrer, PAGE_TRANSITION_LINK, 590 disposition, GlobalRequestID(), 591 should_replace_current_entry, user_gesture); 592} 593 594void NavigatorImpl::RequestTransferURL( 595 RenderFrameHostImpl* render_frame_host, 596 const GURL& url, 597 const std::vector<GURL>& redirect_chain, 598 const Referrer& referrer, 599 PageTransition page_transition, 600 WindowOpenDisposition disposition, 601 const GlobalRequestID& transferred_global_request_id, 602 bool should_replace_current_entry, 603 bool user_gesture) { 604 GURL dest_url(url); 605 SiteInstance* current_site_instance = 606 GetRenderManager(render_frame_host)->current_frame_host()-> 607 GetSiteInstance(); 608 if (!GetContentClient()->browser()->ShouldAllowOpenURL( 609 current_site_instance, url)) { 610 dest_url = GURL(url::kAboutBlankURL); 611 } 612 613 int64 frame_tree_node_id = -1; 614 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) { 615 frame_tree_node_id = 616 render_frame_host->frame_tree_node()->frame_tree_node_id(); 617 } 618 OpenURLParams params( 619 dest_url, referrer, frame_tree_node_id, disposition, page_transition, 620 true /* is_renderer_initiated */); 621 if (redirect_chain.size() > 0) 622 params.redirect_chain = redirect_chain; 623 params.transferred_global_request_id = transferred_global_request_id; 624 params.should_replace_current_entry = should_replace_current_entry; 625 params.user_gesture = user_gesture; 626 627 if (GetRenderManager(render_frame_host)->web_ui()) { 628 // Web UI pages sometimes want to override the page transition type for 629 // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for 630 // automatically generated suggestions). We don't override other types 631 // like TYPED because they have different implications (e.g., autocomplete). 632 if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK)) 633 params.transition = 634 GetRenderManager(render_frame_host)->web_ui()-> 635 GetLinkTransitionType(); 636 637 // Note also that we hide the referrer for Web UI pages. We don't really 638 // want web sites to see a referrer of "chrome://blah" (and some 639 // chrome: URLs might have search terms or other stuff we don't want to 640 // send to the site), so we send no referrer. 641 params.referrer = Referrer(); 642 643 // Navigations in Web UI pages count as browser-initiated navigations. 644 params.is_renderer_initiated = false; 645 } 646 647 if (delegate_) 648 delegate_->RequestOpenURL(render_frame_host, params); 649} 650 651} // namespace content 652