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 |