diff options
author | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-04 21:14:18 +0000 |
---|---|---|
committer | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-04 21:14:18 +0000 |
commit | 65920f331b2945f739abdbb8a3ede4ca68f142a6 (patch) | |
tree | 08f9cbc66775fbabdcf35e97913d9d8762cf4a59 /content | |
parent | 3a1f1144d2385c01e62f9b474b173a8a8af47608 (diff) | |
download | chromium_src-65920f331b2945f739abdbb8a3ede4ca68f142a6.zip chromium_src-65920f331b2945f739abdbb8a3ede4ca68f142a6.tar.gz chromium_src-65920f331b2945f739abdbb8a3ede4ca68f142a6.tar.bz2 |
Move OpenURL from RenderView to RenderFrame.
This CL is follow up attempt at landing this change. The original CL is https://codereview.chromium.org/165063003 and is also ps1.
BUG=304341
R=creis@chromium.org
Review URL: https://codereview.chromium.org/186623004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@254821 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
22 files changed, 533 insertions, 478 deletions
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h index 52f6697..9637d677 100644 --- a/content/browser/frame_host/navigator.h +++ b/content/browser/frame_host/navigator.h @@ -8,6 +8,7 @@ #include "base/memory/ref_counted.h" #include "content/common/content_export.h" #include "content/public/browser/navigation_controller.h" +#include "ui/base/window_open_disposition.h" class GURL; struct FrameHostMsg_DidCommitProvisionalLoad_Params; @@ -88,6 +89,31 @@ class CONTENT_EXPORT Navigator : public base::RefCounted<Navigator> { virtual base::TimeTicks GetCurrentLoadStart(); + // The RenderFrameHostImpl has received a request to open a URL with the + // specified |disposition|. + virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host, + const GURL& url, + const Referrer& referrer, + WindowOpenDisposition disposition, + int64 source_frame_id, + bool should_replace_current_entry, + bool user_gesture) {} + + // The RenderFrameHostImpl wants to transfer the request to a new renderer. + // |redirect_chain| contains any redirect URLs (excluding |url|) that happened + // before the transfer. + virtual void RequestTransferURL( + RenderFrameHostImpl* render_frame_host, + const GURL& url, + const std::vector<GURL>& redirect_chain, + const Referrer& referrer, + PageTransition page_transition, + WindowOpenDisposition disposition, + int64 source_frame_id, + const GlobalRequestID& transferred_global_request_id, + bool should_replace_current_entry, + bool user_gesture) {} + protected: friend class base::RefCounted<Navigator>; virtual ~Navigator() {} diff --git a/content/browser/frame_host/navigator_delegate.h b/content/browser/frame_host/navigator_delegate.h index 75280de..6b871da 100644 --- a/content/browser/frame_host/navigator_delegate.h +++ b/content/browser/frame_host/navigator_delegate.h @@ -9,6 +9,7 @@ #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_controller.h" #include "content/public/common/page_transition_types.h" +#include "ui/base/window_open_disposition.h" class GURL; struct FrameHostMsg_DidCommitProvisionalLoad_Params; @@ -18,6 +19,7 @@ namespace content { class RenderFrameHostImpl; struct LoadCommittedDetails; +struct OpenURLParams; // A delegate API used by Navigator to notify its embedder of navigation // related events. @@ -89,6 +91,10 @@ class CONTENT_EXPORT NavigatorDelegate { RenderFrameHostImpl* render_frame_host, const GURL& url, NavigationController::ReloadType reload_type) {} + + // Opens a URL with the given parameters. See PageNavigator::OpenURL, which + // this forwards to. + virtual void RequestOpenURL(const OpenURLParams& params) {} }; } // namspace content diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index 60b1f825..59a2af2 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc @@ -14,13 +14,16 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/site_instance_impl.h" #include "content/browser/webui/web_ui_controller_factory_registry.h" +#include "content/browser/webui/web_ui_impl.h" #include "content/common/frame_messages.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/global_request_id.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_details.h" +#include "content/public/browser/page_navigator.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/bindings_policy.h" #include "content/public/common/content_client.h" @@ -111,6 +114,13 @@ void MakeNavigateParams(const NavigationEntryImpl& entry, params->frame_to_navigate = entry.GetFrameToNavigate(); } +RenderFrameHostManager* GetRenderManager(RenderFrameHostImpl* rfh) { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess)) + return rfh->frame_tree_node()->render_manager(); + + return rfh->frame_tree_node()->frame_tree()->root()->render_manager(); +} + } // namespace @@ -528,4 +538,97 @@ bool NavigatorImpl::ShouldAssignSiteForURL(const GURL& url) { return GetContentClient()->browser()->ShouldAssignSiteForURL(url); } +void NavigatorImpl::RequestOpenURL( + RenderFrameHostImpl* render_frame_host, + const GURL& url, + const Referrer& referrer, + WindowOpenDisposition disposition, + int64 source_frame_id, + bool should_replace_current_entry, + bool user_gesture) { + SiteInstance* current_site_instance = + GetRenderManager(render_frame_host)->current_frame_host()-> + GetSiteInstance(); + // If this came from a swapped out RenderViewHost, we only allow the request + // if we are still in the same BrowsingInstance. + if (render_frame_host->render_view_host()->IsSwappedOut() && + !render_frame_host->GetSiteInstance()->IsRelatedSiteInstance( + current_site_instance)) { + return; + } + + // Delegate to RequestTransferURL because this is just the generic + // case where |old_request_id| is empty. + // TODO(creis): Pass the redirect_chain into this method to support client + // redirects. http://crbug.com/311721. + std::vector<GURL> redirect_chain; + RequestTransferURL( + render_frame_host, url, redirect_chain, referrer, PAGE_TRANSITION_LINK, + disposition, source_frame_id, GlobalRequestID(), + should_replace_current_entry, user_gesture); +} + +void NavigatorImpl::RequestTransferURL( + RenderFrameHostImpl* render_frame_host, + const GURL& url, + const std::vector<GURL>& redirect_chain, + const Referrer& referrer, + PageTransition page_transition, + WindowOpenDisposition disposition, + int64 source_frame_id, + const GlobalRequestID& transferred_global_request_id, + bool should_replace_current_entry, + bool user_gesture) { + GURL dest_url(url); + SiteInstance* current_site_instance = + GetRenderManager(render_frame_host)->current_frame_host()-> + GetSiteInstance(); + if (!GetContentClient()->browser()->ShouldAllowOpenURL( + current_site_instance, url)) { + dest_url = GURL(kAboutBlankURL); + } + + // Look up the FrameTreeNode ID corresponding to source_frame_id. + int64 frame_tree_node_id = -1; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && + source_frame_id != -1) { + FrameTreeNode* source_node = + render_frame_host->frame_tree_node()->frame_tree()->FindByRoutingID( + source_frame_id, transferred_global_request_id.child_id); + if (source_node) + frame_tree_node_id = source_node->frame_tree_node_id(); + } + OpenURLParams params( + dest_url, referrer, source_frame_id, frame_tree_node_id, disposition, + page_transition, true /* is_renderer_initiated */); + if (redirect_chain.size() > 0) + params.redirect_chain = redirect_chain; + params.transferred_global_request_id = transferred_global_request_id; + params.should_replace_current_entry = should_replace_current_entry; + params.user_gesture = user_gesture; + + if (GetRenderManager(render_frame_host)->web_ui()) { + // Web UI pages sometimes want to override the page transition type for + // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for + // automatically generated suggestions). We don't override other types + // like TYPED because they have different implications (e.g., autocomplete). + if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK)) + params.transition = + GetRenderManager(render_frame_host)->web_ui()-> + GetLinkTransitionType(); + + // Note also that we hide the referrer for Web UI pages. We don't really + // want web sites to see a referrer of "chrome://blah" (and some + // chrome: URLs might have search terms or other stuff we don't want to + // send to the site), so we send no referrer. + params.referrer = Referrer(); + + // Navigations in Web UI pages count as browser-initiated navigations. + params.is_renderer_initiated = false; + } + + if (delegate_) + delegate_->RequestOpenURL(params); +} + } // namespace content diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h index 2565ffb..14f1ce5 100644 --- a/content/browser/frame_host/navigator_impl.h +++ b/content/browser/frame_host/navigator_impl.h @@ -51,6 +51,24 @@ class CONTENT_EXPORT NavigatorImpl : public Navigator { RenderFrameHostImpl* render_frame_host, NavigationController::ReloadType reload_type) OVERRIDE; virtual base::TimeTicks GetCurrentLoadStart() OVERRIDE; + virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host, + const GURL& url, + const Referrer& referrer, + WindowOpenDisposition disposition, + int64 source_frame_id, + bool should_replace_current_entry, + bool user_gesture) OVERRIDE; + virtual void RequestTransferURL( + RenderFrameHostImpl* render_frame_host, + const GURL& url, + const std::vector<GURL>& redirect_chain, + const Referrer& referrer, + PageTransition page_transition, + WindowOpenDisposition disposition, + int64 source_frame_id, + const GlobalRequestID& transferred_global_request_id, + bool should_replace_current_entry, + bool user_gesture) OVERRIDE; private: virtual ~NavigatorImpl() {} diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 00b8397..fbf0aae 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -162,6 +162,7 @@ bool RenderFrameHostImpl::OnMessageReceived(const IPC::Message &msg) { OnNavigate(msg)) IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading) IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading) + IPC_MESSAGE_HANDLER(FrameHostMsg_OpenURL, OnOpenURL) IPC_MESSAGE_HANDLER(FrameHostMsg_SwapOut_ACK, OnSwapOutACK) IPC_MESSAGE_HANDLER(FrameHostMsg_ContextMenu, OnContextMenu) IPC_END_MESSAGE_MAP_EX() @@ -192,6 +193,16 @@ void RenderFrameHostImpl::OnDetach() { frame_tree_->RemoveFrame(frame_tree_node_); } +void RenderFrameHostImpl::OnOpenURL( + const FrameHostMsg_OpenURL_Params& params) { + GURL validated_url(params.url); + GetProcess()->FilterURL(false, &validated_url); + + frame_tree_node_->navigator()->RequestOpenURL( + this, validated_url, params.referrer, params.disposition, params.frame_id, + params.should_replace_current_entry, params.user_gesture); +} + void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame( int parent_routing_id, bool is_main_frame, diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 4b83d44..7db02602 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h @@ -15,6 +15,7 @@ class GURL; struct FrameHostMsg_DidFailProvisionalLoadWithError_Params; +struct FrameHostMsg_OpenURL_Params; struct FrameMsg_Navigate_Params; namespace base { @@ -131,6 +132,7 @@ class CONTENT_EXPORT RenderFrameHostImpl : public RenderFrameHost { // IPC Message handlers. void OnDetach(); + void OnOpenURL(const FrameHostMsg_OpenURL_Params& params); void OnDidStartProvisionalLoadForFrame(int parent_routing_id, bool main_frame, const GURL& url); diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc index 1887c68..5db47137 100644 --- a/content/browser/frame_host/render_frame_host_manager.cc +++ b/content/browser/frame_host/render_frame_host_manager.cc @@ -16,6 +16,7 @@ #include "content/browser/frame_host/interstitial_page_impl.h" #include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/navigation_entry_impl.h" +#include "content/browser/frame_host/navigator.h" #include "content/browser/frame_host/render_frame_host_factory.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/renderer_host/cross_site_transferring_request.h" @@ -297,10 +298,14 @@ void RenderFrameHostManager::SwappedOut(RenderViewHost* render_view_host) { GURL transfer_url = pending_nav_params_->transfer_url_chain.back(); pending_nav_params_->transfer_url_chain.pop_back(); + RenderFrameHostImpl* render_frame_host = + static_cast<RenderFrameHostImpl*>(render_view_host->GetMainFrame()); + // We don't know whether the original request had |user_action| set to true. // However, since we force the navigation to be in the current tab, it // doesn't matter. - render_view_host->GetDelegate()->RequestTransferURL( + render_frame_host->frame_tree_node()->navigator()->RequestTransferURL( + render_frame_host, transfer_url, pending_nav_params_->transfer_url_chain, pending_nav_params_->referrer, @@ -352,8 +357,8 @@ void RenderFrameHostManager::SwappedOutFrame( // We don't know whether the original request had |user_action| set to true. // However, since we force the navigation to be in the current tab, it // doesn't matter. - // TODO(creis): Move RequestTransferURL to RenderFrameHost's navigator. - render_frame_host->render_view_host()->GetDelegate()->RequestTransferURL( + render_frame_host->frame_tree_node()->navigator()->RequestTransferURL( + render_frame_host, transfer_url, pending_nav_params_->transfer_url_chain, pending_nav_params_->referrer, diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h index 7b9a64c..e7f9684ff 100644 --- a/content/browser/renderer_host/render_view_host_delegate.h +++ b/content/browser/renderer_host/render_view_host_delegate.h @@ -204,29 +204,6 @@ class CONTENT_EXPORT RenderViewHostDelegate { RenderViewHost* render_view_host, int32 page_id) {} - // The page wants to open a URL with the specified disposition. - virtual void RequestOpenURL(RenderViewHost* rvh, - const GURL& url, - const Referrer& referrer, - WindowOpenDisposition disposition, - int64 source_frame_id, - bool is_redirect, - bool user_gesture) {} - - // The page wants to transfer the request to a new renderer. - // |redirect_chain| contains any redirect URLs (excluding |url|) that happened - // before the transfer. - virtual void RequestTransferURL( - const GURL& url, - const std::vector<GURL>& redirect_chain, - const Referrer& referrer, - PageTransition page_transition, - WindowOpenDisposition disposition, - int64 source_frame_id, - const GlobalRequestID& old_request_id, - bool is_redirect, - bool user_gesture) {} - // The page wants to close the active view in this tab. virtual void RouteCloseEvent(RenderViewHost* rvh) {} diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 05d75ab..55918f0 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc @@ -1162,7 +1162,6 @@ bool RenderViewHostImpl::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentOnLoadCompletedInMainFrame, OnDocumentOnLoadCompletedInMainFrame) IPC_MESSAGE_HANDLER(ViewHostMsg_ToggleFullscreen, OnToggleFullscreen) - IPC_MESSAGE_HANDLER(ViewHostMsg_OpenURL, OnOpenURL) IPC_MESSAGE_HANDLER(ViewHostMsg_DidContentsPreferredSizeChange, OnDidContentsPreferredSizeChange) IPC_MESSAGE_HANDLER(ViewHostMsg_DidChangeScrollOffset, @@ -1399,16 +1398,6 @@ void RenderViewHostImpl::OnToggleFullscreen(bool enter_fullscreen) { WasResized(); } -void RenderViewHostImpl::OnOpenURL( - const ViewHostMsg_OpenURL_Params& params) { - GURL validated_url(params.url); - GetProcess()->FilterURL(false, &validated_url); - - delegate_->RequestOpenURL( - this, validated_url, params.referrer, params.disposition, params.frame_id, - params.should_replace_current_entry, params.user_gesture); -} - void RenderViewHostImpl::OnDidContentsPreferredSizeChange( const gfx::Size& new_size) { delegate_->UpdatePreferredSize(new_size); diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index 9fdbd0a..a6ed120 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h @@ -37,7 +37,6 @@ struct AccessibilityHostMsg_EventParams; struct AccessibilityHostMsg_LocationChangeParams; struct MediaPlayerAction; struct ViewHostMsg_CreateWindow_Params; -struct ViewHostMsg_OpenURL_Params; struct ViewHostMsg_SelectionBounds_Params; struct ViewHostMsg_ShowPopup_Params; struct FrameMsg_Navigate_Params; @@ -566,7 +565,6 @@ class CONTENT_EXPORT RenderViewHostImpl void OnDocumentAvailableInMainFrame(); void OnDocumentOnLoadCompletedInMainFrame(int32 page_id); void OnToggleFullscreen(bool enter_fullscreen); - void OnOpenURL(const ViewHostMsg_OpenURL_Params& params); void OnDidContentsPreferredSizeChange(const gfx::Size& new_size); void OnDidChangeScrollOffset(); void OnDidChangeScrollbarsForMainFrame(bool has_horizontal_scrollbar, diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc index 883fb8c..4da524a 100644 --- a/content/browser/security_exploit_browsertest.cc +++ b/content/browser/security_exploit_browsertest.cc @@ -6,6 +6,7 @@ #include "base/containers/hash_tables.h" #include "content/browser/dom_storage/dom_storage_context_wrapper.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" +#include "content/browser/frame_host/navigator.h" #include "content/browser/renderer_host/render_view_host_factory.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -56,10 +57,10 @@ RenderViewHostImpl* PrepareToDuplicateHosts(Shell* shell, // Now, simulate a link click coming from the renderer. GURL extension_url("https://bar.com/files/simple_page.html"); WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents()); - wc->RequestOpenURL( - shell->web_contents()->GetRenderViewHost(), extension_url, + wc->GetFrameTree()->root()->navigator()->RequestOpenURL( + wc->GetFrameTree()->root()->current_frame_host(), extension_url, Referrer(), CURRENT_TAB, - wc->GetFrameTree()->GetMainFrame()->GetRoutingID(), + wc->GetFrameTree()->root()->current_frame_host()->GetRoutingID(), false, true); // Since the navigation above requires a cross-process swap, there will be a diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 6472aa0..7a0920b 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -2090,6 +2090,21 @@ void WebContentsImpl::DidStartNavigationToPendingEntry( DidStartNavigationToPendingEntry(url, reload_type)); } +void WebContentsImpl::RequestOpenURL(const OpenURLParams& params) { + WebContents* new_contents = OpenURL(params); + + if (new_contents) { + // Notify observers. + FOR_EACH_OBSERVER(WebContentsObserver, observers_, + DidOpenRequestedURL(new_contents, + params.url, + params.referrer, + params.disposition, + params.transition, + params.source_frame_id)); + } +} + void WebContentsImpl::DidRedirectProvisionalLoad( RenderFrameHostImpl* render_frame_host, const GURL& validated_target_url) { @@ -3033,96 +3048,6 @@ void WebContentsImpl::DocumentOnLoadCompletedInMainFrame( Details<int>(&page_id)); } -void WebContentsImpl::RequestOpenURL(RenderViewHost* rvh, - const GURL& url, - const Referrer& referrer, - WindowOpenDisposition disposition, - int64 source_frame_id, - bool should_replace_current_entry, - bool user_gesture) { - // If this came from a swapped out RenderViewHost, we only allow the request - // if we are still in the same BrowsingInstance. - if (static_cast<RenderViewHostImpl*>(rvh)->IsSwappedOut() && - !rvh->GetSiteInstance()->IsRelatedSiteInstance(GetSiteInstance())) { - return; - } - - // Delegate to RequestTransferURL because this is just the generic - // case where |old_request_id| is empty. - // TODO(creis): Pass the redirect_chain into this method to support client - // redirects. http://crbug.com/311721. - std::vector<GURL> redirect_chain; - RequestTransferURL(url, redirect_chain, referrer, PAGE_TRANSITION_LINK, - disposition, source_frame_id, GlobalRequestID(), - should_replace_current_entry, user_gesture); -} - -void WebContentsImpl::RequestTransferURL( - const GURL& url, - const std::vector<GURL>& redirect_chain, - const Referrer& referrer, - PageTransition page_transition, - WindowOpenDisposition disposition, - int64 source_frame_id, - const GlobalRequestID& old_request_id, - bool should_replace_current_entry, - bool user_gesture) { - WebContents* new_contents = NULL; - GURL dest_url(url); - if (!GetContentClient()->browser()->ShouldAllowOpenURL( - GetSiteInstance(), url)) - dest_url = GURL(kAboutBlankURL); - - // Look up the FrameTreeNode ID corresponding to source_frame_id. - int64 frame_tree_node_id = -1; - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSitePerProcess) && - source_frame_id != -1) { - FrameTreeNode* source_node = frame_tree_.FindByRoutingID( - source_frame_id, old_request_id.child_id); - if (source_node) - frame_tree_node_id = source_node->frame_tree_node_id(); - } - OpenURLParams params(dest_url, referrer, source_frame_id, - frame_tree_node_id, disposition, - page_transition, true /* is_renderer_initiated */); - if (redirect_chain.size() > 0) - params.redirect_chain = redirect_chain; - params.transferred_global_request_id = old_request_id; - params.should_replace_current_entry = should_replace_current_entry; - params.user_gesture = user_gesture; - - if (GetRenderManager()->web_ui()) { - // Web UI pages sometimes want to override the page transition type for - // link clicks (e.g., so the new tab page can specify AUTO_BOOKMARK for - // automatically generated suggestions). We don't override other types - // like TYPED because they have different implications (e.g., autocomplete). - if (PageTransitionCoreTypeIs(params.transition, PAGE_TRANSITION_LINK)) - params.transition = GetRenderManager()->web_ui()->GetLinkTransitionType(); - - // Note also that we hide the referrer for Web UI pages. We don't really - // want web sites to see a referrer of "chrome://blah" (and some - // chrome: URLs might have search terms or other stuff we don't want to - // send to the site), so we send no referrer. - params.referrer = Referrer(); - - // Navigations in Web UI pages count as browser-initiated navigations. - params.is_renderer_initiated = false; - } - - new_contents = OpenURL(params); - - if (new_contents) { - // Notify observers. - FOR_EACH_OBSERVER(WebContentsObserver, observers_, - DidOpenRequestedURL(new_contents, - dest_url, - referrer, - disposition, - params.transition, - source_frame_id)); - } -} - void WebContentsImpl::RouteCloseEvent(RenderViewHost* rvh) { // Tell the active RenderViewHost to run unload handlers and close, as long // as the request came from a RenderViewHost in the same BrowsingInstance. diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index c798c55..45e4224 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -352,23 +352,6 @@ class CONTENT_EXPORT WebContentsImpl virtual void DocumentOnLoadCompletedInMainFrame( RenderViewHost* render_view_host, int32 page_id) OVERRIDE; - virtual void RequestOpenURL(RenderViewHost* rvh, - const GURL& url, - const Referrer& referrer, - WindowOpenDisposition disposition, - int64 source_frame_id, - bool should_replace_current_entry, - bool user_gesture) OVERRIDE; - virtual void RequestTransferURL( - const GURL& url, - const std::vector<GURL>& redirect_chain, - const Referrer& referrer, - PageTransition page_transition, - WindowOpenDisposition disposition, - int64 source_frame_id, - const GlobalRequestID& transferred_global_request_id, - bool should_replace_current_entry, - bool user_gesture) OVERRIDE; virtual void RouteCloseEvent(RenderViewHost* rvh) OVERRIDE; virtual void RouteMessageEvent( RenderViewHost* rvh, @@ -489,6 +472,7 @@ class CONTENT_EXPORT WebContentsImpl RenderFrameHostImpl* render_frame_host, const GURL& url, NavigationController::ReloadType reload_type) OVERRIDE; + virtual void RequestOpenURL(const OpenURLParams& params) OVERRIDE; // RenderWidgetHostDelegate -------------------------------------------------- diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 4782282..a8a2898 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h @@ -243,6 +243,15 @@ IPC_STRUCT_BEGIN(FrameMsg_Navigate_Params) IPC_STRUCT_MEMBER(base::TimeTicks, browser_navigation_start) IPC_STRUCT_END() +IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params) + IPC_STRUCT_MEMBER(GURL, url) + IPC_STRUCT_MEMBER(content::Referrer, referrer) + IPC_STRUCT_MEMBER(WindowOpenDisposition, disposition) + IPC_STRUCT_MEMBER(int64, frame_id) + IPC_STRUCT_MEMBER(bool, should_replace_current_entry) + IPC_STRUCT_MEMBER(bool, user_gesture) +IPC_STRUCT_END() + // ----------------------------------------------------------------------------- // Messages sent from the browser to the renderer. @@ -344,6 +353,9 @@ IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStartLoading) // notion of the throbber stopping. IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStopLoading) +// Requests that the given URL be opened in the specified manner. +IPC_MESSAGE_ROUTED1(FrameHostMsg_OpenURL, FrameHostMsg_OpenURL_Params) + // Following message is used to communicate the values received by the // callback binding the JS to Cpp. // An instance of browser that has an automation host listening to it can diff --git a/content/common/swapped_out_messages.cc b/content/common/swapped_out_messages.cc index c41a645..855b786 100644 --- a/content/common/swapped_out_messages.cc +++ b/content/common/swapped_out_messages.cc @@ -21,7 +21,7 @@ bool SwappedOutMessages::CanSendWhileSwappedOut(const IPC::Message* msg) { case InputHostMsg_HandleInputEvent_ACK::ID: case ViewHostMsg_UpdateRect::ID: // Allow targeted navigations while swapped out. - case ViewHostMsg_OpenURL::ID: + case FrameHostMsg_OpenURL::ID: case ViewHostMsg_Focus::ID: // Handled by RenderViewHost. case ViewHostMsg_RenderProcessGone::ID: diff --git a/content/common/view_messages.h b/content/common/view_messages.h index f210824..54a6aa8 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -337,15 +337,6 @@ IPC_STRUCT_BEGIN(ViewHostMsg_DateTimeDialogValue_Params) IPC_STRUCT_MEMBER(std::vector<content::DateTimeSuggestion>, suggestions) IPC_STRUCT_END() -IPC_STRUCT_BEGIN(ViewHostMsg_OpenURL_Params) - IPC_STRUCT_MEMBER(GURL, url) - IPC_STRUCT_MEMBER(content::Referrer, referrer) - IPC_STRUCT_MEMBER(WindowOpenDisposition, disposition) - IPC_STRUCT_MEMBER(int64, frame_id) - IPC_STRUCT_MEMBER(bool, should_replace_current_entry) - IPC_STRUCT_MEMBER(bool, user_gesture) -IPC_STRUCT_END() - IPC_STRUCT_BEGIN(ViewHostMsg_SelectionBounds_Params) IPC_STRUCT_MEMBER(gfx::Rect, anchor_rect) IPC_STRUCT_MEMBER(blink::WebTextDirection, anchor_dir) @@ -1483,9 +1474,6 @@ IPC_SYNC_MESSAGE_ROUTED4_2(ViewHostMsg_RunJavaScriptMessage, bool /* out - success */, base::string16 /* out - user_input field */) -// Requests that the given URL be opened in the specified manner. -IPC_MESSAGE_ROUTED1(ViewHostMsg_OpenURL, ViewHostMsg_OpenURL_Params) - // Notifies that the preferred size of the content changed. IPC_MESSAGE_ROUTED1(ViewHostMsg_DidContentsPreferredSizeChange, gfx::Size /* pref_size */) diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 5ede1bc..e5ed785 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc @@ -46,6 +46,7 @@ #include "content/renderer/dom_automation_controller.h" #include "content/renderer/internal_document_state_data.h" #include "content/renderer/npapi/plugin_channel_host.h" +#include "content/renderer/render_process.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" #include "content/renderer/render_widget_fullscreen_pepper.h" @@ -54,6 +55,7 @@ #include "content/renderer/websharedworker_proxy.h" #include "net/base/data_url.h" #include "net/base/net_errors.h" +#include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/http/http_util.h" #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -94,6 +96,7 @@ using blink::WebFrame; using blink::WebHistoryItem; using blink::WebHTTPBody; using blink::WebNavigationPolicy; +using blink::WebNavigationType; using blink::WebPluginParams; using blink::WebReferrerPolicy; using blink::WebSearchableFormData; @@ -211,6 +214,44 @@ static void MaybeHandleDebugURL(const GURL& url) { #endif // ADDRESS_SANITIZER } +// Returns false unless this is a top-level navigation. +static bool IsTopLevelNavigation(WebFrame* frame) { + return frame->parent() == NULL; +} + +// Returns false unless this is a top-level navigation that crosses origins. +static bool IsNonLocalTopLevelNavigation(const GURL& url, + WebFrame* frame, + WebNavigationType type, + bool is_form_post) { + if (!IsTopLevelNavigation(frame)) + return false; + + // Navigations initiated within Webkit are not sent out to the external host + // in the following cases. + // 1. The url scheme is not http/https + // 2. The origin of the url and the opener is the same in which case the + // opener relationship is maintained. + // 3. Reloads/form submits/back forward navigations + if (!url.SchemeIs(kHttpScheme) && !url.SchemeIs(kHttpsScheme)) + return false; + + if (type != blink::WebNavigationTypeReload && + type != blink::WebNavigationTypeBackForward && !is_form_post) { + // The opener relationship between the new window and the parent allows the + // new window to script the parent and vice versa. This is not allowed if + // the origins of the two domains are different. This can be treated as a + // top level navigation and routed back to the host. + blink::WebFrame* opener = frame->opener(); + if (!opener) + return true; + + if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin()) + return true; + } + return false; +} + } // namespace static RenderFrameImpl* (*g_create_render_frame_impl)(RenderViewImpl*, int32) = @@ -1107,7 +1148,7 @@ void RenderFrameImpl::loadURLExternally( request.url(), referrer, suggested_name)); } else { - render_view_->OpenURL(frame, request.url(), referrer, policy); + OpenURL(frame, request.url(), referrer, policy); } } @@ -1119,7 +1160,7 @@ blink::WebNavigationPolicy RenderFrameImpl::decidePolicyForNavigation( blink::WebNavigationPolicy default_policy, bool is_redirect) { DCHECK(!frame_ || frame_ == frame); - return render_view_->DecidePolicyForNavigation( + return DecidePolicyForNavigation( this, frame, extra_data, request, type, default_policy, is_redirect); } @@ -2282,4 +2323,263 @@ void RenderFrameImpl::didStopLoading() { Send(new FrameHostMsg_DidStopLoading(routing_id_)); } +WebNavigationPolicy RenderFrameImpl::DecidePolicyForNavigation( + RenderFrame* render_frame, + WebFrame* frame, + WebDataSource::ExtraData* extraData, + const WebURLRequest& request, + WebNavigationType type, + WebNavigationPolicy default_policy, + bool is_redirect) { +#ifdef OS_ANDROID + // The handlenavigation API is deprecated and will be removed once + // crbug.com/325351 is resolved. + if (request.url() != GURL(kSwappedOutURL) && + GetContentClient()->renderer()->HandleNavigation( + render_frame, + static_cast<DocumentState*>(extraData), + render_view_->opener_id_, + frame, + request, + type, + default_policy, + is_redirect)) { + return blink::WebNavigationPolicyIgnore; + } +#endif + + Referrer referrer(RenderViewImpl::GetReferrerFromRequest(frame, request)); + + if (is_swapped_out_ || render_view_->is_swapped_out()) { + if (request.url() != GURL(kSwappedOutURL)) { + // Targeted links may try to navigate a swapped out frame. Allow the + // browser process to navigate the tab instead. Note that it is also + // possible for non-targeted navigations (from this view) to arrive + // here just after we are swapped out. It's ok to send them to the + // browser, as long as they're for the top level frame. + // TODO(creis): Ensure this supports targeted form submissions when + // fixing http://crbug.com/101395. + if (frame->parent() == NULL) { + OpenURL(frame, request.url(), referrer, default_policy); + return blink::WebNavigationPolicyIgnore; // Suppress the load here. + } + + // We should otherwise ignore in-process iframe navigations, if they + // arrive just after we are swapped out. + return blink::WebNavigationPolicyIgnore; + } + + // Allow kSwappedOutURL to complete. + return default_policy; + } + + // Webkit is asking whether to navigate to a new URL. + // This is fine normally, except if we're showing UI from one security + // context and they're trying to navigate to a different context. + const GURL& url = request.url(); + + // A content initiated navigation may have originated from a link-click, + // script, drag-n-drop operation, etc. + bool is_content_initiated = static_cast<DocumentState*>(extraData)-> + navigation_state()->is_content_initiated(); + + // Experimental: + // If --enable-strict-site-isolation or --site-per-process is enabled, send + // all top-level navigations to the browser to let it swap processes when + // crossing site boundaries. This is currently expected to break some script + // calls and navigations, such as form submissions. + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + bool force_swap_due_to_flag = + command_line.HasSwitch(switches::kEnableStrictSiteIsolation) || + command_line.HasSwitch(switches::kSitePerProcess); + if (force_swap_due_to_flag && + !frame->parent() && (is_content_initiated || is_redirect)) { + WebString origin_str = frame->document().securityOrigin().toString(); + GURL frame_url(origin_str.utf8().data()); + // TODO(cevans): revisit whether this site check is still necessary once + // crbug.com/101395 is fixed. + bool same_domain_or_host = + net::registry_controlled_domains::SameDomainOrHost( + frame_url, + url, + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); + if (!same_domain_or_host || frame_url.scheme() != url.scheme()) { + OpenURL(frame, url, referrer, default_policy); + return blink::WebNavigationPolicyIgnore; + } + } + + // If the browser is interested, then give it a chance to look at the request. + if (is_content_initiated) { + bool is_form_post = ((type == blink::WebNavigationTypeFormSubmitted) || + (type == blink::WebNavigationTypeFormResubmitted)) && + EqualsASCII(request.httpMethod(), "POST"); + bool browser_handles_request = + render_view_->renderer_preferences_ + .browser_handles_non_local_top_level_requests + && IsNonLocalTopLevelNavigation(url, frame, type, is_form_post); + if (!browser_handles_request) { + browser_handles_request = IsTopLevelNavigation(frame) && + render_view_->renderer_preferences_ + .browser_handles_all_top_level_requests; + } + + if (browser_handles_request) { + // Reset these counters as the RenderView could be reused for the next + // navigation. + render_view_->page_id_ = -1; + render_view_->last_page_id_sent_to_browser_ = -1; + OpenURL(frame, url, referrer, default_policy); + return blink::WebNavigationPolicyIgnore; // Suppress the load here. + } + } + + // Use the frame's original request's URL rather than the document's URL for + // subsequent checks. For a popup, the document's URL may become the opener + // window's URL if the opener has called document.write(). + // See http://crbug.com/93517. + GURL old_url(frame->dataSource()->request().url()); + + // Detect when we're crossing a permission-based boundary (e.g. into or out of + // an extension or app origin, leaving a WebUI page, etc). We only care about + // top-level navigations (not iframes). But we sometimes navigate to + // about:blank to clear a tab, and we want to still allow that. + // + // Note: this is known to break POST submissions when crossing process + // boundaries until http://crbug.com/101395 is fixed. This is better for + // security than loading a WebUI, extension or app page in the wrong process. + // POST requests don't work because this mechanism does not preserve form + // POST data. We will need to send the request's httpBody data up to the + // browser process, and issue a special POST navigation in WebKit (via + // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl + // for examples of how to send the httpBody data. + if (!frame->parent() && is_content_initiated && + !url.SchemeIs(chrome::kAboutScheme)) { + bool send_referrer = false; + + // All navigations to or from WebUI URLs or within WebUI-enabled + // RenderProcesses must be handled by the browser process so that the + // correct bindings and data sources can be registered. + // Similarly, navigations to view-source URLs or within ViewSource mode + // must be handled by the browser process (except for reloads - those are + // safe to leave within the renderer). + // Lastly, access to file:// URLs from non-file:// URL pages must be + // handled by the browser so that ordinary renderer processes don't get + // blessed with file permissions. + int cumulative_bindings = RenderProcess::current()->GetEnabledBindings(); + bool is_initial_navigation = render_view_->page_id_ == -1; + bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) || + (cumulative_bindings & BINDINGS_POLICY_WEB_UI) || + url.SchemeIs(kViewSourceScheme) || + (frame->isViewSourceModeEnabled() && + type != blink::WebNavigationTypeReload); + + if (!should_fork && url.SchemeIs(kFileScheme)) { + // Fork non-file to file opens. Check the opener URL if this is the + // initial navigation in a newly opened window. + GURL source_url(old_url); + if (is_initial_navigation && source_url.is_empty() && frame->opener()) + source_url = frame->opener()->top()->document().url(); + DCHECK(!source_url.is_empty()); + should_fork = !source_url.SchemeIs(kFileScheme); + } + + if (!should_fork) { + // Give the embedder a chance. + should_fork = GetContentClient()->renderer()->ShouldFork( + frame, url, request.httpMethod().utf8(), is_initial_navigation, + is_redirect, &send_referrer); + } + + if (should_fork) { + OpenURL( + frame, url, send_referrer ? referrer : Referrer(), default_policy); + return blink::WebNavigationPolicyIgnore; // Suppress the load here. + } + } + + // Detect when a page is "forking" a new tab that can be safely rendered in + // its own process. This is done by sites like Gmail that try to open links + // in new windows without script connections back to the original page. We + // treat such cases as browser navigations (in which we will create a new + // renderer for a cross-site navigation), rather than WebKit navigations. + // + // We use the following heuristic to decide whether to fork a new page in its + // own process: + // The parent page must open a new tab to about:blank, set the new tab's + // window.opener to null, and then redirect the tab to a cross-site URL using + // JavaScript. + // + // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer + // (see below). + bool is_fork = + // Must start from a tab showing about:blank, which is later redirected. + old_url == GURL(kAboutBlankURL) && + // Must be the first real navigation of the tab. + render_view_->historyBackListCount() < 1 && + render_view_->historyForwardListCount() < 1 && + // The parent page must have set the child's window.opener to null before + // redirecting to the desired URL. + frame->opener() == NULL && + // Must be a top-level frame. + frame->parent() == NULL && + // Must not have issued the request from this page. + is_content_initiated && + // Must be targeted at the current tab. + default_policy == blink::WebNavigationPolicyCurrentTab && + // Must be a JavaScript navigation, which appears as "other". + type == blink::WebNavigationTypeOther; + + if (is_fork) { + // Open the URL via the browser, not via WebKit. + OpenURL(frame, url, Referrer(), default_policy); + return blink::WebNavigationPolicyIgnore; + } + + return default_policy; +} + +void RenderFrameImpl::OpenURL(WebFrame* frame, + const GURL& url, + const Referrer& referrer, + WebNavigationPolicy policy) { + DCHECK_EQ(frame_, frame); + + FrameHostMsg_OpenURL_Params params; + params.url = url; + params.referrer = referrer; + params.disposition = RenderViewImpl::NavigationPolicyToDisposition(policy); + params.frame_id = RenderFrameImpl::FromWebFrame(frame)->GetRoutingID(); + WebDataSource* ds = frame->provisionalDataSource(); + if (ds) { + DocumentState* document_state = DocumentState::FromDataSource(ds); + NavigationState* navigation_state = document_state->navigation_state(); + if (navigation_state->is_content_initiated()) { + params.should_replace_current_entry = ds->replacesCurrentHistoryItem(); + } else { + // This is necessary to preserve the should_replace_current_entry value on + // cross-process redirects, in the event it was set by a previous process. + // + // TODO(davidben): Avoid this awkward duplication of state. See comment on + // NavigationState::should_replace_current_entry(). + params.should_replace_current_entry = + navigation_state->should_replace_current_entry(); + } + } else { + params.should_replace_current_entry = false; + } + params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); + if (GetContentClient()->renderer()->AllowPopup()) + params.user_gesture = true; + + if (policy == blink::WebNavigationPolicyNewBackgroundTab || + policy == blink::WebNavigationPolicyNewForegroundTab || + policy == blink::WebNavigationPolicyNewWindow || + policy == blink::WebNavigationPolicyNewPopup) { + WebUserGestureIndicator::consumeUserGesture(); + } + + Send(new FrameHostMsg_OpenURL(routing_id_, params)); +} + } // namespace content diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index e5b750a..609d631 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h @@ -15,6 +15,7 @@ #include "base/observer_list.h" #include "base/process/process_handle.h" #include "base/strings/string16.h" +#include "content/public/common/referrer.h" #include "content/public/renderer/render_frame.h" #include "content/renderer/renderer_webcookiejar_impl.h" #include "ipc/ipc_message.h" @@ -360,6 +361,19 @@ class CONTENT_EXPORT RenderFrameImpl void OnContextMenuClosed(const CustomContextMenuContext& custom_context); void OnCustomContextMenuAction(const CustomContextMenuContext& custom_context, unsigned action); + // Virtual since overridden by WebTestProxy for layout tests. + virtual blink::WebNavigationPolicy DecidePolicyForNavigation( + RenderFrame* render_frame, + blink::WebFrame* frame, + blink::WebDataSource::ExtraData* extraData, + const blink::WebURLRequest& request, + blink::WebNavigationType type, + blink::WebNavigationPolicy default_policy, + bool is_redirect); + void OpenURL(blink::WebFrame* frame, + const GURL& url, + const Referrer& referrer, + blink::WebNavigationPolicy policy); // Returns whether |params.selection_text| should be synchronized to the // browser before bringing up the context menu. Static for testing. diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index bf4357f..f4db0f2 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -378,44 +378,6 @@ Referrer RenderViewImpl::GetReferrerFromRequest( request.referrerPolicy()); } -// Returns false unless this is a top-level navigation. -static bool IsTopLevelNavigation(WebFrame* frame) { - return frame->parent() == NULL; -} - -// Returns false unless this is a top-level navigation that crosses origins. -static bool IsNonLocalTopLevelNavigation(const GURL& url, - WebFrame* frame, - WebNavigationType type, - bool is_form_post) { - if (!IsTopLevelNavigation(frame)) - return false; - - // Navigations initiated within Webkit are not sent out to the external host - // in the following cases. - // 1. The url scheme is not http/https - // 2. The origin of the url and the opener is the same in which case the - // opener relationship is maintained. - // 3. Reloads/form submits/back forward navigations - if (!url.SchemeIs(kHttpScheme) && !url.SchemeIs(kHttpsScheme)) - return false; - - if (type != blink::WebNavigationTypeReload && - type != blink::WebNavigationTypeBackForward && !is_form_post) { - // The opener relationship between the new window and the parent allows the - // new window to script the parent and vice versa. This is not allowed if - // the origins of the two domains are different. This can be treated as a - // top level navigation and routed back to the host. - blink::WebFrame* opener = frame->opener(); - if (!opener) - return true; - - if (url.GetOrigin() != GURL(opener->document().url()).GetOrigin()) - return true; - } - return false; -} - // static void RenderViewImpl::NotifyTimezoneChange(blink::WebFrame* frame) { v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); @@ -426,7 +388,8 @@ void RenderViewImpl::NotifyTimezoneChange(blink::WebFrame* frame) { NotifyTimezoneChange(child); } -static WindowOpenDisposition NavigationPolicyToDisposition( +// static +WindowOpenDisposition RenderViewImpl::NavigationPolicyToDisposition( WebNavigationPolicy policy) { switch (policy) { case blink::WebNavigationPolicyIgnore: @@ -1630,47 +1593,6 @@ void RenderViewImpl::SendUpdateState(const WebHistoryItem& item) { routing_id_, page_id_, HistoryItemToPageState(item))); } -void RenderViewImpl::OpenURL(WebFrame* frame, - const GURL& url, - const Referrer& referrer, - WebNavigationPolicy policy) { - ViewHostMsg_OpenURL_Params params; - params.url = url; - params.referrer = referrer; - params.disposition = NavigationPolicyToDisposition(policy); - params.frame_id = RenderFrameImpl::FromWebFrame(frame)->GetRoutingID(); - WebDataSource* ds = frame->provisionalDataSource(); - if (ds) { - DocumentState* document_state = DocumentState::FromDataSource(ds); - NavigationState* navigation_state = document_state->navigation_state(); - if (navigation_state->is_content_initiated()) { - params.should_replace_current_entry = ds->replacesCurrentHistoryItem(); - } else { - // This is necessary to preserve the should_replace_current_entry value on - // cross-process redirects, in the event it was set by a previous process. - // - // TODO(davidben): Avoid this awkward duplication of state. See comment on - // NavigationState::should_replace_current_entry(). - params.should_replace_current_entry = - navigation_state->should_replace_current_entry(); - } - } else { - params.should_replace_current_entry = false; - } - params.user_gesture = WebUserGestureIndicator::isProcessingUserGesture(); - if (GetContentClient()->renderer()->AllowPopup()) - params.user_gesture = true; - - if (policy == blink::WebNavigationPolicyNewBackgroundTab || - policy == blink::WebNavigationPolicyNewForegroundTab || - policy == blink::WebNavigationPolicyNewWindow || - policy == blink::WebNavigationPolicyNewPopup) { - WebUserGestureIndicator::consumeUserGesture(); - } - - Send(new ViewHostMsg_OpenURL(routing_id_, params)); -} - // WebViewDelegate ------------------------------------------------------------ void RenderViewImpl::LoadNavigationErrorPage( @@ -2587,217 +2509,6 @@ const std::string& RenderViewImpl::GetAcceptLanguages() const { return renderer_preferences_.accept_languages; } -WebNavigationPolicy RenderViewImpl::DecidePolicyForNavigation( - RenderFrame* render_frame, WebFrame* frame, - WebDataSource::ExtraData* extraData, const WebURLRequest& request, - WebNavigationType type, WebNavigationPolicy default_policy, - bool is_redirect) { -#ifdef OS_ANDROID - // The handlenavigation API is deprecated and will be removed once - // crbug.com/325351 is resolved. - if (request.url() != GURL(kSwappedOutURL) && - GetContentClient()->renderer()->HandleNavigation( - render_frame, - static_cast<DocumentState*>(extraData), - opener_id_, - frame, - request, - type, - default_policy, - is_redirect)) { - return blink::WebNavigationPolicyIgnore; - } -#endif - - Referrer referrer(GetReferrerFromRequest(frame, request)); - - if (is_swapped_out_) { - if (request.url() != GURL(kSwappedOutURL)) { - // Targeted links may try to navigate a swapped out frame. Allow the - // browser process to navigate the tab instead. Note that it is also - // possible for non-targeted navigations (from this view) to arrive - // here just after we are swapped out. It's ok to send them to the - // browser, as long as they're for the top level frame. - // TODO(creis): Ensure this supports targeted form submissions when - // fixing http://crbug.com/101395. - if (frame->parent() == NULL) { - OpenURL(frame, request.url(), referrer, default_policy); - return blink::WebNavigationPolicyIgnore; // Suppress the load here. - } - - // We should otherwise ignore in-process iframe navigations, if they - // arrive just after we are swapped out. - return blink::WebNavigationPolicyIgnore; - } - - // Allow kSwappedOutURL to complete. - return default_policy; - } - - // Webkit is asking whether to navigate to a new URL. - // This is fine normally, except if we're showing UI from one security - // context and they're trying to navigate to a different context. - const GURL& url = request.url(); - - // A content initiated navigation may have originated from a link-click, - // script, drag-n-drop operation, etc. - bool is_content_initiated = static_cast<DocumentState*>(extraData)-> - navigation_state()->is_content_initiated(); - - // Experimental: - // If --enable-strict-site-isolation or --site-per-process is enabled, send - // all top-level navigations to the browser to let it swap processes when - // crossing site boundaries. This is currently expected to break some script - // calls and navigations, such as form submissions. - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - bool force_swap_due_to_flag = - command_line.HasSwitch(switches::kEnableStrictSiteIsolation) || - command_line.HasSwitch(switches::kSitePerProcess); - if (force_swap_due_to_flag && - !frame->parent() && (is_content_initiated || is_redirect)) { - WebString origin_str = frame->document().securityOrigin().toString(); - GURL frame_url(origin_str.utf8().data()); - // TODO(cevans): revisit whether this site check is still necessary once - // crbug.com/101395 is fixed. - bool same_domain_or_host = - net::registry_controlled_domains::SameDomainOrHost( - frame_url, - url, - net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - if (!same_domain_or_host || frame_url.scheme() != url.scheme()) { - OpenURL(frame, url, referrer, default_policy); - return blink::WebNavigationPolicyIgnore; - } - } - - // If the browser is interested, then give it a chance to look at the request. - if (is_content_initiated) { - bool is_form_post = ((type == blink::WebNavigationTypeFormSubmitted) || - (type == blink::WebNavigationTypeFormResubmitted)) && - EqualsASCII(request.httpMethod(), "POST"); - bool browser_handles_request = - renderer_preferences_.browser_handles_non_local_top_level_requests && - IsNonLocalTopLevelNavigation(url, frame, type, is_form_post); - if (!browser_handles_request) { - browser_handles_request = IsTopLevelNavigation(frame) && - renderer_preferences_.browser_handles_all_top_level_requests; - } - - if (browser_handles_request) { - // Reset these counters as the RenderView could be reused for the next - // navigation. - page_id_ = -1; - last_page_id_sent_to_browser_ = -1; - OpenURL(frame, url, referrer, default_policy); - return blink::WebNavigationPolicyIgnore; // Suppress the load here. - } - } - - // Use the frame's original request's URL rather than the document's URL for - // subsequent checks. For a popup, the document's URL may become the opener - // window's URL if the opener has called document.write(). - // See http://crbug.com/93517. - GURL old_url(frame->dataSource()->request().url()); - - // Detect when we're crossing a permission-based boundary (e.g. into or out of - // an extension or app origin, leaving a WebUI page, etc). We only care about - // top-level navigations (not iframes). But we sometimes navigate to - // about:blank to clear a tab, and we want to still allow that. - // - // Note: this is known to break POST submissions when crossing process - // boundaries until http://crbug.com/101395 is fixed. This is better for - // security than loading a WebUI, extension or app page in the wrong process. - // POST requests don't work because this mechanism does not preserve form - // POST data. We will need to send the request's httpBody data up to the - // browser process, and issue a special POST navigation in WebKit (via - // FrameLoader::loadFrameRequest). See ResourceDispatcher and WebURLLoaderImpl - // for examples of how to send the httpBody data. - if (!frame->parent() && is_content_initiated && - !url.SchemeIs(chrome::kAboutScheme)) { - bool send_referrer = false; - - // All navigations to or from WebUI URLs or within WebUI-enabled - // RenderProcesses must be handled by the browser process so that the - // correct bindings and data sources can be registered. - // Similarly, navigations to view-source URLs or within ViewSource mode - // must be handled by the browser process (except for reloads - those are - // safe to leave within the renderer). - // Lastly, access to file:// URLs from non-file:// URL pages must be - // handled by the browser so that ordinary renderer processes don't get - // blessed with file permissions. - int cumulative_bindings = RenderProcess::current()->GetEnabledBindings(); - bool is_initial_navigation = page_id_ == -1; - bool should_fork = HasWebUIScheme(url) || HasWebUIScheme(old_url) || - (cumulative_bindings & BINDINGS_POLICY_WEB_UI) || - url.SchemeIs(kViewSourceScheme) || - (frame->isViewSourceModeEnabled() && - type != blink::WebNavigationTypeReload); - - if (!should_fork && url.SchemeIs(kFileScheme)) { - // Fork non-file to file opens. Check the opener URL if this is the - // initial navigation in a newly opened window. - GURL source_url(old_url); - if (is_initial_navigation && source_url.is_empty() && frame->opener()) - source_url = frame->opener()->top()->document().url(); - DCHECK(!source_url.is_empty()); - should_fork = !source_url.SchemeIs(kFileScheme); - } - - if (!should_fork) { - // Give the embedder a chance. - should_fork = GetContentClient()->renderer()->ShouldFork( - frame, url, request.httpMethod().utf8(), is_initial_navigation, - is_redirect, &send_referrer); - } - - if (should_fork) { - OpenURL( - frame, url, send_referrer ? referrer : Referrer(), default_policy); - return blink::WebNavigationPolicyIgnore; // Suppress the load here. - } - } - - // Detect when a page is "forking" a new tab that can be safely rendered in - // its own process. This is done by sites like Gmail that try to open links - // in new windows without script connections back to the original page. We - // treat such cases as browser navigations (in which we will create a new - // renderer for a cross-site navigation), rather than WebKit navigations. - // - // We use the following heuristic to decide whether to fork a new page in its - // own process: - // The parent page must open a new tab to about:blank, set the new tab's - // window.opener to null, and then redirect the tab to a cross-site URL using - // JavaScript. - // - // TODO(creis): Deprecate this logic once we can rely on rel=noreferrer - // (see below). - bool is_fork = - // Must start from a tab showing about:blank, which is later redirected. - old_url == GURL(kAboutBlankURL) && - // Must be the first real navigation of the tab. - historyBackListCount() < 1 && - historyForwardListCount() < 1 && - // The parent page must have set the child's window.opener to null before - // redirecting to the desired URL. - frame->opener() == NULL && - // Must be a top-level frame. - frame->parent() == NULL && - // Must not have issued the request from this page. - is_content_initiated && - // Must be targeted at the current tab. - default_policy == blink::WebNavigationPolicyCurrentTab && - // Must be a JavaScript navigation, which appears as "other". - type == blink::WebNavigationTypeOther; - - if (is_fork) { - // Open the URL via the browser, not via WebKit. - OpenURL(frame, url, Referrer(), default_policy); - return blink::WebNavigationPolicyIgnore; - } - - return default_policy; -} - void RenderViewImpl::willSendSubmitEvent(blink::WebFrame* frame, const blink::WebFormElement& form) { FOR_EACH_OBSERVER( diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h index 2df9c78..808dc0d 100644 --- a/content/renderer/render_view_impl.h +++ b/content/renderer/render_view_impl.h @@ -57,6 +57,7 @@ #include "third_party/WebKit/public/web/WebPageVisibilityState.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebViewClient.h" +#include "ui/base/window_open_disposition.h" #include "ui/surface/transport_dib.h" #include "webkit/common/webpreferences.h" @@ -332,17 +333,6 @@ class CONTENT_EXPORT RenderViewImpl blink::WebFrame* frame, const blink::WebURL& url, blink::WebMediaPlayerClient* client); - // Temporary call until this code moves to RenderFrame. - // virtual since overriden by WebTestProxy for layout tests. - virtual blink::WebNavigationPolicy DecidePolicyForNavigation( - RenderFrame* render_frame, - blink::WebFrame* frame, - blink::WebDataSource::ExtraData* extraData, - const blink::WebURLRequest& request, - blink::WebNavigationType type, - blink::WebNavigationPolicy default_policy, - bool is_redirect); - // Returns the length of the session history of this RenderView. Note that // this only coincides with the actual length of the session history if this // RenderView is the currently active RenderView of a WebContents. @@ -810,6 +800,9 @@ class CONTENT_EXPORT RenderViewImpl static void NotifyTimezoneChange(blink::WebFrame* frame); + static WindowOpenDisposition NavigationPolicyToDisposition( + blink::WebNavigationPolicy policy); + void UpdateTitle(blink::WebFrame* frame, const base::string16& title, blink::WebTextDirection title_direction); void UpdateSessionHistory(blink::WebFrame* frame); @@ -831,11 +824,6 @@ class CONTENT_EXPORT RenderViewImpl void UpdateEncoding(blink::WebFrame* frame, const std::string& encoding_name); - void OpenURL(blink::WebFrame* frame, - const GURL& url, - const Referrer& referrer, - blink::WebNavigationPolicy policy); - bool RunJavaScriptMessage(JavaScriptMessageType type, const base::string16& message, const base::string16& default_value, diff --git a/content/shell/renderer/test_runner/WebFrameTestProxy.h b/content/shell/renderer/test_runner/WebFrameTestProxy.h index 3d81f2c..238712b 100644 --- a/content/shell/renderer/test_runner/WebFrameTestProxy.h +++ b/content/shell/renderer/test_runner/WebFrameTestProxy.h @@ -144,6 +144,10 @@ public: } virtual blink::WebNavigationPolicy decidePolicyForNavigation(blink::WebFrame* frame, blink::WebDataSource::ExtraData* extraData, const blink::WebURLRequest& request, blink::WebNavigationType type, blink::WebNavigationPolicy defaultPolicy, bool isRedirect) { + blink::WebNavigationPolicy policy = m_baseProxy->decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect); + if (policy == blink::WebNavigationPolicyIgnore) + return policy; + return Base::decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect); } virtual bool willCheckAndDispatchMessageEvent(blink::WebFrame* sourceFrame, blink::WebFrame* targetFrame, blink::WebSecurityOrigin target, blink::WebDOMMessageEvent event) diff --git a/content/shell/renderer/test_runner/WebTestProxy.h b/content/shell/renderer/test_runner/WebTestProxy.h index 1cf3ba6..0aa4f7f 100644 --- a/content/shell/renderer/test_runner/WebTestProxy.h +++ b/content/shell/renderer/test_runner/WebTestProxy.h @@ -477,13 +477,6 @@ public: { return WebTestProxyBase::runModalBeforeUnloadDialog(frame, message); } - virtual blink::WebNavigationPolicy DecidePolicyForNavigation(content::RenderFrame* render_frame, blink::WebFrame* frame, blink::WebDataSource::ExtraData* extraData, const blink::WebURLRequest& request, blink::WebNavigationType type, blink::WebNavigationPolicy defaultPolicy, bool isRedirect) - { - blink::WebNavigationPolicy policy = WebTestProxyBase::decidePolicyForNavigation(frame, extraData, request, type, defaultPolicy, isRedirect); - if (policy == blink::WebNavigationPolicyIgnore) - return policy; - return Base::DecidePolicyForNavigation(render_frame, frame, extraData, request, type, defaultPolicy, isRedirect); - } virtual bool willCheckAndDispatchMessageEvent(blink::WebFrame* sourceFrame, blink::WebFrame* targetFrame, blink::WebSecurityOrigin target, blink::WebDOMMessageEvent event) { if (WebTestProxyBase::willCheckAndDispatchMessageEvent(sourceFrame, targetFrame, target, event)) |