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

Side by Side Diff: net/ocsp/nss_ocsp.cc

Issue 460067: Don't call RemoveDestructionObserver on non-IO thread. (Closed)
Patch Set: fix maruel and wtc comments Created 11 years 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698