| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/ocsp/nss_ocsp.h" | 5 #include "net/ocsp/nss_ocsp.h" |
| 6 | 6 |
| 7 #include <certt.h> | 7 #include <certt.h> |
| 8 #include <certdb.h> | 8 #include <certdb.h> |
| 9 #include <ocsp.h> | 9 #include <ocsp.h> |
| 10 #include <nspr.h> | 10 #include <nspr.h> |
| 11 #include <nss.h> | 11 #include <nss.h> |
| 12 #include <secerr.h> | 12 #include <secerr.h> |
| 13 | 13 |
| 14 #include <string> | 14 #include <string> |
| 15 | 15 |
| 16 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
| 17 #include "base/condition_variable.h" | 17 #include "base/condition_variable.h" |
| 18 #include "base/logging.h" | 18 #include "base/logging.h" |
| 19 #include "base/message_loop.h" | 19 #include "base/message_loop.h" |
| 20 #include "base/singleton.h" |
| 20 #include "base/thread.h" | 21 #include "base/thread.h" |
| 21 #include "base/time.h" | 22 #include "base/time.h" |
| 22 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
| 23 #include "net/base/io_buffer.h" | 24 #include "net/base/io_buffer.h" |
| 24 #include "net/base/load_flags.h" | 25 #include "net/base/load_flags.h" |
| 25 #include "net/http/http_response_headers.h" | 26 #include "net/http/http_response_headers.h" |
| 26 #include "net/url_request/url_request.h" | 27 #include "net/url_request/url_request.h" |
| 27 #include "net/url_request/url_request_context.h" | 28 #include "net/url_request/url_request_context.h" |
| 28 | 29 |
| 29 namespace { | 30 namespace { |
| 30 | 31 |
| 31 static const int kRecvBufferSize = 4096; | 32 const int kRecvBufferSize = 4096; |
| 32 | 33 |
| 33 // All OCSP handlers should be called in the context of | 34 // All OCSP handlers should be called in the context of |
| 34 // CertVerifier's thread (i.e. worker pool, not on the I/O thread). | 35 // CertVerifier's thread (i.e. worker pool, not on the I/O thread). |
| 35 // It supports blocking mode only. | 36 // It supports blocking mode only. |
| 36 | 37 |
| 37 class OCSPInitSingleton : public MessageLoop::DestructionObserver { | 38 class OCSPInitSingleton : public MessageLoop::DestructionObserver { |
| 38 public: | 39 public: |
| 40 // Called on IO thread. |
| 39 virtual void WillDestroyCurrentMessageLoop() { | 41 virtual void WillDestroyCurrentMessageLoop() { |
| 42 AutoLock autolock(lock_); |
| 43 DCHECK_EQ(MessageLoopForIO::current(), io_loop_); |
| 40 io_loop_ = NULL; | 44 io_loop_ = NULL; |
| 45 request_context_ = NULL; |
| 41 }; | 46 }; |
| 42 | 47 |
| 43 MessageLoop* io_thread() const { | 48 // Called from worker thread. |
| 44 return io_loop_; | 49 void PostTaskToIOLoop( |
| 50 const tracked_objects::Location& from_here, Task* task) { |
| 51 AutoLock autolock(lock_); |
| 52 if (io_loop_) |
| 53 io_loop_->PostTask(from_here, task); |
| 45 } | 54 } |
| 46 | 55 |
| 47 // This is static method because it is called before NSS initialization, | 56 // This is static method because it is called before NSS initialization, |
| 48 // that is, before OCSPInitSingleton is initialized. | 57 // that is, before OCSPInitSingleton is initialized. |
| 49 static void set_url_request_context(URLRequestContext* request_context) { | 58 static void set_url_request_context(URLRequestContext* request_context) { |
| 50 request_context_ = request_context; | 59 request_context_ = request_context; |
| 51 } | 60 } |
| 52 static URLRequestContext* url_request_context() { | 61 static URLRequestContext* url_request_context() { |
| 53 return request_context_; | 62 return request_context_; |
| 54 } | 63 } |
| 55 | 64 |
| 56 private: | 65 private: |
| 57 friend struct DefaultSingletonTraits<OCSPInitSingleton>; | 66 friend struct DefaultSingletonTraits<OCSPInitSingleton>; |
| 67 |
| 58 OCSPInitSingleton(); | 68 OCSPInitSingleton(); |
| 59 virtual ~OCSPInitSingleton() { | 69 virtual ~OCSPInitSingleton() { |
| 60 if (io_loop_) | 70 // IO thread was already deleted before the singleton is deleted |
| 61 io_loop_->RemoveDestructionObserver(this); | 71 // in AtExitManager. |
| 62 request_context_ = NULL; | 72 AutoLock autolock(lock_); |
| 73 DCHECK(!io_loop_); |
| 74 DCHECK(!request_context_); |
| 63 } | 75 } |
| 64 | 76 |
| 65 SEC_HttpClientFcn client_fcn_; | 77 SEC_HttpClientFcn client_fcn_; |
| 66 | 78 |
| 79 // |lock_| protects |io_loop_|. |
| 80 Lock lock_; |
| 67 // I/O thread. | 81 // I/O thread. |
| 68 MessageLoop* io_loop_; // I/O thread | 82 MessageLoop* io_loop_; // I/O thread |
| 69 | |
| 70 // URLRequestContext for OCSP handlers. | 83 // URLRequestContext for OCSP handlers. |
| 71 static URLRequestContext* request_context_; | 84 static URLRequestContext* request_context_; |
| 72 | 85 |
| 73 DISALLOW_COPY_AND_ASSIGN(OCSPInitSingleton); | 86 DISALLOW_COPY_AND_ASSIGN(OCSPInitSingleton); |
| 74 }; | 87 }; |
| 75 | 88 |
| 76 URLRequestContext* OCSPInitSingleton::request_context_ = NULL; | 89 URLRequestContext* OCSPInitSingleton::request_context_ = NULL; |
| 77 | 90 |
| 78 // Concrete class for SEC_HTTP_REQUEST_SESSION. | 91 // Concrete class for SEC_HTTP_REQUEST_SESSION. |
| 79 // Public methods except virtual methods of URLRequest::Delegate (On* methods) | 92 // Public methods except virtual methods of URLRequest::Delegate (On* methods) |
| 80 // run on certificate verifier thread (worker thread). | 93 // run on certificate verifier thread (worker thread). |
| 81 // Virtual methods of URLRequest::Delegate and private methods run | 94 // Virtual methods of URLRequest::Delegate and private methods run |
| 82 // on IO thread. | 95 // on IO thread. |
| 83 class OCSPRequestSession | 96 class OCSPRequestSession |
| 84 : public base::RefCountedThreadSafe<OCSPRequestSession>, | 97 : public base::RefCountedThreadSafe<OCSPRequestSession>, |
| 85 public URLRequest::Delegate, | 98 public URLRequest::Delegate, |
| 86 public MessageLoop::DestructionObserver { | 99 public MessageLoop::DestructionObserver { |
| 87 public: | 100 public: |
| 88 OCSPRequestSession(const GURL& url, | 101 OCSPRequestSession(const GURL& url, |
| 89 const char* http_request_method, | 102 const char* http_request_method, |
| 90 base::TimeDelta timeout) | 103 base::TimeDelta timeout) |
| 91 : url_(url), | 104 : url_(url), |
| 92 http_request_method_(http_request_method), | 105 http_request_method_(http_request_method), |
| 93 timeout_(timeout), | 106 timeout_(timeout), |
| 94 request_(NULL), | 107 request_(NULL), |
| 95 buffer_(new net::IOBuffer(kRecvBufferSize)), | 108 buffer_(new net::IOBuffer(kRecvBufferSize)), |
| 96 response_code_(-1), | 109 response_code_(-1), |
| 97 cv_(&lock_), | 110 cv_(&lock_), |
| 98 io_loop_(Singleton<OCSPInitSingleton>::get()->io_thread()), | 111 io_loop_(NULL), |
| 99 finished_(false) {} | 112 finished_(false) {} |
| 100 | 113 |
| 101 void SetPostData(const char* http_data, PRUint32 http_data_len, | 114 void SetPostData(const char* http_data, PRUint32 http_data_len, |
| 102 const char* http_content_type) { | 115 const char* http_content_type) { |
| 103 upload_content_.assign(http_data, http_data_len); | 116 upload_content_.assign(http_data, http_data_len); |
| 104 upload_content_type_.assign(http_content_type); | 117 upload_content_type_.assign(http_content_type); |
| 105 } | 118 } |
| 106 | 119 |
| 107 void AddHeader(const char* http_header_name, const char* http_header_value) { | 120 void AddHeader(const char* http_header_name, const char* http_header_value) { |
| 108 if (!extra_request_headers_.empty()) | 121 if (!extra_request_headers_.empty()) |
| 109 extra_request_headers_ += "\r\n"; | 122 extra_request_headers_ += "\r\n"; |
| 110 StringAppendF(&extra_request_headers_, | 123 StringAppendF(&extra_request_headers_, |
| 111 "%s: %s", http_header_name, http_header_value); | 124 "%s: %s", http_header_name, http_header_value); |
| 112 } | 125 } |
| 113 | 126 |
| 114 void Start() { | 127 void Start() { |
| 115 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. | 128 // At this point, it runs on worker thread. |
| 116 AutoLock autolock(lock_); | 129 // |io_loop_| was initialized to be NULL in constructor, and |
| 117 if (io_loop_) { | 130 // set only in StartURLRequest, so no need to lock |lock_| here. |
| 118 io_loop_->PostTask( | 131 DCHECK(!io_loop_); |
| 119 FROM_HERE, | 132 Singleton<OCSPInitSingleton>()->PostTaskToIOLoop( |
| 120 NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest)); | 133 FROM_HERE, |
| 121 } | 134 NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest)); |
| 122 } | 135 } |
| 123 | 136 |
| 124 bool Started() const { | 137 bool Started() const { |
| 125 return request_ != NULL; | 138 return request_ != NULL; |
| 126 } | 139 } |
| 127 | 140 |
| 128 void Cancel() { | 141 void Cancel() { |
| 129 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. | 142 // IO thread may set |io_loop_| to NULL, so protect by |lock_|. |
| 130 AutoLock autolock(lock_); | 143 AutoLock autolock(lock_); |
| 131 CancelLocked(); | 144 CancelLocked(); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 AutoLock autolock(lock_); | 244 AutoLock autolock(lock_); |
| 232 io_loop_ = NULL; | 245 io_loop_ = NULL; |
| 233 } | 246 } |
| 234 CancelURLRequest(); | 247 CancelURLRequest(); |
| 235 } | 248 } |
| 236 | 249 |
| 237 private: | 250 private: |
| 238 friend class base::RefCountedThreadSafe<OCSPRequestSession>; | 251 friend class base::RefCountedThreadSafe<OCSPRequestSession>; |
| 239 | 252 |
| 240 virtual ~OCSPRequestSession() { | 253 virtual ~OCSPRequestSession() { |
| 254 // When this destructor is called, there should be only one thread that has |
| 255 // a reference to this object, and so that thread doesn't need to lock |
| 256 // |lock_| here. |
| 241 DCHECK(!request_); | 257 DCHECK(!request_); |
| 242 if (io_loop_) | 258 DCHECK(!io_loop_); |
| 243 io_loop_->RemoveDestructionObserver(this); | |
| 244 } | 259 } |
| 245 | 260 |
| 261 // Must call this method while holding |lock_|. |
| 246 void CancelLocked() { | 262 void CancelLocked() { |
| 263 lock_.AssertAcquired(); |
| 247 if (io_loop_) { | 264 if (io_loop_) { |
| 248 io_loop_->PostTask( | 265 io_loop_->PostTask( |
| 249 FROM_HERE, | 266 FROM_HERE, |
| 250 NewRunnableMethod(this, &OCSPRequestSession::CancelURLRequest)); | 267 NewRunnableMethod(this, &OCSPRequestSession::CancelURLRequest)); |
| 251 } | 268 } |
| 252 } | 269 } |
| 253 | 270 |
| 254 void StartURLRequest() { | 271 void StartURLRequest() { |
| 255 DCHECK_EQ(MessageLoopForIO::current(), io_loop_); | |
| 256 DCHECK(!request_); | 272 DCHECK(!request_); |
| 257 | 273 |
| 258 io_loop_->AddDestructionObserver(this); | 274 URLRequestContext* url_request_context = |
| 275 OCSPInitSingleton::url_request_context(); |
| 276 if (url_request_context == NULL) |
| 277 return; |
| 278 |
| 279 { |
| 280 AutoLock autolock(lock_); |
| 281 DCHECK(!io_loop_); |
| 282 io_loop_ = MessageLoopForIO::current(); |
| 283 io_loop_->AddDestructionObserver(this); |
| 284 } |
| 259 | 285 |
| 260 request_ = new URLRequest(url_, this); | 286 request_ = new URLRequest(url_, this); |
| 261 request_->set_context( | 287 request_->set_context(url_request_context); |
| 262 Singleton<OCSPInitSingleton>::get()->url_request_context()); | |
| 263 // To meet the privacy requirements of off-the-record mode. | 288 // To meet the privacy requirements of off-the-record mode. |
| 264 request_->set_load_flags( | 289 request_->set_load_flags( |
| 265 net::LOAD_DISABLE_CACHE|net::LOAD_DO_NOT_SAVE_COOKIES); | 290 net::LOAD_DISABLE_CACHE|net::LOAD_DO_NOT_SAVE_COOKIES); |
| 266 | 291 |
| 267 if (http_request_method_ == "POST") { | 292 if (http_request_method_ == "POST") { |
| 268 DCHECK(!upload_content_.empty()); | 293 DCHECK(!upload_content_.empty()); |
| 269 DCHECK(!upload_content_type_.empty()); | 294 DCHECK(!upload_content_type_.empty()); |
| 270 | 295 |
| 271 request_->set_method("POST"); | 296 request_->set_method("POST"); |
| 272 if (!extra_request_headers_.empty()) | 297 if (!extra_request_headers_.empty()) |
| 273 extra_request_headers_ += "\r\n"; | 298 extra_request_headers_ += "\r\n"; |
| 274 StringAppendF(&extra_request_headers_, | 299 StringAppendF(&extra_request_headers_, |
| 275 "Content-Type: %s", upload_content_type_.c_str()); | 300 "Content-Type: %s", upload_content_type_.c_str()); |
| 276 request_->AppendBytesToUpload(upload_content_.data(), | 301 request_->AppendBytesToUpload(upload_content_.data(), |
| 277 static_cast<int>(upload_content_.size())); | 302 static_cast<int>(upload_content_.size())); |
| 278 } | 303 } |
| 279 if (!extra_request_headers_.empty()) | 304 if (!extra_request_headers_.empty()) |
| 280 request_->SetExtraRequestHeaders(extra_request_headers_); | 305 request_->SetExtraRequestHeaders(extra_request_headers_); |
| 281 | 306 |
| 282 request_->Start(); | 307 request_->Start(); |
| 283 AddRef(); // Release after |request_| deleted. | 308 AddRef(); // Release after |request_| deleted. |
| 284 } | 309 } |
| 285 | 310 |
| 286 void CancelURLRequest() { | 311 void CancelURLRequest() { |
| 287 if (io_loop_) | 312 #ifndef NDEBUG |
| 288 DCHECK_EQ(MessageLoopForIO::current(), io_loop_); | 313 { |
| 314 AutoLock autolock(lock_); |
| 315 if (io_loop_) |
| 316 DCHECK_EQ(MessageLoopForIO::current(), io_loop_); |
| 317 } |
| 318 #endif |
| 289 if (request_) { | 319 if (request_) { |
| 290 request_->Cancel(); | 320 request_->Cancel(); |
| 291 delete request_; | 321 delete request_; |
| 292 request_ = NULL; | 322 request_ = NULL; |
| 293 { | 323 { |
| 294 AutoLock autolock(lock_); | 324 AutoLock autolock(lock_); |
| 295 finished_ = true; | 325 finished_ = true; |
| 296 io_loop_ = NULL; | 326 io_loop_ = NULL; |
| 297 } | 327 } |
| 298 cv_.Signal(); | 328 cv_.Signal(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); | 393 DISALLOW_COPY_AND_ASSIGN(OCSPServerSession); |
| 364 }; | 394 }; |
| 365 | 395 |
| 366 | 396 |
| 367 // OCSP Http Client functions. | 397 // OCSP Http Client functions. |
| 368 // Our Http Client functions operate in blocking mode. | 398 // Our Http Client functions operate in blocking mode. |
| 369 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, | 399 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum, |
| 370 SEC_HTTP_SERVER_SESSION* pSession) { | 400 SEC_HTTP_SERVER_SESSION* pSession) { |
| 371 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum; | 401 LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum; |
| 372 DCHECK(!MessageLoop::current()); | 402 DCHECK(!MessageLoop::current()); |
| 373 if (Singleton<OCSPInitSingleton>::get()->url_request_context() == NULL) { | 403 if (OCSPInitSingleton::url_request_context() == NULL) { |
| 374 LOG(ERROR) << "No URLRequestContext for OCSP handler."; | 404 LOG(ERROR) << "No URLRequestContext for OCSP handler."; |
| 375 return SECFailure; | 405 return SECFailure; |
| 376 } | 406 } |
| 377 *pSession = new OCSPServerSession(host, portnum); | 407 *pSession = new OCSPServerSession(host, portnum); |
| 378 return SECSuccess; | 408 return SECSuccess; |
| 379 } | 409 } |
| 380 | 410 |
| 381 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, | 411 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session, |
| 382 PRPollDesc **pPollDesc) { | 412 PRPollDesc **pPollDesc) { |
| 383 LOG(INFO) << "OCSP keep alive"; | 413 LOG(INFO) << "OCSP keep alive"; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 531 LOG(INFO) << "OCSP free"; | 561 LOG(INFO) << "OCSP free"; |
| 532 DCHECK(!MessageLoop::current()); | 562 DCHECK(!MessageLoop::current()); |
| 533 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); | 563 OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request); |
| 534 req->Cancel(); | 564 req->Cancel(); |
| 535 req->Release(); | 565 req->Release(); |
| 536 return SECSuccess; | 566 return SECSuccess; |
| 537 } | 567 } |
| 538 | 568 |
| 539 OCSPInitSingleton::OCSPInitSingleton() | 569 OCSPInitSingleton::OCSPInitSingleton() |
| 540 : io_loop_(MessageLoopForIO::current()) { | 570 : io_loop_(MessageLoopForIO::current()) { |
| 571 DCHECK(io_loop_); |
| 541 io_loop_->AddDestructionObserver(this); | 572 io_loop_->AddDestructionObserver(this); |
| 542 client_fcn_.version = 1; | 573 client_fcn_.version = 1; |
| 543 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; | 574 SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1; |
| 544 ft->createSessionFcn = OCSPCreateSession; | 575 ft->createSessionFcn = OCSPCreateSession; |
| 545 ft->keepAliveSessionFcn = OCSPKeepAliveSession; | 576 ft->keepAliveSessionFcn = OCSPKeepAliveSession; |
| 546 ft->freeSessionFcn = OCSPFreeSession; | 577 ft->freeSessionFcn = OCSPFreeSession; |
| 547 ft->createFcn = OCSPCreate; | 578 ft->createFcn = OCSPCreate; |
| 548 ft->setPostDataFcn = OCSPSetPostData; | 579 ft->setPostDataFcn = OCSPSetPostData; |
| 549 ft->addHeaderFcn = OCSPAddHeader; | 580 ft->addHeaderFcn = OCSPAddHeader; |
| 550 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; | 581 ft->trySendAndReceiveFcn = OCSPTrySendAndReceive; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 567 // This function would be called before NSS initialization. | 598 // This function would be called before NSS initialization. |
| 568 void SetURLRequestContextForOCSP(URLRequestContext* request_context) { | 599 void SetURLRequestContextForOCSP(URLRequestContext* request_context) { |
| 569 OCSPInitSingleton::set_url_request_context(request_context); | 600 OCSPInitSingleton::set_url_request_context(request_context); |
| 570 } | 601 } |
| 571 | 602 |
| 572 URLRequestContext* GetURLRequestContextForOCSP() { | 603 URLRequestContext* GetURLRequestContextForOCSP() { |
| 573 return OCSPInitSingleton::url_request_context(); | 604 return OCSPInitSingleton::url_request_context(); |
| 574 } | 605 } |
| 575 | 606 |
| 576 } // namespace net | 607 } // namespace net |
| OLD | NEW |