Back to index

lightning-sunbird  0.9+nobinonly
nsSecureBrowserUIImpl.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2001
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Hubbie Shaw
00024  *   Doug Turner <dougt@netscape.com>
00025  *   Stuart Parmenter <pavlov@netscape.com>
00026  *   Brian Ryner <bryner@brianryner.com>
00027  *   Terry Hayes <thayes@netscape.com>
00028  *   Kai Engert <kaie@netscape.com>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either the GNU General Public License Version 2 or later (the "GPL"), or
00032  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 
00044 #ifdef MOZ_LOGGING
00045 #define FORCE_PR_LOG
00046 #endif
00047 
00048 #include "nspr.h"
00049 #include "prlog.h"
00050 #include "prmem.h"
00051 
00052 #include "nsISecureBrowserUI.h"
00053 #include "nsSecureBrowserUIImpl.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsIInterfaceRequestor.h"
00056 #include "nsIInterfaceRequestorUtils.h"
00057 #include "nsIServiceManager.h"
00058 #include "nsIScriptGlobalObject.h"
00059 #include "nsIObserverService.h"
00060 #include "nsIDocumentLoader.h"
00061 #include "nsCURILoader.h"
00062 #include "nsIDocShell.h"
00063 #include "nsIDocumentViewer.h"
00064 #include "nsIDocument.h"
00065 #include "nsIPrincipal.h"
00066 #include "nsIDOMElement.h"
00067 #include "nsPIDOMWindow.h"
00068 #include "nsIContent.h"
00069 #include "nsIWebProgress.h"
00070 #include "nsIChannel.h"
00071 #include "nsIHttpChannel.h"
00072 #include "nsIFileChannel.h"
00073 #include "nsIWyciwygChannel.h"
00074 #include "nsIFTPChannel.h"
00075 #include "nsITransportSecurityInfo.h"
00076 #include "nsIURI.h"
00077 #include "nsISecurityEventSink.h"
00078 #include "nsIPrompt.h"
00079 #include "nsIFormSubmitObserver.h"
00080 #include "nsISecurityWarningDialogs.h"
00081 #include "nsIProxyObjectManager.h"
00082 #include "nsNetUtil.h"
00083 #include "nsCRT.h"
00084 
00085 #define SECURITY_STRING_BUNDLE_URL "chrome://pipnss/locale/security.properties"
00086 
00087 #define IS_SECURE(state) ((state & 0xFFFF) == STATE_IS_SECURE)
00088 
00089 #if defined(PR_LOGGING)
00090 //
00091 // Log module for nsSecureBroswerUI logging...
00092 //
00093 // To enable logging (see prlog.h for full details):
00094 //
00095 //    set NSPR_LOG_MODULES=nsSecureBroswerUI:5
00096 //    set NSPR_LOG_FILE=nspr.log
00097 //
00098 // this enables PR_LOG_DEBUG level information and places all output in
00099 // the file nspr.log
00100 //
00101 PRLogModuleInfo* gSecureDocLog = nsnull;
00102 #endif /* PR_LOGGING */
00103 
00104 struct RequestHashEntry : PLDHashEntryHdr {
00105     void *r;
00106 };
00107 
00108 PR_STATIC_CALLBACK(const void *)
00109 RequestMapGetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00110 {
00111   RequestHashEntry *entry = NS_STATIC_CAST(RequestHashEntry*, hdr);
00112   return entry->r;
00113 }
00114 
00115 PR_STATIC_CALLBACK(PRBool)
00116 RequestMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00117                          const void *key)
00118 {
00119   const RequestHashEntry *entry = NS_STATIC_CAST(const RequestHashEntry*, hdr);
00120   return entry->r == key;
00121 }
00122 
00123 PR_STATIC_CALLBACK(PRBool)
00124 RequestMapInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
00125                      const void *key)
00126 {
00127   RequestHashEntry *entry = NS_STATIC_CAST(RequestHashEntry*, hdr);
00128   entry->r = (void*)key;
00129   return PR_TRUE;
00130 }
00131 
00132 static PLDHashTableOps gMapOps = {
00133   PL_DHashAllocTable,
00134   PL_DHashFreeTable,
00135   RequestMapGetKey,
00136   PL_DHashVoidPtrKeyStub,
00137   RequestMapMatchEntry,
00138   PL_DHashMoveEntryStub,
00139   PL_DHashClearEntryStub,
00140   PL_DHashFinalizeStub,
00141   RequestMapInitEntry
00142 };
00143 
00144 
00145 nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
00146   : mPreviousSecurityState(lis_no_security),
00147     mIsViewSource(PR_FALSE)
00148 {
00149   mTransferringRequests.ops = nsnull;
00150   mNewToplevelSecurityState = STATE_IS_INSECURE;
00151   mNewToplevelSecurityStateKnown = PR_TRUE;
00152   ResetStateTracking();
00153   
00154 #if defined(PR_LOGGING)
00155   if (!gSecureDocLog)
00156     gSecureDocLog = PR_NewLogModule("nsSecureBrowserUI");
00157 #endif /* PR_LOGGING */
00158 }
00159 
00160 nsSecureBrowserUIImpl::~nsSecureBrowserUIImpl()
00161 {
00162   if (mTransferringRequests.ops) {
00163     PL_DHashTableFinish(&mTransferringRequests);
00164     mTransferringRequests.ops = nsnull;
00165   }
00166 }
00167 
00168 NS_IMPL_ISUPPORTS6(nsSecureBrowserUIImpl,
00169                    nsISecureBrowserUI,
00170                    nsIWebProgressListener,
00171                    nsIFormSubmitObserver,
00172                    nsIObserver,
00173                    nsISupportsWeakReference,
00174                    nsISSLStatusProvider)
00175 
00176 
00177 NS_IMETHODIMP
00178 nsSecureBrowserUIImpl::Init(nsIDOMWindow *window)
00179 {
00180   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00181          ("SecureUI:%p: Init: mWindow: %p, window: %p\n", this, mWindow.get(),
00182           window));
00183 
00184   if (!window) {
00185     NS_WARNING("Null window passed to nsSecureBrowserUIImpl::Init()");
00186     return NS_ERROR_INVALID_ARG;
00187   }
00188 
00189   if (mWindow) {
00190     NS_WARNING("Trying to init an nsSecureBrowserUIImpl twice");
00191     return NS_ERROR_ALREADY_INITIALIZED;
00192   }
00193   
00194   nsresult rv = NS_OK;
00195   mWindow = window;
00196 
00197   nsCOMPtr<nsIStringBundleService> service(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
00198   if (NS_FAILED(rv)) return rv;
00199   
00200   // We do not need to test for mStringBundle here...
00201   // Anywhere we use it, we will test before using.  Some
00202   // embedded users of PSM may want to reuse our
00203   // nsSecureBrowserUIImpl implementation without the
00204   // bundle.
00205   service->CreateBundle(SECURITY_STRING_BUNDLE_URL, getter_AddRefs(mStringBundle));
00206 
00207   // hook up to the form post notifications:
00208   nsCOMPtr<nsIObserverService> svc(do_GetService("@mozilla.org/observer-service;1", &rv));
00209   if (NS_SUCCEEDED(rv)) {
00210     rv = svc->AddObserver(this, NS_FORMSUBMIT_SUBJECT, PR_TRUE);
00211   }
00212   
00213   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(mWindow));
00214   if (!sgo) return NS_ERROR_FAILURE;
00215 
00216   nsIDocShell *docShell = sgo->GetDocShell();
00217 
00218   // The Docshell will own the SecureBrowserUI object
00219   if (!docShell)
00220     return NS_ERROR_FAILURE;
00221 
00222   docShell->SetSecurityUI(this);
00223 
00224   /* GetWebProgress(mWindow) */
00225   // hook up to the webprogress notifications.
00226   nsCOMPtr<nsIWebProgress> wp(do_GetInterface(docShell));
00227   if (!wp) return NS_ERROR_FAILURE;
00228   /* end GetWebProgress */
00229   
00230   wp->AddProgressListener(NS_STATIC_CAST(nsIWebProgressListener*,this),
00231                           nsIWebProgress::NOTIFY_STATE_ALL | 
00232                           nsIWebProgress::NOTIFY_LOCATION  |
00233                           nsIWebProgress::NOTIFY_SECURITY);
00234 
00235 
00236   return NS_OK;
00237 }
00238 
00239 NS_IMETHODIMP
00240 nsSecureBrowserUIImpl::GetState(PRUint32* aState)
00241 {
00242   NS_ENSURE_ARG(aState);
00243   
00244   switch (mPreviousSecurityState)
00245   {
00246     case lis_broken_security:
00247       *aState = STATE_IS_BROKEN;
00248       break;
00249 
00250     case lis_mixed_security:
00251       *aState = STATE_IS_BROKEN;
00252       break;
00253 
00254     case lis_low_security:
00255       *aState = STATE_IS_SECURE | STATE_SECURE_LOW;
00256       break;
00257 
00258     case lis_high_security:
00259       *aState = STATE_IS_SECURE | STATE_SECURE_HIGH;
00260       break;
00261 
00262     default:
00263     case lis_no_security:
00264       *aState = STATE_IS_INSECURE;
00265       break;
00266 
00267   }
00268   
00269   return NS_OK;
00270 }
00271 
00272 NS_IMETHODIMP
00273 nsSecureBrowserUIImpl::GetTooltipText(nsAString& aText)
00274 {
00275   if (mPreviousSecurityState == lis_mixed_security)
00276   {
00277     GetBundleString(NS_LITERAL_STRING("SecurityButtonMixedContentTooltipText").get(),
00278                     aText);
00279   }
00280   else if (!mInfoTooltip.IsEmpty())
00281   {
00282     aText = mInfoTooltip;
00283   }
00284   else
00285   {
00286     GetBundleString(NS_LITERAL_STRING("SecurityButtonTooltipText").get(),
00287                     aText);
00288   }
00289 
00290   return NS_OK;
00291 }
00292 
00293 NS_IMETHODIMP
00294 nsSecureBrowserUIImpl::Observe(nsISupports*, const char*,
00295                                const PRUnichar*)
00296 {
00297   return NS_ERROR_NOT_IMPLEMENTED;
00298 }
00299 
00300 
00301 static nsresult IsChildOfDomWindow(nsIDOMWindow *parent, nsIDOMWindow *child,
00302                                    PRBool* value)
00303 {
00304   *value = PR_FALSE;
00305   
00306   if (parent == child) {
00307     *value = PR_TRUE;
00308     return NS_OK;
00309   }
00310   
00311   nsCOMPtr<nsIDOMWindow> childsParent;
00312   child->GetParent(getter_AddRefs(childsParent));
00313   
00314   if (childsParent && childsParent.get() != child)
00315     IsChildOfDomWindow(parent, childsParent, value);
00316   
00317   return NS_OK;
00318 }
00319 
00320 static PRUint32 GetSecurityStateFromChannel(nsIChannel* aChannel)
00321 {
00322   nsresult res;
00323   PRUint32 securityState;
00324 
00325   // qi for the psm information about this channel load.
00326   nsCOMPtr<nsISupports> info;
00327   aChannel->GetSecurityInfo(getter_AddRefs(info));
00328   nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
00329   if (!psmInfo) {
00330     PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - no nsITransportSecurityInfo for %p\n",
00331                                          aChannel, (nsISupports *)info));
00332     return nsIWebProgressListener::STATE_IS_INSECURE;
00333   }
00334   PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - info is %p\n", aChannel,
00335                                        (nsISupports *)info));
00336   
00337   res = psmInfo->GetSecurityState(&securityState);
00338   if (NS_FAILED(res)) {
00339     PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - GetSecurityState failed: %d\n",
00340                                          aChannel, res));
00341     securityState = nsIWebProgressListener::STATE_IS_BROKEN;
00342   }
00343   
00344   PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState:%p - Returning %d\n", aChannel,
00345                                        securityState));
00346   return securityState;
00347 }
00348 
00349 
00350 NS_IMETHODIMP
00351 nsSecureBrowserUIImpl::Notify(nsIContent* formNode,
00352                               nsIDOMWindowInternal* window, nsIURI* actionURL,
00353                               PRBool* cancelSubmit)
00354 {
00355   // Return NS_OK unless we want to prevent this form from submitting.
00356   *cancelSubmit = PR_FALSE;
00357   if (!window || !actionURL || !formNode)
00358     return NS_OK;
00359   
00360   nsCOMPtr<nsIDocument> document = formNode->GetDocument();
00361   if (!document) return NS_OK;
00362 
00363   nsIPrincipal *principal = document->GetPrincipal();
00364   
00365   if (!principal)
00366   {
00367     *cancelSubmit = PR_TRUE;
00368     return NS_OK;
00369   }
00370 
00371   nsCOMPtr<nsIURI> formURL;
00372   if (NS_FAILED(principal->GetURI(getter_AddRefs(formURL))) ||
00373       !formURL)
00374   {
00375     formURL = document->GetDocumentURI();
00376   }
00377 
00378   nsCOMPtr<nsIDOMWindow> postingWindow =
00379     do_QueryInterface(document->GetWindow());
00380   // We can't find this document's window, cancel it.
00381   if (!postingWindow)
00382   {
00383     NS_WARNING("If you see this and can explain why it should be allowed, note in Bug 332324");
00384     *cancelSubmit = PR_TRUE;
00385     return NS_OK;
00386   }
00387 
00388   PRBool isChild;
00389   IsChildOfDomWindow(mWindow, postingWindow, &isChild);
00390   
00391   // This notify call is not for our window, ignore it.
00392   if (!isChild)
00393     return NS_OK;
00394   
00395   PRBool okayToPost;
00396   nsresult res = CheckPost(formURL, actionURL, &okayToPost);
00397   
00398   if (NS_SUCCEEDED(res) && !okayToPost)
00399     *cancelSubmit = PR_TRUE;
00400   
00401   return res;
00402 }
00403 
00404 //  nsIWebProgressListener
00405 NS_IMETHODIMP 
00406 nsSecureBrowserUIImpl::OnProgressChange(nsIWebProgress* aWebProgress,
00407                                         nsIRequest* aRequest,
00408                                         PRInt32 aCurSelfProgress,
00409                                         PRInt32 aMaxSelfProgress,
00410                                         PRInt32 aCurTotalProgress,
00411                                         PRInt32 aMaxTotalProgress)
00412 {
00413   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
00414   return NS_OK;
00415 }
00416 
00417 void nsSecureBrowserUIImpl::ResetStateTracking()
00418 {
00419   mInfoTooltip.Truncate();
00420   mDocumentRequestsInProgress = 0;
00421   mSubRequestsHighSecurity = 0;
00422   mSubRequestsLowSecurity = 0;
00423   mSubRequestsBrokenSecurity = 0;
00424   mSubRequestsNoSecurity = 0;
00425   if (mTransferringRequests.ops) {
00426     PL_DHashTableFinish(&mTransferringRequests);
00427     mTransferringRequests.ops = nsnull;
00428   }
00429   PL_DHashTableInit(&mTransferringRequests, &gMapOps, nsnull,
00430                     sizeof(RequestHashEntry), 16);
00431 }
00432 
00433 nsresult
00434 nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest *aRequest)
00435 {
00436   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00437 
00438   if (!channel) {
00439     mNewToplevelSecurityState = nsIWebProgressListener::STATE_IS_INSECURE;
00440   } else {
00441     mNewToplevelSecurityState = GetSecurityStateFromChannel(channel);
00442 
00443     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00444            ("SecureUI:%p: OnStateChange: remember mNewToplevelSecurityState => %x\n", this,
00445             mNewToplevelSecurityState));
00446 
00447     // Get SSL Status information if possible
00448     nsCOMPtr<nsISupports> info;
00449     channel->GetSecurityInfo(getter_AddRefs(info));
00450     nsCOMPtr<nsISSLStatusProvider> sp = do_QueryInterface(info);
00451     if (sp) {
00452       // Ignore result
00453       sp->GetSSLStatus(getter_AddRefs(mSSLStatus));
00454     }
00455 
00456     if (info) {
00457       nsCOMPtr<nsITransportSecurityInfo> secInfo(do_QueryInterface(info));
00458       if (secInfo) {
00459         secInfo->GetShortSecurityDescription(getter_Copies(mInfoTooltip));
00460       }
00461     }
00462   }
00463 
00464   // assume mNewToplevelSecurityState was set in this scope!
00465   // see code that is directly above
00466 
00467   mNewToplevelSecurityStateKnown = PR_TRUE;
00468   return UpdateSecurityState(aRequest);
00469 }
00470 
00471 void
00472 nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsIRequest *aRequest)
00473 {
00474   // For wyciwyg channels in subdocuments we only update our
00475   // subrequest state members.
00476   PRUint32 reqState = nsIWebProgressListener::STATE_IS_INSECURE;
00477   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00478 
00479   if (channel) {
00480     reqState = GetSecurityStateFromChannel(channel);
00481   }
00482 
00483   if (reqState & STATE_IS_SECURE) {
00484     if (reqState & STATE_SECURE_LOW || reqState & STATE_SECURE_MED) {
00485       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00486              ("SecureUI:%p: OnStateChange: subreq LOW\n", this));
00487       ++mSubRequestsLowSecurity;
00488     } else {
00489       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00490              ("SecureUI:%p: OnStateChange: subreq HIGH\n", this));
00491       ++mSubRequestsHighSecurity;
00492     }
00493   } else if (reqState & STATE_IS_BROKEN) {
00494     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00495            ("SecureUI:%p: OnStateChange: subreq BROKEN\n", this));
00496     ++mSubRequestsBrokenSecurity;
00497   } else {
00498     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00499            ("SecureUI:%p: OnStateChange: subreq INSECURE\n", this));
00500     ++mSubRequestsNoSecurity;
00501   }
00502 }
00503 
00504 
00505 
00506 NS_IMETHODIMP
00507 nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
00508                                      nsIRequest* aRequest,
00509                                      PRUint32 aProgressStateFlags,
00510                                      nsresult aStatus)
00511 {
00512   /*
00513     All discussion, unless otherwise mentioned, only refers to
00514     http, https, file or wyciwig requests.
00515 
00516 
00517     Redirects are evil, well, some of them.
00518     There are mutliple forms of redirects.
00519 
00520     Redirects caused by http refresh content are ok, because experiments show,
00521     with those redirects, the old page contents and their requests will come to STOP
00522     completely, before any progress from new refreshed page content is reported.
00523     So we can safely treat them as separate page loading transactions.
00524 
00525     Evil are redirects at the http protocol level, like code 302.
00526 
00527     If the toplevel documents gets replaced, i.e. redirected with 302, we do not care for the 
00528     security state of the initial transaction, which has now been redirected, 
00529     we only care for the new page load.
00530     
00531     For the implementation of the security UI, we make an assumption, that is hopefully true.
00532     
00533     Imagine, the received page that was delivered with the 302 redirection answer,
00534     also delivered html content.
00535 
00536     What happens if the parser starts to analyze the content and tries to load contained sub objects?
00537     
00538     In that case we would see start and stop requests for subdocuments, some for the previous document,
00539     some for the new target document. And only those for the new toplevel document may be
00540     taken into consideration, when deciding about the security state of the next toplevel document.
00541     
00542     Because security state is being looked at, when loading stops for (sub)documents, this 
00543     could cause real confusion, because we have to decide, whether an incoming progress 
00544     belongs to the new toplevel page, or the previous, already redirected page.
00545     
00546     Can we simplify here?
00547     
00548     If a redirect at the http protocol level is seen, can we safely assume, its html content
00549     will not be parsed, anylzed, and no embedded objects will get loaded (css, js, images),
00550     because the redirect is already happening?
00551     
00552     If we can assume that, this really simplify things. Because we will never see notification
00553     for sub requests that need to get ignored.
00554     
00555     I would like to make this assumption for now, but please let me (kaie) know if I'm wrong.
00556     
00557     Excurse:
00558       If my assumption is wrong, then we would require more tracking information.
00559       We need to keep lists of all pointers to request object that had been seen since the
00560       last toplevel start event.
00561       If the start for a redirected page is seen, the list of releveant object must be cleared,
00562       and only progress for requests which start after it must be analyzed.
00563       All other events must be ignored, as they belong to now irrelevant previous top level documents.
00564 
00565 
00566     Frames are also evil.
00567 
00568     First we need a decision.
00569     kaie thinks: 
00570       Only if the toplevel frame is secure, we should try to display secure lock icons.
00571       If some of the inner contents are insecure, we display mixed mode.
00572       
00573       But if the top level frame is not secure, why indicate a mixed lock icon at all?
00574       I think we should always display an open lock icon, if the top level frameset is insecure.
00575       
00576       That's the way Netscape Communicator behaves, and I think we should do the same.
00577       
00578       The user will not know which parts are secure and which are not,
00579       and any certificate information, displayed in the tooltip or in the "page info"
00580       will only be relevant for some subframe(s), and the user will not know which ones,
00581       so we shouldn't display it as a general attribute of the displayed page.
00582 
00583     Why are frames evil?
00584     
00585     Because the progress for the toplevel frame document is not easily distinguishable
00586     from subframes. The same STATE bits are reported.
00587 
00588     While at first sight, when a new page load happens,
00589     the toplevel frameset document has also the STATE_IS_NETWORK bit in it.
00590     But this can't really be used. Because in case that document causes a http 302 redirect, 
00591     the real top level frameset will no longer have that bit.
00592     
00593     But we need some way to distinguish top level frames from inner frames.
00594     
00595     I saw that the web progress we get delivered has a reference to the toplevel DOM window.
00596     
00597     I suggest, we look at all incoming requests.
00598     If a request is NOT for the toplevel DOM window, we will always treat it as a subdocument request,
00599     regardless of whether the load flags indicate a top level document.
00600   */
00601 
00602   nsCOMPtr<nsIDOMWindow> windowForProgress;
00603   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
00604 
00605   const PRBool isToplevelProgress = (windowForProgress.get() == mWindow.get());
00606   
00607 #ifdef PR_LOGGING
00608   if (windowForProgress)
00609   {
00610     if (isToplevelProgress)
00611     {
00612       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00613              ("SecureUI:%p: OnStateChange: progress: for toplevel\n", this));
00614     }
00615     else
00616     {
00617       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00618              ("SecureUI:%p: OnStateChange: progress: for something else\n", this));
00619     }
00620   }
00621   else
00622   {
00623       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00624              ("SecureUI:%p: OnStateChange: progress: no window known\n", this));
00625   }
00626 #endif
00627 
00628   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00629          ("SecureUI:%p: OnStateChange\n", this));
00630 
00631   if (mIsViewSource)
00632     return NS_OK;
00633 
00634   if (!aRequest)
00635   {
00636     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00637            ("SecureUI:%p: OnStateChange with null request\n", this));
00638     return NS_ERROR_NULL_POINTER;
00639   }
00640 
00641 #ifdef PR_LOGGING
00642   if (PR_LOG_TEST(gSecureDocLog, PR_LOG_DEBUG)) {
00643     nsXPIDLCString reqname;
00644     aRequest->GetName(reqname);
00645     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00646            ("SecureUI:%p: %p %p OnStateChange %x %s\n", this, aWebProgress,
00647             aRequest, aProgressStateFlags, reqname.get()));
00648   }
00649 #endif
00650 
00651   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
00652 
00653   if (channel)
00654   {
00655     nsCOMPtr<nsIURI> uri;
00656     channel->GetURI(getter_AddRefs(uri));
00657     if (uri)
00658     {
00659       PRBool vs;
00660       if (NS_SUCCEEDED(uri->SchemeIs("javascript", &vs)) && vs)
00661       {
00662         // We ignore the progress events for javascript URLs.
00663         // If a document loading gets triggered, we will see more events.
00664         return NS_OK;
00665       }
00666     }
00667   }
00668 
00669   PRUint32 loadFlags = 0;
00670   aRequest->GetLoadFlags(&loadFlags);
00671 
00672 #ifdef PR_LOGGING
00673   if (aProgressStateFlags & STATE_START
00674       &&
00675       aProgressStateFlags & STATE_IS_REQUEST
00676       &&
00677       isToplevelProgress
00678       &&
00679       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
00680   {
00681     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00682            ("SecureUI:%p: OnStateChange: SOMETHING STARTS FOR TOPMOST DOCUMENT\n", this));
00683   }
00684 
00685   if (aProgressStateFlags & STATE_STOP
00686       &&
00687       aProgressStateFlags & STATE_IS_REQUEST
00688       &&
00689       isToplevelProgress
00690       &&
00691       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
00692   {
00693     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00694            ("SecureUI:%p: OnStateChange: SOMETHING STOPS FOR TOPMOST DOCUMENT\n", this));
00695   }
00696 #endif
00697 
00698   PRBool isSubDocumentRelevant = PR_TRUE;
00699 
00700   // We are only interested in requests that load in the browser window...
00701   nsCOMPtr<nsIHttpChannel> httpRequest(do_QueryInterface(aRequest));
00702   if (!httpRequest) {
00703     nsCOMPtr<nsIFileChannel> fileRequest(do_QueryInterface(aRequest));
00704     if (!fileRequest) {
00705       nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
00706       if (!wyciwygRequest) {
00707         nsCOMPtr<nsIFTPChannel> ftpRequest(do_QueryInterface(aRequest));
00708         if (!ftpRequest) {
00709           PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00710                  ("SecureUI:%p: OnStateChange: not relevant for sub content\n", this));
00711           isSubDocumentRelevant = PR_FALSE;
00712         }
00713       }
00714     }
00715   }
00716 
00717 #if defined(DEBUG)
00718   nsCString info2;
00719   PRUint32 testFlags = loadFlags;
00720 
00721   if (testFlags & nsIChannel::LOAD_DOCUMENT_URI)
00722   {
00723     testFlags -= nsIChannel::LOAD_DOCUMENT_URI;
00724     info2.Append("LOAD_DOCUMENT_URI ");
00725   }
00726   if (testFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
00727   {
00728     testFlags -= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI;
00729     info2.Append("LOAD_RETARGETED_DOCUMENT_URI ");
00730   }
00731   if (testFlags & nsIChannel::LOAD_REPLACE)
00732   {
00733     testFlags -= nsIChannel::LOAD_REPLACE;
00734     info2.Append("LOAD_REPLACE ");
00735   }
00736 
00737   const char *_status = NS_SUCCEEDED(aStatus) ? "1" : "0";
00738 
00739   nsCString info;
00740   PRUint32 f = aProgressStateFlags;
00741   if (f & nsIWebProgressListener::STATE_START)
00742   {
00743     f -= nsIWebProgressListener::STATE_START;
00744     info.Append("START ");
00745   }
00746   if (f & nsIWebProgressListener::STATE_REDIRECTING)
00747   {
00748     f -= nsIWebProgressListener::STATE_REDIRECTING;
00749     info.Append("REDIRECTING ");
00750   }
00751   if (f & nsIWebProgressListener::STATE_TRANSFERRING)
00752   {
00753     f -= nsIWebProgressListener::STATE_TRANSFERRING;
00754     info.Append("TRANSFERRING ");
00755   }
00756   if (f & nsIWebProgressListener::STATE_NEGOTIATING)
00757   {
00758     f -= nsIWebProgressListener::STATE_NEGOTIATING;
00759     info.Append("NEGOTIATING ");
00760   }
00761   if (f & nsIWebProgressListener::STATE_STOP)
00762   {
00763     f -= nsIWebProgressListener::STATE_STOP;
00764     info.Append("STOP ");
00765   }
00766   if (f & nsIWebProgressListener::STATE_IS_REQUEST)
00767   {
00768     f -= nsIWebProgressListener::STATE_IS_REQUEST;
00769     info.Append("IS_REQUEST ");
00770   }
00771   if (f & nsIWebProgressListener::STATE_IS_DOCUMENT)
00772   {
00773     f -= nsIWebProgressListener::STATE_IS_DOCUMENT;
00774     info.Append("IS_DOCUMENT ");
00775   }
00776   if (f & nsIWebProgressListener::STATE_IS_NETWORK)
00777   {
00778     f -= nsIWebProgressListener::STATE_IS_NETWORK;
00779     info.Append("IS_NETWORK ");
00780   }
00781   if (f & nsIWebProgressListener::STATE_IS_WINDOW)
00782   {
00783     f -= nsIWebProgressListener::STATE_IS_WINDOW;
00784     info.Append("IS_WINDOW ");
00785   }
00786   if (f & nsIWebProgressListener::STATE_IS_INSECURE)
00787   {
00788     f -= nsIWebProgressListener::STATE_IS_INSECURE;
00789     info.Append("IS_INSECURE ");
00790   }
00791   if (f & nsIWebProgressListener::STATE_IS_BROKEN)
00792   {
00793     f -= nsIWebProgressListener::STATE_IS_BROKEN;
00794     info.Append("IS_BROKEN ");
00795   }
00796   if (f & nsIWebProgressListener::STATE_IS_SECURE)
00797   {
00798     f -= nsIWebProgressListener::STATE_IS_SECURE;
00799     info.Append("IS_SECURE ");
00800   }
00801   if (f & nsIWebProgressListener::STATE_SECURE_HIGH)
00802   {
00803     f -= nsIWebProgressListener::STATE_SECURE_HIGH;
00804     info.Append("SECURE_HIGH ");
00805   }
00806   if (f & nsIWebProgressListener::STATE_SECURE_MED)
00807   {
00808     f -= nsIWebProgressListener::STATE_SECURE_MED;
00809     info.Append("SECURE_MED ");
00810   }
00811   if (f & nsIWebProgressListener::STATE_SECURE_LOW)
00812   {
00813     f -= nsIWebProgressListener::STATE_SECURE_LOW;
00814     info.Append("SECURE_LOW ");
00815   }
00816 
00817   if (f > 0)
00818   {
00819     info.Append("f contains unknown flag!");
00820   }
00821 
00822   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00823          ("SecureUI:%p: OnStateChange: %s %s -- %s\n", this, _status, 
00824           info.get(), info2.get()));
00825 
00826   if (aProgressStateFlags & STATE_STOP
00827       &&
00828       channel)
00829   {
00830     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00831            ("SecureUI:%p: OnStateChange: seeing STOP with security state: %d\n", this,
00832             GetSecurityStateFromChannel(channel)
00833             ));
00834   }
00835 #endif
00836 
00837   if (aProgressStateFlags & STATE_TRANSFERRING
00838       &&
00839       aProgressStateFlags & STATE_IS_REQUEST)
00840   {
00841     // The listing of a request in mTransferringRequests
00842     // means, there has already been data transfered.
00843 
00844     PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_ADD);
00845     
00846     return NS_OK;
00847   }
00848 
00849   PRBool requestHasTransferedData = PR_FALSE;
00850 
00851   if (aProgressStateFlags & STATE_STOP
00852       &&
00853       aProgressStateFlags & STATE_IS_REQUEST)
00854   {
00855     PLDHashEntryHdr *entry = PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_LOOKUP);
00856     if (PL_DHASH_ENTRY_IS_BUSY(entry))
00857     {
00858       PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_REMOVE);
00859 
00860       requestHasTransferedData = PR_TRUE;
00861     }
00862   }
00863 
00864   if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
00865   {
00866     // The original consumer (this) is no longer the target of the load.
00867     // Ignore any events with this flag, do not allow them to update
00868     // our secure UI state.
00869     return NS_OK;
00870   }
00871 
00872   if (aProgressStateFlags & STATE_START
00873       &&
00874       aProgressStateFlags & STATE_IS_REQUEST
00875       &&
00876       isToplevelProgress
00877       &&
00878       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
00879   {
00880     if (!mDocumentRequestsInProgress)
00881     {
00882       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00883              ("SecureUI:%p: OnStateChange: start for toplevel document\n", this
00884               ));
00885 
00886       ResetStateTracking();
00887       mNewToplevelSecurityStateKnown = PR_FALSE;
00888     }
00889 
00890     // By using a counter, this code also works when the toplevel
00891     // document get's redirected, but the STOP request for the 
00892     // previous toplevel document has not yet have been received.
00893 
00894     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00895            ("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
00896             ));
00897 
00898     ++mDocumentRequestsInProgress;
00899     
00900     return NS_OK;
00901   }
00902 
00903   if (aProgressStateFlags & STATE_STOP
00904       &&
00905       aProgressStateFlags & STATE_IS_REQUEST
00906       &&
00907       isToplevelProgress
00908       &&
00909       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
00910   {
00911     if (mDocumentRequestsInProgress <= 0)
00912     {
00913       // Ignore stop requests unless a document load is in progress
00914       // Unfortunately on application start, see some stops without having seen any starts...
00915       return NS_OK;
00916     }
00917 
00918     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
00919            ("SecureUI:%p: OnStateChange: --mDocumentRequestsInProgress\n", this
00920             ));
00921 
00922     if (!mToplevelEventSink && channel)
00923     {
00924       ObtainEventSink(channel);
00925     }
00926 
00927     --mDocumentRequestsInProgress;
00928 
00929     if (requestHasTransferedData) {
00930       // Data has been transferred for the single toplevel
00931       // request. Evaluate the security state.
00932 
00933       return EvaluateAndUpdateSecurityState(aRequest);
00934     }
00935     
00936     return NS_OK;
00937   }
00938   
00939   if (aProgressStateFlags & STATE_STOP
00940       &&
00941       aProgressStateFlags & STATE_IS_REQUEST)
00942   {
00943     if (!isSubDocumentRelevant)
00944       return NS_OK;
00945     
00946     // if we arrive here, LOAD_DOCUMENT_URI is not set
00947     
00948     // We only care for the security state of sub requests which have actually transfered data.
00949 
00950     if (requestHasTransferedData)
00951     {  
00952       UpdateSubrequestMembers(aRequest);
00953       
00954       // Care for the following scenario:
00955       // A new top level document load might have already started,
00956       // but the security state of the new top level document might not yet been known.
00957       // 
00958       // At this point, we are learning about the security state of a sub-document.
00959       // We must not update the security state based on the sub content,
00960       // if the new top level state is not yet known.
00961       //
00962       // We skip updating the security state in this case.
00963 
00964       if (mNewToplevelSecurityStateKnown)
00965         return UpdateSecurityState(aRequest);
00966     }
00967 
00968     return NS_OK;
00969   }
00970 
00971   return NS_OK;
00972 }
00973 
00974 void nsSecureBrowserUIImpl::ObtainEventSink(nsIChannel *channel)
00975 {
00976   if (!mToplevelEventSink)
00977     NS_QueryNotificationCallbacks(channel, mToplevelEventSink);
00978 }
00979 
00980 nsresult nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest)
00981 {
00982   lockIconState newSecurityState;
00983 
00984   PRBool showWarning = PR_FALSE;
00985   lockIconState warnSecurityState;
00986 
00987   if (mNewToplevelSecurityState & STATE_IS_SECURE)
00988   {
00989     if (mNewToplevelSecurityState & STATE_SECURE_LOW
00990         ||
00991         mNewToplevelSecurityState & STATE_SECURE_MED)
00992     {
00993       if (mSubRequestsBrokenSecurity
00994           ||
00995           mSubRequestsNoSecurity)
00996       {
00997         newSecurityState = lis_mixed_security;
00998       }
00999       else
01000       {
01001         newSecurityState = lis_low_security;
01002       }
01003     }
01004     else
01005     {
01006       // toplevel is high security
01007 
01008       if (mSubRequestsBrokenSecurity
01009           ||
01010           mSubRequestsNoSecurity)
01011       {
01012         newSecurityState = lis_mixed_security;
01013       }
01014       else if (mSubRequestsLowSecurity)
01015       {
01016         newSecurityState = lis_low_security;
01017       }
01018       else
01019       {
01020         newSecurityState = lis_high_security;
01021       }
01022     }
01023   }
01024   else
01025   if (mNewToplevelSecurityState & STATE_IS_BROKEN)
01026   {
01027     // indicating BROKEN is more important than MIXED.
01028   
01029     newSecurityState = lis_broken_security;
01030   }
01031   else
01032   {
01033     newSecurityState = lis_no_security;
01034   }
01035 
01036   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
01037          ("SecureUI:%p: UpdateSecurityState:  old-new  %d - %d\n", this,
01038          mPreviousSecurityState, newSecurityState
01039           ));
01040 
01041   if (mPreviousSecurityState != newSecurityState)
01042   {
01043     // must show alert
01044     
01045     // we'll treat "broken" exactly like "insecure",
01046     // i.e. we do not show alerts when switching between broken and insecure
01047 
01048     /*
01049       from                 to           shows alert
01050     ------------------------------     ---------------
01051 
01052     no or broken -> no or broken    => <NOTHING SHOWN>
01053 
01054     no or broken -> mixed           => mixed alert
01055     no or broken -> low             => low alert
01056     no or broken -> high            => high alert
01057     
01058     mixed, high, low -> no, broken  => leaving secure
01059 
01060     mixed        -> low             => low alert
01061     mixed        -> high            => high alert
01062 
01063     high         -> low             => low alert
01064     high         -> mixed           => mixed
01065     
01066     low          -> high            => high
01067     low          -> mixed           => mixed
01068 
01069 
01070       security    icon
01071       ----------------
01072     
01073       no          open
01074       mixed       broken
01075       broken      broken
01076       low         low
01077       high        high
01078     */
01079 
01080     showWarning = PR_TRUE;
01081     
01082     switch (mPreviousSecurityState)
01083     {
01084       case lis_no_security:
01085       case lis_broken_security:
01086         switch (newSecurityState)
01087         {
01088           case lis_no_security:
01089           case lis_broken_security:
01090             showWarning = PR_FALSE;
01091             break;
01092           
01093           default:
01094             break;
01095         }
01096       
01097       default:
01098         break;
01099     }
01100     
01101     if (showWarning)
01102     {
01103       warnSecurityState = newSecurityState;
01104     }
01105 
01106     mPreviousSecurityState = newSecurityState;
01107 
01108     if (lis_no_security == newSecurityState)
01109     {
01110       mSSLStatus = nsnull;
01111       mInfoTooltip.Truncate();
01112     }
01113   }
01114 
01115   if (mToplevelEventSink)
01116   {
01117     PRUint32 newState = STATE_IS_INSECURE;
01118 
01119     switch (newSecurityState)
01120     {
01121       case lis_broken_security:
01122         newState = STATE_IS_BROKEN;
01123         break;
01124 
01125       case lis_mixed_security:
01126         newState = STATE_IS_BROKEN;
01127         break;
01128 
01129       case lis_low_security:
01130         newState = STATE_IS_SECURE | STATE_SECURE_LOW;
01131         break;
01132 
01133       case lis_high_security:
01134         newState = STATE_IS_SECURE | STATE_SECURE_HIGH;
01135         break;
01136 
01137       default:
01138       case lis_no_security:
01139         newState = STATE_IS_INSECURE;
01140         break;
01141 
01142     }
01143 
01144     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
01145            ("SecureUI:%p: UpdateSecurityState: calling OnSecurityChange\n", this
01146             ));
01147 
01148     mToplevelEventSink->OnSecurityChange(aRequest, newState);
01149   }
01150   else
01151   {
01152     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
01153            ("SecureUI:%p: UpdateSecurityState: NO mToplevelEventSink!\n", this
01154             ));
01155 
01156   }
01157 
01158   if (showWarning)
01159   {
01160     switch (warnSecurityState)
01161     {
01162       case lis_no_security:
01163       case lis_broken_security:
01164         ConfirmLeavingSecure();
01165         break;
01166 
01167       case lis_mixed_security:
01168         ConfirmMixedMode();
01169         break;
01170 
01171       case lis_low_security:
01172         ConfirmEnteringWeak();
01173         break;
01174 
01175       case lis_high_security:
01176         ConfirmEnteringSecure();
01177         break;
01178     }
01179   }
01180 
01181   return NS_OK; 
01182 }
01183 
01184 NS_IMETHODIMP
01185 nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
01186                                         nsIRequest* aRequest,
01187                                         nsIURI* aLocation)
01188 {
01189   if (aLocation)
01190   {
01191     PRBool vs;
01192 
01193     nsresult rv = aLocation->SchemeIs("view-source", &vs);
01194     NS_ENSURE_SUCCESS(rv, rv);
01195 
01196     if (vs) {
01197       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
01198              ("SecureUI:%p: OnLocationChange: view-source\n", this));
01199     }
01200 
01201     mIsViewSource = vs;
01202   }
01203 
01204   mCurrentURI = aLocation;
01205 
01206   // If the location change does not have a corresponding request, then we
01207   // assume that it does not impact the security state.
01208   if (!aRequest)
01209     return NS_OK;
01210 
01211   // The location bar has changed, so we must update the security state.  The
01212   // only concern with doing this here is that a page may transition from being
01213   // reported as completely secure to being reported as partially secure
01214   // (mixed).  This may be confusing for users, and it may bother users who
01215   // like seeing security dialogs.  However, it seems prudent given that page
01216   // loading may never end in some edge cases (perhaps by a site with malicious
01217   // intent).
01218 
01219   nsCOMPtr<nsIDOMWindow> windowForProgress;
01220   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
01221 
01222   if (windowForProgress.get() == mWindow.get()) {
01223     // For toplevel channels, update the security state right away.
01224     return EvaluateAndUpdateSecurityState(aRequest);
01225   }
01226 
01227   // For channels in subdocuments we only update our subrequest state members.
01228   UpdateSubrequestMembers(aRequest);
01229 
01230   // Care for the following scenario:
01231 
01232   // A new toplevel document load might have already started, but the security
01233   // state of the new toplevel document might not yet be known.
01234   // 
01235   // At this point, we are learning about the security state of a sub-document.
01236   // We must not update the security state based on the sub content, if the new
01237   // top level state is not yet known.
01238   //
01239   // We skip updating the security state in this case.
01240 
01241   if (mNewToplevelSecurityStateKnown)
01242     return UpdateSecurityState(aRequest);
01243 
01244   return NS_OK;
01245 }
01246 
01247 NS_IMETHODIMP
01248 nsSecureBrowserUIImpl::OnStatusChange(nsIWebProgress* aWebProgress,
01249                                       nsIRequest* aRequest,
01250                                       nsresult aStatus,
01251                                       const PRUnichar* aMessage)
01252 {
01253   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
01254   return NS_OK;
01255 }
01256 
01257 nsresult
01258 nsSecureBrowserUIImpl::OnSecurityChange(nsIWebProgress *aWebProgress,
01259                                         nsIRequest *aRequest,
01260                                         PRUint32 state)
01261 {
01262 #if defined(DEBUG)
01263   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
01264   if (!channel)
01265     return NS_OK;
01266 
01267   nsCOMPtr<nsIURI> aURI;
01268   channel->GetURI(getter_AddRefs(aURI));
01269   
01270   if (aURI) {
01271     nsCAutoString temp;
01272     aURI->GetSpec(temp);
01273     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
01274            ("SecureUI:%p: OnSecurityChange: (%x) %s\n", this,
01275             state, temp.get()));
01276   }
01277 #endif
01278 
01279   return NS_OK;
01280 }
01281 
01282 // nsISSLStatusProvider methods
01283 NS_IMETHODIMP
01284 nsSecureBrowserUIImpl::GetSSLStatus(nsISupports** _result)
01285 {
01286   NS_ASSERTION(_result, "non-NULL destination required");
01287 
01288   *_result = mSSLStatus;
01289   NS_IF_ADDREF(*_result);
01290 
01291   return NS_OK;
01292 }
01293 
01294 nsresult
01295 nsSecureBrowserUIImpl::IsURLHTTPS(nsIURI* aURL, PRBool* value)
01296 {
01297   *value = PR_FALSE;
01298 
01299   if (!aURL)
01300     return NS_OK;
01301 
01302   return aURL->SchemeIs("https", value);
01303 }
01304 
01305 nsresult
01306 nsSecureBrowserUIImpl::IsURLJavaScript(nsIURI* aURL, PRBool* value)
01307 {
01308   *value = PR_FALSE;
01309 
01310   if (!aURL)
01311     return NS_OK;
01312 
01313   return aURL->SchemeIs("javascript", value);
01314 }
01315 
01316 void
01317 nsSecureBrowserUIImpl::GetBundleString(const PRUnichar* name,
01318                                        nsAString &outString)
01319 {
01320   if (mStringBundle && name) {
01321     PRUnichar *ptrv = nsnull;
01322     if (NS_SUCCEEDED(mStringBundle->GetStringFromName(name,
01323                                                       &ptrv)))
01324       outString = ptrv;
01325     else
01326       outString.SetLength(0);
01327 
01328     nsMemory::Free(ptrv);
01329 
01330   } else {
01331     outString.SetLength(0);
01332   }
01333 }
01334 
01335 nsresult
01336 nsSecureBrowserUIImpl::CheckPost(nsIURI *formURL, nsIURI *actionURL, PRBool *okayToPost)
01337 {
01338   PRBool formSecure, actionSecure, actionJavaScript;
01339   *okayToPost = PR_TRUE;
01340 
01341   nsresult rv = IsURLHTTPS(formURL, &formSecure);
01342   if (NS_FAILED(rv))
01343     return rv;
01344 
01345   rv = IsURLHTTPS(actionURL, &actionSecure);
01346   if (NS_FAILED(rv))
01347     return rv;
01348 
01349   rv = IsURLJavaScript(actionURL, &actionJavaScript);
01350   if (NS_FAILED(rv))
01351     return rv;
01352 
01353   // If we are posting to a secure link, all is okay.
01354   // It doesn't matter whether the currently viewed page is secure or not,
01355   // because the data will be sent to a secure URL.
01356   if (actionSecure) {
01357     return NS_OK;
01358   }
01359 
01360   // Action is a JavaScript call, not an actual post. That's okay too.
01361   if (actionJavaScript) {
01362     return NS_OK;
01363   }
01364 
01365   // posting to insecure webpage from a secure webpage.
01366   if (formSecure) {
01367     *okayToPost = ConfirmPostToInsecureFromSecure();
01368   } else {
01369     *okayToPost = ConfirmPostToInsecure();
01370   }
01371 
01372   return NS_OK;
01373 }
01374 
01375 //
01376 // Implementation of an nsIInterfaceRequestor for use
01377 // as context for NSS calls
01378 //
01379 class nsUIContext : public nsIInterfaceRequestor
01380 {
01381 public:
01382   NS_DECL_ISUPPORTS
01383   NS_DECL_NSIINTERFACEREQUESTOR
01384 
01385   nsUIContext(nsIDOMWindow *window);
01386   virtual ~nsUIContext();
01387 
01388 private:
01389   nsCOMPtr<nsIDOMWindow> mWindow;
01390 };
01391 
01392 NS_IMPL_ISUPPORTS1(nsUIContext, nsIInterfaceRequestor)
01393 
01394 nsUIContext::nsUIContext(nsIDOMWindow *aWindow)
01395 : mWindow(aWindow)
01396 {
01397 }
01398 
01399 nsUIContext::~nsUIContext()
01400 {
01401 }
01402 
01403 /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
01404 NS_IMETHODIMP nsUIContext::GetInterface(const nsIID & uuid, void * *result)
01405 {
01406   nsresult rv;
01407 
01408   if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
01409     nsCOMPtr<nsIDOMWindowInternal> internal = do_QueryInterface(mWindow, &rv);
01410     if (NS_FAILED(rv)) return rv;
01411 
01412     nsIPrompt *prompt;
01413 
01414     rv = internal->GetPrompter(&prompt);
01415     *result = prompt;
01416   } else if (uuid.Equals(NS_GET_IID(nsIDOMWindow))) {
01417     *result = mWindow;
01418     NS_ADDREF ((nsISupports*) *result);
01419     rv = NS_OK;
01420   } else {
01421     rv = NS_ERROR_NO_INTERFACE;
01422   }
01423 
01424   return rv;
01425 }
01426 
01427 nsresult nsSecureBrowserUIImpl::
01428 GetNSSDialogs(nsISecurityWarningDialogs **result)
01429 {
01430   nsresult rv;
01431   nsCOMPtr<nsISecurityWarningDialogs> my_result(do_GetService(NS_SECURITYWARNINGDIALOGS_CONTRACTID, &rv));
01432 
01433   if (NS_FAILED(rv)) 
01434     return rv;
01435 
01436   nsCOMPtr<nsIProxyObjectManager> proxyman(do_GetService(NS_XPCOMPROXY_CONTRACTID));
01437   if (!proxyman)
01438     return NS_ERROR_FAILURE;
01439 
01440   nsCOMPtr<nsISupports> proxiedResult;
01441   proxyman->GetProxyForObject(NS_UI_THREAD_EVENTQ,
01442                               NS_GET_IID(nsISecurityWarningDialogs),
01443                               my_result, PROXY_SYNC,
01444                               getter_AddRefs(proxiedResult));
01445 
01446   if (!proxiedResult) {
01447     return NS_ERROR_FAILURE;
01448   }
01449 
01450   return CallQueryInterface(proxiedResult, result);
01451 }
01452 
01453 PRBool nsSecureBrowserUIImpl::
01454 ConfirmEnteringSecure()
01455 {
01456   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01457 
01458   GetNSSDialogs(getter_AddRefs(dialogs));
01459   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01460 
01461   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01462 
01463   PRBool confirms;
01464   dialogs->ConfirmEnteringSecure(ctx, &confirms);
01465 
01466   return confirms;
01467 }
01468 
01469 PRBool nsSecureBrowserUIImpl::
01470 ConfirmEnteringWeak()
01471 {
01472   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01473 
01474   GetNSSDialogs(getter_AddRefs(dialogs));
01475   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01476 
01477   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01478 
01479   PRBool confirms;
01480   dialogs->ConfirmEnteringWeak(ctx, &confirms);
01481 
01482   return confirms;
01483 }
01484 
01485 PRBool nsSecureBrowserUIImpl::
01486 ConfirmLeavingSecure()
01487 {
01488   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01489 
01490   GetNSSDialogs(getter_AddRefs(dialogs));
01491   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01492 
01493   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01494 
01495   PRBool confirms;
01496   dialogs->ConfirmLeavingSecure(ctx, &confirms);
01497 
01498   return confirms;
01499 }
01500 
01501 PRBool nsSecureBrowserUIImpl::
01502 ConfirmMixedMode()
01503 {
01504   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01505 
01506   GetNSSDialogs(getter_AddRefs(dialogs));
01507   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01508 
01509   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01510 
01511   PRBool confirms;
01512   dialogs->ConfirmMixedMode(ctx, &confirms);
01513 
01514   return confirms;
01515 }
01516 
01522 PRBool nsSecureBrowserUIImpl::
01523 ConfirmPostToInsecure()
01524 {
01525   nsresult rv;
01526 
01527   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01528 
01529   GetNSSDialogs(getter_AddRefs(dialogs));
01530   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01531 
01532   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01533 
01534   PRBool result;
01535 
01536   rv = dialogs->ConfirmPostToInsecure(ctx, &result);
01537   if (NS_FAILED(rv)) return PR_FALSE;
01538 
01539   return result;
01540 }
01541 
01547 PRBool nsSecureBrowserUIImpl::
01548 ConfirmPostToInsecureFromSecure()
01549 {
01550   nsresult rv;
01551 
01552   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
01553 
01554   GetNSSDialogs(getter_AddRefs(dialogs));
01555   if (!dialogs) return PR_FALSE;  // Should this allow PR_TRUE for unimplemented?
01556 
01557   nsCOMPtr<nsIInterfaceRequestor> ctx = new nsUIContext(mWindow);
01558 
01559   PRBool result;
01560 
01561   rv = dialogs->ConfirmPostToInsecureFromSecure(ctx, &result);
01562   if (NS_FAILED(rv)) return PR_FALSE;
01563 
01564   return result;
01565 }