Back to index

lightning-sunbird  0.9+nobinonly
nsNSSCallbacks.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Brian Ryner <bryner@brianryner.com>
00025  *   Terry Hayes <thayes@netscape.com>
00026  *   Kai Engert <kengert@redhat.com>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 #include "nsNSSComponent.h" // for PIPNSS string bundle calls.
00042 #include "nsNSSCallbacks.h"
00043 #include "nsNSSCertificate.h"
00044 #include "nsISSLStatus.h"
00045 #include "nsNSSIOLayer.h" // for nsNSSSocketInfo
00046 #include "nsIWebProgressListener.h"
00047 #include "nsIStringBundle.h"
00048 #include "nsXPIDLString.h"
00049 #include "nsCOMPtr.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsReadableUtils.h"
00052 #include "nsIPrompt.h"
00053 #include "nsProxiedService.h"
00054 #include "nsIInterfaceRequestor.h"
00055 #include "nsIInterfaceRequestorUtils.h"
00056 #include "nsCRT.h"
00057 #include "nsNSSShutDown.h"
00058 #include "nsNSSEvent.h"
00059 #include "nsIUploadChannel.h"
00060 #include "nsSSLThread.h"
00061 #include "nsAutoLock.h"
00062 #include "nsIThread.h"
00063 #include "nsIWindowWatcher.h"
00064 #include "nsIPrompt.h"
00065 
00066 #include "ssl.h"
00067 #include "cert.h"
00068 #include "ocsp.h"
00069 
00070 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
00071 
00072 #ifdef PR_LOGGING
00073 extern PRLogModuleInfo* gPIPNSSLog;
00074 #endif
00075 
00076 struct nsHTTPDownloadEvent : PLEvent {
00077   nsHTTPDownloadEvent();
00078   ~nsHTTPDownloadEvent();
00079   
00080   nsNSSHttpRequestSession *mRequestSession; // no ownership
00081   
00082   nsCOMPtr<nsHTTPListener> mListener;
00083   PRBool mResponsibleForDoneSignal;
00084 };
00085 
00086 nsHTTPDownloadEvent::nsHTTPDownloadEvent()
00087 :mResponsibleForDoneSignal(PR_TRUE)
00088 {
00089 }
00090 
00091 nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
00092 {
00093   if (mResponsibleForDoneSignal && mListener)
00094     mListener->send_done_signal();
00095 }
00096 
00097 static void PR_CALLBACK HandleHTTPDownloadPLEvent(nsHTTPDownloadEvent *aEvent)
00098 {
00099   if((!aEvent) || (!aEvent->mListener))
00100     return;
00101 
00102   nsresult rv;
00103   nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
00104   if (NS_FAILED(rv))
00105     return;
00106 
00107   nsCOMPtr<nsIChannel> chan;
00108   ios->NewChannel(aEvent->mRequestSession->mURL, nsnull, nsnull, getter_AddRefs(chan));
00109   if (NS_FAILED(rv))
00110     return;
00111 
00112   // Create a loadgroup for this new channel.  This way if the channel
00113   // is redirected, we'll have a way to cancel the resulting channel.
00114   nsCOMPtr<nsILoadGroup> loadGroup =
00115     do_CreateInstance(NS_LOADGROUP_CONTRACTID);
00116   chan->SetLoadGroup(loadGroup);
00117 
00118   if (aEvent->mRequestSession->mHasPostData)
00119   {
00120     nsCOMPtr<nsIInputStream> uploadStream;
00121     rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
00122                               PR_FALSE,
00123                               aEvent->mRequestSession->mPostData,
00124                               0, ios);
00125     if (NS_FAILED(rv))
00126       return;
00127 
00128     nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan, &rv));
00129     if (NS_FAILED(rv))
00130       return;
00131 
00132     rv = uploadChannel->SetUploadStream(uploadStream, 
00133                                         aEvent->mRequestSession->mPostContentType,
00134                                         -1);
00135     if (NS_FAILED(rv))
00136       return;
00137   }
00138 
00139   nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan, &rv);
00140   if (NS_FAILED(rv))
00141     return;
00142 
00143   rv = hchan->SetRequestMethod(aEvent->mRequestSession->mRequestMethod);
00144   if (NS_FAILED(rv))
00145     return;
00146 
00147   nsSSLThread::rememberPendingHTTPRequest(loadGroup);
00148 
00149   aEvent->mResponsibleForDoneSignal = PR_FALSE;
00150   aEvent->mListener->mResponsibleForDoneSignal = PR_TRUE;
00151 
00152   rv = NS_NewStreamLoader(getter_AddRefs(aEvent->mListener->mLoader), 
00153                           hchan, 
00154                           aEvent->mListener, 
00155                           nsnull);
00156 
00157   if (NS_FAILED(rv)) {
00158     aEvent->mListener->mResponsibleForDoneSignal = PR_FALSE;
00159     aEvent->mResponsibleForDoneSignal = PR_TRUE;
00160     
00161     nsSSLThread::rememberPendingHTTPRequest(nsnull);
00162   }
00163 }
00164 
00165 static void PR_CALLBACK DestroyHTTPDownloadPLEvent(nsHTTPDownloadEvent* aEvent)
00166 {
00167   delete aEvent;
00168 }
00169 
00170 struct nsCancelHTTPDownloadEvent : PLEvent {
00171 };
00172 
00173 static void PR_CALLBACK HandleCancelHTTPDownloadPLEvent(nsCancelHTTPDownloadEvent *aEvent)
00174 {
00175   nsSSLThread::cancelPendingHTTPRequest();
00176 }
00177 
00178 static void PR_CALLBACK DestroyCancelHTTPDownloadPLEvent(nsCancelHTTPDownloadEvent* aEvent)
00179 {
00180   delete aEvent;
00181 }
00182 
00183 SECStatus nsNSSHttpServerSession::createSessionFcn(const char *host,
00184                                                    PRUint16 portnum,
00185                                                    SEC_HTTP_SERVER_SESSION *pSession)
00186 {
00187   if (!host || !pSession)
00188     return SECFailure;
00189 
00190   nsNSSHttpServerSession *hss = new nsNSSHttpServerSession;
00191   if (!hss)
00192     return SECFailure;
00193 
00194   hss->mHost = host;
00195   hss->mPort = portnum;
00196 
00197   *pSession = hss;
00198   return SECSuccess;
00199 }
00200 
00201 SECStatus nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session,
00202                                              const char *http_protocol_variant,
00203                                              const char *path_and_query_string,
00204                                              const char *http_request_method, 
00205                                              const PRIntervalTime timeout, 
00206                                              SEC_HTTP_REQUEST_SESSION *pRequest)
00207 {
00208   if (!session || !http_protocol_variant || !path_and_query_string || 
00209       !http_request_method || !pRequest)
00210     return SECFailure;
00211 
00212   nsNSSHttpServerSession* hss = NS_STATIC_CAST(nsNSSHttpServerSession*, session);
00213   if (!hss)
00214     return SECFailure;
00215 
00216   nsNSSHttpRequestSession *rs = new nsNSSHttpRequestSession;
00217   if (!rs)
00218     return SECFailure;
00219 
00220   rs->mTimeoutInterval = timeout;
00221 
00222   rs->mURL.Append(nsDependentCString(http_protocol_variant));
00223   rs->mURL.AppendLiteral("://");
00224   rs->mURL.Append(hss->mHost);
00225   rs->mURL.AppendLiteral(":");
00226   rs->mURL.AppendInt(hss->mPort);
00227   rs->mURL.Append(path_and_query_string);
00228 
00229   rs->mRequestMethod = nsDependentCString(http_request_method);
00230 
00231   *pRequest = (void*)rs;
00232   return SECSuccess;
00233 }
00234 
00235 SECStatus nsNSSHttpRequestSession::setPostDataFcn(const char *http_data, 
00236                                                   const PRUint32 http_data_len,
00237                                                   const char *http_content_type)
00238 {
00239   mHasPostData = PR_TRUE;
00240   mPostData.Assign(http_data, http_data_len);
00241   mPostContentType.Assign(http_content_type);
00242 
00243   return SECSuccess;
00244 }
00245 
00246 SECStatus nsNSSHttpRequestSession::addHeaderFcn(const char *http_header_name, 
00247                                                 const char *http_header_value)
00248 {
00249   return SECFailure; // not yet implemented
00250 
00251   // All http code needs to be postponed to the UI thread.
00252   // Once this gets implemented, we need to add a string list member to
00253   // nsNSSHttpRequestSession and queue up the headers,
00254   // so they can be added in HandleHTTPDownloadPLEvent.
00255   //
00256   // The header will need to be set using 
00257   //   mHttpChannel->SetRequestHeader(nsDependentCString(http_header_name), 
00258   //                                  nsDependentCString(http_header_value), 
00259   //                                  PR_FALSE)));
00260 }
00261 
00262 #define CONDITION_WAIT_TIME PR_MillisecondsToInterval(250)
00263 
00264 SECStatus nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc **pPollDesc,
00265                                                         PRUint16 *http_response_code, 
00266                                                         const char **http_response_content_type, 
00267                                                         const char **http_response_headers, 
00268                                                         const char **http_response_data, 
00269                                                         PRUint32 *http_response_data_len)
00270 {
00271   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
00272          ("nsNSSHttpRequestSession::trySendAndReceiveFcn to %s\n", mURL.get()));
00273 
00274   if (nsIThread::IsMainThread())
00275   {
00276     nsresult rv;
00277     nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00278     if (NS_FAILED(rv))
00279       return SECFailure;
00280 
00281     nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
00282     if (wwatch){
00283       nsCOMPtr<nsIPrompt> prompter;
00284       wwatch->GetNewPrompter(0, getter_AddRefs(prompter));
00285 
00286       nsString message;
00287       nssComponent->GetPIPNSSBundleString("OCSPDeadlock", message);
00288 
00289       if(prompter) {
00290         nsPSMUITracker tracker;
00291         if (!tracker.isUIForbidden()) {
00292           prompter->Alert(0, message.get());
00293         }
00294       }
00295     }
00296 
00297     return SECFailure;
00298   }
00299 
00300   const int max_retries = 5;
00301   int retry_count = 0;
00302   PRBool retryable_error = PR_FALSE;
00303   SECStatus result_sec_status = SECFailure;
00304 
00305   do
00306   {
00307     if (retry_count > 0)
00308     {
00309       if (retryable_error)
00310       {
00311         PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
00312                ("nsNSSHttpRequestSession::trySendAndReceiveFcn - sleeping and retrying: %d of %d\n",
00313                 retry_count, max_retries));
00314       }
00315 
00316       PR_Sleep( PR_MillisecondsToInterval(300) * retry_count );
00317     }
00318 
00319     ++retry_count;
00320     retryable_error = PR_FALSE;
00321 
00322     result_sec_status =
00323       internal_send_receive_attempt(retryable_error, pPollDesc, http_response_code,
00324                                     http_response_content_type, http_response_headers,
00325                                     http_response_data, http_response_data_len);
00326   }
00327   while (retryable_error &&
00328          retry_count < max_retries);
00329 
00330 #ifdef PR_LOGGING
00331   if (retry_count > 1)
00332   {
00333     if (retryable_error)
00334       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
00335              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - still failing, giving up...\n"));
00336     else
00337       PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
00338              ("nsNSSHttpRequestSession::trySendAndReceiveFcn - success at attempt %d\n",
00339               retry_count));
00340   }
00341 #endif
00342 
00343   return result_sec_status;
00344 }
00345 
00346 SECStatus
00347 nsNSSHttpRequestSession::internal_send_receive_attempt(PRBool &retryable_error,
00348                                                        PRPollDesc **pPollDesc,
00349                                                        PRUint16 *http_response_code,
00350                                                        const char **http_response_content_type,
00351                                                        const char **http_response_headers,
00352                                                        const char **http_response_data,
00353                                                        PRUint32 *http_response_data_len)
00354 {
00355   if (pPollDesc) *pPollDesc = nsnull;
00356   if (http_response_code) *http_response_code = 0;
00357   if (http_response_content_type) *http_response_content_type = 0;
00358   if (http_response_headers) *http_response_headers = 0;
00359   if (http_response_data) *http_response_data = 0;
00360 
00361   PRUint32 acceptableResultSize = 0;
00362 
00363   if (http_response_data_len)
00364   {
00365     acceptableResultSize = *http_response_data_len;
00366     *http_response_data_len = 0;
00367   }
00368   
00369   nsCOMPtr<nsIEventQueue> uiQueue = nsNSSEventGetUIEventQueue();
00370   if (!uiQueue)
00371     return SECFailure;
00372 
00373   if (!mListener)
00374     return SECFailure;
00375 
00376   if (NS_FAILED(mListener->InitLocks()))
00377     return SECFailure;
00378 
00379   PRLock *waitLock = mListener->mLock;
00380   PRCondVar *waitCondition = mListener->mCondition;
00381   volatile PRBool &waitFlag = mListener->mWaitFlag;
00382   waitFlag = PR_TRUE;
00383 
00384   nsHTTPDownloadEvent *event = new nsHTTPDownloadEvent;
00385   if (!event)
00386     return SECFailure;
00387 
00388   event->mListener = mListener;
00389   event->mRequestSession = this;
00390 
00391   PL_InitEvent(event, nsnull, (PLHandleEventProc)HandleHTTPDownloadPLEvent, 
00392                               (PLDestroyEventProc)DestroyHTTPDownloadPLEvent);
00393   nsresult rv = uiQueue->PostEvent(event);
00394   if (NS_FAILED(rv))
00395   {
00396     event->mResponsibleForDoneSignal = PR_FALSE;
00397     delete event;
00398     return SECFailure;
00399   }
00400 
00401   PRBool request_canceled = PR_FALSE;
00402   PRBool aborted_wait = PR_FALSE;
00403 
00404   {
00405     nsAutoLock locker(waitLock);
00406 
00407     const PRIntervalTime start_time = PR_IntervalNow();
00408     const PRIntervalTime wait_interval = CONDITION_WAIT_TIME;
00409 
00410     while (waitFlag)
00411     {
00412       PR_WaitCondVar(waitCondition, wait_interval);
00413       
00414       if (!waitFlag)
00415         break;
00416 
00417       if (!request_canceled)
00418       {
00419         if ((PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval)
00420         {
00421           request_canceled = PR_TRUE;
00422           // but we'll to continue to wait for waitFlag
00423           
00424           nsCancelHTTPDownloadEvent *cancelevent = new nsCancelHTTPDownloadEvent;
00425           PL_InitEvent(cancelevent, nsnull, (PLHandleEventProc)HandleCancelHTTPDownloadPLEvent, 
00426                                             (PLDestroyEventProc)DestroyCancelHTTPDownloadPLEvent);
00427           rv = uiQueue->PostEvent(cancelevent);
00428           if (NS_FAILED(rv))
00429           {
00430             NS_WARNING("cannot post cancel event");
00431             delete cancelevent;
00432             aborted_wait = PR_TRUE;
00433             break;
00434           }
00435         }
00436       }
00437     }
00438   }
00439 
00440   if (aborted_wait)
00441   {
00442     // we couldn't cancel it, let's no longer reference it
00443     nsSSLThread::rememberPendingHTTPRequest(nsnull);
00444   }
00445 
00446   if (request_canceled)
00447     return SECFailure;
00448 
00449   if (NS_FAILED(mListener->mResultCode))
00450   {
00451     if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED
00452         ||
00453         mListener->mResultCode == NS_ERROR_NET_RESET)
00454     {
00455       retryable_error = PR_TRUE;
00456     }
00457     return SECFailure;
00458   }
00459 
00460   if (http_response_code)
00461     *http_response_code = mListener->mHttpResponseCode;
00462 
00463   if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) {
00464 
00465     *http_response_data_len = mListener->mResultLen;
00466   
00467     // acceptableResultSize == 0 means: any size is acceptable
00468     if (acceptableResultSize != 0
00469         &&
00470         acceptableResultSize < mListener->mResultLen)
00471     {
00472       return SECFailure;
00473     }
00474 
00475     // return data by reference, result data will be valid 
00476     // until "this" gets destroyed by NSS
00477     *http_response_data = (const char*)mListener->mResultData;
00478   }
00479 
00480   if (mListener->mHttpRequestSucceeded && http_response_content_type) {
00481     if (mListener->mHttpResponseContentType.Length()) {
00482       *http_response_content_type = mListener->mHttpResponseContentType.get();
00483     }
00484   }
00485 
00486   return SECSuccess;
00487 }
00488 
00489 SECStatus nsNSSHttpRequestSession::cancelFcn()
00490 {
00491   // As of today, only the blocking variant of the http interface
00492   // has been implemented. Implementing cancelFcn will be necessary
00493   // as soon as we implement the nonblocking variant.
00494   return SECSuccess;
00495 }
00496 
00497 SECStatus nsNSSHttpRequestSession::freeFcn()
00498 {
00499   delete this;
00500   return SECSuccess;
00501 }
00502 
00503 nsNSSHttpRequestSession::nsNSSHttpRequestSession()
00504 : mHasPostData(PR_FALSE),
00505   mTimeoutInterval(0),
00506   mListener(new nsHTTPListener)
00507 {
00508 }
00509 
00510 nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
00511 {
00512 }
00513 
00514 SEC_HttpClientFcn nsNSSHttpInterface::sNSSInterfaceTable;
00515 
00516 void nsNSSHttpInterface::initTable()
00517 {
00518   sNSSInterfaceTable.version = 1;
00519   SEC_HttpClientFcnV1 &v1 = sNSSInterfaceTable.fcnTable.ftable1;
00520   v1.createSessionFcn = createSessionFcn;
00521   v1.keepAliveSessionFcn = keepAliveFcn;
00522   v1.freeSessionFcn = freeSessionFcn;
00523   v1.createFcn = createFcn;
00524   v1.setPostDataFcn = setPostDataFcn;
00525   v1.addHeaderFcn = addHeaderFcn;
00526   v1.trySendAndReceiveFcn = trySendAndReceiveFcn;
00527   v1.cancelFcn = cancelFcn;
00528   v1.freeFcn = freeFcn;
00529 }
00530 
00531 void nsNSSHttpInterface::registerHttpClient()
00532 {
00533   SEC_RegisterDefaultHttpClient(&sNSSInterfaceTable);
00534 }
00535 
00536 void nsNSSHttpInterface::unregisterHttpClient()
00537 {
00538   SEC_RegisterDefaultHttpClient(nsnull);
00539 }
00540 
00541 nsHTTPListener::nsHTTPListener()
00542 : mResultData(nsnull),
00543   mResultLen(0),
00544   mLock(nsnull),
00545   mCondition(nsnull),
00546   mWaitFlag(PR_TRUE),
00547   mResponsibleForDoneSignal(PR_FALSE)
00548 {
00549 }
00550 
00551 nsresult nsHTTPListener::InitLocks()
00552 {
00553   mLock = PR_NewLock();
00554   if (!mLock)
00555     return NS_ERROR_OUT_OF_MEMORY;
00556   
00557   mCondition = PR_NewCondVar(mLock);
00558   if (!mCondition)
00559   {
00560     PR_DestroyLock(mLock);
00561     mLock = nsnull;
00562     return NS_ERROR_OUT_OF_MEMORY;
00563   }
00564   
00565   return NS_OK;
00566 }
00567 
00568 nsHTTPListener::~nsHTTPListener()
00569 {
00570   if (mResponsibleForDoneSignal)
00571     send_done_signal();
00572 
00573   if (mCondition)
00574     PR_DestroyCondVar(mCondition);
00575   
00576   if (mLock)
00577     PR_DestroyLock(mLock);
00578 }
00579 
00580 NS_IMPL_THREADSAFE_ISUPPORTS1(nsHTTPListener, nsIStreamLoaderObserver)
00581 
00582 NS_IMETHODIMP
00583 nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
00584                                  nsISupports* aContext,
00585                                  nsresult aStatus,
00586                                  PRUint32 stringLen,
00587                                  const PRUint8* string)
00588 {
00589   mResultCode = aStatus;
00590 
00591   nsCOMPtr<nsIRequest> req;
00592   nsCOMPtr<nsIHttpChannel> hchan;
00593 
00594   nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
00595   
00596 #ifdef PR_LOGGING
00597   if (NS_FAILED(aStatus))
00598   {
00599     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
00600            ("nsHTTPListener::OnStreamComplete status failed %d", aStatus));
00601   }
00602 #endif
00603 
00604   if (NS_SUCCEEDED(rv))
00605     hchan = do_QueryInterface(req, &rv);
00606 
00607   if (NS_SUCCEEDED(rv))
00608   {
00609     rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
00610     if (NS_FAILED(rv))
00611       mHttpRequestSucceeded = PR_FALSE;
00612 
00613     mResultLen = stringLen;
00614     mResultData = string; // reference. Make sure loader lives as long as this
00615 
00616     unsigned int rcode;
00617     rv = hchan->GetResponseStatus(&rcode);
00618     if (NS_FAILED(rv))
00619       mHttpResponseCode = 500;
00620     else
00621       mHttpResponseCode = rcode;
00622 
00623     hchan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"), 
00624                                     mHttpResponseContentType);
00625   }
00626 
00627   if (mResponsibleForDoneSignal)
00628     send_done_signal();
00629   
00630   return aStatus;
00631 }
00632 
00633 void nsHTTPListener::send_done_signal()
00634 {
00635   nsSSLThread::rememberPendingHTTPRequest(nsnull);
00636   
00637   mResponsibleForDoneSignal = PR_FALSE;
00638 
00639   {
00640     nsAutoLock locker(mLock);
00641     mWaitFlag = PR_FALSE;
00642     PR_NotifyAllCondVar(mCondition);
00643   }
00644 }
00645 
00646 /* Implementation of nsISSLStatus */
00647 class nsSSLStatus
00648   : public nsISSLStatus
00649 {
00650 public:
00651   NS_DECL_ISUPPORTS
00652   NS_DECL_NSISSLSTATUS
00653 
00654   nsSSLStatus();
00655   virtual ~nsSSLStatus();
00656 
00657   /* public for initilization in this file */
00658   nsCOMPtr<nsIX509Cert> mServerCert;
00659   PRUint32 mKeyLength;
00660   PRUint32 mSecretKeyLength;
00661   nsXPIDLCString mCipherName;
00662 };
00663 
00664 NS_IMETHODIMP
00665 nsSSLStatus::GetServerCert(nsIX509Cert** _result)
00666 {
00667   NS_ASSERTION(_result, "non-NULL destination required");
00668 
00669   *_result = mServerCert;
00670   NS_IF_ADDREF(*_result);
00671 
00672   return NS_OK;
00673 }
00674 
00675 NS_IMETHODIMP
00676 nsSSLStatus::GetKeyLength(PRUint32* _result)
00677 {
00678   NS_ASSERTION(_result, "non-NULL destination required");
00679 
00680   *_result = mKeyLength;
00681 
00682   return NS_OK;
00683 }
00684 
00685 NS_IMETHODIMP
00686 nsSSLStatus::GetSecretKeyLength(PRUint32* _result)
00687 {
00688   NS_ASSERTION(_result, "non-NULL destination required");
00689 
00690   *_result = mSecretKeyLength;
00691 
00692   return NS_OK;
00693 }
00694 
00695 NS_IMETHODIMP
00696 nsSSLStatus::GetCipherName(char** _result)
00697 {
00698   NS_ASSERTION(_result, "non-NULL destination required");
00699 
00700   *_result = PL_strdup(mCipherName.get());
00701 
00702   return NS_OK;
00703 }
00704 
00705 nsSSLStatus::nsSSLStatus()
00706 : mKeyLength(0), mSecretKeyLength(0)
00707 {
00708 }
00709 
00710 NS_IMPL_THREADSAFE_ISUPPORTS1(nsSSLStatus, nsISSLStatus)
00711 
00712 nsSSLStatus::~nsSSLStatus()
00713 {
00714 }
00715 
00716 
00717 char* PR_CALLBACK
00718 PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg) {
00719   nsNSSShutDownPreventionLock locker;
00720   nsresult rv = NS_OK;
00721   PRUnichar *password = nsnull;
00722   PRBool value = PR_FALSE;
00723   nsIInterfaceRequestor *ir = NS_STATIC_CAST(nsIInterfaceRequestor*, arg);
00724   nsCOMPtr<nsIPrompt> proxyPrompt;
00725 
00726   // If no context is provided, no prompt is possible.
00727   if (!ir)
00728     return nsnull;
00729 
00730   /* TODO: Retry should generate a different dialog message */
00731 /*
00732   if (retry)
00733     return nsnull;
00734 */
00735 
00736   // The interface requestor object may not be safe, so
00737   // proxy the call to get the nsIPrompt.
00738 
00739   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
00740   if (!proxyman) return nsnull;
00741 
00742   nsCOMPtr<nsIInterfaceRequestor> proxiedCallbacks;
00743   proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00744                               NS_GET_IID(nsIInterfaceRequestor),
00745                               ir,
00746                               PROXY_SYNC,
00747                               getter_AddRefs(proxiedCallbacks));
00748 
00749   // Get the desired interface
00750   nsCOMPtr<nsIPrompt> prompt(do_GetInterface(proxiedCallbacks));
00751   if (!prompt) {
00752     NS_ASSERTION(PR_FALSE, "callbacks does not implement nsIPrompt");
00753     return nsnull;
00754   }
00755 
00756   // Finally, get a proxy for the nsIPrompt
00757   proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
00758                              NS_GET_IID(nsIPrompt),
00759                               prompt,
00760                               PROXY_SYNC,
00761                               getter_AddRefs(proxyPrompt));
00762 
00763 
00764   nsAutoString promptString;
00765   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00766 
00767   if (NS_FAILED(rv))
00768     return nsnull; 
00769 
00770   const PRUnichar* formatStrings[1] = { ToNewUnicode(NS_ConvertUTF8toUCS2(PK11_GetTokenName(slot))) };
00771   rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
00772                                       formatStrings, 1,
00773                                       promptString);
00774   nsMemory::Free(NS_CONST_CAST(PRUnichar*, formatStrings[0]));
00775 
00776   if (NS_FAILED(rv))
00777     return nsnull;
00778 
00779   {
00780     nsPSMUITracker tracker;
00781     if (tracker.isUIForbidden()) {
00782       rv = NS_ERROR_NOT_AVAILABLE;
00783     }
00784     else {
00785       rv = proxyPrompt->PromptPassword(nsnull, promptString.get(),
00786                                        &password, nsnull, nsnull, &value);
00787     }
00788   }
00789   
00790   if (NS_SUCCEEDED(rv) && value) {
00791     char* str = ToNewUTF8String(nsDependentString(password));
00792     Recycle(password);
00793     return str;
00794   }
00795 
00796   return nsnull;
00797 }
00798 
00799 void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
00800   nsNSSShutDownPreventionLock locker;
00801   PRInt32 sslStatus;
00802   char* signer = nsnull;
00803   char* cipherName = nsnull;
00804   PRInt32 keyLength;
00805   nsresult rv;
00806   PRInt32 encryptBits;
00807 
00808   if (SECSuccess != SSL_SecurityStatus(fd, &sslStatus, &cipherName, &keyLength,
00809                                        &encryptBits, &signer, nsnull)) {
00810     return;
00811   }
00812 
00813   PRInt32 secStatus;
00814   if (sslStatus == SSL_SECURITY_STATUS_OFF)
00815     secStatus = nsIWebProgressListener::STATE_IS_BROKEN;
00816   else if (encryptBits >= 90)
00817     secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
00818                  nsIWebProgressListener::STATE_SECURE_HIGH);
00819   else
00820     secStatus = (nsIWebProgressListener::STATE_IS_SECURE |
00821                  nsIWebProgressListener::STATE_SECURE_LOW);
00822 
00823   CERTCertificate *peerCert = SSL_PeerCertificate(fd);
00824   char* caName = CERT_GetOrgName(&peerCert->issuer);
00825   CERT_DestroyCertificate(peerCert);
00826   if (!caName) {
00827     caName = signer;
00828   }
00829 
00830   // If the CA name is RSA Data Security, then change the name to the real
00831   // name of the company i.e. VeriSign, Inc.
00832   if (nsCRT::strcmp((const char*)caName, "RSA Data Security, Inc.") == 0) {
00833     // In this case, caName != signer since the logic implies signer
00834     // would be at minimal "O=RSA Data Security, Inc" because caName
00835     // is what comes after to O=.  So we're OK just freeing this memory
00836     // without checking to see if it's equal to signer;
00837     NS_ASSERTION(caName != signer, "caName was equal to caName when it shouldn't be");
00838     PR_Free(caName);
00839     caName = PL_strdup("Verisign, Inc.");
00840   }
00841 
00842   nsAutoString shortDesc;
00843   const PRUnichar* formatStrings[1] = { ToNewUnicode(NS_ConvertUTF8toUCS2(caName)) };
00844   nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
00845   if (NS_SUCCEEDED(rv)) {
00846     rv = nssComponent->PIPBundleFormatStringFromName("SignedBy",
00847                                                    formatStrings, 1,
00848                                                    shortDesc);
00849 
00850     nsMemory::Free(NS_CONST_CAST(PRUnichar*, formatStrings[0]));
00851 
00852     nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
00853     infoObject->SetSecurityState(secStatus);
00854     infoObject->SetShortSecurityDescription(shortDesc.get());
00855 
00856     /* Set the SSL Status information */
00857     nsCOMPtr<nsSSLStatus> status = new nsSSLStatus();
00858 
00859     CERTCertificate *serverCert = SSL_PeerCertificate(fd);
00860     if (serverCert) {
00861       status->mServerCert = new nsNSSCertificate(serverCert);
00862       CERT_DestroyCertificate(serverCert);
00863     }
00864 
00865     status->mKeyLength = keyLength;
00866     status->mSecretKeyLength = encryptBits;
00867     status->mCipherName.Adopt(cipherName);
00868 
00869     infoObject->SetSSLStatus(status);
00870   }
00871 
00872   if (caName != signer) {
00873     PR_Free(caName);
00874   }
00875   PR_Free(signer);
00876 }
00877 
00878 SECStatus PR_CALLBACK AuthCertificateCallback(void* client_data, PRFileDesc* fd,
00879                                               PRBool checksig, PRBool isServer) {
00880   nsNSSShutDownPreventionLock locker;
00881 
00882   // first the default action
00883   SECStatus rv = SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
00884 
00885   // We want to remember the CA certs in the temp db, so that the application can find the
00886   // complete chain at any time it might need it.
00887   // But we keep only those CA certs in the temp db, that we didn't already know.
00888   
00889   if (SECSuccess == rv) {
00890     CERTCertificate *serverCert = SSL_PeerCertificate(fd);
00891     if (serverCert) {
00892       CERTCertList *certList = CERT_GetCertChainFromCert(serverCert, PR_Now(), certUsageSSLCA);
00893 
00894       nsCOMPtr<nsINSSComponent> nssComponent;
00895       
00896       for (CERTCertListNode *node = CERT_LIST_HEAD(certList);
00897            !CERT_LIST_END(node, certList);
00898            node = CERT_LIST_NEXT(node)) {
00899 
00900         if (node->cert->slot) {
00901           // This cert was found on a token, no need to remember it in the temp db.
00902           continue;
00903         }
00904 
00905         if (node->cert->isperm) {
00906           // We don't need to remember certs already stored in perm db.
00907           continue;
00908         }
00909         
00910         if (node->cert == serverCert) {
00911           // We don't want to remember the server cert, 
00912           // the code that cares for displaying page info does this already.
00913           continue;
00914         }
00915         
00916         // We have found a signer cert that we want to remember.
00917 
00918         if (!nssComponent) {
00919           // delay getting the service until we really need it
00920           nsresult rv;
00921           nssComponent = do_GetService(kNSSComponentCID, &rv);
00922         }
00923         
00924         if (nssComponent) {
00925           nssComponent->RememberCert(node->cert);
00926         }
00927       }
00928 
00929       CERT_DestroyCertList(certList);
00930       CERT_DestroyCertificate(serverCert);
00931     }
00932   }
00933 
00934   return rv;
00935 }