diff options
-rw-r--r-- | chrome/browser/io_thread.cc | 9 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 16 | ||||
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.h | 1 | ||||
-rw-r--r-- | chrome/browser/profile_impl.cc | 1 | ||||
-rw-r--r-- | chrome/common/net/url_request_context_getter.cc | 3 | ||||
-rw-r--r-- | chrome/common/net/url_request_context_getter.h | 15 | ||||
-rw-r--r-- | net/ocsp/nss_ocsp.cc | 264 | ||||
-rw-r--r-- | net/ocsp/nss_ocsp.h | 5 | ||||
-rw-r--r-- | net/proxy/proxy_script_fetcher.cc | 1 | ||||
-rw-r--r-- | net/url_request/url_request_context.cc | 3 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 8 |
11 files changed, 223 insertions, 103 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 682e390..7ff8c4b 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc @@ -26,6 +26,9 @@ #include "net/base/net_util.h" #include "net/http/http_auth_filter.h" #include "net/http/http_auth_handler_factory.h" +#if defined(USE_NSS) +#include "net/ocsp/nss_ocsp.h" +#endif // defined(USE_NSS) #include "net/proxy/proxy_script_fetcher.h" namespace { @@ -160,6 +163,12 @@ void IOThread::ChangedToOnTheRecord() { void IOThread::Init() { BrowserProcessSubThread::Init(); + DCHECK_EQ(MessageLoop::TYPE_IO, message_loop()->type()); + +#if defined(USE_NSS) + net::SetMessageLoopForOCSP(); +#endif // defined(USE_NSS) + DCHECK(!globals_); globals_ = new Globals; diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 9f053f3..28f7621 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -314,11 +314,6 @@ ChromeURLRequestContext* FactoryForOriginal::Create() { appcache_service_->set_request_context(context); -#if defined(USE_NSS) - // TODO(ukai): find a better way to set the URLRequestContext for OCSP. - net::SetURLRequestContextForOCSP(context); -#endif - context->set_net_log(io_thread_globals->net_log.get()); return context; } @@ -559,6 +554,14 @@ URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() { if (!url_request_context_) { DCHECK(factory_.get()); url_request_context_ = factory_->Create(); + if (is_main()) { + url_request_context_->set_is_main(true); +#if defined(USE_NSS) + // TODO(ukai): find a better way to set the URLRequestContext for OCSP. + net::SetURLRequestContextForOCSP(url_request_context_); +#endif + } + factory_.reset(); } @@ -756,7 +759,8 @@ ChromeURLRequestContext::~ChromeURLRequestContext() { } #if defined(USE_NSS) - if (this == net::GetURLRequestContextForOCSP()) { + if (is_main()) { + DCHECK_EQ(this, net::GetURLRequestContextForOCSP()); // We are releasing the URLRequestContext used by OCSP handlers. net::SetURLRequestContextForOCSP(NULL); } diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h index 183ad4a..a580282 100644 --- a/chrome/browser/net/chrome_url_request_context.h +++ b/chrome/browser/net/chrome_url_request_context.h @@ -211,7 +211,6 @@ class ChromeURLRequestContext : public URLRequestContext { bool is_off_the_record_; private: - DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContext); }; diff --git a/chrome/browser/profile_impl.cc b/chrome/browser/profile_impl.cc index 779cb4d..f02e070 100644 --- a/chrome/browser/profile_impl.cc +++ b/chrome/browser/profile_impl.cc @@ -713,6 +713,7 @@ URLRequestContextGetter* ProfileImpl::GetRequestContext() { // created first. if (!default_request_context_) { default_request_context_ = request_context_; + request_context_->set_is_main(true); // TODO(eroman): this isn't terribly useful anymore now that the // URLRequestContext is constructed by the IO thread... NotificationService::current()->Notify( diff --git a/chrome/common/net/url_request_context_getter.cc b/chrome/common/net/url_request_context_getter.cc index c53f782..57feb0e 100644 --- a/chrome/common/net/url_request_context_getter.cc +++ b/chrome/common/net/url_request_context_getter.cc @@ -10,7 +10,7 @@ net::CookieStore* URLRequestContextGetter::GetCookieStore() { return GetURLRequestContext()->cookie_store(); } -URLRequestContextGetter::URLRequestContextGetter() {} +URLRequestContextGetter::URLRequestContextGetter() : is_main_(false) {} URLRequestContextGetter::~URLRequestContextGetter() {} @@ -28,4 +28,3 @@ void URLRequestContextGetter::OnDestruct() { // If no IO message loop proxy was available, we will just leak memory. // This is also true if the IO thread is gone. } - diff --git a/chrome/common/net/url_request_context_getter.h b/chrome/common/net/url_request_context_getter.h index 89b28b5..2b6ea82 100644 --- a/chrome/common/net/url_request_context_getter.h +++ b/chrome/common/net/url_request_context_getter.h @@ -35,6 +35,14 @@ class URLRequestContextGetter // may be used). virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() = 0; + // Controls whether or not the URLRequestContextGetter considers itself to be + // the the "main" URLRequestContextGetter. Note that each Profile will have a + // "default" URLRequestContextGetter. Therefore, "is_main" refers to the + // default URLRequestContextGetter for the "main" Profile. + // TODO(willchan): Move this code to ChromeURLRequestContextGetter, since this + // ia a browser process specific concept. + void set_is_main(bool is_main) { is_main_ = is_main; } + protected: friend class DeleteTask<URLRequestContextGetter>; friend struct URLRequestContextGetterTraits; @@ -42,10 +50,16 @@ class URLRequestContextGetter URLRequestContextGetter(); virtual ~URLRequestContextGetter(); + bool is_main() const { return is_main_; } + private: // OnDestruct is meant to ensure deletion on the thread on which the request // IO happens. void OnDestruct(); + + // Indicates whether or not this is the default URLRequestContextGetter for + // the main Profile. + bool is_main_; }; struct URLRequestContextGetterTraits { @@ -55,4 +69,3 @@ struct URLRequestContextGetterTraits { }; #endif // CHROME_COMMON_NET_URL_REQUEST_CONTEXT_GETTER_H_ - diff --git a/net/ocsp/nss_ocsp.cc b/net/ocsp/nss_ocsp.cc index dc1851f..3faeb54 100644 --- a/net/ocsp/nss_ocsp.cc +++ b/net/ocsp/nss_ocsp.cc @@ -9,16 +9,19 @@ #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" @@ -33,6 +36,93 @@ 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 @@ -69,97 +159,58 @@ SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request); char* GetAlternateOCSPAIAInfo(CERTCertificate *cert); -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; - }; - - // 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); - } - - // 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_; - } - +class OCSPNSSInitialization { private: - friend struct DefaultSingletonTraits<OCSPInitSingleton>; - - 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(); - } + friend struct base::DefaultLazyInstanceTraits<OCSPNSSInitialization>; - // 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_; - // |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); + DISALLOW_COPY_AND_ASSIGN(OCSPNSSInitialization); }; -URLRequestContext* OCSPInitSingleton::request_context_ = NULL; +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(); + } + + // 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(); + } +} + +OCSPNSSInitialization::~OCSPNSSInitialization() {} + +base::LazyInstance<OCSPNSSInitialization> g_ocsp_nss_initialization( + base::LINKER_INITIALIZED); // Concrete class for SEC_HTTP_REQUEST_SESSION. // Public methods except virtual methods of URLRequest::Delegate (On* methods) @@ -200,7 +251,7 @@ class OCSPRequestSession // |io_loop_| was initialized to be NULL in constructor, and // set only in StartURLRequest, so no need to lock |lock_| here. DCHECK(!io_loop_); - Singleton<OCSPInitSingleton>()->PostTaskToIOLoop( + g_ocsp_io_loop.Get().PostTaskToIOLoop( FROM_HERE, NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest)); } @@ -339,11 +390,14 @@ class OCSPRequestSession } } + // Runs on |g_ocsp_io_loop|'s IO loop. void StartURLRequest() { DCHECK(!request_); - URLRequestContext* url_request_context = - OCSPInitSingleton::url_request_context(); + pthread_mutex_lock(&g_request_context_lock); + URLRequestContext* url_request_context = g_request_context; + pthread_mutex_unlock(&g_request_context_lock); + if (url_request_context == NULL) return; @@ -476,7 +530,10 @@ SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, SEC_HTTP_SERVER_SESSION* pSession) { VLOG(1) << "OCSP create session: host=" << host << " port=" << portnum; DCHECK(!MessageLoop::current()); - if (OCSPInitSingleton::url_request_context() == NULL) { + pthread_mutex_lock(&g_request_context_lock); + URLRequestContext* request_context = g_request_context; + pthread_mutex_unlock(&g_request_context_lock); + if (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 @@ -783,17 +840,40 @@ char* GetAlternateOCSPAIAInfo(CERTCertificate *cert) { 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() { - Singleton<OCSPInitSingleton>::get(); + g_ocsp_io_loop.Get().StartUsing(); + g_ocsp_nss_initialization.Get(); } // This function would be called before NSS initialization. void SetURLRequestContextForOCSP(URLRequestContext* request_context) { - OCSPInitSingleton::set_url_request_context(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); } URLRequestContext* GetURLRequestContextForOCSP() { - return OCSPInitSingleton::url_request_context(); + 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; } } // namespace net diff --git a/net/ocsp/nss_ocsp.h b/net/ocsp/nss_ocsp.h index a31d025..97d69b9 100644 --- a/net/ocsp/nss_ocsp.h +++ b/net/ocsp/nss_ocsp.h @@ -10,6 +10,11 @@ class URLRequestContext; namespace net { +// Sets the MessageLoop for OCSP to the current message loop. +// This should be called before EnsureOCSPInit() if you want to +// control the message loop for OCSP. +void SetMessageLoopForOCSP(); + // Initializes OCSP handlers for NSS. This must be called before any // certificate verification functions. This function is thread-safe, and OCSP // handlers will only ever be initialized once. diff --git a/net/proxy/proxy_script_fetcher.cc b/net/proxy/proxy_script_fetcher.cc index 0398134..0856430 100644 --- a/net/proxy/proxy_script_fetcher.cc +++ b/net/proxy/proxy_script_fetcher.cc @@ -412,4 +412,5 @@ size_t ProxyScriptFetcher::SetSizeConstraintForUnittest(size_t size_bytes) { return prev; } + } // namespace net diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc index 329f83f..518d43a 100644 --- a/net/url_request/url_request_context.cc +++ b/net/url_request/url_request_context.cc @@ -16,7 +16,8 @@ URLRequestContext::URLRequestContext() http_auth_handler_factory_(NULL), network_delegate_(NULL), cookie_policy_(NULL), - transport_security_state_(NULL) { + transport_security_state_(NULL), + is_main_(false) { } const std::string& URLRequestContext::GetUserAgent(const GURL& url) const { diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 96de77d..bbbae67 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -109,6 +109,11 @@ class URLRequestContext referrer_charset_ = charset; } + // Controls whether or not the URLRequestContext considers itself to be the + // "main" URLRequestContext. + bool is_main() const { return is_main_; } + void set_is_main(bool is_main) { is_main_ = is_main; } + protected: friend class base::RefCountedThreadSafe<URLRequestContext>; @@ -137,6 +142,9 @@ class URLRequestContext std::string referrer_charset_; private: + // Indicates whether or not this is the main URLRequestContext. + bool is_main_; + DISALLOW_COPY_AND_ASSIGN(URLRequestContext); }; |