| Index: net/ocsp/nss_ocsp.cc
|
| ===================================================================
|
| --- net/ocsp/nss_ocsp.cc (revision 60752)
|
| +++ net/ocsp/nss_ocsp.cc (working copy)
|
| @@ -9,19 +9,16 @@
|
| #include <ocsp.h>
|
| #include <nspr.h>
|
| #include <nss.h>
|
| -#include <pthread.h>
|
| #include <secerr.h>
|
|
|
| #include <string>
|
|
|
| -#include "base/basictypes.h"
|
| #include "base/compiler_specific.h"
|
| #include "base/condition_variable.h"
|
| #include "base/histogram.h"
|
| -#include "base/lazy_instance.h"
|
| -#include "base/lock.h"
|
| #include "base/logging.h"
|
| #include "base/message_loop.h"
|
| +#include "base/singleton.h"
|
| #include "base/string_util.h"
|
| #include "base/stringprintf.h"
|
| #include "base/thread.h"
|
| @@ -36,93 +33,6 @@
|
|
|
| namespace {
|
|
|
| -// Protects |g_request_context|.
|
| -pthread_mutex_t g_request_context_lock = PTHREAD_MUTEX_INITIALIZER;
|
| -static URLRequestContext* g_request_context = NULL;
|
| -
|
| -class OCSPIOLoop : public MessageLoop::DestructionObserver {
|
| - public:
|
| - // MessageLoop::DestructionObserver:
|
| - virtual void WillDestroyCurrentMessageLoop();
|
| -
|
| - void StartUsing() {
|
| - AutoLock autolock(lock_);
|
| - used_ = true;
|
| - }
|
| -
|
| - bool used() const {
|
| - AutoLock autolock(lock_);
|
| - return used_;
|
| - }
|
| -
|
| - // Called from worker thread.
|
| - void PostTaskToIOLoop(const tracked_objects::Location& from_here, Task* task);
|
| -
|
| - void EnsureIOLoop();
|
| -
|
| - private:
|
| - friend struct base::DefaultLazyInstanceTraits<OCSPIOLoop>;
|
| -
|
| - OCSPIOLoop();
|
| - ~OCSPIOLoop();
|
| -
|
| - mutable Lock lock_;
|
| - bool used_; // Protected by |lock_|.
|
| - // This should not be modified after |used_|.
|
| - MessageLoopForIO* io_loop_; // Protected by |lock_|.
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(OCSPIOLoop);
|
| -};
|
| -
|
| -OCSPIOLoop::OCSPIOLoop()
|
| - : used_(false),
|
| - io_loop_(MessageLoopForIO::current()) {
|
| - DCHECK(io_loop_);
|
| - io_loop_->AddDestructionObserver(this);
|
| -}
|
| -
|
| -OCSPIOLoop::~OCSPIOLoop() {
|
| - // IO thread was already deleted before the singleton is deleted
|
| - // in AtExitManager.
|
| - {
|
| - AutoLock autolock(lock_);
|
| - DCHECK(!io_loop_);
|
| - DCHECK(!used_);
|
| - }
|
| -
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - DCHECK(!g_request_context);
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| -}
|
| -
|
| -void OCSPIOLoop::WillDestroyCurrentMessageLoop() {
|
| - // Prevent the worker thread from trying to access |io_loop_|.
|
| - {
|
| - AutoLock autolock(lock_);
|
| - DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
|
| - io_loop_ = NULL;
|
| - used_ = false;
|
| - }
|
| -
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - g_request_context = NULL;
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| -}
|
| -
|
| -void OCSPIOLoop::PostTaskToIOLoop(
|
| - const tracked_objects::Location& from_here, Task* task) {
|
| - AutoLock autolock(lock_);
|
| - if (io_loop_)
|
| - io_loop_->PostTask(from_here, task);
|
| -}
|
| -
|
| -void OCSPIOLoop::EnsureIOLoop() {
|
| - AutoLock autolock(lock_);
|
| - DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
|
| -}
|
| -
|
| -base::LazyInstance<OCSPIOLoop> g_ocsp_io_loop(base::LINKER_INITIALIZED);
|
| -
|
| const int kRecvBufferSize = 4096;
|
|
|
| // All OCSP handlers should be called in the context of
|
| @@ -159,59 +69,98 @@
|
|
|
| char* GetAlternateOCSPAIAInfo(CERTCertificate *cert);
|
|
|
| -class OCSPNSSInitialization {
|
| - private:
|
| - friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>;
|
| +class OCSPInitSingleton : public MessageLoop::DestructionObserver {
|
| + public:
|
| + // Called on IO thread.
|
| + virtual void WillDestroyCurrentMessageLoop() {
|
| + AutoLock autolock(lock_);
|
| + DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
|
| + io_loop_ = NULL;
|
| + request_context_ = NULL;
|
| + };
|
|
|
| - OCSPNSSInitialization();
|
| - ~OCSPNSSInitialization();
|
| + // Called from worker thread.
|
| + void PostTaskToIOLoop(
|
| + const tracked_objects::Location& from_here, Task* task) {
|
| + AutoLock autolock(lock_);
|
| + if (io_loop_)
|
| + io_loop_->PostTask(from_here, task);
|
| + }
|
|
|
| - SEC_HttpClientFcn client_fcn_;
|
| + // This is static method because it is called before NSS initialization,
|
| + // that is, before OCSPInitSingleton is initialized.
|
| + static void set_url_request_context(URLRequestContext* request_context) {
|
| + request_context_ = request_context;
|
| + }
|
| + static URLRequestContext* url_request_context() {
|
| + return request_context_;
|
| + }
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization);
|
| -};
|
| + private:
|
| + friend struct DefaultSingletonTraits<OCSPInitSingleton>;
|
|
|
| -OCSPNSSInitialization::OCSPNSSInitialization() {
|
| - // NSS calls the functions in the function table to download certificates
|
| - // or CRLs or talk to OCSP responders over HTTP. These functions must
|
| - // set an NSS/NSPR error code when they fail. Otherwise NSS will get the
|
| - // residual error code from an earlier failed function call.
|
| - client_fcn_.version = 1;
|
| - SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
|
| - ft->createSessionFcn = OCSPCreateSession;
|
| - ft->keepAliveSessionFcn = OCSPKeepAliveSession;
|
| - ft->freeSessionFcn = OCSPFreeSession;
|
| - ft->createFcn = OCSPCreate;
|
| - ft->setPostDataFcn = OCSPSetPostData;
|
| - ft->addHeaderFcn = OCSPAddHeader;
|
| - ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
|
| - ft->cancelFcn = NULL;
|
| - ft->freeFcn = OCSPFree;
|
| - SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
|
| - if (status != SECSuccess) {
|
| - NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
|
| + OCSPInitSingleton()
|
| + : io_loop_(MessageLoopForIO::current()) {
|
| + DCHECK(io_loop_);
|
| + io_loop_->AddDestructionObserver(this);
|
| +
|
| + // NSS calls the functions in the function table to download certificates
|
| + // or CRLs or talk to OCSP responders over HTTP. These functions must
|
| + // set an NSS/NSPR error code when they fail. Otherwise NSS will get the
|
| + // residual error code from an earlier failed function call.
|
| + client_fcn_.version = 1;
|
| + SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
|
| + ft->createSessionFcn = OCSPCreateSession;
|
| + ft->keepAliveSessionFcn = OCSPKeepAliveSession;
|
| + ft->freeSessionFcn = OCSPFreeSession;
|
| + ft->createFcn = OCSPCreate;
|
| + ft->setPostDataFcn = OCSPSetPostData;
|
| + ft->addHeaderFcn = OCSPAddHeader;
|
| + ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
|
| + ft->cancelFcn = NULL;
|
| + ft->freeFcn = OCSPFree;
|
| + SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
|
| + if (status != SECSuccess) {
|
| + NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
|
| + }
|
| +
|
| + // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the
|
| + // CRLs for Network Solutions Certificate Authority have bad signatures,
|
| + // which causes certificates issued by that CA to be reported as revoked.
|
| + // By using OCSP for those certificates, which don't have AIA extensions,
|
| + // we can work around these bugs. See http://crbug.com/41730.
|
| + CERT_StringFromCertFcn old_callback = NULL;
|
| + status = CERT_RegisterAlternateOCSPAIAInfoCallBack(
|
| + GetAlternateOCSPAIAInfo, &old_callback);
|
| + if (status == SECSuccess) {
|
| + DCHECK(!old_callback);
|
| + } else {
|
| + NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
|
| + }
|
| }
|
|
|
| - // Work around NSS bugs 524013 and 564334. NSS incorrectly thinks the
|
| - // CRLs for Network Solutions Certificate Authority have bad signatures,
|
| - // which causes certificates issued by that CA to be reported as revoked.
|
| - // By using OCSP for those certificates, which don't have AIA extensions,
|
| - // we can work around these bugs. See http://crbug.com/41730.
|
| - CERT_StringFromCertFcn old_callback = NULL;
|
| - status = CERT_RegisterAlternateOCSPAIAInfoCallBack(
|
| - GetAlternateOCSPAIAInfo, &old_callback);
|
| - if (status == SECSuccess) {
|
| - DCHECK(!old_callback);
|
| - } else {
|
| - NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
|
| + virtual ~OCSPInitSingleton() {
|
| + // IO thread was already deleted before the singleton is deleted
|
| + // in AtExitManager.
|
| + AutoLock autolock(lock_);
|
| + DCHECK(!io_loop_);
|
| + DCHECK(!request_context_);
|
| }
|
| -}
|
|
|
| -OCSPNSSInitialization::~OCSPNSSInitialization() {}
|
| + SEC_HttpClientFcn client_fcn_;
|
|
|
| -base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization(
|
| - base::LINKER_INITIALIZED);
|
| + // |lock_| protects |io_loop_|.
|
| + Lock lock_;
|
| + // I/O thread.
|
| + MessageLoop* io_loop_; // I/O thread
|
| + // URLRequestContext for OCSP handlers.
|
| + static URLRequestContext* request_context_;
|
|
|
| + DISALLOW_COPY_AND_ASSIGN(OCSPInitSingleton);
|
| +};
|
| +
|
| +URLRequestContext* OCSPInitSingleton::request_context_ = NULL;
|
| +
|
| // Concrete class for SEC_HTTP_REQUEST_SESSION.
|
| // Public methods except virtual methods of URLRequest::Delegate (On* methods)
|
| // run on certificate verifier thread (worker thread).
|
| @@ -251,7 +200,7 @@
|
| // |io_loop_| was initialized to be NULL in constructor, and
|
| // set only in StartURLRequest, so no need to lock |lock_| here.
|
| DCHECK(!io_loop_);
|
| - g_ocsp_io_loop.Get().PostTaskToIOLoop(
|
| + Singleton<OCSPInitSingleton>()->PostTaskToIOLoop(
|
| FROM_HERE,
|
| NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest));
|
| }
|
| @@ -390,14 +339,11 @@
|
| }
|
| }
|
|
|
| - // Runs on |g_ocsp_io_loop|'s IO loop.
|
| void StartURLRequest() {
|
| DCHECK(!request_);
|
|
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - URLRequestContext* url_request_context = g_request_context;
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| -
|
| + URLRequestContext* url_request_context =
|
| + OCSPInitSingleton::url_request_context();
|
| if (url_request_context == NULL)
|
| return;
|
|
|
| @@ -530,10 +476,7 @@
|
| SEC_HTTP_SERVER_SESSION* pSession) {
|
| LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum;
|
| DCHECK(!MessageLoop::current());
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - URLRequestContext* request_context = g_request_context;
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| - if (request_context == NULL) {
|
| + if (OCSPInitSingleton::url_request_context() == NULL) {
|
| LOG(ERROR) << "No URLRequestContext for OCSP handler.";
|
| // The application failed to call SetURLRequestContextForOCSP, so we
|
| // can't create and use URLRequest. PR_NOT_IMPLEMENTED_ERROR is not an
|
| @@ -840,40 +783,17 @@
|
|
|
| namespace net {
|
|
|
| -void SetMessageLoopForOCSP() {
|
| - // Must have a MessageLoopForIO.
|
| - DCHECK(MessageLoopForIO::current());
|
| -
|
| - bool used = g_ocsp_io_loop.Get().used();
|
| -
|
| - // Should not be called when g_ocsp_io_loop has already been used.
|
| - DCHECK(!used);
|
| -}
|
| -
|
| void EnsureOCSPInit() {
|
| - g_ocsp_io_loop.Get().StartUsing();
|
| - g_ocsp_nss_initialization.Get();
|
| + Singleton<OCSPInitSingleton>::get();
|
| }
|
|
|
| // This function would be called before NSS initialization.
|
| void SetURLRequestContextForOCSP(URLRequestContext* request_context) {
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - if (request_context) {
|
| - DCHECK(request_context->is_main());
|
| - DCHECK(!g_request_context);
|
| - } else {
|
| - DCHECK(g_request_context);
|
| - }
|
| - g_request_context = request_context;
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| + OCSPInitSingleton::set_url_request_context(request_context);
|
| }
|
|
|
| URLRequestContext* GetURLRequestContextForOCSP() {
|
| - pthread_mutex_lock(&g_request_context_lock);
|
| - URLRequestContext* request_context = g_request_context;
|
| - pthread_mutex_unlock(&g_request_context_lock);
|
| - DCHECK(request_context->is_main());
|
| - return request_context;
|
| + return OCSPInitSingleton::url_request_context();
|
| }
|
|
|
| } // namespace net
|
|
|