Chromium Code Reviews| Index: net/cert/internal/path_builder.cc |
| diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc |
| index 36cd9d45f8d97bf2c5ae27fbec47cb9bda3ee4f4..46ff13d56a785985b71306e23161cbd81ceb90fb 100644 |
| --- a/net/cert/internal/path_builder.cc |
| +++ b/net/cert/internal/path_builder.cc |
| @@ -7,7 +7,6 @@ |
| #include <set> |
| #include <unordered_set> |
| -#include "base/callback_helpers.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "net/base/net_errors.h" |
| @@ -71,24 +70,17 @@ class CertIssuersIter { |
| CertIssuerSources* cert_issuer_sources, |
| 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 |
| - // ready, ASYNC is returned and |callback| will be called once |*out_cert| has |
| - // been set. If |callback| is null, always completes synchronously. |
| - // |
| - // In either case, if all issuers have been exhausted, |*out| is cleared. |
| - CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out, |
| - const base::Closure& callback); |
| + // Gets the next candidate issuer, or clears |*out| when all issuers have been |
| + // exhausted. |
| + void GetNextIssuer(CertificateOrTrustAnchor* out); |
| // Returns the |cert| for which issuers are being retrieved. |
| const ParsedCertificate* cert() const { return cert_.get(); } |
| scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
| private: |
| + void AddIssuers(ParsedCertificateList issuers); |
| void DoAsyncIssuerQuery(); |
| - void GotAsyncAnchors(TrustAnchors anchors); |
| - void GotAsyncCerts(CertIssuerSource::Request* request); |
| - void NotifyIfNecessary(); |
| scoped_refptr<ParsedCertificate> cert_; |
| CertIssuerSources* cert_issuer_sources_; |
| @@ -119,19 +111,12 @@ class CertIssuersIter { |
| // 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_; |
| + // If asynchronous requests were made, which ones are still outstanding? |
|
mattm
2016/10/28 02:11:55
comment is a bit confusing / indirect. maybe menti
eroman
2016/11/23 22:10:21
Done.
|
| + size_t cur_async_request_ = 0; |
| // 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 |
| - // result is ready. |
| - CertificateOrTrustAnchor* out_; |
| - base::Closure callback_; |
| DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
| }; |
| @@ -145,30 +130,15 @@ CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
| DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
| } |
| -CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| - const base::Closure& callback) { |
| - // Should not be called again while already waiting for an async result. |
| - DCHECK(callback_.is_null()); |
| - |
| +void CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out) { |
| if (!did_initial_query_) { |
| did_initial_query_ = true; |
| - trust_store_->FindTrustAnchorsForCert( |
| - cert_, |
| - callback.is_null() ? TrustStore::TrustAnchorsCallback() |
| - : base::Bind(&CertIssuersIter::GotAsyncAnchors, |
| - base::Unretained(this)), |
| - &anchors_, &pending_anchor_request_); |
| + trust_store_->FindTrustAnchorsForCert(cert_, &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)); |
| - } |
| + AddIssuers(std::move(new_issuers)); |
| } |
| DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() |
| << " sync issuers"; |
| @@ -186,15 +156,31 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| << anchors_.size(); |
| // Still have anchors that haven't been returned yet, return one of them. |
| *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); |
| - return CompletionStatus::SYNC; |
| + return; |
| } |
| - if (pending_anchor_request_) { |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << ") Still waiting for async trust anchor results."; |
| - out_ = out; |
| - callback_ = callback; |
| - return CompletionStatus::ASYNC; |
| + // If there aren't any issuers left, block until async results are ready. |
| + if (cur_issuer_ >= issuers_.size()) { |
| + if (!did_async_issuer_query_) { |
| + // Now issue request(s) for async ones (AIA, etc). |
| + DoAsyncIssuerQuery(); |
| + } |
| + |
| + // TODO(eroman): Rather than blocking on the async requests in FIFO order, |
| + // consume in the order they become ready. |
| + while (cur_async_request_ < pending_async_requests_.size()) { |
| + ParsedCertificateList new_issuers; |
| + pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); |
| + if (new_issuers.empty()) { |
| + // Request is exhausted, no more results pending from that |
| + // CertIssuerSource. |
| + pending_async_requests_[cur_async_request_++].reset(); |
| + continue; |
| + } |
| + |
| + AddIssuers(std::move(new_issuers)); |
| + break; |
| + } |
| } |
| if (cur_issuer_ < issuers_.size()) { |
| @@ -205,148 +191,40 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| // A reference to the returned issuer is retained, since |present_issuers_| |
| // points to data owned by it. |
| *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); |
| - return CompletionStatus::SYNC; |
| - } |
| - |
| - if (did_async_issuer_query_) { |
| - if (pending_async_results_ == 0) { |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << ") Reached the end of all available issuers."; |
| - // Reached the end of all available issuers. |
| - *out = CertificateOrTrustAnchor(); |
| - return CompletionStatus::SYNC; |
| - } |
| - |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << ") Still waiting for async results from other " |
| - "CertIssuerSources."; |
| - // Still waiting for async results from other CertIssuerSources. |
| - out_ = out; |
| - callback_ = callback; |
| - return CompletionStatus::ASYNC; |
| + return; |
| } |
| - // Reached the end of synchronously gathered issuers. |
| - if (callback.is_null()) { |
| - // Synchronous-only mode, don't try to query async sources. |
| - *out = CertificateOrTrustAnchor(); |
| - return CompletionStatus::SYNC; |
| - } |
| - |
| - // Now issue request(s) for async ones (AIA, etc). |
| - DoAsyncIssuerQuery(); |
| + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| + << ") Reached the end of all available issuers."; |
| + // Reached the end of all available issuers. |
| + *out = CertificateOrTrustAnchor(); |
| +} |
| - 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::AddIssuers(ParsedCertificateList 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) << "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; |
| + cur_async_request_ = 0; |
| for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| std::unique_ptr<CertIssuerSource::Request> request; |
| - cert_issuer_source->AsyncGetIssuersOf( |
| - cert(), |
| - base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), |
| - &request); |
| + cert_issuer_source->AsyncGetIssuersOf(cert(), &request); |
| if (request) { |
| DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
| << ") pending..."; |
| - pending_async_results_++; |
| pending_async_requests_.push_back(std::move(request)); |
| } |
| } |
| } |
| -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(); |
| - |
| - NotifyIfNecessary(); |
| -} |
| - |
| -void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { |
| - DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) |
| - << ")"; |
| - while (true) { |
| - scoped_refptr<ParsedCertificate> cert; |
| - CompletionStatus status = request->GetNext(&cert); |
| - if (!cert) { |
| - if (status == CompletionStatus::SYNC) { |
| - // Request is exhausted, no more results pending from that |
| - // CertIssuerSource. |
| - DCHECK_GT(pending_async_results_, 0U); |
| - pending_async_results_--; |
| - } |
| - break; |
| - } |
| - DCHECK_EQ(status, CompletionStatus::SYNC); |
| - if (present_issuers_.find(cert->der_cert().AsStringPiece()) != |
| - present_issuers_.end()) |
| - continue; |
| - present_issuers_.insert(cert->der_cert().AsStringPiece()); |
| - issuers_.push_back(std::move(cert)); |
| - } |
| - |
| - // 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()) { |
| - 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 issuer " << cur_issuer_ << " of " |
| - << issuers_.size(); |
| - *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); |
| - base::ResetAndReturn(&callback_).Run(); |
| - 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(); |
| - return; |
| - } |
| - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| - << "): empty result, but other async results " |
| - "pending, waiting.."; |
| - } |
| -} |
| - |
| // CertIssuerIterPath tracks which certs are present in the path and prevents |
| // paths from being built which repeat any certs (including different versions |
| // of the same cert, based on Subject+SubjectAltName+SPKI). |
| @@ -446,11 +324,9 @@ class CertPathIter { |
| // CertPathIter. |
| void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); |
| - // Gets the next candidate path. If a path is ready synchronously, SYNC is |
| - // returned and the path is stored in |*path|. If a path is not ready, |
| - // ASYNC is returned and |callback| will be called once |*path| has been set. |
| - // In either case, if all paths have been exhausted, |*path| is cleared. |
| - CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback); |
| + // Gets the next candidate path, or clears |*path| when all paths have been |
| + // exhausted. |
| + void GetNextPath(CertPath* path); |
| private: |
| enum State { |
| @@ -461,13 +337,9 @@ class CertPathIter { |
| STATE_BACKTRACK, |
| }; |
| - CompletionStatus DoLoop(bool allow_async); |
| - |
| - CompletionStatus DoGetNextIssuer(bool allow_async); |
| - CompletionStatus DoGetNextIssuerComplete(); |
| - CompletionStatus DoBackTrack(); |
| - |
| - void HandleGotNextIssuer(void); |
| + void DoGetNextIssuer(); |
| + void DoGetNextIssuerComplete(); |
| + void DoBackTrack(); |
| // Stores the next candidate issuer, until it is used during the |
| // STATE_GET_NEXT_ISSUER_COMPLETE step. |
| @@ -483,8 +355,6 @@ class CertPathIter { |
| // The output variable for storing the next candidate path, which the client |
| // passes in to GetNextPath. Only used for a single path output. |
| CertPath* out_path_; |
| - // The callback to be called if an async lookup generated a candidate path. |
| - base::Closure callback_; |
| // Current state of the state machine. |
| State next_state_; |
| @@ -501,22 +371,10 @@ void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
| cert_issuer_sources_.push_back(cert_issuer_source); |
| } |
| -CompletionStatus CertPathIter::GetNextPath(CertPath* path, |
| - const base::Closure& callback) { |
| +// TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
| +void CertPathIter::GetNextPath(CertPath* path) { |
| out_path_ = path; |
| out_path_->Clear(); |
| - CompletionStatus rv = DoLoop(!callback.is_null()); |
| - if (rv == CompletionStatus::ASYNC) { |
| - callback_ = callback; |
| - } else { |
| - // Clear the reference to the output parameter as a precaution. |
| - out_path_ = nullptr; |
| - } |
| - return rv; |
| -} |
| - |
| -CompletionStatus CertPathIter::DoLoop(bool allow_async) { |
| - CompletionStatus result = CompletionStatus::SYNC; |
| do { |
| State state = next_state_; |
| next_state_ = STATE_NONE; |
| @@ -525,39 +383,32 @@ CompletionStatus CertPathIter::DoLoop(bool allow_async) { |
| NOTREACHED(); |
| break; |
| case STATE_GET_NEXT_ISSUER: |
| - result = DoGetNextIssuer(allow_async); |
| + DoGetNextIssuer(); |
| break; |
| case STATE_GET_NEXT_ISSUER_COMPLETE: |
| - result = DoGetNextIssuerComplete(); |
| + DoGetNextIssuerComplete(); |
| break; |
| case STATE_RETURN_A_PATH: |
| // If the returned path did not verify, keep looking for other paths |
| // (the trust root is not part of cur_path_, so don't need to |
| // backtrack). |
| next_state_ = STATE_GET_NEXT_ISSUER; |
| - result = CompletionStatus::SYNC; |
| break; |
| case STATE_BACKTRACK: |
| - result = DoBackTrack(); |
| + DoBackTrack(); |
| break; |
| } |
| - } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && |
| - next_state_ != STATE_RETURN_A_PATH); |
| + } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); |
| - return result; |
| + out_path_ = nullptr; |
| } |
| -CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { |
| +void CertPathIter::DoGetNextIssuer() { |
| next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
| - CompletionStatus rv = cur_path_.back()->GetNextIssuer( |
| - &next_issuer_, allow_async |
| - ? base::Bind(&CertPathIter::HandleGotNextIssuer, |
| - base::Unretained(this)) |
| - : base::Closure()); |
| - return rv; |
| + cur_path_.back()->GetNextIssuer(&next_issuer_); |
| } |
| -CompletionStatus CertPathIter::DoGetNextIssuerComplete() { |
| +void CertPathIter::DoGetNextIssuerComplete() { |
| // If the issuer is a trust anchor signal readiness. |
| if (next_issuer_.IsTrustAnchor()) { |
| DVLOG(1) << "CertPathIter got anchor(" |
| @@ -566,14 +417,14 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() { |
| cur_path_.CopyPath(&out_path_->certs); |
| out_path_->trust_anchor = std::move(next_issuer_.anchor); |
| next_issuer_ = CertificateOrTrustAnchor(); |
| - return CompletionStatus::SYNC; |
| + return; |
| } |
| if (next_issuer_.IsCertificate()) { |
| // Skip this cert if it is already in the chain. |
| if (cur_path_.IsPresent(next_issuer_.cert.get())) { |
| next_state_ = STATE_GET_NEXT_ISSUER; |
| - return CompletionStatus::SYNC; |
| + return; |
| } |
| cur_path_.Append(base::MakeUnique<CertIssuersIter>( |
| @@ -590,10 +441,9 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() { |
| // more for the previous cert. |
| next_state_ = STATE_BACKTRACK; |
| } |
| - return CompletionStatus::SYNC; |
| } |
| -CompletionStatus CertPathIter::DoBackTrack() { |
| +void CertPathIter::DoBackTrack() { |
| DVLOG(1) << "CertPathIter backtracking..."; |
| cur_path_.Pop(); |
| if (cur_path_.Empty()) { |
| @@ -603,17 +453,6 @@ CompletionStatus CertPathIter::DoBackTrack() { |
| // Continue exploring issuers of the previous path. |
| next_state_ = STATE_GET_NEXT_ISSUER; |
| } |
| - return CompletionStatus::SYNC; |
| -} |
| - |
| -void CertPathIter::HandleGotNextIssuer(void) { |
| - DCHECK(!callback_.is_null()); |
| - CompletionStatus rv = DoLoop(true /* allow_async */); |
| - if (rv == CompletionStatus::SYNC) { |
| - // Clear the reference to the output parameter as a precaution. |
| - out_path_ = nullptr; |
| - base::ResetAndReturn(&callback_).Run(); |
| - } |
| } |
| CertPathBuilder::ResultPath::ResultPath() = default; |
| @@ -658,19 +497,10 @@ void CertPathBuilder::AddCertIssuerSource( |
| cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
| } |
| -CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { |
| +// TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
| +void CertPathBuilder::Run() { |
| DCHECK_EQ(STATE_NONE, next_state_); |
| next_state_ = STATE_GET_NEXT_PATH; |
| - CompletionStatus rv = DoLoop(!callback.is_null()); |
| - |
| - if (rv == CompletionStatus::ASYNC) |
| - callback_ = callback; |
| - |
| - return rv; |
| -} |
| - |
| -CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { |
| - CompletionStatus result = CompletionStatus::SYNC; |
| do { |
| State state = next_state_; |
| @@ -680,38 +510,25 @@ CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { |
| NOTREACHED(); |
| break; |
| case STATE_GET_NEXT_PATH: |
| - result = DoGetNextPath(allow_async); |
| + DoGetNextPath(); |
| break; |
| case STATE_GET_NEXT_PATH_COMPLETE: |
| - result = DoGetNextPathComplete(); |
| + DoGetNextPathComplete(); |
| break; |
| } |
| - } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE); |
| - |
| - return result; |
| + } while (next_state_ != STATE_NONE); |
| } |
| -CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) { |
| +void CertPathBuilder::DoGetNextPath() { |
| next_state_ = STATE_GET_NEXT_PATH_COMPLETE; |
| - CompletionStatus rv = cert_path_iter_->GetNextPath( |
| - &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath, |
| - base::Unretained(this)) |
| - : base::Closure()); |
| - return rv; |
| -} |
| - |
| -void CertPathBuilder::HandleGotNextPath() { |
| - DCHECK(!callback_.is_null()); |
| - CompletionStatus rv = DoLoop(true /* allow_async */); |
| - if (rv == CompletionStatus::SYNC) |
| - base::ResetAndReturn(&callback_).Run(); |
| + cert_path_iter_->GetNextPath(&next_path_); |
| } |
| -CompletionStatus CertPathBuilder::DoGetNextPathComplete() { |
| +void CertPathBuilder::DoGetNextPathComplete() { |
| if (next_path_.IsEmpty()) { |
| // No more paths to check, signal completion. |
| next_state_ = STATE_NONE; |
| - return CompletionStatus::SYNC; |
| + return; |
| } |
| // Verify the entire certificate chain. |
| @@ -729,14 +546,13 @@ CompletionStatus CertPathBuilder::DoGetNextPathComplete() { |
| // Found a valid path, return immediately. |
| // TODO(mattm): add debug/test mode that tries all possible paths. |
| next_state_ = STATE_NONE; |
| - return CompletionStatus::SYNC; |
| + return; |
| } |
| // Path did not verify. Try more paths. If there are no more paths, the result |
| // will be returned next time DoGetNextPathComplete is called with next_path_ |
| // empty. |
| next_state_ = STATE_GET_NEXT_PATH; |
| - return CompletionStatus::SYNC; |
| } |
| void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { |