• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "net/ocsp/nss_ocsp.h"
6 
7 #include <certt.h>
8 #include <certdb.h>
9 #include <ocsp.h>
10 #include <nspr.h>
11 #include <nss.h>
12 #include <secerr.h>
13 
14 #include <string>
15 
16 #include "base/compiler_specific.h"
17 #include "base/condition_variable.h"
18 #include "base/logging.h"
19 #include "base/message_loop.h"
20 #include "base/singleton.h"
21 #include "base/thread.h"
22 #include "base/time.h"
23 #include "googleurl/src/gurl.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/load_flags.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/url_request.h"
28 #include "net/url_request/url_request_context.h"
29 
30 namespace {
31 
32 const int kRecvBufferSize = 4096;
33 
34 // All OCSP handlers should be called in the context of
35 // CertVerifier's thread (i.e. worker pool, not on the I/O thread).
36 // It supports blocking mode only.
37 
38 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
39                             SEC_HTTP_SERVER_SESSION* pSession);
40 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,
41                                PRPollDesc **pPollDesc);
42 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session);
43 
44 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session,
45                      const char* http_protocol_variant,
46                      const char* path_and_query_string,
47                      const char* http_request_method,
48                      const PRIntervalTime timeout,
49                      SEC_HTTP_REQUEST_SESSION* pRequest);
50 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request,
51                           const char* http_data,
52                           const PRUint32 http_data_len,
53                           const char* http_content_type);
54 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request,
55                         const char* http_header_name,
56                         const char* http_header_value);
57 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request,
58                                 PRPollDesc** pPollDesc,
59                                 PRUint16* http_response_code,
60                                 const char** http_response_content_type,
61                                 const char** http_response_headers,
62                                 const char** http_response_data,
63                                 PRUint32* http_response_data_len);
64 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request);
65 
66 class OCSPInitSingleton : public MessageLoop::DestructionObserver {
67  public:
68   // Called on IO thread.
WillDestroyCurrentMessageLoop()69   virtual void WillDestroyCurrentMessageLoop() {
70     AutoLock autolock(lock_);
71     DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
72     io_loop_ = NULL;
73     request_context_ = NULL;
74   };
75 
76   // Called from worker thread.
PostTaskToIOLoop(const tracked_objects::Location & from_here,Task * task)77   void PostTaskToIOLoop(
78       const tracked_objects::Location& from_here, Task* task) {
79     AutoLock autolock(lock_);
80     if (io_loop_)
81       io_loop_->PostTask(from_here, task);
82   }
83 
84   // This is static method because it is called before NSS initialization,
85   // that is, before OCSPInitSingleton is initialized.
set_url_request_context(URLRequestContext * request_context)86   static void set_url_request_context(URLRequestContext* request_context) {
87     request_context_ = request_context;
88   }
url_request_context()89   static URLRequestContext* url_request_context() {
90     return request_context_;
91   }
92 
93  private:
94   friend struct DefaultSingletonTraits<OCSPInitSingleton>;
95 
OCSPInitSingleton()96   OCSPInitSingleton()
97       : io_loop_(MessageLoopForIO::current()) {
98     DCHECK(io_loop_);
99     io_loop_->AddDestructionObserver(this);
100     client_fcn_.version = 1;
101     SEC_HttpClientFcnV1Struct *ft = &client_fcn_.fcnTable.ftable1;
102     ft->createSessionFcn = OCSPCreateSession;
103     ft->keepAliveSessionFcn = OCSPKeepAliveSession;
104     ft->freeSessionFcn = OCSPFreeSession;
105     ft->createFcn = OCSPCreate;
106     ft->setPostDataFcn = OCSPSetPostData;
107     ft->addHeaderFcn = OCSPAddHeader;
108     ft->trySendAndReceiveFcn = OCSPTrySendAndReceive;
109     ft->cancelFcn = NULL;
110     ft->freeFcn = OCSPFree;
111     SECStatus status = SEC_RegisterDefaultHttpClient(&client_fcn_);
112     if (status != SECSuccess) {
113       NOTREACHED() << "Error initializing OCSP: " << PR_GetError();
114     }
115   }
116 
~OCSPInitSingleton()117   virtual ~OCSPInitSingleton() {
118     // IO thread was already deleted before the singleton is deleted
119     // in AtExitManager.
120     AutoLock autolock(lock_);
121     DCHECK(!io_loop_);
122     DCHECK(!request_context_);
123   }
124 
125   SEC_HttpClientFcn client_fcn_;
126 
127   // |lock_| protects |io_loop_|.
128   Lock lock_;
129   // I/O thread.
130   MessageLoop* io_loop_;  // I/O thread
131   // URLRequestContext for OCSP handlers.
132   static URLRequestContext* request_context_;
133 
134   DISALLOW_COPY_AND_ASSIGN(OCSPInitSingleton);
135 };
136 
137 URLRequestContext* OCSPInitSingleton::request_context_ = NULL;
138 
139 // Concrete class for SEC_HTTP_REQUEST_SESSION.
140 // Public methods except virtual methods of URLRequest::Delegate (On* methods)
141 // run on certificate verifier thread (worker thread).
142 // Virtual methods of URLRequest::Delegate and private methods run
143 // on IO thread.
144 class OCSPRequestSession
145     : public base::RefCountedThreadSafe<OCSPRequestSession>,
146       public URLRequest::Delegate,
147       public MessageLoop::DestructionObserver {
148  public:
OCSPRequestSession(const GURL & url,const char * http_request_method,base::TimeDelta timeout)149   OCSPRequestSession(const GURL& url,
150                      const char* http_request_method,
151                      base::TimeDelta timeout)
152       : url_(url),
153         http_request_method_(http_request_method),
154         timeout_(timeout),
155         request_(NULL),
156         buffer_(new net::IOBuffer(kRecvBufferSize)),
157         response_code_(-1),
158         cv_(&lock_),
159         io_loop_(NULL),
160         finished_(false) {}
161 
SetPostData(const char * http_data,PRUint32 http_data_len,const char * http_content_type)162   void SetPostData(const char* http_data, PRUint32 http_data_len,
163                    const char* http_content_type) {
164     upload_content_.assign(http_data, http_data_len);
165     upload_content_type_.assign(http_content_type);
166   }
167 
AddHeader(const char * http_header_name,const char * http_header_value)168   void AddHeader(const char* http_header_name, const char* http_header_value) {
169     if (!extra_request_headers_.empty())
170       extra_request_headers_ += "\r\n";
171     StringAppendF(&extra_request_headers_,
172                   "%s: %s", http_header_name, http_header_value);
173   }
174 
Start()175   void Start() {
176     // At this point, it runs on worker thread.
177     // |io_loop_| was initialized to be NULL in constructor, and
178     // set only in StartURLRequest, so no need to lock |lock_| here.
179     DCHECK(!io_loop_);
180     Singleton<OCSPInitSingleton>()->PostTaskToIOLoop(
181         FROM_HERE,
182         NewRunnableMethod(this, &OCSPRequestSession::StartURLRequest));
183   }
184 
Started() const185   bool Started() const {
186     return request_ != NULL;
187   }
188 
Cancel()189   void Cancel() {
190     // IO thread may set |io_loop_| to NULL, so protect by |lock_|.
191     AutoLock autolock(lock_);
192     CancelLocked();
193   }
194 
Finished() const195   bool Finished() const {
196     AutoLock autolock(lock_);
197     return finished_;
198   }
199 
Wait()200   bool Wait() {
201     base::TimeDelta timeout = timeout_;
202     AutoLock autolock(lock_);
203     while (!finished_) {
204       base::TimeTicks last_time = base::TimeTicks::Now();
205       cv_.TimedWait(timeout);
206       // Check elapsed time
207       base::TimeDelta elapsed_time = base::TimeTicks::Now() - last_time;
208       timeout -= elapsed_time;
209       if (timeout < base::TimeDelta()) {
210         LOG(INFO) << "OCSP Timed out";
211         if (!finished_)
212           CancelLocked();
213         break;
214       }
215     }
216     return finished_;
217   }
218 
url() const219   const GURL& url() const {
220     return url_;
221   }
222 
http_request_method() const223   const std::string& http_request_method() const {
224     return http_request_method_;
225   }
226 
timeout() const227   base::TimeDelta timeout() const {
228     return timeout_;
229   }
230 
http_response_code() const231   PRUint16 http_response_code() const {
232     DCHECK(finished_);
233     return response_code_;
234   }
235 
http_response_content_type() const236   const std::string& http_response_content_type() const {
237     DCHECK(finished_);
238     return response_content_type_;
239   }
240 
http_response_headers() const241   const std::string& http_response_headers() const {
242     DCHECK(finished_);
243     return response_headers_->raw_headers();
244   }
245 
http_response_data() const246   const std::string& http_response_data() const {
247     DCHECK(finished_);
248     return data_;
249   }
250 
OnResponseStarted(URLRequest * request)251   virtual void OnResponseStarted(URLRequest* request) {
252     DCHECK_EQ(request, request_);
253     DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
254 
255     int bytes_read = 0;
256     if (request->status().is_success()) {
257       response_code_ = request_->GetResponseCode();
258       response_headers_ = request_->response_headers();
259       response_headers_->GetMimeType(&response_content_type_);
260       request_->Read(buffer_, kRecvBufferSize, &bytes_read);
261     }
262     OnReadCompleted(request_, bytes_read);
263   }
264 
OnReadCompleted(URLRequest * request,int bytes_read)265   virtual void OnReadCompleted(URLRequest* request, int bytes_read) {
266     DCHECK_EQ(request, request_);
267     DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
268 
269     do {
270       if (!request_->status().is_success() || bytes_read <= 0)
271         break;
272       data_.append(buffer_->data(), bytes_read);
273     } while (request_->Read(buffer_, kRecvBufferSize, &bytes_read));
274 
275     if (!request_->status().is_io_pending()) {
276       delete request_;
277       request_ = NULL;
278       io_loop_->RemoveDestructionObserver(this);
279       {
280         AutoLock autolock(lock_);
281         finished_ = true;
282         io_loop_ = NULL;
283       }
284       cv_.Signal();
285       Release();  // Balanced with StartURLRequest().
286     }
287   }
288 
WillDestroyCurrentMessageLoop()289   virtual void WillDestroyCurrentMessageLoop() {
290     DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
291     {
292       AutoLock autolock(lock_);
293       io_loop_ = NULL;
294     }
295     CancelURLRequest();
296   }
297 
298  private:
299   friend class base::RefCountedThreadSafe<OCSPRequestSession>;
300 
~OCSPRequestSession()301   virtual ~OCSPRequestSession() {
302     // When this destructor is called, there should be only one thread that has
303     // a reference to this object, and so that thread doesn't need to lock
304     // |lock_| here.
305     DCHECK(!request_);
306     DCHECK(!io_loop_);
307   }
308 
309   // Must call this method while holding |lock_|.
CancelLocked()310   void CancelLocked() {
311     lock_.AssertAcquired();
312     if (io_loop_) {
313       io_loop_->PostTask(
314           FROM_HERE,
315           NewRunnableMethod(this, &OCSPRequestSession::CancelURLRequest));
316     }
317   }
318 
StartURLRequest()319   void StartURLRequest() {
320     DCHECK(!request_);
321 
322     URLRequestContext* url_request_context =
323         OCSPInitSingleton::url_request_context();
324     if (url_request_context == NULL)
325       return;
326 
327     {
328       AutoLock autolock(lock_);
329       DCHECK(!io_loop_);
330       io_loop_ = MessageLoopForIO::current();
331       io_loop_->AddDestructionObserver(this);
332     }
333 
334     request_ = new URLRequest(url_, this);
335     request_->set_context(url_request_context);
336     // To meet the privacy requirements of off-the-record mode.
337     request_->set_load_flags(
338         net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SAVE_COOKIES |
339         net::LOAD_DO_NOT_SEND_COOKIES);
340 
341     if (http_request_method_ == "POST") {
342       DCHECK(!upload_content_.empty());
343       DCHECK(!upload_content_type_.empty());
344 
345       request_->set_method("POST");
346       if (!extra_request_headers_.empty())
347         extra_request_headers_ += "\r\n";
348       StringAppendF(&extra_request_headers_,
349                     "Content-Type: %s", upload_content_type_.c_str());
350       request_->AppendBytesToUpload(upload_content_.data(),
351                                     static_cast<int>(upload_content_.size()));
352     }
353     if (!extra_request_headers_.empty())
354       request_->SetExtraRequestHeaders(extra_request_headers_);
355 
356     request_->Start();
357     AddRef();  // Release after |request_| deleted.
358   }
359 
CancelURLRequest()360   void CancelURLRequest() {
361 #ifndef NDEBUG
362     {
363       AutoLock autolock(lock_);
364       if (io_loop_)
365         DCHECK_EQ(MessageLoopForIO::current(), io_loop_);
366     }
367 #endif
368     if (request_) {
369       request_->Cancel();
370       delete request_;
371       request_ = NULL;
372       // |io_loop_| may be NULL here if it called from
373       // WillDestroyCurrentMessageLoop().
374       if (io_loop_)
375         io_loop_->RemoveDestructionObserver(this);
376       {
377         AutoLock autolock(lock_);
378         finished_ = true;
379         io_loop_ = NULL;
380       }
381       cv_.Signal();
382       Release();  // Balanced with StartURLRequest().
383     }
384   }
385 
386   GURL url_;                      // The URL we eventually wound up at
387   std::string http_request_method_;
388   base::TimeDelta timeout_;       // The timeout for OCSP
389   URLRequest* request_;           // The actual request this wraps
390   scoped_refptr<net::IOBuffer> buffer_;  // Read buffer
391   std::string extra_request_headers_;  // Extra headers for the request, if any
392   std::string upload_content_;    // HTTP POST payload
393   std::string upload_content_type_;  // MIME type of POST payload
394 
395   int response_code_;             // HTTP status code for the request
396   std::string response_content_type_;
397   scoped_refptr<net::HttpResponseHeaders> response_headers_;
398   std::string data_;              // Results of the requst
399 
400   // |lock_| protects |finished_| and |io_loop_|.
401   mutable Lock lock_;
402   ConditionVariable cv_;
403 
404   MessageLoop* io_loop_;          // Message loop of the IO thread
405   bool finished_;
406 
407   DISALLOW_COPY_AND_ASSIGN(OCSPRequestSession);
408 };
409 
410 // Concrete class for SEC_HTTP_SERVER_SESSION.
411 class OCSPServerSession {
412  public:
OCSPServerSession(const char * host,PRUint16 port)413   OCSPServerSession(const char* host, PRUint16 port)
414       : host_(host), port_(port) {}
~OCSPServerSession()415   ~OCSPServerSession() {}
416 
CreateRequest(const char * http_protocol_variant,const char * path_and_query_string,const char * http_request_method,const PRIntervalTime timeout)417   OCSPRequestSession* CreateRequest(const char* http_protocol_variant,
418                                     const char* path_and_query_string,
419                                     const char* http_request_method,
420                                     const PRIntervalTime timeout) {
421     // We dont' support "https" because we haven't thought about
422     // whether it's safe to re-enter this code from talking to an OCSP
423     // responder over SSL.
424     if (strcmp(http_protocol_variant, "http") != 0)
425       return NULL;
426 
427     // TODO(ukai): If |host| is an IPv6 literal, we need to quote it with
428     //  square brackets [].
429     std::string url_string(StringPrintf("%s://%s:%d%s",
430                                         http_protocol_variant,
431                                         host_.c_str(),
432                                         port_,
433                                         path_and_query_string));
434     LOG(INFO) << "URL [" << url_string << "]";
435     GURL url(url_string);
436     return new OCSPRequestSession(
437         url, http_request_method,
438         base::TimeDelta::FromMilliseconds(PR_IntervalToMilliseconds(timeout)));
439   }
440 
441 
442  private:
443   std::string host_;
444   int port_;
445 
446   DISALLOW_COPY_AND_ASSIGN(OCSPServerSession);
447 };
448 
449 
450 // OCSP Http Client functions.
451 // Our Http Client functions operate in blocking mode.
OCSPCreateSession(const char * host,PRUint16 portnum,SEC_HTTP_SERVER_SESSION * pSession)452 SECStatus OCSPCreateSession(const char* host, PRUint16 portnum,
453                             SEC_HTTP_SERVER_SESSION* pSession) {
454   LOG(INFO) << "OCSP create session: host=" << host << " port=" << portnum;
455   DCHECK(!MessageLoop::current());
456   if (OCSPInitSingleton::url_request_context() == NULL) {
457     LOG(ERROR) << "No URLRequestContext for OCSP handler.";
458     return SECFailure;
459   }
460   *pSession = new OCSPServerSession(host, portnum);
461   return SECSuccess;
462 }
463 
OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,PRPollDesc ** pPollDesc)464 SECStatus OCSPKeepAliveSession(SEC_HTTP_SERVER_SESSION session,
465                                PRPollDesc **pPollDesc) {
466   LOG(INFO) << "OCSP keep alive";
467   DCHECK(!MessageLoop::current());
468   if (pPollDesc)
469     *pPollDesc = NULL;
470   return SECSuccess;
471 }
472 
OCSPFreeSession(SEC_HTTP_SERVER_SESSION session)473 SECStatus OCSPFreeSession(SEC_HTTP_SERVER_SESSION session) {
474   LOG(INFO) << "OCSP free session";
475   DCHECK(!MessageLoop::current());
476   delete reinterpret_cast<OCSPServerSession*>(session);
477   return SECSuccess;
478 }
479 
OCSPCreate(SEC_HTTP_SERVER_SESSION session,const char * http_protocol_variant,const char * path_and_query_string,const char * http_request_method,const PRIntervalTime timeout,SEC_HTTP_REQUEST_SESSION * pRequest)480 SECStatus OCSPCreate(SEC_HTTP_SERVER_SESSION session,
481                      const char* http_protocol_variant,
482                      const char* path_and_query_string,
483                      const char* http_request_method,
484                      const PRIntervalTime timeout,
485                      SEC_HTTP_REQUEST_SESSION* pRequest) {
486   LOG(INFO) << "OCSP create protocol=" << http_protocol_variant
487             << " path_and_query=" << path_and_query_string
488             << " http_request_method=" << http_request_method
489             << " timeout=" << timeout;
490   DCHECK(!MessageLoop::current());
491   OCSPServerSession* ocsp_session =
492       reinterpret_cast<OCSPServerSession*>(session);
493 
494   OCSPRequestSession* req = ocsp_session->CreateRequest(http_protocol_variant,
495                                                         path_and_query_string,
496                                                         http_request_method,
497                                                         timeout);
498   SECStatus rv = SECFailure;
499   if (req) {
500     req->AddRef();  // Release in OCSPFree().
501     rv = SECSuccess;
502   }
503   *pRequest = req;
504   return rv;
505 }
506 
OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request,const char * http_data,const PRUint32 http_data_len,const char * http_content_type)507 SECStatus OCSPSetPostData(SEC_HTTP_REQUEST_SESSION request,
508                           const char* http_data,
509                           const PRUint32 http_data_len,
510                           const char* http_content_type) {
511   LOG(INFO) << "OCSP set post data len=" << http_data_len;
512   DCHECK(!MessageLoop::current());
513   OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
514 
515   req->SetPostData(http_data, http_data_len, http_content_type);
516   return SECSuccess;
517 }
518 
OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request,const char * http_header_name,const char * http_header_value)519 SECStatus OCSPAddHeader(SEC_HTTP_REQUEST_SESSION request,
520                         const char* http_header_name,
521                         const char* http_header_value) {
522   LOG(INFO) << "OCSP add header name=" << http_header_name
523             << " value=" << http_header_value;
524   DCHECK(!MessageLoop::current());
525   OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
526 
527   req->AddHeader(http_header_name, http_header_value);
528   return SECSuccess;
529 }
530 
531 // Sets response of |req| in the output parameters.
532 // It is helper routine for OCSP trySendAndReceiveFcn.
533 // |http_response_data_len| could be used as input parameter.  If it has
534 // non-zero value, it is considered as maximum size of |http_response_data|.
OCSPSetResponse(OCSPRequestSession * req,PRUint16 * http_response_code,const char ** http_response_content_type,const char ** http_response_headers,const char ** http_response_data,PRUint32 * http_response_data_len)535 bool OCSPSetResponse(OCSPRequestSession* req,
536                      PRUint16* http_response_code,
537                      const char** http_response_content_type,
538                      const char** http_response_headers,
539                      const char** http_response_data,
540                      PRUint32* http_response_data_len) {
541   DCHECK(req->Finished());
542   const std::string& data = req->http_response_data();
543   if (http_response_data_len && *http_response_data_len) {
544     if (*http_response_data_len < data.size()) {
545       LOG(ERROR) << "data size too large: " << *http_response_data_len
546                  << " < " << data.size();
547       *http_response_data_len = data.size();
548       return false;
549     }
550   }
551   LOG(INFO) << "OCSP response "
552             << " response_code=" << req->http_response_code()
553             << " content_type=" << req->http_response_content_type()
554             << " header=" << req->http_response_headers()
555             << " data_len=" << data.size();
556   if (http_response_code)
557     *http_response_code = req->http_response_code();
558   if (http_response_content_type)
559     *http_response_content_type = req->http_response_content_type().c_str();
560   if (http_response_headers)
561     *http_response_headers = req->http_response_headers().c_str();
562   if (http_response_data)
563     *http_response_data = data.data();
564   if (http_response_data_len)
565     *http_response_data_len = data.size();
566   return true;
567 }
568 
OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request,PRPollDesc ** pPollDesc,PRUint16 * http_response_code,const char ** http_response_content_type,const char ** http_response_headers,const char ** http_response_data,PRUint32 * http_response_data_len)569 SECStatus OCSPTrySendAndReceive(SEC_HTTP_REQUEST_SESSION request,
570                                 PRPollDesc** pPollDesc,
571                                 PRUint16* http_response_code,
572                                 const char** http_response_content_type,
573                                 const char** http_response_headers,
574                                 const char** http_response_data,
575                                 PRUint32* http_response_data_len) {
576   LOG(INFO) << "OCSP try send and receive";
577   DCHECK(!MessageLoop::current());
578   OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
579   // We support blocking mode only.
580   if (pPollDesc)
581     *pPollDesc = NULL;
582 
583   if (req->Started() || req->Finished()) {
584     // We support blocking mode only, so this function shouldn't be called
585     // again when req has stareted or finished.
586     NOTREACHED();
587     goto failed;
588   }
589   req->Start();
590   if (!req->Wait())
591     goto failed;
592 
593   // If the response code is -1, the request failed and there is no response.
594   if (req->http_response_code() == static_cast<PRUint16>(-1))
595     goto failed;
596 
597   return OCSPSetResponse(
598       req, http_response_code,
599       http_response_content_type,
600       http_response_headers,
601       http_response_data,
602       http_response_data_len) ? SECSuccess : SECFailure;
603 
604  failed:
605   if (http_response_data_len) {
606     // We must always set an output value, even on failure.  The output value 0
607     // means the failure was unrelated to the acceptable response data length.
608     *http_response_data_len = 0;
609   }
610   return SECFailure;
611 }
612 
OCSPFree(SEC_HTTP_REQUEST_SESSION request)613 SECStatus OCSPFree(SEC_HTTP_REQUEST_SESSION request) {
614   LOG(INFO) << "OCSP free";
615   DCHECK(!MessageLoop::current());
616   OCSPRequestSession* req = reinterpret_cast<OCSPRequestSession*>(request);
617   req->Cancel();
618   req->Release();
619   return SECSuccess;
620 }
621 
622 }  // anonymous namespace
623 
624 namespace net {
625 
EnsureOCSPInit()626 void EnsureOCSPInit() {
627   Singleton<OCSPInitSingleton>::get();
628 }
629 
630 // This function would be called before NSS initialization.
SetURLRequestContextForOCSP(URLRequestContext * request_context)631 void SetURLRequestContextForOCSP(URLRequestContext* request_context) {
632   OCSPInitSingleton::set_url_request_context(request_context);
633 }
634 
GetURLRequestContextForOCSP()635 URLRequestContext* GetURLRequestContextForOCSP() {
636   return OCSPInitSingleton::url_request_context();
637 }
638 
639 }  // namespace net
640