cert_verifier.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/cert_verifier.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/compiler_specific.h"
8201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/lock.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/message_loop.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/stl_util-inl.h"
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/worker_pool.h"
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/x509_certificate.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(USE_NSS)
1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <private/pprthred.h>  // PR_DetachThread
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen////////////////////////////////////////////////////////////////////////////
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Life of a request:
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// CertVerifier CertVerifierJob       CertVerifierWorker          Request
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |                       (origin loop)    (worker loop)
2721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//   Verify()
2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->-------------------<creates>
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->----<creates>
3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->---------------------------------------------------<creates>
3421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->--------------------Start
3621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |                           |
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |                        PostTask
3821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |                                     <starts verifying>
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->-----AddRequest                         |
4121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                    |
4221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                    |
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                    |
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                  Finish
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                    |
4621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                                 PostTask
4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//
4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                   |
4921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                                DoReply
5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |----<-----------------------|
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//  HandleResult
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |
5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//      |---->-----HandleResult
5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                      |
5521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//                      |------>-----------------------------------Post
5621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//
5721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//
5821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen//
5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// On a cache hit, CertVerifier::Verify() returns synchronously without
6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// posting a task to a worker thread.
6121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// The number of CachedCertVerifyResult objects that we'll cache.
6321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic const unsigned kMaxCacheEntries = 256;
6421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// The number of seconds for which we'll cache a cache entry.
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic const unsigned kTTLSecs = 1800;  // 30 minutes.
6721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
6821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsennamespace {
6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass DefaultTimeService : public CertVerifier::TimeService {
7121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen public:
7221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // CertVerifier::TimeService methods:
7321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual base::Time Now() { return base::Time::Now(); }
7421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
7521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}  // namespace
7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenCachedCertVerifyResult::CachedCertVerifyResult() : error(ERR_FAILED) {
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
8021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenCachedCertVerifyResult::~CachedCertVerifyResult() {}
8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool CachedCertVerifyResult::HasExpired(const base::Time current_time) const {
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return current_time >= expiry;
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Represents the output and result callback of a request.
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass CertVerifierRequest {
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierRequest(CompletionCallback* callback,
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                      CertVerifyResult* verify_result)
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : callback_(callback),
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        verify_result_(verify_result) {
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Ensures that the result callback will never be made.
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void Cancel() {
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    callback_ = NULL;
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    verify_result_ = NULL;
10021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Copies the contents of |verify_result| to the caller's
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // CertVerifyResult and calls the callback.
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void Post(const CachedCertVerifyResult& verify_result) {
10521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (callback_) {
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      *verify_result_ = verify_result.result;
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      callback_->Run(verify_result.error);
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete this;
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CompletionCallback* callback_;
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifyResult* verify_result_;
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// CertVerifierWorker runs on a worker thread and takes care of the blocking
11921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// process of performing the certificate verification.  Deletes itself
12021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// eventually if Start() succeeds.
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass CertVerifierWorker {
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen public:
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierWorker(X509Certificate* cert,
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                     const std::string& hostname,
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                     int flags,
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                     CertVerifier* cert_verifier)
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : cert_(cert),
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        hostname_(hostname),
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        flags_(flags),
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        origin_loop_(MessageLoop::current()),
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        cert_verifier_(cert_verifier),
13221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        canceled_(false),
13321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        error_(ERR_FAILED) {
13421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
13521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool Start() {
13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK_EQ(MessageLoop::current(), origin_loop_);
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return WorkerPool::PostTask(
14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen               FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::Run),
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen               true /* task is slow */);
142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Cancel is called from the origin loop when the CertVerifier is getting
14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // deleted.
14621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void Cancel() {
14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK_EQ(MessageLoop::current(), origin_loop_);
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    AutoLock locked(lock_);
14921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    canceled_ = true;
15021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void Run() {
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Runs on a worker thread.
15521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    error_ = cert_->Verify(hostname_, flags_, &verify_result_);
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(USE_NSS)
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Detach the thread from NSPR.
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Calling NSS functions attaches the thread to NSPR, which stores
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // the NSPR thread ID in thread-specific data.
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // The threads in our thread pool terminate after we have called
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // PR_Cleanup.  Unless we detach them from NSPR, net_unittests gets
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // segfaults on shutdown when the threads' thread-specific data
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // destructors run.
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    PR_DetachThread();
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    Finish();
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // DoReply runs on the origin thread.
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void DoReply() {
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DCHECK_EQ(MessageLoop::current(), origin_loop_);
17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    {
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // We lock here because the worker thread could still be in Finished,
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // after the PostTask, but before unlocking |lock_|. If we do not lock in
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // this case, we will end up deleting a locked Lock, which can lead to
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // memory leaks or worse errors.
17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      AutoLock locked(lock_);
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!canceled_) {
17921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        cert_verifier_->HandleResult(cert_, hostname_, flags_,
18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                     error_, verify_result_);
18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete this;
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void Finish() {
18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Runs on the worker thread.
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // We assume that the origin loop outlives the CertVerifier. If the
18921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // CertVerifier is deleted, it will call Cancel on us. If it does so
19021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // before the Acquire, we'll delete ourselves and return. If it's trying to
19121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // do so concurrently, then it'll block on the lock and we'll call PostTask
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // while the CertVerifier (and therefore the MessageLoop) is still alive.
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // If it does so after this function, we assume that the MessageLoop will
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // process pending tasks. In which case we'll notice the |canceled_| flag
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // in DoReply.
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
19721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool canceled;
19821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    {
19921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      AutoLock locked(lock_);
20021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      canceled = canceled_;
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!canceled) {
20221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        origin_loop_->PostTask(
20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen            FROM_HERE, NewRunnableMethod(this, &CertVerifierWorker::DoReply));
20421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
20521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
20721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (canceled)
20821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      delete this;
20921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_refptr<X509Certificate> cert_;
21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  const std::string hostname_;
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  const int flags_;
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  MessageLoop* const origin_loop_;
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifier* const cert_verifier_;
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // lock_ protects canceled_.
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Lock lock_;
219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
22021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // If canceled_ is true,
22121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // * origin_loop_ cannot be accessed by the worker thread,
22221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // * cert_verifier_ cannot be accessed by any thread.
22321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool canceled_;
22421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
22521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  int error_;
22621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifyResult verify_result_;
22721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
22821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DISALLOW_COPY_AND_ASSIGN(CertVerifierWorker);
22921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// A CertVerifierJob is a one-to-one counterpart of a CertVerifierWorker. It
23221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// lives only on the CertVerifier's origin message loop.
23321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenclass CertVerifierJob {
23421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen public:
23521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  explicit CertVerifierJob(CertVerifierWorker* worker) : worker_(worker) {
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
23821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ~CertVerifierJob() {
23921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (worker_)
24021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      worker_->Cancel();
24121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void AddRequest(CertVerifierRequest* request) {
24421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    requests_.push_back(request);
24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
24721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void HandleResult(const CachedCertVerifyResult& verify_result) {
24821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    worker_ = NULL;
24921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    PostAll(verify_result);
25021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
25221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen private:
25321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void PostAll(const CachedCertVerifyResult& verify_result) {
25421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    std::vector<CertVerifierRequest*> requests;
25521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    requests_.swap(requests);
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
25721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (std::vector<CertVerifierRequest*>::iterator
25821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen         i = requests.begin(); i != requests.end(); i++) {
25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      (*i)->Post(verify_result);
26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      // Post() causes the CertVerifierRequest to delete itself.
26121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
26221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  std::vector<CertVerifierRequest*> requests_;
26521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierWorker* worker_;
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
26921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenCertVerifier::CertVerifier()
27021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : time_service_(new DefaultTimeService),
27121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      requests_(0),
27221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cache_hits_(0),
27321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      inflight_joins_(0) {
27421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
27521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
27621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenCertVerifier::CertVerifier(TimeService* time_service)
27721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : time_service_(time_service),
27821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      requests_(0),
27921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cache_hits_(0),
28021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      inflight_joins_(0) {
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottCertVerifier::~CertVerifier() {
28421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  STLDeleteValues(&inflight_);
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint CertVerifier::Verify(X509Certificate* cert,
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         const std::string& hostname,
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         int flags,
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         CertVerifyResult* verify_result,
29121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                         CompletionCallback* callback,
29221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                         RequestHandle* out_req) {
29321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(CalledOnValidThread());
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
29521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!callback || !verify_result || hostname.empty()) {
29621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    *out_req = NULL;
29721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return ERR_INVALID_ARGUMENT;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  requests_++;
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
30221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  const RequestParams key = {cert->fingerprint(), hostname, flags};
30321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // First check the cache.
30421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  std::map<RequestParams, CachedCertVerifyResult>::iterator i;
30521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  i = cache_.find(key);
30621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (i != cache_.end()) {
30721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!i->second.HasExpired(time_service_->Now())) {
30821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cache_hits_++;
30921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      *out_req = NULL;
31021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      *verify_result = i->second.result;
31121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return i->second.error;
31221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
31321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Cache entry has expired.
31421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cache_.erase(i);
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
31721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // No cache hit. See if an identical request is currently in flight.
31821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierJob* job;
31921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  std::map<RequestParams, CertVerifierJob*>::const_iterator j;
32021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  j = inflight_.find(key);
32121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (j != inflight_.end()) {
32221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // An identical request is in flight already. We'll just attach our
32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // callback.
32421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    inflight_joins_++;
32521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    job = j->second;
32621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  } else {
32721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Need to make a new request.
32821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CertVerifierWorker* worker = new CertVerifierWorker(cert, hostname, flags,
32921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                        this);
33021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    job = new CertVerifierJob(worker);
33121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    inflight_.insert(std::make_pair(key, job));
33221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!worker->Start()) {
33321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      inflight_.erase(key);
33421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      delete job;
33521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      delete worker;
33621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      *out_req = NULL;
33721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return ERR_FAILED;  // TODO(wtc): Log an error message.
33821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
33921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
34021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
34121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierRequest* request =
34221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      new CertVerifierRequest(callback, verify_result);
34321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  job->AddRequest(request);
34421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  *out_req = request;
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_IO_PENDING;
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
347c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CertVerifier::CancelRequest(RequestHandle req) {
34921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(CalledOnValidThread());
35021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierRequest* request = reinterpret_cast<CertVerifierRequest*>(req);
35121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  request->Cancel();
35221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
35321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
35421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CertVerifier::ClearCache() {
35521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(CalledOnValidThread());
35621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
35721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cache_.clear();
35821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Leaves inflight_ alone.
35921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
36021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
36121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsensize_t CertVerifier::GetCacheSize() const {
36221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(CalledOnValidThread());
36321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
36421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return cache_.size();
36521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
36621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
36721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// HandleResult is called by CertVerifierWorker on the origin message loop.
36821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// It deletes CertVerifierJob.
36921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid CertVerifier::HandleResult(X509Certificate* cert,
37021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                const std::string& hostname,
37121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                int flags,
37221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                int error,
37321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                const CertVerifyResult& verify_result) {
37421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(CalledOnValidThread());
37521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
37621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  const base::Time current_time(time_service_->Now());
37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CachedCertVerifyResult cached_result;
37921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cached_result.error = error;
38021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cached_result.result = verify_result;
38121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  uint32 ttl = kTTLSecs;
38221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cached_result.expiry = current_time + base::TimeDelta::FromSeconds(ttl);
38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  const RequestParams key = {cert->fingerprint(), hostname, flags};
38521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK_GE(kMaxCacheEntries, 1u);
38721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK_LE(cache_.size(), kMaxCacheEntries);
38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (cache_.size() == kMaxCacheEntries) {
38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Need to remove an element of the cache.
39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    std::map<RequestParams, CachedCertVerifyResult>::iterator i, cur;
39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (i = cache_.begin(); i != cache_.end(); ) {
39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cur = i++;
39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (cur->second.HasExpired(current_time))
39421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        cache_.erase(cur);
39521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
39621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
39721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (cache_.size() == kMaxCacheEntries) {
39821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // If we didn't clear out any expired entries, we just remove the first
39921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // element. Crummy but simple.
40021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cache_.erase(cache_.begin());
40121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
40221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
40321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cache_.insert(std::make_pair(key, cached_result));
40421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
40521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  std::map<RequestParams, CertVerifierJob*>::iterator j;
40621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  j = inflight_.find(key);
40721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (j == inflight_.end()) {
40821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    NOTREACHED();
40921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return;
41021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
41121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifierJob* job = j->second;
41221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  inflight_.erase(j);
41321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
41421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  job->HandleResult(cached_result);
41521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  delete job;
41621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
41721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
41821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen/////////////////////////////////////////////////////////////////////
41921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
42021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenSingleRequestCertVerifier::SingleRequestCertVerifier(
42121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CertVerifier* cert_verifier)
42221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    : cert_verifier_(cert_verifier),
42321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cur_request_(NULL),
42421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cur_request_callback_(NULL),
42521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      ALLOW_THIS_IN_INITIALIZER_LIST(
42621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          callback_(this, &SingleRequestCertVerifier::OnVerifyCompletion)) {
42721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(cert_verifier_ != NULL);
42821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
42921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
43021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenSingleRequestCertVerifier::~SingleRequestCertVerifier() {
43121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (cur_request_) {
43221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cert_verifier_->CancelRequest(cur_request_);
43321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cur_request_ = NULL;
43421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
43521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
43621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
43721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenint SingleRequestCertVerifier::Verify(X509Certificate* cert,
43821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                      const std::string& hostname,
43921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                      int flags,
44021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                      CertVerifyResult* verify_result,
44121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                      CompletionCallback* callback) {
44221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Should not be already in use.
44321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(!cur_request_ && !cur_request_callback_);
44421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
44521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Do a synchronous verification.
44621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!callback)
44721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return cert->Verify(hostname, flags, verify_result);
44821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
44921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CertVerifier::RequestHandle request = NULL;
45021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
45121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // We need to be notified of completion before |callback| is called, so that
45221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // we can clear out |cur_request_*|.
45321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  int rv = cert_verifier_->Verify(
45421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cert, hostname, flags, verify_result, &callback_, &request);
45521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
45621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (rv == ERR_IO_PENDING) {
45721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Cleared in OnVerifyCompletion().
45821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cur_request_ = request;
45921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cur_request_callback_ = callback;
46021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
46121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
46221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return rv;
46321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
46421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
46521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SingleRequestCertVerifier::OnVerifyCompletion(int result) {
46621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(cur_request_ && cur_request_callback_);
46721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
46821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  CompletionCallback* callback = cur_request_callback_;
46921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
47021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Clear the outstanding request information.
47121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cur_request_ = NULL;
47221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  cur_request_callback_ = NULL;
47321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
47421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Call the user's original callback.
47521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  callback->Run(result);
47621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
47721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
47921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
48021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenDISABLE_RUNNABLE_METHOD_REFCOUNT(net::CertVerifierWorker);
48121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
482