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