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.
5 #include "content/browser/frame_host/navigator_impl.h"
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"
39 FrameMsg_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.
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;
62 return FrameMsg_Navigate_Type::NORMAL;
65 void 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;
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();
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();
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());
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();
121 params->redirects.clear();
124 params->can_load_local_resources = entry.GetCanLoadLocalResources();
125 params->frame_to_navigate = entry.GetFrameToNavigate();
126 params->browser_navigation_start = navigation_start;
129 RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) {
130 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
131 switches::kSitePerProcess))
132 return rfh->frame_tree_node()->render_manager();
134 return rfh->frame_tree_node()->frame_tree()->root()->render_manager();
140 NavigatorImpl::NavigatorImpl(
141 NavigationControllerImpl* navigation_controller,
142 NavigatorDelegate* delegate)
143 : controller_(navigation_controller),
144 delegate_(delegate) {
147 NavigationController* NavigatorImpl::GetController() {
151 void NavigatorImpl::DidStartProvisionalLoad(
152 RenderFrameHostImpl* render_frame_host,
154 bool is_transition_navigation) {
155 bool is_error_page = (url.spec() == kUnreachableWebDataURL);
156 bool is_iframe_srcdoc = (url.spec() == kAboutSrcDocURL);
157 GURL validated_url(url);
158 RenderProcessHost* render_process_host = render_frame_host->GetProcess();
159 render_process_host->FilterURL(false, &validated_url);
161 bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
162 NavigationEntryImpl* pending_entry =
163 NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry());
165 // If there is no browser-initiated pending entry for this navigation and it
166 // is not for the error URL, create a pending entry using the current
167 // SiteInstance, and ensure the address bar updates accordingly. We don't
168 // know the referrer or extra headers at this point, but the referrer will
169 // be set properly upon commit.
170 bool has_browser_initiated_pending_entry = pending_entry &&
171 !pending_entry->is_renderer_initiated();
172 if (!has_browser_initiated_pending_entry && !is_error_page) {
173 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
174 controller_->CreateNavigationEntry(validated_url,
176 content::PAGE_TRANSITION_LINK,
177 true /* is_renderer_initiated */,
179 controller_->GetBrowserContext()));
180 entry->set_site_instance(
181 static_cast<SiteInstanceImpl*>(
182 render_frame_host->render_view_host()->GetSiteInstance()));
183 // TODO(creis): If there's a pending entry already, find a safe way to
184 // update it instead of replacing it and copying over things like this.
186 entry->set_transferred_global_request_id(
187 pending_entry->transferred_global_request_id());
188 entry->set_should_replace_entry(pending_entry->should_replace_entry());
189 entry->SetRedirectChain(pending_entry->GetRedirectChain());
191 controller_->SetPendingEntry(entry);
193 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
196 if (delegate_ && is_transition_navigation)
197 delegate_->DidStartNavigationTransition(render_frame_host);
201 // Notify the observer about the start of the provisional load.
202 delegate_->DidStartProvisionalLoad(
203 render_frame_host, validated_url, is_error_page, is_iframe_srcdoc);
208 void NavigatorImpl::DidFailProvisionalLoadWithError(
209 RenderFrameHostImpl* render_frame_host,
210 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
211 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec()
212 << ", error_code: " << params.error_code
213 << ", error_description: " << params.error_description
214 << ", showing_repost_interstitial: " <<
215 params.showing_repost_interstitial
216 << ", frame_id: " << render_frame_host->GetRoutingID();
217 GURL validated_url(params.url);
218 RenderProcessHost* render_process_host = render_frame_host->GetProcess();
219 render_process_host->FilterURL(false, &validated_url);
221 if (net::ERR_ABORTED == params.error_code) {
222 // EVIL HACK ALERT! Ignore failed loads when we're showing interstitials.
223 // This means that the interstitial won't be torn down properly, which is
224 // bad. But if we have an interstitial, go back to another tab type, and
225 // then load the same interstitial again, we could end up getting the first
226 // interstitial's "failed" message (as a result of the cancel) when we're on
227 // the second one. We can't tell this apart, so we think we're tearing down
228 // the current page which will cause a crash later on.
230 // http://code.google.com/p/chromium/issues/detail?id=2855
231 // Because this will not tear down the interstitial properly, if "back" is
232 // back to another tab type, the interstitial will still be somewhat alive
233 // in the previous tab type. If you navigate somewhere that activates the
234 // tab with the interstitial again, you'll see a flash before the new load
235 // commits of the interstitial page.
236 FrameTreeNode* root =
237 render_frame_host->frame_tree_node()->frame_tree()->root();
238 if (root->render_manager()->interstitial_page() != NULL) {
239 LOG(WARNING) << "Discarding message during interstitial.";
243 // We used to cancel the pending renderer here for cross-site downloads.
244 // However, it's not safe to do that because the download logic repeatedly
245 // looks for this WebContents based on a render ID. Instead, we just
246 // leave the pending renderer around until the next navigation event
247 // (Navigate, DidNavigate, etc), which will clean it up properly.
249 // TODO(creis): Find a way to cancel any pending RFH here.
252 // We usually clear the pending entry when it fails, so that an arbitrary URL
253 // isn't left visible above a committed page. This must be enforced when
254 // the pending entry isn't visible (e.g., renderer-initiated navigations) to
255 // prevent URL spoofs for in-page navigations that don't go through
256 // DidStartProvisionalLoadForFrame.
258 // However, we do preserve the pending entry in some cases, such as on the
259 // initial navigation of an unmodified blank tab. We also allow the delegate
260 // to say when it's safe to leave aborted URLs in the omnibox, to let the user
261 // edit the URL and try again. This may be useful in cases that the committed
262 // page cannot be attacker-controlled. In these cases, we still allow the
263 // view to clear the pending entry and typed URL if the user requests
264 // (e.g., hitting Escape with focus in the address bar).
266 // Note: don't touch the transient entry, since an interstitial may exist.
267 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() ||
268 delegate_->ShouldPreserveAbortedURLs();
269 if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() ||
270 !should_preserve_entry) {
271 controller_->DiscardPendingEntry();
273 // Also force the UI to refresh.
274 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL);
278 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params);
281 void NavigatorImpl::DidFailLoadWithError(
282 RenderFrameHostImpl* render_frame_host,
285 const base::string16& error_description) {
287 delegate_->DidFailLoadWithError(
288 render_frame_host, url, error_code,
293 void NavigatorImpl::DidRedirectProvisionalLoad(
294 RenderFrameHostImpl* render_frame_host,
296 const GURL& source_url,
297 const GURL& target_url) {
298 // TODO(creis): Remove this method and have the pre-rendering code listen to
299 // WebContentsObserver::DidGetRedirectForResourceRequest instead.
300 // See http://crbug.com/78512.
301 GURL validated_source_url(source_url);
302 GURL validated_target_url(target_url);
303 RenderProcessHost* render_process_host = render_frame_host->GetProcess();
304 render_process_host->FilterURL(false, &validated_source_url);
305 render_process_host->FilterURL(false, &validated_target_url);
306 NavigationEntry* entry;
308 entry = controller_->GetPendingEntry();
310 entry = controller_->GetEntryWithPageID(
311 render_frame_host->GetSiteInstance(), page_id);
313 if (!entry || entry->GetURL() != validated_source_url)
317 delegate_->DidRedirectProvisionalLoad(
318 render_frame_host, validated_target_url);
322 bool NavigatorImpl::NavigateToEntry(
323 RenderFrameHostImpl* render_frame_host,
324 const NavigationEntryImpl& entry,
325 NavigationController::ReloadType reload_type) {
326 TRACE_EVENT0("browser", "NavigatorImpl::NavigateToEntry");
328 // The renderer will reject IPC messages with URLs longer than
329 // this limit, so don't attempt to navigate with a longer URL.
330 if (entry.GetURL().spec().size() > GetMaxURLChars()) {
331 LOG(WARNING) << "Refusing to load URL as it exceeds " << GetMaxURLChars()
336 // This will be used to set the Navigation Timing API navigationStart
337 // parameter for browser navigations in new tabs (intents, tabs opened through
338 // "Open link in new tab"). We need to keep it above RFHM::Navigate() call to
339 // capture the time needed for the RenderFrameHost initialization.
340 base::TimeTicks navigation_start = base::TimeTicks::Now();
342 RenderFrameHostManager* manager =
343 render_frame_host->frame_tree_node()->render_manager();
344 RenderFrameHostImpl* dest_render_frame_host = manager->Navigate(entry);
345 if (!dest_render_frame_host)
346 return false; // Unable to create the desired RenderFrameHost.
348 // Make sure no code called via RFHM::Navigate clears the pending entry.
349 CHECK_EQ(controller_->GetPendingEntry(), &entry);
351 // For security, we should never send non-Web-UI URLs to a Web UI renderer.
352 // Double check that here.
353 int enabled_bindings =
354 dest_render_frame_host->render_view_host()->GetEnabledBindings();
355 bool is_allowed_in_web_ui_renderer =
356 WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
357 controller_->GetBrowserContext(), entry.GetURL());
358 if ((enabled_bindings & BINDINGS_POLICY_WEB_UI) &&
359 !is_allowed_in_web_ui_renderer) {
360 // Log the URL to help us diagnose any future failures of this CHECK.
361 GetContentClient()->SetActiveURL(entry.GetURL());
365 // Notify observers that we will navigate in this RenderFrame.
367 delegate_->AboutToNavigateRenderFrame(dest_render_frame_host);
369 // WebContents uses this to fill LoadNotificationDetails when the load
370 // completes, so that PerformanceMonitor that listens to the notification can
371 // record the load time. PerformanceMonitor is no longer maintained.
372 // TODO(ppi): make this go away.
373 current_load_start_ = base::TimeTicks::Now();
375 // Navigate in the desired RenderFrameHost.
376 FrameMsg_Navigate_Params navigate_params;
377 MakeNavigateParams(entry, *controller_, reload_type, navigation_start,
379 dest_render_frame_host->Navigate(navigate_params);
381 // Make sure no code called via RFH::Navigate clears the pending entry.
382 CHECK_EQ(controller_->GetPendingEntry(), &entry);
384 if (entry.GetPageID() == -1) {
385 // HACK!! This code suppresses javascript: URLs from being added to
386 // session history, which is what we want to do for javascript: URLs that
387 // do not generate content. What we really need is a message from the
388 // renderer telling us that a new page was not created. The same message
389 // could be used for mailto: URLs and the like.
390 if (entry.GetURL().SchemeIs(url::kJavaScriptScheme))
394 // Notify observers about navigation.
396 delegate_->DidStartNavigationToPendingEntry(dest_render_frame_host,
404 bool NavigatorImpl::NavigateToPendingEntry(
405 RenderFrameHostImpl* render_frame_host,
406 NavigationController::ReloadType reload_type) {
407 return NavigateToEntry(
409 *NavigationEntryImpl::FromNavigationEntry(controller_->GetPendingEntry()),
413 base::TimeTicks NavigatorImpl::GetCurrentLoadStart() {
414 return current_load_start_;
417 void NavigatorImpl::DidNavigate(
418 RenderFrameHostImpl* render_frame_host,
419 const FrameHostMsg_DidCommitProvisionalLoad_Params& input_params) {
420 FrameHostMsg_DidCommitProvisionalLoad_Params params(input_params);
421 FrameTree* frame_tree = render_frame_host->frame_tree_node()->frame_tree();
422 bool use_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
423 switches::kSitePerProcess);
425 if (use_site_per_process) {
426 // TODO(creis): Until we mirror the frame tree in the subframe's process,
427 // cross-process subframe navigations happen in a renderer's main frame.
428 // Correct the transition type here if we know it is for a subframe.
429 NavigationEntryImpl* pending_entry =
430 NavigationEntryImpl::FromNavigationEntry(
431 controller_->GetPendingEntry());
432 if (!render_frame_host->frame_tree_node()->IsMainFrame() &&
434 pending_entry->frame_tree_node_id() ==
435 render_frame_host->frame_tree_node()->frame_tree_node_id()) {
436 params.transition = PAGE_TRANSITION_AUTO_SUBFRAME;
440 if (PageTransitionIsMainFrame(params.transition)) {
442 // When overscroll navigation gesture is enabled, a screenshot of the page
443 // in its current state is taken so that it can be used during the
444 // nav-gesture. It is necessary to take the screenshot here, before
445 // calling RenderFrameHostManager::DidNavigateMainFrame, because that can
446 // change WebContents::GetRenderViewHost to return the new host, instead
447 // of the one that may have just been swapped out.
448 if (delegate_->CanOverscrollContent()) {
449 // Don't take screenshots if we are staying on the same page. We want
450 // in-page navigations to be super fast, and taking a screenshot
451 // currently blocks GPU for a longer time than we are willing to
452 // tolerate in this use case.
453 if (!params.was_within_same_page)
454 controller_->TakeScreenshot();
457 // Run tasks that must execute just before the commit.
458 bool is_navigation_within_page = controller_->IsURLInPageNavigation(
459 params.url, params.was_within_same_page, render_frame_host);
460 delegate_->DidNavigateMainFramePreCommit(is_navigation_within_page);
463 if (!use_site_per_process)
464 frame_tree->root()->render_manager()->DidNavigateFrame(render_frame_host);
467 // When using --site-per-process, we notify the RFHM for all navigations,
468 // not just main frame navigations.
469 if (use_site_per_process) {
470 FrameTreeNode* frame = render_frame_host->frame_tree_node();
471 frame->render_manager()->DidNavigateFrame(render_frame_host);
474 // Update the site of the SiteInstance if it doesn't have one yet, unless
475 // assigning a site is not necessary for this URL. In that case, the
476 // SiteInstance can still be considered unused until a navigation to a real
478 SiteInstanceImpl* site_instance =
479 static_cast<SiteInstanceImpl*>(render_frame_host->GetSiteInstance());
480 if (!site_instance->HasSite() &&
481 ShouldAssignSiteForURL(params.url)) {
482 site_instance->SetSite(params.url);
485 // Need to update MIME type here because it's referred to in
486 // UpdateNavigationCommands() called by RendererDidNavigate() to
487 // determine whether or not to enable the encoding menu.
488 // It's updated only for the main frame. For a subframe,
489 // RenderView::UpdateURL does not set params.contents_mime_type.
490 // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
491 // TODO(jungshik): Add a test for the encoding menu to avoid
492 // regressing it again.
493 // TODO(nasko): Verify the correctness of the above comment, since some of the
494 // code doesn't exist anymore. Also, move this code in the
495 // PageTransitionIsMainFrame code block above.
496 if (PageTransitionIsMainFrame(params.transition) && delegate_)
497 delegate_->SetMainFrameMimeType(params.contents_mime_type);
499 LoadCommittedDetails details;
500 bool did_navigate = controller_->RendererDidNavigate(render_frame_host,
503 // For now, keep track of each frame's URL in its FrameTreeNode. This lets
504 // us estimate our process count for implementing OOP iframes.
505 // TODO(creis): Remove this when we track which pages commit in each frame.
506 render_frame_host->frame_tree_node()->set_current_url(params.url);
508 // Send notification about committed provisional loads. This notification is
509 // different from the NAV_ENTRY_COMMITTED notification which doesn't include
510 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
511 if (details.type != NAVIGATION_TYPE_NAV_IGNORE && delegate_) {
512 DCHECK_EQ(!render_frame_host->GetParent(),
513 did_navigate ? details.is_main_frame : false);
514 PageTransition transition_type = params.transition;
515 // Whether or not a page transition was triggered by going backward or
516 // forward in the history is only stored in the navigation controller's
519 (controller_->GetLastCommittedEntry()->GetTransitionType() &
520 PAGE_TRANSITION_FORWARD_BACK)) {
521 transition_type = PageTransitionFromInt(
522 params.transition | PAGE_TRANSITION_FORWARD_BACK);
525 delegate_->DidCommitProvisionalLoad(render_frame_host,
531 return; // No navigation happened.
533 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
534 // for the appropriate notification (best) or you can add it to
535 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
536 // necessary, please).
538 // Run post-commit tasks.
540 if (details.is_main_frame)
541 delegate_->DidNavigateMainFramePostCommit(details, params);
543 delegate_->DidNavigateAnyFramePostCommit(
544 render_frame_host, details, params);
548 bool NavigatorImpl::ShouldAssignSiteForURL(const GURL& url) {
549 // about:blank should not "use up" a new SiteInstance. The SiteInstance can
550 // still be used for a normal web site.
551 if (url == GURL(url::kAboutBlankURL))
554 // The embedder will then have the opportunity to determine if the URL
555 // should "use up" the SiteInstance.
556 return GetContentClient()->browser()->ShouldAssignSiteForURL(url);
559 void NavigatorImpl::RequestOpenURL(
560 RenderFrameHostImpl* render_frame_host,
562 const Referrer& referrer,
563 WindowOpenDisposition disposition,
564 bool should_replace_current_entry,
566 SiteInstance* current_site_instance =
567 GetRenderManager(render_frame_host)->current_frame_host()->
569 // If this came from a swapped out RenderViewHost, we only allow the request
570 // if we are still in the same BrowsingInstance.
571 if (render_frame_host->render_view_host()->IsSwappedOut() &&
572 !render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
573 current_site_instance)) {
577 // Delegate to RequestTransferURL because this is just the generic
578 // case where |old_request_id| is empty.
579 // TODO(creis): Pass the redirect_chain into this method to support client
580 // redirects. http://crbug.com/311721.
581 std::vector<GURL> redirect_chain;
583 render_frame_host, url, redirect_chain, referrer, PAGE_TRANSITION_LINK,
584 disposition, GlobalRequestID(),
585 should_replace_current_entry, user_gesture);
588 void NavigatorImpl::RequestTransferURL(
589 RenderFrameHostImpl* render_frame_host,
591 const std::vector<GURL>& redirect_chain,
592 const Referrer& referrer,
593 PageTransition page_transition,
594 WindowOpenDisposition disposition,
595 const GlobalRequestID& transferred_global_request_id,
596 bool should_replace_current_entry,
599 SiteInstance* current_site_instance =
600 GetRenderManager(render_frame_host)->current_frame_host()->
602 if (!GetContentClient()->browser()->ShouldAllowOpenURL(
603 current_site_instance, url)) {
604 dest_url = GURL(url::kAboutBlankURL);
607 int64 frame_tree_node_id = -1;
608 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
609 switches::kSitePerProcess)) {
611 render_frame_host->frame_tree_node()->frame_tree_node_id();
613 OpenURLParams params(
614 dest_url, referrer, frame_tree_node_id, disposition, page_transition,
615 true /* is_renderer_initiated */);
616 if (redirect_chain.size() > 0)
617 params.redirect_chain = redirect_chain;
618 params.transferred_global_request_id = transferred_global_request_id;
619 params.should_replace_current_entry = should_replace_current_entry;
620 params.user_gesture = user_gesture;
622 if (GetRenderManager(render_frame_host)->web_ui()) {
623 // Web UI pages sometimes want to override the page transition type for
624 // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for
625 // automatically generated suggestions). We don't override other types
626 // like TYPED because they have different implications (e.g., autocomplete).
627 if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK))
629 GetRenderManager(render_frame_host)->web_ui()->
630 GetLinkTransitionType();
632 // Note also that we hide the referrer for Web UI pages. We don't really
633 // want web sites to see a referrer of "chrome://blah" (and some
634 // chrome: URLs might have search terms or other stuff we don't want to
635 // send to the site), so we send no referrer.
636 params.referrer = Referrer();
638 // Navigations in Web UI pages count as browser-initiated navigations.
639 params.is_renderer_initiated = false;
643 delegate_->RequestOpenURL(render_frame_host, params);
646 } // namespace content