Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Unified Diff: net/base/cert_verifier.cc

Issue 9476035: Make CertVerifier a pure virtual interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Win shared fix Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/base/cert_verifier.h ('k') | net/base/cert_verifier_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/base/cert_verifier.cc
===================================================================
--- net/base/cert_verifier.cc (revision 128056)
+++ net/base/cert_verifier.cc (working copy)
@@ -4,499 +4,12 @@
#include "net/base/cert_verifier.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/metrics/histogram.h"
-#include "base/stl_util.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "base/threading/worker_pool.h"
-#include "net/base/crl_set.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/x509_certificate.h"
-#include "net/base/x509_certificate_net_log_param.h"
+#include "net/base/multi_threaded_cert_verifier.h"
-#if defined(USE_NSS)
-#include <private/pprthred.h> // PR_DetachThread
-#endif
-
namespace net {
-////////////////////////////////////////////////////////////////////////////
-
-// Life of a request:
-//
-// CertVerifier CertVerifierJob CertVerifierWorker Request
-// | (origin loop) (worker loop)
-// |
-// Verify()
-// |---->-------------------<creates>
-// |
-// |---->----<creates>
-// |
-// |---->---------------------------------------------------<creates>
-// |
-// |---->--------------------Start
-// | |
-// | PostTask
-// |
-// | <starts verifying>
-// |---->-----AddRequest |
-// |
-// |
-// |
-// Finish
-// |
-// PostTask
-//
-// |
-// DoReply
-// |----<-----------------------|
-// HandleResult
-// |
-// |---->-----HandleResult
-// |
-// |------>-----------------------------------Post
-//
-//
-//
-// On a cache hit, CertVerifier::Verify() returns synchronously without
-// posting a task to a worker thread.
-
-namespace {
-
-// The default value of max_cache_entries_.
-const unsigned kMaxCacheEntries = 256;
-
-// The number of seconds for which we'll cache a cache entry.
-const unsigned kTTLSecs = 1800; // 30 minutes.
-
-} // namespace
-
-CertVerifier::CachedResult::CachedResult() : error(ERR_FAILED) {}
-
-CertVerifier::CachedResult::~CachedResult() {}
-
-// Represents the output and result callback of a request.
-class CertVerifierRequest {
- public:
- CertVerifierRequest(const CompletionCallback& callback,
- CertVerifyResult* verify_result,
- const BoundNetLog& net_log)
- : callback_(callback),
- verify_result_(verify_result),
- net_log_(net_log) {
- net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST, NULL);
- }
-
- ~CertVerifierRequest() {
- }
-
- // Ensures that the result callback will never be made.
- void Cancel() {
- callback_.Reset();
- verify_result_ = NULL;
- net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST, NULL);
- }
-
- // Copies the contents of |verify_result| to the caller's
- // CertVerifyResult and calls the callback.
- void Post(const CertVerifier::CachedResult& verify_result) {
- if (!callback_.is_null()) {
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_REQUEST, NULL);
- *verify_result_ = verify_result.result;
- callback_.Run(verify_result.error);
- }
- delete this;
- }
-
- bool canceled() const { return callback_.is_null(); }
-
- const BoundNetLog& net_log() const { return net_log_; }
-
- private:
- CompletionCallback callback_;
- CertVerifyResult* verify_result_;
- const BoundNetLog net_log_;
-};
-
-
-// CertVerifierWorker runs on a worker thread and takes care of the blocking
-// process of performing the certificate verification. Deletes itself
-// eventually if Start() succeeds.
-class CertVerifierWorker {
- public:
- CertVerifierWorker(X509Certificate* cert,
- const std::string& hostname,
- int flags,
- CRLSet* crl_set,
- CertVerifier* cert_verifier)
- : cert_(cert),
- hostname_(hostname),
- flags_(flags),
- crl_set_(crl_set),
- origin_loop_(MessageLoop::current()),
- cert_verifier_(cert_verifier),
- canceled_(false),
- error_(ERR_FAILED) {
- }
-
- // Returns the certificate being verified. May only be called /before/
- // Start() is called.
- X509Certificate* certificate() const { return cert_; }
-
- bool Start() {
- DCHECK_EQ(MessageLoop::current(), origin_loop_);
-
- return base::WorkerPool::PostTask(
- FROM_HERE, base::Bind(&CertVerifierWorker::Run, base::Unretained(this)),
- true /* task is slow */);
- }
-
- // Cancel is called from the origin loop when the CertVerifier is getting
- // deleted.
- void Cancel() {
- DCHECK_EQ(MessageLoop::current(), origin_loop_);
- base::AutoLock locked(lock_);
- canceled_ = true;
- }
-
- private:
- void Run() {
- // Runs on a worker thread.
- error_ = cert_->Verify(hostname_, flags_, crl_set_, &verify_result_);
-#if defined(USE_NSS)
- // Detach the thread from NSPR.
- // Calling NSS functions attaches the thread to NSPR, which stores
- // the NSPR thread ID in thread-specific data.
- // The threads in our thread pool terminate after we have called
- // PR_Cleanup. Unless we detach them from NSPR, net_unittests gets
- // segfaults on shutdown when the threads' thread-specific data
- // destructors run.
- PR_DetachThread();
-#endif
- Finish();
- }
-
- // DoReply runs on the origin thread.
- void DoReply() {
- DCHECK_EQ(MessageLoop::current(), origin_loop_);
- {
- // We lock here because the worker thread could still be in Finished,
- // after the PostTask, but before unlocking |lock_|. If we do not lock in
- // this case, we will end up deleting a locked Lock, which can lead to
- // memory leaks or worse errors.
- base::AutoLock locked(lock_);
- if (!canceled_) {
- cert_verifier_->HandleResult(cert_, hostname_, flags_,
- error_, verify_result_);
- }
- }
- delete this;
- }
-
- void Finish() {
- // Runs on the worker thread.
- // We assume that the origin loop outlives the CertVerifier. If the
- // CertVerifier is deleted, it will call Cancel on us. If it does so
- // before the Acquire, we'll delete ourselves and return. If it's trying to
- // do so concurrently, then it'll block on the lock and we'll call PostTask
- // while the CertVerifier (and therefore the MessageLoop) is still alive.
- // If it does so after this function, we assume that the MessageLoop will
- // process pending tasks. In which case we'll notice the |canceled_| flag
- // in DoReply.
-
- bool canceled;
- {
- base::AutoLock locked(lock_);
- canceled = canceled_;
- if (!canceled) {
- origin_loop_->PostTask(
- FROM_HERE, base::Bind(
- &CertVerifierWorker::DoReply, base::Unretained(this)));
- }
- }
-
- if (canceled)
- delete this;
- }
-
- scoped_refptr<X509Certificate> cert_;
- const std::string hostname_;
- const int flags_;
- scoped_refptr<CRLSet> crl_set_;
- MessageLoop* const origin_loop_;
- CertVerifier* const cert_verifier_;
-
- // lock_ protects canceled_.
- base::Lock lock_;
-
- // If canceled_ is true,
- // * origin_loop_ cannot be accessed by the worker thread,
- // * cert_verifier_ cannot be accessed by any thread.
- bool canceled_;
-
- int error_;
- CertVerifyResult verify_result_;
-
- DISALLOW_COPY_AND_ASSIGN(CertVerifierWorker);
-};
-
-// A CertVerifierJob is a one-to-one counterpart of a CertVerifierWorker. It
-// lives only on the CertVerifier's origin message loop.
-class CertVerifierJob {
- public:
- CertVerifierJob(CertVerifierWorker* worker,
- const BoundNetLog& net_log)
- : start_time_(base::TimeTicks::Now()),
- worker_(worker),
- net_log_(net_log) {
- scoped_refptr<NetLog::EventParameters> params(
- new X509CertificateNetLogParam(worker_->certificate()));
- net_log_.BeginEvent(NetLog::TYPE_CERT_VERIFIER_JOB, params);
- }
-
- ~CertVerifierJob() {
- if (worker_) {
- net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_JOB, NULL);
- worker_->Cancel();
- DeleteAllCanceled();
- }
- }
-
- void AddRequest(CertVerifierRequest* request) {
- request->net_log().AddEvent(
- NetLog::TYPE_CERT_VERIFIER_REQUEST_BOUND_TO_JOB,
- make_scoped_refptr(new NetLogSourceParameter(
- "source_dependency", net_log_.source())));
-
- requests_.push_back(request);
- }
-
- void HandleResult(const CertVerifier::CachedResult& verify_result) {
- worker_ = NULL;
- net_log_.EndEvent(NetLog::TYPE_CERT_VERIFIER_JOB, NULL);
- UMA_HISTOGRAM_CUSTOM_TIMES("Net.CertVerifier_Job_Latency",
- base::TimeTicks::Now() - start_time_,
- base::TimeDelta::FromMilliseconds(1),
- base::TimeDelta::FromMinutes(10),
- 100);
- PostAll(verify_result);
- }
-
- private:
- void PostAll(const CertVerifier::CachedResult& verify_result) {
- std::vector<CertVerifierRequest*> requests;
- requests_.swap(requests);
-
- for (std::vector<CertVerifierRequest*>::iterator
- i = requests.begin(); i != requests.end(); i++) {
- (*i)->Post(verify_result);
- // Post() causes the CertVerifierRequest to delete itself.
- }
- }
-
- void DeleteAllCanceled() {
- for (std::vector<CertVerifierRequest*>::iterator
- i = requests_.begin(); i != requests_.end(); i++) {
- if ((*i)->canceled()) {
- delete *i;
- } else {
- LOG(DFATAL) << "CertVerifierRequest leaked!";
- }
- }
- }
-
- const base::TimeTicks start_time_;
- std::vector<CertVerifierRequest*> requests_;
- CertVerifierWorker* worker_;
- const BoundNetLog net_log_;
-};
-
-CertVerifier::CertVerifier()
- : cache_(kMaxCacheEntries),
- requests_(0),
- cache_hits_(0),
- inflight_joins_(0) {
- CertDatabase::AddObserver(this);
+CertVerifier* CertVerifier::CreateDefault() {
+ return new MultiThreadedCertVerifier();
}
-CertVerifier::~CertVerifier() {
- STLDeleteValues(&inflight_);
-
- CertDatabase::RemoveObserver(this);
-}
-
-int CertVerifier::Verify(X509Certificate* cert,
- const std::string& hostname,
- int flags,
- CRLSet* crl_set,
- CertVerifyResult* verify_result,
- const CompletionCallback& callback,
- RequestHandle* out_req,
- const BoundNetLog& net_log) {
- DCHECK(CalledOnValidThread());
-
- if (callback.is_null() || !verify_result || hostname.empty()) {
- *out_req = NULL;
- return ERR_INVALID_ARGUMENT;
- }
-
- requests_++;
-
- const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(),
- hostname, flags);
- const CertVerifierCache::value_type* cached_entry =
- cache_.Get(key, base::TimeTicks::Now());
- if (cached_entry) {
- ++cache_hits_;
- *out_req = NULL;
- *verify_result = cached_entry->result;
- return cached_entry->error;
- }
-
- // No cache hit. See if an identical request is currently in flight.
- CertVerifierJob* job;
- std::map<RequestParams, CertVerifierJob*>::const_iterator j;
- j = inflight_.find(key);
- if (j != inflight_.end()) {
- // An identical request is in flight already. We'll just attach our
- // callback.
- inflight_joins_++;
- job = j->second;
- } else {
- // Need to make a new request.
- CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags,
- crl_set, this);
- job = new CertVerifierJob(
- worker,
- BoundNetLog::Make(net_log.net_log(), NetLog::SOURCE_CERT_VERIFIER_JOB));
- if (!worker->Start()) {
- delete job;
- delete worker;
- *out_req = NULL;
- // TODO(wtc): log to the NetLog.
- LOG(ERROR) << "CertVerifierWorker couldn't be started.";
- return ERR_INSUFFICIENT_RESOURCES; // Just a guess.
- }
- inflight_.insert(std::make_pair(key, job));
- }
-
- CertVerifierRequest* request =
- new CertVerifierRequest(callback, verify_result, net_log);
- job->AddRequest(request);
- *out_req = request;
- return ERR_IO_PENDING;
-}
-
-void CertVerifier::CancelRequest(RequestHandle req) {
- DCHECK(CalledOnValidThread());
- CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req);
- request->Cancel();
-}
-
-// HandleResult is called by CertVerifierWorker on the origin message loop.
-// It deletes CertVerifierJob.
-void CertVerifier::HandleResult(X509Certificate* cert,
- const std::string& hostname,
- int flags,
- int error,
- const CertVerifyResult& verify_result) {
- DCHECK(CalledOnValidThread());
-
- const RequestParams key(cert->fingerprint(), cert->ca_fingerprint(),
- hostname, flags);
-
- CachedResult cached_result;
- cached_result.error = error;
- cached_result.result = verify_result;
- cache_.Put(key, cached_result, base::TimeTicks::Now(),
- base::TimeDelta::FromSeconds(kTTLSecs));
-
- std::map<RequestParams, CertVerifierJob*>::iterator j;
- j = inflight_.find(key);
- if (j == inflight_.end()) {
- NOTREACHED();
- return;
- }
- CertVerifierJob* job = j->second;
- inflight_.erase(j);
-
- job->HandleResult(cached_result);
- delete job;
-}
-
-void CertVerifier::OnCertTrustChanged(const X509Certificate* cert) {
- DCHECK(CalledOnValidThread());
-
- ClearCache();
-}
-
-/////////////////////////////////////////////////////////////////////
-
-SingleRequestCertVerifier::SingleRequestCertVerifier(
- CertVerifier* cert_verifier)
- : cert_verifier_(cert_verifier),
- cur_request_(NULL) {
- DCHECK(cert_verifier_ != NULL);
-}
-
-SingleRequestCertVerifier::~SingleRequestCertVerifier() {
- if (cur_request_) {
- cert_verifier_->CancelRequest(cur_request_);
- cur_request_ = NULL;
- }
-}
-
-int SingleRequestCertVerifier::Verify(X509Certificate* cert,
- const std::string& hostname,
- int flags,
- CRLSet* crl_set,
- CertVerifyResult* verify_result,
- const CompletionCallback& callback,
- const BoundNetLog& net_log) {
- // Should not be already in use.
- DCHECK(!cur_request_ && cur_request_callback_.is_null());
-
- // Do a synchronous verification.
- if (callback.is_null())
- return cert->Verify(hostname, flags, crl_set, verify_result);
-
- CertVerifier::RequestHandle request = NULL;
-
- // We need to be notified of completion before |callback| is called, so that
- // we can clear out |cur_request_*|.
- int rv = cert_verifier_->Verify(
- cert, hostname, flags, crl_set, verify_result,
- base::Bind(&SingleRequestCertVerifier::OnVerifyCompletion,
- base::Unretained(this)),
- &request, net_log);
-
- if (rv == ERR_IO_PENDING) {
- // Cleared in OnVerifyCompletion().
- cur_request_ = request;
- cur_request_callback_ = callback;
- }
-
- return rv;
-}
-
-void SingleRequestCertVerifier::OnVerifyCompletion(int result) {
- DCHECK(cur_request_ && !cur_request_callback_.is_null());
-
- CompletionCallback callback = cur_request_callback_;
-
- // Clear the outstanding request information.
- cur_request_ = NULL;
- cur_request_callback_.Reset();
-
- // Call the user's original callback.
- callback.Run(result);
-}
-
} // namespace net
« no previous file with comments | « net/base/cert_verifier.h ('k') | net/base/cert_verifier_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698