From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Mon, 3 Jun 2019 14:20:05 -0700 Subject: frame_host_manager.patch Allows embedder to intercept site instances chosen by chromium and respond with custom instance. Also allows for us to at-runtime enable or disable this patch. diff --git a/content/browser/browsing_instance.cc b/content/browser/browsing_instance.cc index 2fdd2b3f3f8dcc14a2675b1c115d7b700a33c2e0..9f20f0f37890af424aba566f88653e6142d944eb 100644 --- a/content/browser/browsing_instance.cc +++ b/content/browser/browsing_instance.cc @@ -77,6 +77,13 @@ scoped_refptr BrowsingInstance::GetSiteInstanceForURL( return instance; } +scoped_refptr BrowsingInstance::CreateSiteInstanceForURL( + const GURL& url) { + scoped_refptr instance = new SiteInstanceImpl(this); + instance->SetSite(UrlInfo(url, false)); + return instance; +} + SiteInfo BrowsingInstance::GetSiteInfoForURL(const UrlInfo& url_info, bool allow_default_instance) { scoped_refptr site_instance = diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h index 65e627f2fa89352b0be27b5813d71a622bf1d326..113f4fd00f1cf994b39f64c9da38785545ba321f 100644 --- a/content/browser/browsing_instance.h +++ b/content/browser/browsing_instance.h @@ -149,6 +149,11 @@ class CONTENT_EXPORT BrowsingInstance final const UrlInfo& url_info, bool allow_default_instance); + // Create a new SiteInstance for the given URL bound the current + // BrowsingInstance. + scoped_refptr CreateSiteInstanceForURL( + const GURL& url); + // Adds the given SiteInstance to our map, to ensure that we do not create // another SiteInstance for the same site. void RegisterSiteInstance(SiteInstanceImpl* site_instance); diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc index 29394a1584371f9304a30544e6f223acc8817e3b..d6596daf05721be7e8a9b939f162525199b85695 100644 --- a/content/browser/renderer_host/navigation_request.cc +++ b/content/browser/renderer_host/navigation_request.cc @@ -1454,6 +1454,21 @@ void NavigationRequest::BeginNavigation() { if (IsSameDocument()) { render_frame_host_ = frame_tree_node_->current_frame_host(); } else { + // In Electron, a new process is started for every navigation when node is + // integrated in the renderer. Since GetFrameHostForNavigation is called more + // than once per navigation, we want to return the same frame host once + // the response has started, otherwise if the frame host that started the response + // and the frame host that is available for commit don't match then request will + // be cancelled. We rely on the NavigationRequest::state_ to determine this + // factor + // + // bool has_response_started = + // (request->state() >= NavigationRequest::WILL_PROCESS_RESPONSE && + // !speculative_render_frame_host_); + // + // Hence this call is necesary before the call to GetFrameHostForNavigation. + SetState(REUSE_SITE_INSTANCE); + // Select an appropriate RenderFrameHost. std::string frame_host_choice_reason; render_frame_host_ = @@ -5343,6 +5358,7 @@ void NavigationRequest::CheckStateTransition(NavigationState state) const { {WILL_START_REQUEST, { WILL_REDIRECT_REQUEST, WILL_PROCESS_RESPONSE, + REUSE_SITE_INSTANCE, READY_TO_COMMIT, DID_COMMIT, CANCELING, @@ -5356,10 +5372,14 @@ void NavigationRequest::CheckStateTransition(NavigationState state) const { WILL_FAIL_REQUEST, }}, {WILL_PROCESS_RESPONSE, { + REUSE_SITE_INSTANCE, READY_TO_COMMIT, CANCELING, WILL_FAIL_REQUEST, }}, + {REUSE_SITE_INSTANCE, { + READY_TO_COMMIT, + }}, {READY_TO_COMMIT, { NOT_STARTED, DID_COMMIT, diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h index dd495343ea53fa03f9f7b6f06e5da00d2e5c9903..66ea89b7ecbe249f0c7b7f779c2e325f474ac913 100644 --- a/content/browser/renderer_host/navigation_request.h +++ b/content/browser/renderer_host/navigation_request.h @@ -131,6 +131,10 @@ class CONTENT_EXPORT NavigationRequest // asynchronous. WILL_PROCESS_RESPONSE, + // Electron: state that is between than WILL_PROCESS_RESPONSE and + // READY_TO_COMMIT to force reuse the same site instance. + REUSE_SITE_INSTANCE, + // The response started on the IO thread and is ready to be committed. READY_TO_COMMIT, diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index 3f9343bcdef5848f6017f1b1a73dc5306cd0c2a0..aa72c3a7ede9e62a3945304f5a38b17f55f7b09c 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc @@ -2724,6 +2724,16 @@ scoped_refptr RenderFrameHostManager::GetSiteInstanceForNavigationRequest( NavigationRequest* request, std::string* reason) { + // Compute the SiteInstance that the navigation should use, which will be + // either the current SiteInstance or a new one. + // + // TODO(clamy): We should also consider as a candidate SiteInstance the + // speculative SiteInstance that was computed on redirects. + SiteInstanceImpl* candidate_site_instance = + speculative_render_frame_host_ + ? speculative_render_frame_host_->GetSiteInstance() + : nullptr; + SiteInstance* current_site_instance = render_frame_host_->GetSiteInstance(); // All children of MHTML documents must be MHTML documents. They all live in @@ -2751,10 +2761,60 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( // // TODO(clamy): We should also consider as a candidate SiteInstance the // speculative SiteInstance that was computed on redirects. - SiteInstanceImpl* candidate_site_instance = - speculative_render_frame_host_ - ? speculative_render_frame_host_->GetSiteInstance() - : nullptr; + if (!GetContentClient()->browser()->CanUseCustomSiteInstance() && + frame_tree_node_->IsMainFrame()) { + BrowserContext* browser_context = + delegate_->GetControllerForRenderManager().GetBrowserContext(); + bool has_navigation_started = request->state() != NavigationRequest::NOT_STARTED; + bool has_response_started = + (request->state() >= NavigationRequest::WILL_PROCESS_RESPONSE && + !speculative_render_frame_host_); + // Gives user a chance to choose a custom site instance. + SiteInstance* affinity_site_instance = nullptr; + scoped_refptr overriden_site_instance; + bool should_register_site_instance = false; + ContentBrowserClient::SiteInstanceForNavigationType siteInstanceType = + GetContentClient()->browser()->ShouldOverrideSiteInstanceForNavigation( + current_frame_host(), speculative_frame_host(), browser_context, + request->common_params().url, has_navigation_started, + has_response_started, &affinity_site_instance); + switch (siteInstanceType) { + case ContentBrowserClient::SiteInstanceForNavigationType:: + FORCE_CANDIDATE_OR_NEW: + overriden_site_instance = + candidate_site_instance + ? candidate_site_instance + : current_site_instance->CreateRelatedSiteInstance( + request->common_params().url); + should_register_site_instance = true; + break; + case ContentBrowserClient::SiteInstanceForNavigationType::FORCE_NEW: + overriden_site_instance = current_site_instance->CreateRelatedSiteInstance( + request->common_params().url); + should_register_site_instance = true; + break; + case ContentBrowserClient::SiteInstanceForNavigationType::FORCE_CURRENT: + overriden_site_instance = render_frame_host_->GetSiteInstance(); + break; + case ContentBrowserClient::SiteInstanceForNavigationType::FORCE_AFFINITY: + DCHECK(affinity_site_instance); + overriden_site_instance = + scoped_refptr(affinity_site_instance); + break; + case ContentBrowserClient::SiteInstanceForNavigationType::ASK_CHROMIUM: + DCHECK(!affinity_site_instance); + break; + default: + break; + } + if (overriden_site_instance) { + if (should_register_site_instance) { + GetContentClient()->browser()->RegisterPendingSiteInstance( + render_frame_host_.get(), overriden_site_instance.get()); + } + return overriden_site_instance; + } + } // Account for renderer-initiated reload as well. // Needed as a workaround for https://crbug.com/1045524, remove it when it is @@ -2794,6 +2854,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest( request->ResetStateForSiteInstanceChange(); } + GetContentClient()->browser()->RegisterPendingSiteInstance( + render_frame_host_.get(), dest_site_instance.get()); + return dest_site_instance; } diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc index 34f32197686fbb350a065cb2ce554a7b4ae917b5..7196c8a8b1be2d4e3496de2de1e8f62430696021 100644 --- a/content/browser/site_instance_impl.cc +++ b/content/browser/site_instance_impl.cc @@ -742,6 +742,10 @@ bool SiteInstanceImpl::HasRelatedSiteInstance(const SiteInfo& site_info) { return browsing_instance_->HasSiteInstance(site_info); } +scoped_refptr SiteInstanceImpl::CreateRelatedSiteInstance(const GURL& url) { + return browsing_instance_->CreateSiteInstanceForURL(url); +} + scoped_refptr SiteInstanceImpl::GetRelatedSiteInstance( const GURL& url) { return GetRelatedSiteInstanceImpl( diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h index 3dc0f0cf7f3e9b9e75cf053817e9ac5fba0182bc..16759a044e24ac3c0719a57e196fbf3e2975f1b9 100644 --- a/content/browser/site_instance_impl.h +++ b/content/browser/site_instance_impl.h @@ -321,6 +321,7 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance, BrowserContext* GetBrowserContext() override; const GURL& GetSiteURL() override; scoped_refptr GetRelatedSiteInstance(const GURL& url) override; + scoped_refptr CreateRelatedSiteInstance(const GURL& url) override; bool IsRelatedSiteInstance(const SiteInstance* instance) override; size_t GetRelatedActiveContentsCount() override; bool RequiresDedicatedProcess() override; diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 05b2d9b76ae5c5f2a39303282a9c5c7326489d3b..f811ea8efeeace5a59a53714a8f8ac3b194f3ba5 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc @@ -65,6 +65,21 @@ namespace content { +bool ContentBrowserClient::CanUseCustomSiteInstance() { + return false; +} + +ContentBrowserClient::SiteInstanceForNavigationType ContentBrowserClient::ShouldOverrideSiteInstanceForNavigation( + content::RenderFrameHost* current_rfh, + content::RenderFrameHost* speculative_rfh, + content::BrowserContext* browser_context, + const GURL& url, + bool has_navigation_started, + bool has_request_started, + content::SiteInstance** affinity_site_instance) const { + return SiteInstanceForNavigationType::ASK_CHROMIUM; +} + std::unique_ptr ContentBrowserClient::CreateBrowserMainParts( const MainFunctionParams& parameters) { return nullptr; diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index bdb9c61af7c5b84c358a8e0282e4c06fcb05fdfe..57a8cc905275440349607bbce381da5ca679ea6d 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -254,8 +254,45 @@ class CONTENT_EXPORT ContentBrowserClient { using IsClipboardPasteAllowedCallback = base::OnceCallback; + // Identifies the type of site instance to use for a navigation. + enum SiteInstanceForNavigationType { + // Use either the candidate site instance or, if it doesn't exist + // a new, unrelated site instance for the navigation. + FORCE_CANDIDATE_OR_NEW = 0, + + // Use the current site instance for the navigation. + FORCE_CURRENT, + + // Use a new, unrelated site instance. + FORCE_NEW, + + // Use the provided affinity site instance for the navigation. + FORCE_AFFINITY, + + // Delegate the site instance creation to Chromium. + ASK_CHROMIUM + }; + virtual ~ContentBrowserClient() = default; + // Electron: Allows disabling the below ShouldOverride patch + virtual bool CanUseCustomSiteInstance(); + + // Electron: Allows overriding the SiteInstance when navigating. + virtual SiteInstanceForNavigationType ShouldOverrideSiteInstanceForNavigation( + content::RenderFrameHost* current_rfh, + content::RenderFrameHost* speculative_rfh, + content::BrowserContext* browser_context, + const GURL& url, + bool has_navigation_started, + bool has_request_started, + content::SiteInstance** affinity_site_instance) const; + + // Electron: Registers a pending site instance during a navigation. + virtual void RegisterPendingSiteInstance( + content::RenderFrameHost* rfh, + content::SiteInstance* pending_site_instance) {} + // Allows the embedder to set any number of custom BrowserMainParts // implementations for the browser startup code. See comments in // browser_main_parts.h. diff --git a/content/public/browser/site_instance.h b/content/public/browser/site_instance.h index a721f2fbab6e621085a8c7806abd92b8077340a8..e9b936e05e1d6ac8ea6eb5eb4d412b37ae4acc86 100644 --- a/content/public/browser/site_instance.h +++ b/content/public/browser/site_instance.h @@ -135,6 +135,11 @@ class CONTENT_EXPORT SiteInstance : public base::RefCounted { // corresponds to a site URL with the host "example.com". virtual const GURL& GetSiteURL() = 0; + // Create a SiteInstance for the given URL that shares the current + // BrowsingInstance. + virtual scoped_refptr CreateRelatedSiteInstance( + const GURL& url) = 0; + // Gets a SiteInstance for the given URL that shares the current // BrowsingInstance, creating a new SiteInstance if necessary. This ensures // that a BrowsingInstance only has one SiteInstance per site, so that pages