Add a WebContents getter callback in ResourceRequestInfo

This CL adds a method to ResourceRequestInfo that returns a callback that can
be used on the UI thread to get the WebContents associated with the request.It
is used in the SSLErrorHandler code, instead of using a RenderProcessHost ID
and a RenderFrameHost ID directly .This allows SSL error interstitials to work
with PlzNavigate enabled.

BUG = 504347

Review URL: https://codereview.chromium.org/1459473003

Cr-Commit-Position: refs/heads/master@{#361314}
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 5a9bbff..be19ccd 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -312,19 +312,9 @@
                                            bool fatal) {
   ResourceRequestInfoImpl* info = GetRequestInfo();
 
-  int render_process_id;
-  int render_frame_id;
-  if (!info->GetAssociatedRenderFrame(&render_process_id, &render_frame_id))
-    NOTREACHED();
-
   SSLManager::OnSSLCertificateError(
-      weak_ptr_factory_.GetWeakPtr(),
-      info->GetResourceType(),
-      request_->url(),
-      render_process_id,
-      render_frame_id,
-      ssl_info,
-      fatal);
+      weak_ptr_factory_.GetWeakPtr(), info->GetResourceType(), request_->url(),
+      info->GetWebContentsForRequest(), ssl_info, fatal);
 }
 
 void ResourceLoader::OnBeforeNetworkStart(net::URLRequest* unused,
diff --git a/content/browser/loader/resource_request_info_impl.cc b/content/browser/loader/resource_request_info_impl.cc
index 6ed5993..990ac79 100644
--- a/content/browser/loader/resource_request_info_impl.cc
+++ b/content/browser/loader/resource_request_info_impl.cc
@@ -4,15 +4,34 @@
 
 #include "content/browser/loader/resource_request_info_impl.h"
 
+#include "base/command_line.h"
+#include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/loader/global_routing_id.h"
 #include "content/browser/loader/resource_message_filter.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/net/url_request_user_data.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/global_request_id.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/common/process_type.h"
 #include "net/url_request/url_request.h"
 
 namespace content {
 
+namespace {
+
+WebContents* GetWebContentsFromFTNID(int frame_tree_node_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id);
+  if (!frame_tree_node)
+    return nullptr;
+
+  return WebContentsImpl::FromFrameTreeNode(frame_tree_node);
+}
+
+}  // namespace
+
 // ----------------------------------------------------------------------------
 // ResourceRequestInfo
 
@@ -168,6 +187,30 @@
 ResourceRequestInfoImpl::~ResourceRequestInfoImpl() {
 }
 
+base::Callback<WebContents*(void)>
+ResourceRequestInfoImpl::GetWebContentsForRequest() const {
+  // PlzNavigate: navigation requests are created with a valid FrameTreeNode ID
+  // and invalid RenderProcessHost and RenderFrameHost IDs. The FrameTreeNode
+  // ID should be used to access the WebContents.
+  if (frame_tree_node_id_ != -1) {
+    DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+        switches::kEnableBrowserSideNavigation));
+    return base::Bind(&GetWebContentsFromFTNID, frame_tree_node_id_);
+  }
+
+  // In other cases, use the RenderProcessHost ID + RenderFrameHost ID to get
+  // the WebContents.
+  int render_process_host_id = -1;
+  int render_frame_host_id = -1;
+  if (!GetAssociatedRenderFrame(&render_process_host_id,
+                                &render_frame_host_id)) {
+    NOTREACHED();
+  }
+
+  return base::Bind(&WebContentsImpl::FromRenderFrameHostID,
+                    render_process_host_id, render_frame_host_id);
+}
+
 ResourceContext* ResourceRequestInfoImpl::GetContext() const {
   return context_;
 }
diff --git a/content/browser/loader/resource_request_info_impl.h b/content/browser/loader/resource_request_info_impl.h
index 774668a..db1f0a6 100644
--- a/content/browser/loader/resource_request_info_impl.h
+++ b/content/browser/loader/resource_request_info_impl.h
@@ -23,6 +23,7 @@
 class DetachableResourceHandler;
 class ResourceContext;
 class ResourceMessageFilter;
