| 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
|
|
|