| Index: net/http/transport_security_state.cc | 
| diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc | 
| index 16217a0c022e9f2149c698e9b45e9b1e1b6ed9ec..fa53f738f5fee9d86b99bddcf60bb0a952f64858 100644 | 
| --- a/net/http/transport_security_state.cc | 
| +++ b/net/http/transport_security_state.cc | 
| @@ -24,6 +24,8 @@ | 
| #include "crypto/sha2.h" | 
| #include "net/base/host_port_pair.h" | 
| #include "net/cert/ct_policy_status.h" | 
| +#include "net/cert/internal/parse_ocsp.h" | 
| +#include "net/cert/ocsp_staple.h" | 
| #include "net/cert/x509_cert_types.h" | 
| #include "net/cert/x509_certificate.h" | 
| #include "net/dns/dns_util.h" | 
| @@ -155,6 +157,18 @@ bool GetHPKPReport(const HostPortPair& host_port_pair, | 
| return true; | 
| } | 
|  | 
| +std::string OCSPCertStatusToString(OCSPCertStatus::Status status) { | 
| +  switch (status) { | 
| +    case OCSPCertStatus::Status::GOOD: | 
| +      return "GOOD"; | 
| +    case OCSPCertStatus::Status::REVOKED: | 
| +      return "REVOKED"; | 
| +    case OCSPCertStatus::Status::UNKNOWN: | 
| +      return "UNKNOWN"; | 
| +  } | 
| +  return ""; | 
| +} | 
| + | 
| // Do not send a report over HTTPS to the same host that set the | 
| // pin. Such report URIs will result in loops. (A.com has a pinning | 
| // violation which results in a report being sent to A.com, which | 
| @@ -1098,6 +1112,40 @@ void TransportSecurityState::ProcessExpectCTHeader( | 
| ssl_info); | 
| } | 
|  | 
| +void TransportSecurityState::CheckExpectStaple( | 
| +    const HostPortPair& host_port_pair, | 
| +    const X509Certificate& verified_certificate, | 
| +    const X509Certificate& unverified_certificate, | 
| +    const base::Time& verify_time, | 
| +    const base::TimeDelta& max_age, | 
| +    const std::string& ocsp_response) { | 
| +  DCHECK(CalledOnValidThread()); | 
| +  if (!enable_static_expect_staple_ || !report_sender_) | 
| +    return; | 
| + | 
| +  // Check to see if the host is preloaded. | 
| +  ExpectStapleState expect_staple_state; | 
| +  if (!GetStaticExpectStapleState(host_port_pair.host(), &expect_staple_state)) | 
| +    return; | 
| + | 
| +  if (expect_staple_state.report_uri.is_empty()) | 
| +    return; | 
| + | 
| +  // Check the stapled information. | 
| +  std::unique_ptr<ExpectStapleReport> report = | 
| +      ExpectStapleReport::FromRawOCSPResponse(ocsp_response, verify_time, | 
| +                                              max_age, verified_certificate); | 
| + | 
| +  // Report on failure. | 
| +  if (report->staple_error() == ExpectStapleReport::StapleError::OK) | 
| +    return; | 
| +  std::string serialized_report; | 
| +  if (!SerializeExpectStapleReport(host_port_pair, unverified_certificate, | 
| +                                   *report, &serialized_report)) | 
| +    return; | 
| +  report_sender_->Send(expect_staple_state.report_uri, serialized_report); | 
| +} | 
| + | 
| // static | 
| void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { | 
| PreloadResult result; | 
| @@ -1141,6 +1189,40 @@ bool TransportSecurityState::CheckPublicKeyPinsImpl( | 
| validated_certificate_chain, report_status, failure_log); | 
| } | 
|  | 
| +// static | 
| +bool TransportSecurityState::SerializeExpectStapleReport( | 
| +    const HostPortPair& host_port_pair, | 
| +    const X509Certificate& unverified_certificate, | 
| +    const ExpectStapleReport& report, | 
| +    std::string* serialized_report) { | 
| +  base::DictionaryValue report_dict; | 
| +  report_dict.SetString("date-time", TimeToISO8601(report.verify_time())); | 
| +  report_dict.SetString("hostname", host_port_pair.host()); | 
| +  report_dict.SetInteger("port", host_port_pair.port()); | 
| + | 
| +  // Add the list of each stapled OCSP response | 
| +  std::unique_ptr<base::Value> ocsp_responses(new base::ListValue); | 
| +  for (const auto& staple : report.stapled_responses()) { | 
| +    std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue); | 
| +    response->SetBoolean("is-date-valid", staple.is_date_valid); | 
| +    response->SetBoolean("is-correct-certificate", | 
| +                         staple.is_correct_certificate); | 
| +    response->SetString("status", OCSPCertStatusToString(staple.status)); | 
| +    base::ListValue* responses_list = | 
| +        reinterpret_cast<base::ListValue*>(ocsp_responses.get()); | 
| +    responses_list->Append(std::move(response)); | 
| +  } | 
| +  report_dict.Set("ocsp-responses", std::move(ocsp_responses)); | 
| +  report_dict.Set("served-certificate-chain", | 
| +                  GetPEMEncodedChainAsList(&unverified_certificate)); | 
| + | 
| +  if (!base::JSONWriter::Write(report_dict, serialized_report)) { | 
| +    LOG(ERROR) << "Failed to serialize Expect-Staple report"; | 
| +    return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| bool TransportSecurityState::GetStaticDomainState(const std::string& host, | 
| STSState* sts_state, | 
| PKPState* pkp_state) const { | 
|  |