+class WebContents;
 struct GlobalRequestID;
 struct GlobalRoutingID;
 
@@ -92,6 +93,14 @@
   bool IsUsingLoFi() const override;
   bool ShouldReportRawHeaders() const;
 
+  // Returns a callback that returns a pointer to the WebContents this request
+  // is associated with, or nullptr if it no longer exists or the request is
+  // not associated with a WebContents. The callback should only run on the UI
+  // thread.
+  // Note: Not all resource requests will be owned by a WebContents. For
+  // example, requests made by a ServiceWorker.
+  base::Callback<WebContents*(void)> GetWebContentsForRequest() const;
+
   CONTENT_EXPORT void AssociateWithRequest(net::URLRequest* request);
 
   CONTENT_EXPORT int GetRequestID() const;
diff --git a/content/browser/renderer_host/websocket_host.cc b/content/browser/renderer_host/websocket_host.cc
index 70c846e3..8c04e04 100644
--- a/content/browser/renderer_host/websocket_host.cc
+++ b/content/browser/renderer_host/websocket_host.cc
@@ -14,6 +14,7 @@
 #include "content/browser/ssl/ssl_error_handler.h"
 #include "content/browser/ssl/ssl_manager.h"
 #include "content/common/websocket_messages.h"
+#include "content/public/browser/render_frame_host.h"
 #include "ipc/ipc_message_macros.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
@@ -274,13 +275,9 @@
            << " cert_status=" << ssl_info.cert_status << " fatal=" << fatal;
   ssl_error_handler_delegate_.reset(
       new SSLErrorHandlerDelegate(callbacks.Pass()));
-  SSLManager::OnSSLCertificateError(ssl_error_handler_delegate_->GetWeakPtr(),
-                                    RESOURCE_TYPE_SUB_RESOURCE,
-                                    url,
-                                    dispatcher_->render_process_id(),
-                                    render_frame_id_,
-                                    ssl_info,
-                                    fatal);
+  SSLManager::OnSSLCertificateSubresourceError(
+      ssl_error_handler_delegate_->GetWeakPtr(), url,
+      dispatcher_->render_process_id(), render_frame_id_, ssl_info, fatal);
   // The above method is always asynchronous.
   return WebSocketEventInterface::CHANNEL_ALIVE;
 }
diff --git a/content/browser/ssl/ssl_cert_error_handler.cc b/content/browser/ssl/ssl_cert_error_handler.cc
index 9ec7885..54b165d9 100644
--- a/content/browser/ssl/ssl_cert_error_handler.cc
+++ b/content/browser/ssl/ssl_cert_error_handler.cc
@@ -15,19 +15,12 @@
     const base::WeakPtr<Delegate>& delegate,
     ResourceType resource_type,
     const GURL& url,
-    int render_process_id,
-    int render_frame_id,
     const net::SSLInfo& ssl_info,
     bool fatal)
-    : SSLErrorHandler(delegate,
-                      resource_type,
-                      url,
-                      render_process_id,
-                      render_frame_id),
+    : SSLErrorHandler(delegate, resource_type, url),
       ssl_info_(ssl_info),
       cert_error_(net::MapCertStatusToNetError(ssl_info.cert_status)),
-      fatal_(fatal) {
-}
+      fatal_(fatal) {}
 
 SSLCertErrorHandler* SSLCertErrorHandler::AsSSLCertErrorHandler() {
   return this;
diff --git a/content/browser/ssl/ssl_cert_error_handler.h b/content/browser/ssl/ssl_cert_error_handler.h
index e3c4378..11174ed0 100644
--- a/content/browser/ssl/ssl_cert_error_handler.h
+++ b/content/browser/ssl/ssl_cert_error_handler.h
@@ -22,8 +22,6 @@
   SSLCertErrorHandler(const base::WeakPtr<Delegate>& delegate,
                       ResourceType resource_type,
                       const GURL& url,
-                      int render_process_id,
-                      int render_frame_id,
                       const net::SSLInfo& ssl_info,
                       bool fatal);
 
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc
index 45b6dfd..40b2b564 100644
--- a/content/browser/ssl/ssl_error_handler.cc
+++ b/content/browser/ssl/ssl_error_handler.cc
@@ -20,13 +20,9 @@
 
 SSLErrorHandler::SSLErrorHandler(const base::WeakPtr<Delegate>& delegate,
                                  ResourceType resource_type,
-                                 const GURL& url,
-                                 int render_process_id,
-                                 int render_frame_id)
+                                 const GURL& url)
     : manager_(NULL),
       delegate_(delegate),
