| Index: net/cert/internal/cert_issuer_source_collection.cc | 
| diff --git a/net/cert/internal/cert_issuer_source_collection.cc b/net/cert/internal/cert_issuer_source_collection.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..6be9856bd32abbfbd64e8beab349a0e6ca26bde2 | 
| --- /dev/null | 
| +++ b/net/cert/internal/cert_issuer_source_collection.cc | 
| @@ -0,0 +1,145 @@ | 
| +// Copyright 2016 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "net/cert/internal/cert_issuer_source_collection.h" | 
| + | 
| +#include <unordered_map> | 
| + | 
| +#include "base/bind.h" | 
| +#include "net/cert/internal/parsed_certificate.h" | 
| + | 
| +namespace net { | 
| + | 
| +namespace { | 
| + | 
| +using RequestSet = | 
| +    std::unordered_map<CertIssuerSource::Request*, | 
| +                       std::unique_ptr<CertIssuerSource::Request>>; | 
| + | 
| +class CollectionRequest : public CertIssuerSource::Request { | 
| + public: | 
| +  explicit CollectionRequest( | 
| +      const CertIssuerSource::IssuerCallback& issuers_callback); | 
| +  ~CollectionRequest() override; | 
| + | 
| +  // CertIssuerSource::Request implementation. | 
| +  CompletionStatus GetNext(scoped_refptr<ParsedCertificate>* out_cert) override; | 
| + | 
| +  void MakeRequest(scoped_refptr<ParsedCertificate> cert, | 
| +                   CertIssuerSource* source); | 
| +  bool has_requests() const { | 
| +    return !pending_requests_.empty() || !ready_requests_.empty(); | 
| +  } | 
| + | 
| + private: | 
| +  void OnAsyncGetIssuersOf(CertIssuerSource::Request* req); | 
| + | 
| +  CertIssuerSource::IssuerCallback issuers_callback_; | 
| + | 
| +  RequestSet pending_requests_; | 
| +  RequestSet ready_requests_; | 
| + | 
| +  DISALLOW_COPY_AND_ASSIGN(CollectionRequest); | 
| +}; | 
| + | 
| +CollectionRequest::CollectionRequest( | 
| +    const CertIssuerSource::IssuerCallback& issuers_callback) | 
| +    : issuers_callback_(issuers_callback) {} | 
| + | 
| +CollectionRequest::~CollectionRequest() = default; | 
| + | 
| +CompletionStatus CollectionRequest::GetNext( | 
| +    scoped_refptr<ParsedCertificate>* out_cert) { | 
| +  while (!ready_requests_.empty()) { | 
| +    auto it = ready_requests_.begin(); | 
| +    CompletionStatus status = it->second->GetNext(out_cert); | 
| +    if (status == CompletionStatus::ASYNC) { | 
| +      // This Request has no more results ready, but isn't done yet. Move it | 
| +      // back to the pending list. | 
| +      pending_requests_[it->first] = std::move(it->second); | 
| +      ready_requests_.erase(it); | 
| +    } else if (!*out_cert) { | 
| +      // This Request is done, remove it. | 
| +      ready_requests_.erase(it); | 
| +    } else { | 
| +      // This Request returned a result, pass it on. | 
| +      return CompletionStatus::SYNC; | 
| +    } | 
| +    // No result from that Request, loop around try another. | 
| +  } | 
| + | 
| +  *out_cert = nullptr; | 
| +  if (!pending_requests_.empty()) { | 
| +    // No results available at the moment, but there are still pending Requests. | 
| +    return CompletionStatus::ASYNC; | 
| +  } | 
| + | 
| +  // All Requests are complete. | 
| +  return CompletionStatus::SYNC; | 
| +} | 
| + | 
| +void CollectionRequest::MakeRequest(scoped_refptr<ParsedCertificate> cert, | 
| +                                    CertIssuerSource* source) { | 
| +  std::unique_ptr<CertIssuerSource::Request> req; | 
| +  source->AsyncGetIssuersOf(std::move(cert), | 
| +                            base::Bind(&CollectionRequest::OnAsyncGetIssuersOf, | 
| +                                       base::Unretained(this)), | 
| +                            &req); | 
| +  if (req) { | 
| +    CertIssuerSource::Request* req_ptr = req.get(); | 
| +    pending_requests_[req_ptr] = std::move(req); | 
| +  } | 
| +} | 
| + | 
| +void CollectionRequest::OnAsyncGetIssuersOf(CertIssuerSource::Request* req) { | 
| +  bool client_waiting_for_callback = ready_requests_.empty(); | 
| +  // Find the request which just returned some results and move it to the ready | 
| +  // list, if it isn't there already. | 
| +  auto it = pending_requests_.find(req); | 
| +  if (it != pending_requests_.end()) { | 
| +    ready_requests_[it->first] = std::move(it->second); | 
| +    pending_requests_.erase(it); | 
| +    // Notify the client that results are now available. | 
| +    if (client_waiting_for_callback) | 
| +      issuers_callback_.Run(this); | 
| +  } else { | 
| +    // If it wasn't in the pending requests, it must already be in the ready | 
| +    // requests. | 
| +    DCHECK(ready_requests_.count(req)); | 
| +  } | 
| +} | 
| + | 
| +}  // namespace | 
| + | 
| +CertIssuerSourceCollection::CertIssuerSourceCollection() = default; | 
| +CertIssuerSourceCollection::~CertIssuerSourceCollection() = default; | 
| + | 
| +void CertIssuerSourceCollection::AddSource(CertIssuerSource* source) { | 
| +  sources_.push_back(source); | 
| +} | 
| + | 
| +void CertIssuerSourceCollection::SyncGetIssuersOf( | 
| +    const ParsedCertificate* cert, | 
| +    ParsedCertificateList* issuers) { | 
| +  for (CertIssuerSource* source : sources_) | 
| +    source->SyncGetIssuersOf(cert, issuers); | 
| +} | 
| + | 
| +void CertIssuerSourceCollection::AsyncGetIssuersOf( | 
| +    scoped_refptr<ParsedCertificate> cert, | 
| +    const IssuerCallback& issuers_callback, | 
| +    std::unique_ptr<Request>* out_req) { | 
| +  std::unique_ptr<CollectionRequest> req( | 
| +      new CollectionRequest(issuers_callback)); | 
| + | 
| +  for (CertIssuerSource* source : sources_) | 
| +    req->MakeRequest(cert, source); | 
| + | 
| +  if (req->has_requests()) | 
| +    *out_req = std::move(req); | 
| +  else | 
| +    out_req->reset(); | 
| +} | 
| + | 
| +}  // namespace net | 
|  |