| Index: net/cert/internal/path_builder.cc
 | 
| diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc
 | 
| index 10b507bc594c3849d63aa2af78c35ad8a1c5d08a..26e366410e87bfe4844dfa1715db05400bc9bbeb 100644
 | 
| --- a/net/cert/internal/path_builder.cc
 | 
| +++ b/net/cert/internal/path_builder.cc
 | 
| @@ -65,11 +65,11 @@ struct CertificateOrTrustAnchor {
 | 
|  // which may be issuers of |cert|.
 | 
|  class CertIssuersIter {
 | 
|   public:
 | 
| -  // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for
 | 
| -  // the lifetime of the CertIssuersIter.
 | 
| +  // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store|
 | 
| +  // must be valid for the lifetime of the CertIssuersIter.
 | 
|    CertIssuersIter(scoped_refptr<ParsedCertificate> cert,
 | 
|                    CertIssuerSources* cert_issuer_sources,
 | 
| -                  const TrustStore& trust_store);
 | 
| +                  const TrustStore* trust_store);
 | 
|  
 | 
|    // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC
 | 
|    // is returned and the cert is stored in |*cert|.  If an issuer is not
 | 
| @@ -85,10 +85,14 @@ class CertIssuersIter {
 | 
|    scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; }
 | 
|  
 | 
|   private:
 | 
| +  void DoAsyncIssuerQuery();
 | 
| +  void GotAsyncAnchors(TrustAnchors anchors);
 | 
|    void GotAsyncCerts(CertIssuerSource::Request* request);
 | 
| +  void NotifyIfNecessary();
 | 
|  
 | 
|    scoped_refptr<ParsedCertificate> cert_;
 | 
|    CertIssuerSources* cert_issuer_sources_;
 | 
| +  const TrustStore* trust_store_;
 | 
|  
 | 
|    // The list of trust anchors that match the issuer name for |cert_|.
 | 
|    TrustAnchors anchors_;
 | 
| @@ -112,14 +116,16 @@ class CertIssuersIter {
 | 
|    // This points to data owned by |issuers_|.
 | 
|    std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_;
 | 
|  
 | 
| -  // Tracks whether asynchronous requests have been made yet.
 | 
| -  bool did_async_query_ = false;
 | 
| +  // Tracks which requests have been made yet.
 | 
| +  bool did_initial_query_ = false;
 | 
| +  bool did_async_issuer_query_ = false;
 | 
|    // If asynchronous requests were made, how many of them are still outstanding?
 | 
|    size_t pending_async_results_;
 | 
|    // Owns the Request objects for any asynchronous requests so that they will be
 | 
|    // cancelled if CertIssuersIter is destroyed.
 | 
|    std::vector<std::unique_ptr<CertIssuerSource::Request>>
 | 
|        pending_async_requests_;
 | 
| +  std::unique_ptr<TrustStore::Request> pending_anchor_request_;
 | 
|  
 | 
|    // When GetNextIssuer was called and returned asynchronously, |*out_| is
 | 
|    // where the result will be stored, and |callback_| will be run when the
 | 
| @@ -132,28 +138,11 @@ class CertIssuersIter {
 | 
|  
 | 
|  CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert,
 | 
|                                   CertIssuerSources* cert_issuer_sources,
 | 
| -                                 const TrustStore& trust_store)
 | 
| -    : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) {
 | 
| +                                 const TrustStore* trust_store)
 | 
| +    : cert_(in_cert),
 | 
| +      cert_issuer_sources_(cert_issuer_sources),
 | 
| +      trust_store_(trust_store) {
 | 
|    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created";
 | 
| -  trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(),
 | 
| -                                               &anchors_);
 | 
| -
 | 
| -  for (auto* cert_issuer_source : *cert_issuer_sources_) {
 | 
| -    ParsedCertificateList new_issuers;
 | 
| -    cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
 | 
| -    for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
 | 
| -      if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
 | 
| -          present_issuers_.end())
 | 
| -        continue;
 | 
| -      present_issuers_.insert(issuer->der_cert().AsStringPiece());
 | 
| -      issuers_.push_back(std::move(issuer));
 | 
| -    }
 | 