-      render_process_id_(render_process_id),
-      render_frame_id_(render_frame_id),
       request_url_(url),
       resource_type_(resource_type),
       request_has_been_notified_(false) {
@@ -55,13 +51,11 @@
   return NULL;
 }
 
-void SSLErrorHandler::Dispatch() {
+void SSLErrorHandler::Dispatch(
+    const base::Callback<WebContents*(void)>& web_contents_getter) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  WebContents* web_contents = NULL;
-  RenderFrameHost* render_frame_host =
-      RenderFrameHost::FromID(render_process_id_, render_frame_id_);
-  web_contents = WebContents::FromRenderFrameHost(render_frame_host);
+  WebContents* web_contents = web_contents_getter.Run();
 
   if (!web_contents) {
     // We arrived on the UI thread, but the tab we're looking for is no longer
@@ -116,6 +110,11 @@
       base::Bind(&SSLErrorHandler::CompleteTakeNoAction, this));
 }
 
+SSLManager* SSLErrorHandler::GetManager() const {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return manager_;
+}
+
 void SSLErrorHandler::CompleteCancelRequest(int error) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
diff --git a/content/browser/ssl/ssl_error_handler.h b/content/browser/ssl/ssl_error_handler.h
index 26fc147..3596d47 100644
--- a/content/browser/ssl/ssl_error_handler.h
+++ b/content/browser/ssl/ssl_error_handler.h
@@ -25,6 +25,7 @@
 class ResourceDispatcherHostImpl;
 class SSLCertErrorHandler;
 class SSLManager;
+class WebContents;
 
 // An SSLErrorHandler carries information from the IO thread to the UI thread
 // and is dispatched to the appropriate SSLManager when it arrives on the
@@ -65,7 +66,7 @@
   // this error.
   //
   // Call on UI thread.
-  void Dispatch();
+  void Dispatch(const base::Callback<WebContents*(void)>& web_contents_getter);
 
   // Available on either thread.
   const GURL& request_url() const { return request_url_; }
@@ -96,8 +97,9 @@
   // call this.
   void TakeNoAction();
 
-  int render_process_id() const { return render_process_id_; }
-  int render_frame_id() const { return render_frame_id_; }
+  // Returns the manager associated with this SSLErrorHandler.
+  // Should only be accessed on the UI thread.
+  SSLManager* GetManager() const;
 
  protected:
   friend class base::RefCountedThreadSafe<SSLErrorHandler>;
@@ -105,9 +107,7 @@
   // Construct on the IO thread.
   SSLErrorHandler(const base::WeakPtr<Delegate>& delegate,
                   ResourceType resource_type,
-                  const GURL& url,
-                  int render_process_id,
-                  int render_frame_id);
+                  const GURL& url);
 
   virtual ~SSLErrorHandler();
 
@@ -137,11 +137,6 @@
   // Call on the IO thread.
   void CompleteTakeNoAction();
 
-  // We use these members to find the correct SSLManager when we arrive on
-  // the UI thread.
-  int render_process_id_;
-  int render_frame_id_;
-
   // The URL that we requested.
   // This read-only member can be accessed on any thread.
   const GURL request_url_;
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index e4c71e3..cd6c2bea 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -51,8 +51,7 @@
     const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
     const ResourceType resource_type,
     const GURL& url,
