From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
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 732f2711719621ce42a0b13a6035954bada67ab9..62775b566d6e11a06a2516f9c1097b5ad5725247 100644
--- a/content/browser/browsing_instance.cc
+++ b/content/browser/browsing_instance.cc
@@ -91,6 +91,13 @@ scoped_refptr<SiteInstanceImpl> BrowsingInstance::GetSiteInstanceForURL(
   return instance;
 }
 
+scoped_refptr<SiteInstanceImpl> BrowsingInstance::CreateSiteInstanceForURL(
+    const GURL& url) {
+  scoped_refptr<SiteInstanceImpl> instance = new SiteInstanceImpl(this);
+  instance->SetSite(UrlInfo(url, false));
+  return instance;
+}
+
 SiteInfo BrowsingInstance::GetSiteInfoForURL(const UrlInfo& url_info,
                                              bool allow_default_instance) {
   scoped_refptr<SiteInstanceImpl> site_instance =
diff --git a/content/browser/browsing_instance.h b/content/browser/browsing_instance.h
index 75a58c7f56ef990e340ef271aa2d057f3541c47d..ab2679680111cfdc260c8d8dafbfae004f35b8b7 100644
--- a/content/browser/browsing_instance.h
+++ b/content/browser/browsing_instance.h
@@ -150,6 +150,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<SiteInstanceImpl> 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 e4942faa3fbf90c2819620d3f091aea59299522d..60b2b213d6429fa7cff783370cbbeff26a97a859 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1397,6 +1397,21 @@ void NavigationRequest::BeginNavigation() {
     // it immediately.
     EnterChildTraceEvent("ResponseStarted", this);
 
+    // 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.
     render_frame_host_ =
         frame_tree_node_->render_manager()->GetFrameHostForNavigation(this);
@@ -5067,6 +5082,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,
@@ -5080,10 +5096,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 c985c048fed8cda25be2802231f213f8d3dc9b79..5e0c08775d6e504327979218d46e999757ea508b 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -129,6 +129,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 0e0e806b54dc8eae7db6193ccde5cc9181f53c23..0597be2ec564b89e330bfa33bea771a042922c5d 100644
--- a/content/browser/renderer_host/render_frame_host_manager.cc
+++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2563,6 +2563,16 @@ void RenderFrameHostManager::GetCoopCoepCrossOriginIsolationInfo(
 scoped_refptr<SiteInstance>
 RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
     NavigationRequest* request) {
+  // 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
@@ -2582,10 +2592,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<SiteInstance> 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<SiteInstance>(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
@@ -2628,6 +2688,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 55f8ac07069b4a138354648debae5a8733b9e2fa..29c9cdb4fe7a33f664fcdefdcd834b12b8719e06 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -610,6 +610,10 @@ bool SiteInstanceImpl::HasRelatedSiteInstance(const SiteInfo& site_info) {
   return browsing_instance_->HasSiteInstance(site_info);
 }
 
+scoped_refptr<SiteInstance> SiteInstanceImpl::CreateRelatedSiteInstance(const GURL& url) {
+  return browsing_instance_->CreateSiteInstanceForURL(url);
+}
+
 scoped_refptr<SiteInstance> SiteInstanceImpl::GetRelatedSiteInstance(
     const GURL& url) {
   return GetRelatedSiteInstanceImpl(
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 6b317deaf6ecf0932116d93a5ffd5180a12d87c8..6a098f45d69e77ea9cf63fa1c6310cd26f7d8057 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -287,6 +287,7 @@ class CONTENT_EXPORT SiteInstanceImpl final : public SiteInstance,
   BrowserContext* GetBrowserContext() override;
   const GURL& GetSiteURL() override;
   scoped_refptr<SiteInstance> GetRelatedSiteInstance(const GURL& url) override;
+  scoped_refptr<SiteInstance> 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 cafd45df059293bc1cf31e1d7b798e67578f3e9d..c196b783fe0a43bfee98253afe8461a0be18438f 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -63,6 +63,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<BrowserMainParts> 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 3b93afa004fb4d56ade2ab16147b42f26e90e3db..9156388fda045775145302f2c7fd810b0f61bd84 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -253,8 +253,45 @@ class CONTENT_EXPORT ContentBrowserClient {
   using IsClipboardPasteAllowedCallback =
       base::OnceCallback<void(ClipboardPasteAllowed)>;
 
+  // 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() {}
 
+  // 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<SiteInstance> {
   //   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<SiteInstance> 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