| -  }
 | 
| -  // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust
 | 
| -  // anchor subject (or is a trust anchor), that should be sorted higher too.
 | 
| -  // See big list of possible sorting hints in RFC 4158.)
 | 
| -  // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that
 | 
| -  // is done)
 | 
|  }
 | 
|  
 | 
|  CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
| @@ -161,6 +150,35 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
|    // Should not be called again while already waiting for an async result.
 | 
|    DCHECK(callback_.is_null());
 | 
|  
 | 
| +  if (!did_initial_query_) {
 | 
| +    did_initial_query_ = true;
 | 
| +    trust_store_->FindTrustAnchorsForCert(
 | 
| +        cert_.get(),
 | 
| +        callback.is_null() ? TrustStore::TrustAnchorsCallback()
 | 
| +                           : base::Bind(&CertIssuersIter::GotAsyncAnchors,
 | 
| +                                        base::Unretained(this)),
 | 
| +        &anchors_, &pending_anchor_request_);
 | 
| +
 | 
| +    for (auto* cert_issuer_source : *cert_issuer_sources_) {
 | 
| +      ParsedCertificateList new_issuers;
 | 
| +      cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
 | 
| +      for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) {
 | 
| +        if (present_issuers_.find(issuer->der_cert().AsStringPiece()) !=
 | 
| +            present_issuers_.end())
 | 
| +          continue;
 | 
| +        present_issuers_.insert(issuer->der_cert().AsStringPiece());
 | 
| +        issuers_.push_back(std::move(issuer));
 | 
| +      }
 | 
| +    }
 | 
| +    DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size()
 | 
| +             << " sync issuers";
 | 
| +    // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust
 | 
| +    // anchor subject (or is a trust anchor), that should be sorted higher too.
 | 
| +    // See big list of possible sorting hints in RFC 4158.)
 | 
| +    // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that
 | 
| +    // is done)
 | 
| +  }
 | 
| +
 | 
|    // Return possible trust anchors first.
 | 
|    if (cur_anchor_ < anchors_.size()) {
 | 
|      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| @@ -171,6 +189,14 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
|      return CompletionStatus::SYNC;
 | 
|    }
 | 
|  
 | 
| +  if (pending_anchor_request_) {
 | 
| +    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| +             << ") Still waiting for async trust anchor results.";
 | 
| +    out_ = out;
 | 
| +    callback_ = callback;
 | 
| +    return CompletionStatus::ASYNC;
 | 
| +  }
 | 
| +
 | 
|    if (cur_issuer_ < issuers_.size()) {
 | 
|      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
|               << "): returning issuer " << cur_issuer_ << " of "
 | 
| @@ -181,7 +207,8 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
|      *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]);
 | 
|      return CompletionStatus::SYNC;
 | 
|    }
 | 
| -  if (did_async_query_) {
 | 
| +
 | 
| +  if (did_async_issuer_query_) {
 | 
|      if (pending_async_results_ == 0) {
 | 
|        DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
|                 << ") Reached the end of all available issuers.";
 | 
| @@ -207,7 +234,27 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
|    }
 | 
|  
 | 
|    // Now issue request(s) for async ones (AIA, etc).
 | 
| -  did_async_query_ = true;
 | 
| +  DoAsyncIssuerQuery();
 | 
| +
 | 
| +  if (pending_async_results_ == 0) {
 | 
| +    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| +             << ") No cert sources have async results.";
 | 
| +    // No cert sources have async results.
 | 
| +    *out = CertificateOrTrustAnchor();
 | 
| +    return CompletionStatus::SYNC;
 | 
| +  }
 | 
| +
 | 
| +  DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| +           << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_
 | 
| +           << ")";
 | 
| +  out_ = out;
 | 
| +  callback_ = callback;
 | 
| +  return CompletionStatus::ASYNC;
 | 
| +}
 | 
| +
 | 
| +void CertIssuersIter::DoAsyncIssuerQuery() {
 | 
| +  DCHECK(!did_async_issuer_query_);
 | 
| +  did_async_issuer_query_ = true;
 | 
|    pending_async_results_ = 0;
 | 
|    for (auto* cert_issuer_source : *cert_issuer_sources_) {
 | 
|      std::unique_ptr<CertIssuerSource::Request> request;
 | 
| @@ -222,21 +269,16 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out,
 | 
|        pending_async_requests_.push_back(std::move(request));
 | 
|      }
 | 
|    }
 | 
| +}
 | 