-    int render_process_id,
-    int render_frame_id,
+    const base::Callback<WebContents*(void)>& web_contents_getter,
     const net::SSLInfo& ssl_info,
     bool fatal) {
   DCHECK(delegate.get());
@@ -60,8 +59,6 @@
            << net::MapCertStatusToNetError(ssl_info.cert_status)
            << " resource_type: " << resource_type
            << " url: " << url.spec()
-           << " render_process_id: " << render_process_id
-           << " render_frame_id: " << render_frame_id
            << " cert_status: " << std::hex << ssl_info.cert_status;
 
   // A certificate error occurred.  Construct a SSLCertErrorHandler object and
@@ -69,13 +66,23 @@
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&SSLCertErrorHandler::Dispatch,
-                 new SSLCertErrorHandler(delegate,
-                                         resource_type,
-                                         url,
-                                         render_process_id,
-                                         render_frame_id,
-                                         ssl_info,
-                                         fatal)));
+                 new SSLCertErrorHandler(delegate, resource_type, url, ssl_info,
+                                         fatal),
+                 web_contents_getter));
+}
+
+// static
+void SSLManager::OnSSLCertificateSubresourceError(
+    const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
+    const GURL& url,
+    int render_process_id,
+    int render_frame_id,
+    const net::SSLInfo& ssl_info,
+    bool fatal) {
+  OnSSLCertificateError(delegate, RESOURCE_TYPE_SUB_RESOURCE, url,
+                        base::Bind(&WebContentsImpl::FromRenderFrameHostID,
+                                   render_process_id, render_frame_id),
+                        ssl_info, fatal);
 }
 
 // static
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h
index 8128ee8..6e46705 100644
--- a/content/browser/ssl/ssl_manager.h
+++ b/content/browser/ssl/ssl_manager.h
@@ -52,6 +52,16 @@
       const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
       ResourceType resource_type,
       const GURL& url,
+      const base::Callback<WebContents*(void)>& web_contents_getter,
+      const net::SSLInfo& ssl_info,
+      bool fatal);
+
+  // Same as the above, and only works for subresources. Prefer using
+  // OnSSLCertificateError whenever possible (ie when you have access to the
+  // WebContents).
+  static void OnSSLCertificateSubresourceError(
+      const base::WeakPtr<SSLErrorHandler::Delegate>& delegate,
+      const GURL& url,
       int render_process_id,
       int render_frame_id,
       const net::SSLInfo& ssl_info,
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index dab2a5a..ed8d80b3 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -232,17 +232,11 @@
   CertificateRequestResultType result =
       CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE;
   GetContentClient()->browser()->AllowCertificateError(
-      handler->render_process_id(),
-      handler->render_frame_id(),
-      handler->cert_error(),
-      handler->ssl_info(),
-      handler->request_url(),
-      handler->resource_type(),
-      overridable,
-      strict_enforcement,
+      handler->GetManager()->controller()->GetWebContents(),
+      handler->cert_error(), handler->ssl_info(), handler->request_url(),
+      handler->resource_type(), overridable, strict_enforcement,
       expired_previous_decision,
-      base::Bind(&SSLPolicy::OnAllowCertificate,
-                 base::Unretained(this),
+      base::Bind(&SSLPolicy::OnAllowCertificate, base::Unretained(this),
                  make_scoped_refptr(handler)),
       &result);
   switch (result) {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index f768020..c36e3a7 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -566,6 +566,18 @@
       WebContents::FromRenderFrameHost(frame_tree_node->current_frame_host()));
 }
 
+// static
+WebContents* WebContentsImpl::FromRenderFrameHostID(int render_process_host_id,
+                                                    int render_frame_host_id) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  RenderFrameHost* render_frame_host =
+      RenderFrameHost::FromID(render_process_host_id, render_frame_host_id);
+  if (!render_frame_host)
+    return nullptr;
+
+  return WebContents::FromRenderFrameHost(render_frame_host);
+}
+
 RenderFrameHostManager* WebContentsImpl::GetRenderManagerForTesting() {
   return GetRenderManager();
 }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index b397bd7b..8d55780 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -113,6 +113,8 @@
   static std::vector<WebContentsImpl*> GetAllWebContents();
 
   static WebContentsImpl* FromFrameTreeNode(FrameTreeNode* frame_tree_node);
+  static WebContents* FromRenderFrameHostID(int render_process_host_id,
+                                            int render_frame_host_id);
 
   // Creates a swapped out RenderView. This is used by the browser plugin to
   // create a swapped out RenderView in the embedder render process for the