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", "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 // WebContents uses this to fill LoadNotificationDetails when the load
346 // completes, so that PerformanceMonitor that listens to the notification can
347 // record the load time. PerformanceMonitor is no longer maintained.
348 // TODO(ppi): make this go away.
349 current_load_start_
= base::TimeTicks::Now();
351 // Create the navigation parameters.
352 FrameMsg_Navigate_Params navigate_params
;
354 entry
, *controller_
, reload_type
, navigation_start
, &navigate_params
);
356 RenderFrameHostManager
* manager
=
357 render_frame_host
->frame_tree_node()->render_manager();
359 // PlzNavigate: the RenderFrameHosts are no longer asked to navigate. Instead
360 // the RenderFrameHostManager handles the navigation requests for that frame
362 if (CommandLine::ForCurrentProcess()->HasSwitch(
363 switches::kEnableBrowserSideNavigation
)) {
364 return manager
->RequestNavigation(entry
, navigate_params
);
367 RenderFrameHostImpl
* dest_render_frame_host
= manager
->Navigate(entry
);
368 if (!dest_render_frame_host
)
369 return false; // Unable to create the desired RenderFrameHost.
371 // Make sure no code called via RFHM::Navigate clears the pending entry.
372 CHECK_EQ(controller_
->GetPendingEntry(), &entry
);
374 // For security, we should never send non-Web-UI URLs to a Web UI renderer.
375 // Double check that here.
376 CheckWebUIRendererDoesNotDisplayNormalURL(
377 dest_render_frame_host
, entry
.GetURL());
379 // Notify observers that we will navigate in this RenderFrame.
381 delegate_
->AboutToNavigateRenderFrame(dest_render_frame_host
);
383 // Navigate in the desired RenderFrameHost.
384 // We can skip this step in the rare case that this is a transfer navigation
385 // which began in the chosen RenderFrameHost, since the request has already
386 // been issued. In that case, simply resume the response.
387 bool is_transfer_to_same
=
388 navigate_params
.transferred_request_child_id
!= -1 &&
389 navigate_params
.transferred_request_child_id
==
390 dest_render_frame_host
->GetProcess()->GetID();
391 if (!is_transfer_to_same
) {
392 dest_render_frame_host
->Navigate(navigate_params
);
394 // No need to navigate again. Just resume the deferred request.
395 dest_render_frame_host
->GetProcess()->ResumeDeferredNavigation(
396 GlobalRequestID(navigate_params
.transferred_request_child_id
,
397 navigate_params
.transferred_request_request_id
));
400 // Make sure no code called via RFH::Navigate clears the pending entry.
401 CHECK_EQ(controller_
->GetPendingEntry(), &entry
);
403 if (entry
.GetPageID() == -1) {
404 // HACK!! This code suppresses javascript: URLs from being added to
405 // session history, which is what we want to do for javascript: URLs that
406 // do not generate content. What we really need is a message from the
407 // renderer telling us that a new page was not created. The same message
408 // could be used for mailto: URLs and the like.
409 if (entry
.GetURL().SchemeIs(url::kJavaScriptScheme
))
413 // Notify observers about navigation.
415 delegate_
->DidStartNavigationToPendingEntry(dest_render_frame_host
,
423 bool NavigatorImpl::NavigateToPendingEntry(
424 RenderFrameHostImpl
* render_frame_host
,
425 NavigationController::ReloadType reload_type
) {
426 return NavigateToEntry(
428 *NavigationEntryImpl::FromNavigationEntry(controller_
->GetPendingEntry()),
432 base::TimeTicks
NavigatorImpl::GetCurrentLoadStart() {
433 return current_load_start_
;
436 void NavigatorImpl::DidNavigate(
437 RenderFrameHostImpl
* render_frame_host
,
438 const FrameHostMsg_DidCommitProvisionalLoad_Params
& input_params
) {
439 FrameHostMsg_DidCommitProvisionalLoad_Params
params(input_params
);
440 FrameTree
* frame_tree
= render_frame_host
->frame_tree_node()->frame_tree();
441 bool use_site_per_process
= base::CommandLine::ForCurrentProcess()->HasSwitch(
442 switches::kSitePerProcess
);
444 if (use_site_per_process
) {
445 // TODO(creis): Until we mirror the frame tree in the subframe's process,
446 // cross-process subframe navigations happen in a renderer's main frame.
447 // Correct the transition type here if we know it is for a subframe.
448 NavigationEntryImpl
* pending_entry
=
449 NavigationEntryImpl::FromNavigationEntry(
450 controller_
->GetPendingEntry());
451 if (!render_frame_host
->frame_tree_node()->IsMainFrame() &&
453 pending_entry
->frame_tree_node_id() ==
454 render_frame_host
->frame_tree_node()->frame_tree_node_id()) {
455 params
.transition
= PAGE_TRANSITION_AUTO_SUBFRAME
;
459 if (PageTransitionIsMainFrame(params
.transition
)) {
461 // When overscroll navigation gesture is enabled, a screenshot of the page
462 // in its current state is taken so that it can be used during the
463 // nav-gesture. It is necessary to take the screenshot here, before
464 // calling RenderFrameHostManager::DidNavigateMainFrame, because that can
465 // change WebContents::GetRenderViewHost to return the new host, instead
466 // of the one that may have just been swapped out.
467 if (delegate_
->CanOverscrollContent()) {
468 // Don't take screenshots if we are staying on the same page. We want
469 // in-page navigations to be super fast, and taking a screenshot
470 // currently blocks GPU for a longer time than we are willing to
471 // tolerate in this use case.
472 if (!params
.was_within_same_page
)
473 controller_
->TakeScreenshot();
476 // Run tasks that must execute just before the commit.
477 bool is_navigation_within_page
= controller_
->IsURLInPageNavigation(
478 params
.url
, params
.was_within_same_page
, render_frame_host
);
479 delegate_
->DidNavigateMainFramePreCommit(is_navigation_within_page
);
482 if (!use_site_per_process
)
483 frame_tree
->root()->render_manager()->DidNavigateFrame(render_frame_host
);
486 // When using --site-per-process, we notify the RFHM for all navigations,
487 // not just main frame navigations.
488 if (use_site_per_process
) {
489 FrameTreeNode
* frame
= render_frame_host
->frame_tree_node();
490 frame
->render_manager()->DidNavigateFrame(render_frame_host
);
493 // Update the site of the SiteInstance if it doesn't have one yet, unless
494 // assigning a site is not necessary for this URL. In that case, the
495 // SiteInstance can still be considered unused until a navigation to a real
497 SiteInstanceImpl
* site_instance
=
498 static_cast<SiteInstanceImpl
*>(render_frame_host
->GetSiteInstance());
499 if (!site_instance
->HasSite() &&
500 ShouldAssignSiteForURL(params
.url
)) {
501 site_instance
->SetSite(params
.url
);
504 // Need to update MIME type here because it's referred to in
505 // UpdateNavigationCommands() called by RendererDidNavigate() to
506 // determine whether or not to enable the encoding menu.
507 // It's updated only for the main frame. For a subframe,
508 // RenderView::UpdateURL does not set params.contents_mime_type.
509 // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
510 // TODO(jungshik): Add a test for the encoding menu to avoid
511 // regressing it again.
512 // TODO(nasko): Verify the correctness of the above comment, since some of the
513 // code doesn't exist anymore. Also, move this code in the
514 // PageTransitionIsMainFrame code block above.
515 if (PageTransitionIsMainFrame(params
.transition
) && delegate_
)
516 delegate_
->SetMainFrameMimeType(params
.contents_mime_type
);
518 LoadCommittedDetails details
;
519 bool did_navigate
= controller_
->RendererDidNavigate(render_frame_host
,
522 // For now, keep track of each frame's URL in its FrameTreeNode. This lets
523 // us estimate our process count for implementing OOP iframes.
524 // TODO(creis): Remove this when we track which pages commit in each frame.
525 render_frame_host
->frame_tree_node()->set_current_url(params
.url
);
527 // Send notification about committed provisional loads. This notification is
528 // different from the NAV_ENTRY_COMMITTED notification which doesn't include
529 // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
530 if (details
.type
!= NAVIGATION_TYPE_NAV_IGNORE
&& delegate_
) {
531 DCHECK_EQ(!render_frame_host
->GetParent(),
532 did_navigate
? details
.is_main_frame
: false);
533 PageTransition transition_type
= params
.transition
;
534 // Whether or not a page transition was triggered by going backward or
535 // forward in the history is only stored in the navigation controller's
538 (controller_
->GetLastCommittedEntry()->GetTransitionType() &
539 PAGE_TRANSITION_FORWARD_BACK
)) {
540 transition_type
= PageTransitionFromInt(
541 params
.transition
| PAGE_TRANSITION_FORWARD_BACK
);
544 delegate_
->DidCommitProvisionalLoad(render_frame_host
,
550 return; // No navigation happened.
552 // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
553 // for the appropriate notification (best) or you can add it to
554 // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
555 // necessary, please).
557 // Run post-commit tasks.
559 if (details
.is_main_frame
)
560 delegate_
->DidNavigateMainFramePostCommit(details
, params
);
562 delegate_
->DidNavigateAnyFramePostCommit(
563 render_frame_host
, details
, params
);
567 bool NavigatorImpl::ShouldAssignSiteForURL(const GURL
& url
) {
568 // about:blank should not "use up" a new SiteInstance. The SiteInstance can
569 // still be used for a normal web site.
570 if (url
== GURL(url::kAboutBlankURL
))
573 // The embedder will then have the opportunity to determine if the URL
574 // should "use up" the SiteInstance.
575 return GetContentClient()->browser()->ShouldAssignSiteForURL(url
);
578 void NavigatorImpl::RequestOpenURL(
579 RenderFrameHostImpl
* render_frame_host
,
581 const Referrer
& referrer
,
582 WindowOpenDisposition disposition
,
583 bool should_replace_current_entry
,
585 SiteInstance
* current_site_instance
=
586 GetRenderManager(render_frame_host
)->current_frame_host()->
588 // If this came from a swapped out RenderViewHost, we only allow the request
589 // if we are still in the same BrowsingInstance.
590 if (render_frame_host
->render_view_host()->IsSwappedOut() &&
591 !render_frame_host
->GetSiteInstance()->IsRelatedSiteInstance(
592 current_site_instance
)) {
596 // Delegate to RequestTransferURL because this is just the generic
597 // case where |old_request_id| is empty.
598 // TODO(creis): Pass the redirect_chain into this method to support client
599 // redirects. http://crbug.com/311721.
600 std::vector
<GURL
> redirect_chain
;
602 render_frame_host
, url
, redirect_chain
, referrer
, PAGE_TRANSITION_LINK
,
603 disposition
, GlobalRequestID(),
604 should_replace_current_entry
, user_gesture
);
607 void NavigatorImpl::RequestTransferURL(
608 RenderFrameHostImpl
* render_frame_host
,
610 const std::vector
<GURL
>& redirect_chain
,
611 const Referrer
& referrer
,
612 PageTransition page_transition
,
613 WindowOpenDisposition disposition
,
614 const GlobalRequestID
& transferred_global_request_id
,
615 bool should_replace_current_entry
,
618 SiteInstance
* current_site_instance
=
619 GetRenderManager(render_frame_host
)->current_frame_host()->
621 if (!GetContentClient()->browser()->ShouldAllowOpenURL(
622 current_site_instance
, url
)) {
623 dest_url
= GURL(url::kAboutBlankURL
);
626 int64 frame_tree_node_id
= -1;
627 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
628 switches::kSitePerProcess
)) {
630 render_frame_host
->frame_tree_node()->frame_tree_node_id();
632 OpenURLParams
params(
633 dest_url
, referrer
, frame_tree_node_id
, disposition
, page_transition
,
634 true /* is_renderer_initiated */);
635 if (redirect_chain
.size() > 0)
636 params
.redirect_chain
= redirect_chain
;
637 params
.transferred_global_request_id
= transferred_global_request_id
;
638 params
.should_replace_current_entry
= should_replace_current_entry
;
639 params
.user_gesture
= user_gesture
;
641 if (GetRenderManager(render_frame_host
)->web_ui()) {
642 // Web UI pages sometimes want to override the page transition type for
643 // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for
644 // automatically generated suggestions). We don't override other types
645 // like TYPED because they have different implications (e.g., autocomplete).
646 if (PageTransitionCoreTypeIs(params
.transition
, PAGE_TRANSITION_LINK
))
648 GetRenderManager(render_frame_host
)->web_ui()->
649 GetLinkTransitionType();
651 // Note also that we hide the referrer for Web UI pages. We don't really
652 // want web sites to see a referrer of "chrome://blah" (and some
653 // chrome: URLs might have search terms or other stuff we don't want to
654 // send to the site), so we send no referrer.
655 params
.referrer
= Referrer();
657 // Navigations in Web UI pages count as browser-initiated navigations.
658 params
.is_renderer_initiated
= false;
662 delegate_
->RequestOpenURL(render_frame_host
, params
);
665 void NavigatorImpl::CommitNavigation(
666 RenderFrameHostImpl
* render_frame_host
,
667 const NavigationBeforeCommitInfo
& info
) {
668 CheckWebUIRendererDoesNotDisplayNormalURL(
669 render_frame_host
, info
.navigation_url
);
670 // TODO(clamy): the render_frame_host should now send a commit IPC to the
674 void NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(
675 RenderFrameHostImpl
* render_frame_host
,
677 int enabled_bindings
=
678 render_frame_host
->render_view_host()->GetEnabledBindings();
679 bool is_allowed_in_web_ui_renderer
=
680 WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
681 controller_
->GetBrowserContext(), url
);
682 if ((enabled_bindings
& BINDINGS_POLICY_WEB_UI
) &&
683 !is_allowed_in_web_ui_renderer
) {
684 // Log the URL to help us diagnose any future failures of this CHECK.
685 GetContentClient()->SetActiveURL(url
);
690 } // namespace content