Reland of Downgrade lock icon for broken-HTTPS subresources (patchset #2 id:300001 of https://codereview.chromium.org/1497423002/ )

Reason for revert:
Relanding since the speculative revert didn't seem to help with crbug.com/565540

Original issue's description:
> Revert of Downgrade lock icon for broken-HTTPS subresources (patchset #11 id:200001 of https://codereview.chromium.org/1415923015/ )
>
> Reason for revert:
> Speculatively reverting to see if it makes https://code.google.com/p/chromium/issues/detail?id=565540 go away
>
> Note that this revert preserves the histogrammed
> bad_message.h value that was added in CL 1415923015
>
> Original issue's description:
> > Downgrade lock icon for broken-HTTPS subresources
> >
> > This CL attaches a boolean to resource responses to indicate if they
> > have certificate errors. If Blink sees a resource with a cert error, it
> > notifies the renderer via FrameLoaderClient, who then notifies the
> > browser, who treats the situation like mixed content.
> >
> > The browser (//content) ignores subresources with cert errors on HTTP
> > pages, and subresources with the same cert errors as the main
> > resource. This allows embedders to distinguish broken-HTTPS foo.com with
> > a subresource from broken-HTTPS bar.com and broken-HTTPS foo.com with a
> > subresource from broken-HTTPS foo.com.
> >
> > BUG=477868
> >
> > Committed: https://crrev.com/8bfb78c859ab5993eada6db30e4de50aa7403f1c
> > Cr-Commit-Position: refs/heads/master@{#362246}
>
> [email protected],[email protected],[email protected]
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=477868
>
> Committed: https://crrev.com/51ea371ad45bb5887dacf7fca6fe0feef8941262
> Cr-Commit-Position: refs/heads/master@{#363388}

[email protected],[email protected],[email protected]
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=477868

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

Cr-Commit-Position: refs/heads/master@{#364152}
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 6238b25..e8a404f 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -115,6 +115,9 @@
     GetSSLStatusForRequest(request->url(), request->ssl_info(),
                            info->GetChildID(), &ssl_status);
     response->head.security_info = SerializeSecurityInfo(ssl_status);
+    response->head.has_major_certificate_errors =
+        net::IsCertStatusError(ssl_status.cert_status) &&
+        !net::IsCertStatusMinorError(ssl_status.cert_status);
   } else {
     // We should not have any SSL state.
     DCHECK(!request->ssl_info().cert_status);
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index cd6c2bea..c1b42f0 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -134,11 +134,7 @@
   NotifyDidChangeVisibleSSLState();
 }
 
-void SSLManager::DidDisplayInsecureContent() {
-  UpdateEntry(controller_->GetLastCommittedEntry());
-}
-
-void SSLManager::DidRunInsecureContent(const std::string& security_origin) {
+void SSLManager::DidRunInsecureContent(const GURL& security_origin) {
   NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
   policy()->DidRunInsecureContent(navigation_entry, security_origin);
   UpdateEntry(navigation_entry);
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h
index 6e46705..fb31a25 100644
--- a/content/browser/ssl/ssl_manager.h
+++ b/content/browser/ssl/ssl_manager.h
@@ -31,6 +31,7 @@
 struct LoadFromMemoryCacheDetails;
 struct ResourceRedirectDetails;
 struct ResourceRequestDetails;
+struct SSLStatus;
 
 // The SSLManager SSLManager controls the SSL UI elements in a WebContents.  It
 // listens for various events that influence when these elements should or
@@ -88,8 +89,7 @@
   void DidReceiveResourceRedirect(const ResourceRedirectDetails& details);
 
   // Insecure content entry point.
-  void DidDisplayInsecureContent();
-  void DidRunInsecureContent(const std::string& security_origin);
+  void DidRunInsecureContent(const GURL& security_origin);
 
  private:
   // Updates the NavigationEntry with our current state. This will
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index ed8d80b3..06677dc 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -105,7 +105,7 @@
 }
 
 void SSLPolicy::DidRunInsecureContent(NavigationEntryImpl* entry,
-                                      const std::string& security_origin) {
+                                      const GURL& security_origin) {
   if (!entry)
     return;
 
@@ -113,20 +113,16 @@
   if (!site_instance)
       return;
 
-  backend_->HostRanInsecureContent(GURL(security_origin).host(),
+  backend_->HostRanInsecureContent(security_origin.host(),
                                    site_instance->GetProcess()->GetID());
 }
 
 void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
-  // TODO(abarth): This mechanism is wrong.  What we should be doing is sending
-  // this information back through WebKit and out some FrameLoaderClient
-  // methods.
-
-  if (net::IsCertStatusError(info->ssl_cert_status())) {
-    backend_->HostRanInsecureContent(info->url().host(), info->child_id());
-  } else if (info->ssl_cert_id() && info->url().SchemeIsCryptographic()) {
-    // If the scheme is https: or wss: *and* the security info for the cert has
-    // been set (i.e. the cert id is not 0), revoke any previous decisions that
+  if (info->ssl_cert_id() && info->url().SchemeIsCryptographic() &&
+      !net::IsCertStatusError(info->ssl_cert_status())) {
+    // If the scheme is https: or wss: *and* the security info for the
+    // cert has been set (i.e. the cert id is not 0) and the cert did
+    // not have any errors, revoke any previous decisions that
     // have occurred. If the cert info has not been set, do nothing since it
     // isn't known if the connection was actually a valid connection or if it
     // had a cert error.
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h
index 2855a1b..c002bfc 100644
--- a/content/browser/ssl/ssl_policy.h
+++ b/content/browser/ssl/ssl_policy.h
@@ -36,7 +36,7 @@
   void OnCertError(SSLCertErrorHandler* handler);
 
   void DidRunInsecureContent(NavigationEntryImpl* entry,
-                             const std::string& security_origin);
+                             const GURL& security_origin);
 
   // We have started a resource request with the given info.
   void OnRequestStarted(SSLRequestInfo* info);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 327617d..1ca34e2 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -632,6 +632,10 @@
                         OnDidDisplayInsecureContent)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunInsecureContent,
                         OnDidRunInsecureContent)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidDisplayContentWithCertificateErrors,
+                        OnDidDisplayContentWithCertificateErrors)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidRunContentWithCertificateErrors,
+                        OnDidRunContentWithCertificateErrors)
     IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
     IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateZoomLimits, OnUpdateZoomLimits)
     IPC_MESSAGE_HANDLER(ViewHostMsg_PageScaleFactorChanged,
@@ -3170,12 +3174,12 @@
       GetController().GetBrowserContext());
 }
 
-void WebContentsImpl::OnDidRunInsecureContent(
-    const std::string& security_origin, const GURL& target_url) {
+void WebContentsImpl::OnDidRunInsecureContent(const GURL& security_origin,
+                                              const GURL& target_url) {
   LOG(WARNING) << security_origin << " ran insecure content from "
                << target_url.possibly_invalid_spec();
   RecordAction(base::UserMetricsAction("SSL.RanInsecureContent"));
-  if (base::EndsWith(security_origin, kDotGoogleDotCom,
+  if (base::EndsWith(security_origin.spec(), kDotGoogleDotCom,
                      base::CompareCase::INSENSITIVE_ASCII))
     RecordAction(base::UserMetricsAction("SSL.RanInsecureContentGoogle"));
   controller_.ssl_manager()->DidRunInsecureContent(security_origin);
@@ -3183,6 +3187,39 @@
       GetController().GetBrowserContext());
 }
 
+void WebContentsImpl::OnDidDisplayContentWithCertificateErrors(
+    const GURL& url,
+    const std::string& security_info) {
+  SSLStatus ssl;
+  if (!DeserializeSecurityInfo(security_info, &ssl)) {
+    bad_message::ReceivedBadMessage(
+        GetRenderProcessHost(),
+        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
+    return;
+  }
+
+  displayed_insecure_content_ = true;
+  SSLManager::NotifySSLInternalStateChanged(
+      GetController().GetBrowserContext());
+}
+
+void WebContentsImpl::OnDidRunContentWithCertificateErrors(
+    const GURL& security_origin,
+    const GURL& url,
+    const std::string& security_info) {
+  SSLStatus ssl;
+  if (!DeserializeSecurityInfo(security_info, &ssl)) {
+    bad_message::ReceivedBadMessage(
+        GetRenderProcessHost(),
+        bad_message::WC_CONTENT_WITH_CERT_ERRORS_BAD_SECURITY_INFO);
+    return;
+  }
+
+  controller_.ssl_manager()->DidRunInsecureContent(security_origin);
+  SSLManager::NotifySSLInternalStateChanged(
+      GetController().GetBrowserContext());
+}
+
 void WebContentsImpl::OnDocumentLoadedInFrame() {
   if (!HasValidFrameSource())
     return;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 5ef8108..a46f717 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -837,8 +837,14 @@
                                         const std::string& mime_type,
                                         ResourceType resource_type);
   void OnDidDisplayInsecureContent();
-  void OnDidRunInsecureContent(const std::string& security_origin,
+  void OnDidRunInsecureContent(const GURL& security_origin,
                                const GURL& target_url);
+  void OnDidDisplayContentWithCertificateErrors(
+      const GURL& url,
+      const std::string& security_info);
+  void OnDidRunContentWithCertificateErrors(const GURL& security_origin,
+                                            const GURL& url,
+                                            const std::string& security_info);
   void OnDocumentLoadedInFrame();
   void OnDidFinishLoad(const GURL& url);
   void OnGoToEntryAtOffset(int offset);
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index bea6020..dbcff212 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -887,6 +887,7 @@
   response->setTextEncodingName(WebString::fromUTF8(info.charset));
   response->setExpectedContentLength(info.content_length);
   response->setSecurityInfo(info.security_info);
+  response->setHasMajorCertificateErrors(info.has_major_certificate_errors);
   response->setAppCacheID(info.appcache_id);
   response->setAppCacheManifestURL(info.appcache_manifest_url);
   response->setWasCached(!info.load_timing.request_start_time.is_null() &&
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 72d6751..f9604de 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1225,9 +1225,22 @@
 
 // Sent when the renderer runs insecure content in a secure origin.
 IPC_MESSAGE_ROUTED2(FrameHostMsg_DidRunInsecureContent,
-                    std::string /* security_origin */,
+                    GURL /* security_origin */,
                     GURL /* target URL */)
 
+// Sent when the renderer displays content that was loaded with
+// certificate errors.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_DidDisplayContentWithCertificateErrors,
+                    GURL /* resource url */,
+                    std::string /* serialized security info */)
+
+// Sent when the renderer runs content that was loaded with certificate
+// errors.
+IPC_MESSAGE_ROUTED3(FrameHostMsg_DidRunContentWithCertificateErrors,
+                    GURL /* security_origin */,
+                    GURL /* resource url */,
+                    std::string /* serialized security info */)
+
 // Response to FrameMsg_GetSavableResourceLinks.
 IPC_MESSAGE_ROUTED3(FrameHostMsg_SavableResourceLinksResponse,
                     std::vector<GURL> /* savable resource links */,
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 0c970ae..65e7f00 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -119,6 +119,7 @@
   IPC_STRUCT_TRAITS_MEMBER(mime_type)
   IPC_STRUCT_TRAITS_MEMBER(charset)
   IPC_STRUCT_TRAITS_MEMBER(security_info)
+  IPC_STRUCT_TRAITS_MEMBER(has_major_certificate_errors)
   IPC_STRUCT_TRAITS_MEMBER(content_length)
   IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
   IPC_STRUCT_TRAITS_MEMBER(appcache_id)
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index 12f1dd7..1277355 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -19,6 +19,8 @@
   new_response->head.mime_type = head.mime_type;
   new_response->head.charset = head.charset;
   new_response->head.security_info = head.security_info;
+  new_response->head.has_major_certificate_errors =
+      head.has_major_certificate_errors;
   new_response->head.content_length = head.content_length;
   new_response->head.encoded_data_length = head.encoded_data_length;
   new_response->head.appcache_id = head.appcache_id;
diff --git a/content/public/common/resource_response_info.cc b/content/public/common/resource_response_info.cc
index 1d4e304..f05ee19 100644
--- a/content/public/common/resource_response_info.cc
+++ b/content/public/common/resource_response_info.cc
@@ -10,7 +10,8 @@
 namespace content {
 
 ResourceResponseInfo::ResourceResponseInfo()
-    : content_length(-1),
+    : has_major_certificate_errors(false),
+      content_length(-1),
       encoded_data_length(-1),
       appcache_id(kAppCacheNoCacheId),
       was_fetched_via_spdy(false),
@@ -22,8 +23,7 @@
       was_fallback_required_by_service_worker(false),
       response_type_via_service_worker(
           blink::WebServiceWorkerResponseTypeDefault),
-      is_using_lofi(false) {
-}
+      is_using_lofi(false) {}
 
 ResourceResponseInfo::~ResourceResponseInfo() {
 }
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index 1a0f126..8b81f6d 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -50,6 +50,9 @@
   // response.  This may include information about the SSL connection used.
   std::string security_info;
 
+  // True if the resource was loaded in spite of certificate errors.
+  bool has_major_certificate_errors;
+
   // Content length if available. -1 if not available
   int64 content_length;
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 271720e..9e432ba9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -48,6 +48,7 @@
 #include "content/common/savable_subframe.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/common/site_isolation_policy.h"
+#include "content/common/ssl_status_serialization.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/bindings_policy.h"
@@ -575,6 +576,38 @@
       path.NormalizePathSeparatorsTo(FILE_PATH_LITERAL('/')).AsUTF8Unsafe());
 }
 
+bool IsContentWithCertificateErrorsRelevantToUI(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  content::SSLStatus ssl_status;
+  content::SSLStatus main_resource_ssl_status;
+  CHECK(DeserializeSecurityInfo(security_info, &ssl_status));
+  CHECK(DeserializeSecurityInfo(main_resource_security_info,
+                                &main_resource_ssl_status));
+
+  if (!GURL(main_resource_url).SchemeIsCryptographic())
+    return false;
+
+  // Do not handle subresource certificate errors if they are the same
+  // as errors that occured during the main page load. This compares
+  // most, but not all, fields of SSLStatus. For example, this check
+  // does not compare |content_status| because the navigation entry
+  // might have mixed content but also have the exact same SSL
+  // connection properties as the subresource, thereby making the
+  // subresource errors duplicative.
+  return (!url::Origin(GURL(url))
+               .IsSameOriginWith(url::Origin(GURL(main_resource_url))) ||
+          main_resource_ssl_status.security_style !=
+              ssl_status.security_style ||
+          main_resource_ssl_status.cert_id != ssl_status.cert_id ||
+          main_resource_ssl_status.cert_status != ssl_status.cert_status ||
+          main_resource_ssl_status.security_bits != ssl_status.security_bits ||
+          main_resource_ssl_status.connection_status !=
+              ssl_status.connection_status);
+}
+
 }  // namespace
 
 // static
@@ -3680,12 +3713,38 @@
     const blink::WebSecurityOrigin& origin,
     const blink::WebURL& target) {
   Send(new FrameHostMsg_DidRunInsecureContent(
-      routing_id_, origin.toString().utf8(), target));
+      routing_id_, GURL(origin.toString().utf8()), target));
   GetContentClient()->renderer()->RecordRapporURL(
       "ContentSettings.MixedScript.RanMixedScript",
       GURL(origin.toString().utf8()));
 }
 
+void RenderFrameImpl::didDisplayContentWithCertificateErrors(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  if (!IsContentWithCertificateErrorsRelevantToUI(
+          url, security_info, main_resource_url, main_resource_security_info)) {
+    return;
+  }
+  Send(new FrameHostMsg_DidDisplayContentWithCertificateErrors(routing_id_, url,
+                                                               security_info));
+}
+
+void RenderFrameImpl::didRunContentWithCertificateErrors(
+    const blink::WebURL& url,
+    const blink::WebCString& security_info,
+    const blink::WebURL& main_resource_url,
+    const blink::WebCString& main_resource_security_info) {
+  if (!IsContentWithCertificateErrorsRelevantToUI(
+          url, security_info, main_resource_url, main_resource_security_info)) {
+    return;
+  }
+  Send(new FrameHostMsg_DidRunContentWithCertificateErrors(
+      routing_id_, GURL(main_resource_url).GetOrigin(), url, security_info));
+}
+
 void RenderFrameImpl::didChangePerformanceTiming() {
   FOR_EACH_OBSERVER(RenderFrameObserver,
                     observers_,
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 8d3c4f39..9da61e04 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -522,6 +522,16 @@
   void didDisplayInsecureContent() override;
   void didRunInsecureContent(const blink::WebSecurityOrigin& origin,
                              const blink::WebURL& target) override;
+  void didDisplayContentWithCertificateErrors(
+      const blink::WebURL& url,
+      const blink::WebCString& security_info,
+      const blink::WebURL& main_resource_url,
+      const blink::WebCString& main_resource_security_info) override;
+  void didRunContentWithCertificateErrors(
+      const blink::WebURL& url,
+      const blink::WebCString& security_info,
+      const blink::WebURL& main_resource_url,
+      const blink::WebCString& main_resource_security_info) override;
   void didChangePerformanceTiming() override;
   void didCreateScriptContext(blink::WebLocalFrame* frame,
                               v8::Local<v8::Context> context,