|  
 | 
| -  if (pending_async_results_ == 0) {
 | 
| -    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| -             << ") No cert sources have async results.";
 | 
| -    // No cert sources have async results.
 | 
| -    *out = CertificateOrTrustAnchor();
 | 
| -    return CompletionStatus::SYNC;
 | 
| -  }
 | 
| +void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) {
 | 
| +  DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert())
 | 
| +           << "): " << anchors.size() << " anchors";
 | 
| +  for (scoped_refptr<TrustAnchor>& anchor : anchors)
 | 
| +    anchors_.push_back(std::move(anchor));
 | 
| +  pending_anchor_request_.reset();
 | 
|  
 | 
| -  DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| -           << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_
 | 
| -           << ")";
 | 
| -  out_ = out;
 | 
| -  callback_ = callback;
 | 
| -  return CompletionStatus::ASYNC;
 | 
| +  NotifyIfNecessary();
 | 
|  }
 | 
|  
 | 
|  void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
 | 
| @@ -265,25 +307,43 @@ void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) {
 | 
|    // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may
 | 
|    // be more than the ones just inserted, depending on |cur_| value).
 | 
|  
 | 
| +  NotifyIfNecessary();
 | 
| +}
 | 
| +
 | 
| +void CertIssuersIter::NotifyIfNecessary() {
 | 
|    // Notify that more results are available, if necessary.
 | 
|    if (!callback_.is_null()) {
 | 
| -    DCHECK_GE(cur_anchor_, anchors_.size());
 | 
| +    if (cur_anchor_ < anchors_.size()) {
 | 
| +      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| +               << "): async returning anchor " << cur_anchor_ << " of "
 | 
| +               << anchors_.size();
 | 
| +      *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++]));
 | 
| +      base::ResetAndReturn(&callback_).Run();
 | 
| +      return;
 | 
| +    }
 | 
|      if (cur_issuer_ < issuers_.size()) {
 | 
| +      DCHECK(!pending_anchor_request_);
 | 
|        DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| -               << "): async returning item " << cur_issuer_ << " of "
 | 
| +               << "): async returning issuer " << cur_issuer_ << " of "
 | 
|                 << issuers_.size();
 | 
|        *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++]));
 | 
|        base::ResetAndReturn(&callback_).Run();
 | 
| -    } else if (pending_async_results_ == 0) {
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    if (!did_async_issuer_query_)
 | 
| +      DoAsyncIssuerQuery();
 | 
| +
 | 
| +    if (pending_async_results_ == 0) {
 | 
|        DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
|                 << "): async returning empty result";
 | 
|        *out_ = CertificateOrTrustAnchor();
 | 
|        base::ResetAndReturn(&callback_).Run();
 | 
| -    } else {
 | 
| -      DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| -               << "): empty result, but other async results "
 | 
| -                  "pending, waiting..";
 | 
| +      return;
 | 
|      }
 | 
| +    DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert())
 | 
| +             << "): empty result, but other async results "
 | 
| +                "pending, waiting..";
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -517,7 +577,7 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() {
 | 
|      }
 | 
|  
 | 
|      cur_path_.Append(base::WrapUnique(new CertIssuersIter(
 | 
| -        std::move(next_issuer_.cert), &cert_issuer_sources_, *trust_store_)));
 | 
| +        std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)));
 | 
|      next_issuer_ = CertificateOrTrustAnchor();
 | 
|      DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString();
 | 
|      // Continue descending the tree.
 | 
| 
 |