LCOV - code coverage report
Current view: directory - security/manager/boot/src - nsSecureBrowserUIImpl.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 728 0 0.0 %
Date: 2012-06-02 Functions: 50 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998-2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Hubbie Shaw
      24                 :  *   Doug Turner <dougt@netscape.com>
      25                 :  *   Stuart Parmenter <pavlov@netscape.com>
      26                 :  *   Brian Ryner <bryner@brianryner.com>
      27                 :  *   Terry Hayes <thayes@netscape.com>
      28                 :  *   Kai Engert <kaie@netscape.com>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      32                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK ***** */
      43                 : 
      44                 : #ifdef MOZ_LOGGING
      45                 : #define FORCE_PR_LOG
      46                 : #endif
      47                 : 
      48                 : #include "nspr.h"
      49                 : #include "prlog.h"
      50                 : #include "prmem.h"
      51                 : 
      52                 : #include "nsISecureBrowserUI.h"
      53                 : #include "nsSecureBrowserUIImpl.h"
      54                 : #include "nsCOMPtr.h"
      55                 : #include "nsIInterfaceRequestor.h"
      56                 : #include "nsIInterfaceRequestorUtils.h"
      57                 : #include "nsIServiceManager.h"
      58                 : #include "nsIObserverService.h"
      59                 : #include "nsCURILoader.h"
      60                 : #include "nsIDocShell.h"
      61                 : #include "nsIDocument.h"
      62                 : #include "nsIPrincipal.h"
      63                 : #include "nsIDOMElement.h"
      64                 : #include "nsPIDOMWindow.h"
      65                 : #include "nsIContent.h"
      66                 : #include "nsIWebProgress.h"
      67                 : #include "nsIWebProgressListener.h"
      68                 : #include "nsIChannel.h"
      69                 : #include "nsIHttpChannel.h"
      70                 : #include "nsIFileChannel.h"
      71                 : #include "nsIWyciwygChannel.h"
      72                 : #include "nsIFTPChannel.h"
      73                 : #include "nsITransportSecurityInfo.h"
      74                 : #include "nsISSLStatus.h"
      75                 : #include "nsIURI.h"
      76                 : #include "nsISecurityEventSink.h"
      77                 : #include "nsIPrompt.h"
      78                 : #include "nsIFormSubmitObserver.h"
      79                 : #include "nsISecurityWarningDialogs.h"
      80                 : #include "nsISecurityInfoProvider.h"
      81                 : #include "imgIRequest.h"
      82                 : #include "nsThreadUtils.h"
      83                 : #include "nsNetUtil.h"
      84                 : #include "nsNetCID.h"
      85                 : #include "nsCRT.h"
      86                 : 
      87                 : using namespace mozilla;
      88                 : 
      89                 : #define SECURITY_STRING_BUNDLE_URL "chrome://pipnss/locale/security.properties"
      90                 : 
      91                 : #define IS_SECURE(state) ((state & 0xFFFF) == STATE_IS_SECURE)
      92                 : 
      93                 : #if defined(PR_LOGGING)
      94                 : //
      95                 : // Log module for nsSecureBrowserUI logging...
      96                 : //
      97                 : // To enable logging (see prlog.h for full details):
      98                 : //
      99                 : //    set NSPR_LOG_MODULES=nsSecureBrowserUI:5
     100                 : //    set NSPR_LOG_FILE=nspr.log
     101                 : //
     102                 : // this enables PR_LOG_DEBUG level information and places all output in
     103                 : // the file nspr.log
     104                 : //
     105                 : PRLogModuleInfo* gSecureDocLog = nsnull;
     106                 : #endif /* PR_LOGGING */
     107                 : 
     108                 : struct RequestHashEntry : PLDHashEntryHdr {
     109                 :     void *r;
     110                 : };
     111                 : 
     112                 : PR_STATIC_CALLBACK(bool)
     113               0 : RequestMapMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
     114                 :                          const void *key)
     115                 : {
     116               0 :   const RequestHashEntry *entry = static_cast<const RequestHashEntry*>(hdr);
     117               0 :   return entry->r == key;
     118                 : }
     119                 : 
     120                 : PR_STATIC_CALLBACK(bool)
     121               0 : RequestMapInitEntry(PLDHashTable *table, PLDHashEntryHdr *hdr,
     122                 :                      const void *key)
     123                 : {
     124               0 :   RequestHashEntry *entry = static_cast<RequestHashEntry*>(hdr);
     125               0 :   entry->r = (void*)key;
     126               0 :   return true;
     127                 : }
     128                 : 
     129                 : static PLDHashTableOps gMapOps = {
     130                 :   PL_DHashAllocTable,
     131                 :   PL_DHashFreeTable,
     132                 :   PL_DHashVoidPtrKeyStub,
     133                 :   RequestMapMatchEntry,
     134                 :   PL_DHashMoveEntryStub,
     135                 :   PL_DHashClearEntryStub,
     136                 :   PL_DHashFinalizeStub,
     137                 :   RequestMapInitEntry
     138                 : };
     139                 : 
     140                 : #ifdef DEBUG
     141                 : class nsAutoAtomic {
     142                 :   public:
     143               0 :     nsAutoAtomic(PRInt32 &i)
     144               0 :     :mI(i) {
     145               0 :       PR_ATOMIC_INCREMENT(&mI);
     146               0 :     }
     147                 : 
     148               0 :     ~nsAutoAtomic() {
     149               0 :       PR_ATOMIC_DECREMENT(&mI);
     150               0 :     }
     151                 : 
     152                 :   protected:
     153                 :     PRInt32 &mI;
     154                 : 
     155                 :   private:
     156                 :     nsAutoAtomic(); // not accessible
     157                 : };
     158                 : #endif
     159                 : 
     160               0 : nsSecureBrowserUIImpl::nsSecureBrowserUIImpl()
     161                 :   : mReentrantMonitor("nsSecureBrowserUIImpl.mReentrantMonitor")
     162                 :   , mNotifiedSecurityState(lis_no_security)
     163                 :   , mNotifiedToplevelIsEV(false)
     164                 :   , mNewToplevelSecurityState(STATE_IS_INSECURE)
     165                 :   , mNewToplevelIsEV(false)
     166                 :   , mNewToplevelSecurityStateKnown(true)
     167                 :   , mIsViewSource(false)
     168                 :   , mSubRequestsHighSecurity(0)
     169                 :   , mSubRequestsLowSecurity(0)
     170                 :   , mSubRequestsBrokenSecurity(0)
     171                 :   , mSubRequestsNoSecurity(0)
     172                 :   , mRestoreSubrequests(false)
     173                 : #ifdef DEBUG
     174               0 :   , mOnStateLocationChangeReentranceDetection(0)
     175                 : #endif
     176                 : {
     177               0 :   mTransferringRequests.ops = nsnull;
     178               0 :   ResetStateTracking();
     179                 :   
     180                 : #if defined(PR_LOGGING)
     181               0 :   if (!gSecureDocLog)
     182               0 :     gSecureDocLog = PR_NewLogModule("nsSecureBrowserUI");
     183                 : #endif /* PR_LOGGING */
     184               0 : }
     185                 : 
     186               0 : nsSecureBrowserUIImpl::~nsSecureBrowserUIImpl()
     187                 : {
     188               0 :   if (mTransferringRequests.ops) {
     189               0 :     PL_DHashTableFinish(&mTransferringRequests);
     190               0 :     mTransferringRequests.ops = nsnull;
     191                 :   }
     192               0 : }
     193                 : 
     194               0 : NS_IMPL_THREADSAFE_ISUPPORTS6(nsSecureBrowserUIImpl,
     195                 :                               nsISecureBrowserUI,
     196                 :                               nsIWebProgressListener,
     197                 :                               nsIFormSubmitObserver,
     198                 :                               nsIObserver,
     199                 :                               nsISupportsWeakReference,
     200                 :                               nsISSLStatusProvider)
     201                 : 
     202                 : NS_IMETHODIMP
     203               0 : nsSecureBrowserUIImpl::Init(nsIDOMWindow *aWindow)
     204                 : {
     205                 : 
     206                 : #ifdef PR_LOGGING
     207               0 :   nsCOMPtr<nsIDOMWindow> window(do_QueryReferent(mWindow));
     208                 : 
     209               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     210                 :          ("SecureUI:%p: Init: mWindow: %p, aWindow: %p\n", this,
     211                 :           window.get(), aWindow));
     212                 : #endif
     213                 : 
     214               0 :   if (!aWindow) {
     215               0 :     NS_WARNING("Null window passed to nsSecureBrowserUIImpl::Init()");
     216               0 :     return NS_ERROR_INVALID_ARG;
     217                 :   }
     218                 : 
     219               0 :   if (mWindow) {
     220               0 :     NS_WARNING("Trying to init an nsSecureBrowserUIImpl twice");
     221               0 :     return NS_ERROR_ALREADY_INITIALIZED;
     222                 :   }
     223                 : 
     224               0 :   nsCOMPtr<nsPIDOMWindow> pwin(do_QueryInterface(aWindow));
     225               0 :   if (pwin->IsInnerWindow()) {
     226               0 :     pwin = pwin->GetOuterWindow();
     227                 :   }
     228                 : 
     229                 :   nsresult rv;
     230               0 :   mWindow = do_GetWeakReference(pwin, &rv);
     231               0 :   NS_ENSURE_SUCCESS(rv, rv);
     232                 : 
     233               0 :   nsCOMPtr<nsIStringBundleService> service(do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
     234               0 :   if (NS_FAILED(rv)) return rv;
     235                 :   
     236                 :   // We do not need to test for mStringBundle here...
     237                 :   // Anywhere we use it, we will test before using.  Some
     238                 :   // embedded users of PSM may want to reuse our
     239                 :   // nsSecureBrowserUIImpl implementation without the
     240                 :   // bundle.
     241               0 :   service->CreateBundle(SECURITY_STRING_BUNDLE_URL, getter_AddRefs(mStringBundle));
     242                 :   
     243                 :   
     244                 :   // hook up to the form post notifications:
     245               0 :   nsCOMPtr<nsIObserverService> svc(do_GetService("@mozilla.org/observer-service;1", &rv));
     246               0 :   if (NS_SUCCEEDED(rv)) {
     247               0 :     rv = svc->AddObserver(this, NS_FORMSUBMIT_SUBJECT, true);
     248                 :   }
     249                 :   
     250               0 :   nsCOMPtr<nsPIDOMWindow> piwindow(do_QueryInterface(aWindow));
     251               0 :   if (!piwindow) return NS_ERROR_FAILURE;
     252                 : 
     253               0 :   nsIDocShell *docShell = piwindow->GetDocShell();
     254                 : 
     255                 :   // The Docshell will own the SecureBrowserUI object
     256               0 :   if (!docShell)
     257               0 :     return NS_ERROR_FAILURE;
     258                 : 
     259               0 :   docShell->SetSecurityUI(this);
     260                 : 
     261                 :   /* GetWebProgress(mWindow) */
     262                 :   // hook up to the webprogress notifications.
     263               0 :   nsCOMPtr<nsIWebProgress> wp(do_GetInterface(docShell));
     264               0 :   if (!wp) return NS_ERROR_FAILURE;
     265                 :   /* end GetWebProgress */
     266                 :   
     267               0 :   wp->AddProgressListener(static_cast<nsIWebProgressListener*>(this),
     268                 :                           nsIWebProgress::NOTIFY_STATE_ALL | 
     269                 :                           nsIWebProgress::NOTIFY_LOCATION  |
     270               0 :                           nsIWebProgress::NOTIFY_SECURITY);
     271                 : 
     272                 : 
     273               0 :   return NS_OK;
     274                 : }
     275                 : 
     276                 : NS_IMETHODIMP
     277               0 : nsSecureBrowserUIImpl::GetState(PRUint32* aState)
     278                 : {
     279               0 :   ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     280               0 :   return MapInternalToExternalState(aState, mNotifiedSecurityState, mNotifiedToplevelIsEV);
     281                 : }
     282                 : 
     283                 : // static
     284                 : already_AddRefed<nsISupports> 
     285               0 : nsSecureBrowserUIImpl::ExtractSecurityInfo(nsIRequest* aRequest)
     286                 : {
     287               0 :   nsISupports *retval = nsnull; 
     288               0 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     289               0 :   if (channel)
     290               0 :     channel->GetSecurityInfo(&retval);
     291                 :   
     292               0 :   if (!retval) {
     293               0 :     nsCOMPtr<nsISecurityInfoProvider> provider(do_QueryInterface(aRequest));
     294               0 :     if (provider)
     295               0 :       provider->GetSecurityInfo(&retval);
     296                 :   }
     297                 : 
     298               0 :   return retval;
     299                 : }
     300                 : 
     301                 : nsresult
     302               0 : nsSecureBrowserUIImpl::MapInternalToExternalState(PRUint32* aState, lockIconState lock, bool ev)
     303                 : {
     304               0 :   NS_ENSURE_ARG(aState);
     305                 : 
     306               0 :   switch (lock)
     307                 :   {
     308                 :     case lis_broken_security:
     309               0 :       *aState = STATE_IS_BROKEN;
     310               0 :       break;
     311                 : 
     312                 :     case lis_mixed_security:
     313               0 :       *aState = STATE_IS_BROKEN;
     314               0 :       break;
     315                 : 
     316                 :     case lis_low_security:
     317               0 :       *aState = STATE_IS_SECURE | STATE_SECURE_LOW;
     318               0 :       break;
     319                 : 
     320                 :     case lis_high_security:
     321               0 :       *aState = STATE_IS_SECURE | STATE_SECURE_HIGH;
     322               0 :       break;
     323                 : 
     324                 :     default:
     325                 :     case lis_no_security:
     326               0 :       *aState = STATE_IS_INSECURE;
     327               0 :       break;
     328                 :   }
     329                 : 
     330               0 :   if (ev && (*aState & STATE_IS_SECURE))
     331               0 :     *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
     332                 :   
     333               0 :   return NS_OK;
     334                 : }
     335                 : 
     336                 : NS_IMETHODIMP
     337               0 : nsSecureBrowserUIImpl::GetTooltipText(nsAString& aText)
     338                 : {
     339                 :   lockIconState state;
     340               0 :   nsXPIDLString tooltip;
     341                 : 
     342                 :   {
     343               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     344               0 :     state = mNotifiedSecurityState;
     345               0 :     tooltip = mInfoTooltip;
     346                 :   }
     347                 : 
     348               0 :   if (state == lis_mixed_security)
     349                 :   {
     350               0 :     GetBundleString(NS_LITERAL_STRING("SecurityButtonMixedContentTooltipText").get(),
     351               0 :                     aText);
     352                 :   }
     353               0 :   else if (!tooltip.IsEmpty())
     354                 :   {
     355               0 :     aText = tooltip;
     356                 :   }
     357                 :   else
     358                 :   {
     359               0 :     GetBundleString(NS_LITERAL_STRING("SecurityButtonTooltipText").get(),
     360               0 :                     aText);
     361                 :   }
     362                 : 
     363               0 :   return NS_OK;
     364                 : }
     365                 : 
     366                 : NS_IMETHODIMP
     367               0 : nsSecureBrowserUIImpl::Observe(nsISupports*, const char*,
     368                 :                                const PRUnichar*)
     369                 : {
     370               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     371                 : }
     372                 : 
     373                 : 
     374               0 : static nsresult IsChildOfDomWindow(nsIDOMWindow *parent, nsIDOMWindow *child,
     375                 :                                    bool* value)
     376                 : {
     377               0 :   *value = false;
     378                 :   
     379               0 :   if (parent == child) {
     380               0 :     *value = true;
     381               0 :     return NS_OK;
     382                 :   }
     383                 :   
     384               0 :   nsCOMPtr<nsIDOMWindow> childsParent;
     385               0 :   child->GetParent(getter_AddRefs(childsParent));
     386                 :   
     387               0 :   if (childsParent && childsParent.get() != child)
     388               0 :     IsChildOfDomWindow(parent, childsParent, value);
     389                 :   
     390               0 :   return NS_OK;
     391                 : }
     392                 : 
     393               0 : static PRUint32 GetSecurityStateFromSecurityInfo(nsISupports *info)
     394                 : {
     395                 :   nsresult res;
     396                 :   PRUint32 securityState;
     397                 : 
     398               0 :   nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
     399               0 :   if (!psmInfo) {
     400               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - no nsITransportSecurityInfo for %p\n",
     401                 :                                          (nsISupports *)info));
     402               0 :     return nsIWebProgressListener::STATE_IS_INSECURE;
     403                 :   }
     404               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - info is %p\n", 
     405                 :                                        (nsISupports *)info));
     406                 :   
     407               0 :   res = psmInfo->GetSecurityState(&securityState);
     408               0 :   if (NS_FAILED(res)) {
     409               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - GetSecurityState failed: %d\n",
     410                 :                                          res));
     411               0 :     securityState = nsIWebProgressListener::STATE_IS_BROKEN;
     412                 :   }
     413                 :   
     414               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI: GetSecurityState: - Returning %d\n", 
     415                 :                                        securityState));
     416               0 :   return securityState;
     417                 : }
     418                 : 
     419                 : 
     420                 : NS_IMETHODIMP
     421               0 : nsSecureBrowserUIImpl::Notify(nsIDOMHTMLFormElement* aDOMForm,
     422                 :                               nsIDOMWindow* aWindow, nsIURI* actionURL,
     423                 :                               bool* cancelSubmit)
     424                 : {
     425                 :   // Return NS_OK unless we want to prevent this form from submitting.
     426               0 :   *cancelSubmit = false;
     427               0 :   if (!aWindow || !actionURL || !aDOMForm)
     428               0 :     return NS_OK;
     429                 :   
     430               0 :   nsCOMPtr<nsIContent> formNode = do_QueryInterface(aDOMForm);
     431                 : 
     432               0 :   nsCOMPtr<nsIDocument> document = formNode->GetDocument();
     433               0 :   if (!document) return NS_OK;
     434                 : 
     435               0 :   nsIPrincipal *principal = formNode->NodePrincipal();
     436                 :   
     437               0 :   if (!principal)
     438                 :   {
     439               0 :     *cancelSubmit = true;
     440               0 :     return NS_OK;
     441                 :   }
     442                 : 
     443               0 :   nsCOMPtr<nsIURI> formURL;
     444               0 :   if (NS_FAILED(principal->GetURI(getter_AddRefs(formURL))) ||
     445               0 :       !formURL)
     446                 :   {
     447               0 :     formURL = document->GetDocumentURI();
     448                 :   }
     449                 : 
     450                 :   nsCOMPtr<nsIDOMWindow> postingWindow =
     451               0 :     do_QueryInterface(document->GetWindow());
     452                 :   // We can't find this document's window, cancel it.
     453               0 :   if (!postingWindow)
     454                 :   {
     455               0 :     NS_WARNING("If you see this and can explain why it should be allowed, note in Bug 332324");
     456               0 :     *cancelSubmit = true;
     457               0 :     return NS_OK;
     458                 :   }
     459                 : 
     460               0 :   nsCOMPtr<nsIDOMWindow> window;
     461                 :   {
     462               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     463               0 :     window = do_QueryReferent(mWindow);
     464               0 :     NS_ASSERTION(window, "Window has gone away?!");
     465                 :   }
     466                 : 
     467                 :   bool isChild;
     468               0 :   IsChildOfDomWindow(window, postingWindow, &isChild);
     469                 :   
     470                 :   // This notify call is not for our window, ignore it.
     471               0 :   if (!isChild)
     472               0 :     return NS_OK;
     473                 :   
     474                 :   bool okayToPost;
     475               0 :   nsresult res = CheckPost(formURL, actionURL, &okayToPost);
     476                 :   
     477               0 :   if (NS_SUCCEEDED(res) && !okayToPost)
     478               0 :     *cancelSubmit = true;
     479                 :   
     480               0 :   return res;
     481                 : }
     482                 : 
     483                 : //  nsIWebProgressListener
     484                 : NS_IMETHODIMP 
     485               0 : nsSecureBrowserUIImpl::OnProgressChange(nsIWebProgress* aWebProgress,
     486                 :                                         nsIRequest* aRequest,
     487                 :                                         PRInt32 aCurSelfProgress,
     488                 :                                         PRInt32 aMaxSelfProgress,
     489                 :                                         PRInt32 aCurTotalProgress,
     490                 :                                         PRInt32 aMaxTotalProgress)
     491                 : {
     492               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
     493               0 :   return NS_OK;
     494                 : }
     495                 : 
     496               0 : void nsSecureBrowserUIImpl::ResetStateTracking()
     497                 : {
     498               0 :   ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     499                 : 
     500               0 :   mInfoTooltip.Truncate();
     501               0 :   mDocumentRequestsInProgress = 0;
     502               0 :   if (mTransferringRequests.ops) {
     503               0 :     PL_DHashTableFinish(&mTransferringRequests);
     504               0 :     mTransferringRequests.ops = nsnull;
     505                 :   }
     506                 :   PL_DHashTableInit(&mTransferringRequests, &gMapOps, nsnull,
     507               0 :                     sizeof(RequestHashEntry), 16);
     508               0 : }
     509                 : 
     510                 : nsresult
     511               0 : nsSecureBrowserUIImpl::EvaluateAndUpdateSecurityState(nsIRequest* aRequest, nsISupports *info,
     512                 :                                                       bool withNewLocation)
     513                 : {
     514                 :   /* I explicitly ignore the camelCase variable naming style here,
     515                 :      I want to make it clear these are temp variables that relate to the 
     516                 :      member variables with the same suffix.*/
     517                 : 
     518               0 :   PRUint32 temp_NewToplevelSecurityState = nsIWebProgressListener::STATE_IS_INSECURE;
     519               0 :   bool temp_NewToplevelIsEV = false;
     520                 : 
     521               0 :   bool updateStatus = false;
     522               0 :   nsCOMPtr<nsISSLStatus> temp_SSLStatus;
     523                 : 
     524               0 :   bool updateTooltip = false;
     525               0 :   nsXPIDLString temp_InfoTooltip;
     526                 : 
     527               0 :     temp_NewToplevelSecurityState = GetSecurityStateFromSecurityInfo(info);
     528                 : 
     529               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     530                 :            ("SecureUI:%p: OnStateChange: remember mNewToplevelSecurityState => %x\n", this,
     531                 :             temp_NewToplevelSecurityState));
     532                 : 
     533               0 :     nsCOMPtr<nsISSLStatusProvider> sp = do_QueryInterface(info);
     534               0 :     if (sp) {
     535                 :       // Ignore result
     536               0 :       updateStatus = true;
     537               0 :       (void) sp->GetSSLStatus(getter_AddRefs(temp_SSLStatus));
     538               0 :       if (temp_SSLStatus) {
     539                 :         bool aTemp;
     540               0 :         if (NS_SUCCEEDED(temp_SSLStatus->GetIsExtendedValidation(&aTemp))) {
     541               0 :           temp_NewToplevelIsEV = aTemp;
     542                 :         }
     543                 :       }
     544                 :     }
     545                 : 
     546               0 :     if (info) {
     547               0 :       nsCOMPtr<nsITransportSecurityInfo> secInfo(do_QueryInterface(info));
     548               0 :       if (secInfo) {
     549               0 :         updateTooltip = true;
     550               0 :         secInfo->GetShortSecurityDescription(getter_Copies(temp_InfoTooltip));
     551                 :       }
     552                 :     }
     553                 : 
     554                 :   // assume temp_NewToplevelSecurityState was set in this scope!
     555                 :   // see code that is directly above
     556                 : 
     557                 :   {
     558               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     559               0 :     mNewToplevelSecurityStateKnown = true;
     560               0 :     mNewToplevelSecurityState = temp_NewToplevelSecurityState;
     561               0 :     mNewToplevelIsEV = temp_NewToplevelIsEV;
     562               0 :     if (updateStatus) {
     563               0 :       mSSLStatus = temp_SSLStatus;
     564                 :     }
     565               0 :     if (updateTooltip) {
     566               0 :       mInfoTooltip = temp_InfoTooltip;
     567                 :     }
     568               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     569                 :            ("SecureUI:%p: remember securityInfo %p\n", this,
     570                 :             info));
     571                 :     nsCOMPtr<nsIAssociatedContentSecurity> associatedContentSecurityFromRequest =
     572               0 :         do_QueryInterface(aRequest);
     573               0 :     if (associatedContentSecurityFromRequest)
     574               0 :         mCurrentToplevelSecurityInfo = aRequest;
     575                 :     else
     576               0 :         mCurrentToplevelSecurityInfo = info;
     577                 : 
     578                 :     // The subrequest counters are now in sync with 
     579                 :     // mCurrentToplevelSecurityInfo, don't restore after top level
     580                 :     // document load finishes.
     581               0 :     mRestoreSubrequests = false;
     582                 :   }
     583                 : 
     584                 :   return UpdateSecurityState(aRequest, withNewLocation, 
     585               0 :                              updateStatus, updateTooltip);
     586                 : }
     587                 : 
     588                 : void
     589               0 : nsSecureBrowserUIImpl::UpdateSubrequestMembers(nsISupports *securityInfo)
     590                 : {
     591                 :   // For wyciwyg channels in subdocuments we only update our
     592                 :   // subrequest state members.
     593               0 :   PRUint32 reqState = GetSecurityStateFromSecurityInfo(securityInfo);
     594                 : 
     595                 :   // the code above this line should run without a lock
     596               0 :   ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     597                 : 
     598               0 :   if (reqState & STATE_IS_SECURE) {
     599               0 :     if (reqState & STATE_SECURE_LOW || reqState & STATE_SECURE_MED) {
     600               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     601                 :              ("SecureUI:%p: OnStateChange: subreq LOW\n", this));
     602               0 :       ++mSubRequestsLowSecurity;
     603                 :     } else {
     604               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     605                 :              ("SecureUI:%p: OnStateChange: subreq HIGH\n", this));
     606               0 :       ++mSubRequestsHighSecurity;
     607                 :     }
     608               0 :   } else if (reqState & STATE_IS_BROKEN) {
     609               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     610                 :            ("SecureUI:%p: OnStateChange: subreq BROKEN\n", this));
     611               0 :     ++mSubRequestsBrokenSecurity;
     612                 :   } else {
     613               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     614                 :            ("SecureUI:%p: OnStateChange: subreq INSECURE\n", this));
     615               0 :     ++mSubRequestsNoSecurity;
     616                 :   }
     617               0 : }
     618                 : 
     619                 : NS_IMETHODIMP
     620               0 : nsSecureBrowserUIImpl::OnStateChange(nsIWebProgress* aWebProgress,
     621                 :                                      nsIRequest* aRequest,
     622                 :                                      PRUint32 aProgressStateFlags,
     623                 :                                      nsresult aStatus)
     624                 : {
     625                 : #ifdef DEBUG
     626               0 :   nsAutoAtomic atomic(mOnStateLocationChangeReentranceDetection);
     627               0 :   NS_ASSERTION(mOnStateLocationChangeReentranceDetection == 1,
     628                 :                "unexpected parallel nsIWebProgress OnStateChange and/or OnLocationChange notification");
     629                 : #endif
     630                 :   /*
     631                 :     All discussion, unless otherwise mentioned, only refers to
     632                 :     http, https, file or wyciwig requests.
     633                 : 
     634                 : 
     635                 :     Redirects are evil, well, some of them.
     636                 :     There are multiple forms of redirects.
     637                 : 
     638                 :     Redirects caused by http refresh content are ok, because experiments show,
     639                 :     with those redirects, the old page contents and their requests will come to STOP
     640                 :     completely, before any progress from new refreshed page content is reported.
     641                 :     So we can safely treat them as separate page loading transactions.
     642                 : 
     643                 :     Evil are redirects at the http protocol level, like code 302.
     644                 : 
     645                 :     If the toplevel documents gets replaced, i.e. redirected with 302, we do not care for the 
     646                 :     security state of the initial transaction, which has now been redirected, 
     647                 :     we only care for the new page load.
     648                 :     
     649                 :     For the implementation of the security UI, we make an assumption, that is hopefully true.
     650                 :     
     651                 :     Imagine, the received page that was delivered with the 302 redirection answer,
     652                 :     also delivered html content.
     653                 : 
     654                 :     What happens if the parser starts to analyze the content and tries to load contained sub objects?
     655                 :     
     656                 :     In that case we would see start and stop requests for subdocuments, some for the previous document,
     657                 :     some for the new target document. And only those for the new toplevel document may be
     658                 :     taken into consideration, when deciding about the security state of the next toplevel document.
     659                 :     
     660                 :     Because security state is being looked at, when loading stops for (sub)documents, this 
     661                 :     could cause real confusion, because we have to decide, whether an incoming progress 
     662                 :     belongs to the new toplevel page, or the previous, already redirected page.
     663                 :     
     664                 :     Can we simplify here?
     665                 :     
     666                 :     If a redirect at the http protocol level is seen, can we safely assume, its html content
     667                 :     will not be parsed, anylzed, and no embedded objects will get loaded (css, js, images),
     668                 :     because the redirect is already happening?
     669                 :     
     670                 :     If we can assume that, this really simplify things. Because we will never see notification
     671                 :     for sub requests that need to get ignored.
     672                 :     
     673                 :     I would like to make this assumption for now, but please let me (kaie) know if I'm wrong.
     674                 :     
     675                 :     Excurse:
     676                 :       If my assumption is wrong, then we would require more tracking information.
     677                 :       We need to keep lists of all pointers to request object that had been seen since the
     678                 :       last toplevel start event.
     679                 :       If the start for a redirected page is seen, the list of releveant object must be cleared,
     680                 :       and only progress for requests which start after it must be analyzed.
     681                 :       All other events must be ignored, as they belong to now irrelevant previous top level documents.
     682                 : 
     683                 : 
     684                 :     Frames are also evil.
     685                 : 
     686                 :     First we need a decision.
     687                 :     kaie thinks: 
     688                 :       Only if the toplevel frame is secure, we should try to display secure lock icons.
     689                 :       If some of the inner contents are insecure, we display mixed mode.
     690                 :       
     691                 :       But if the top level frame is not secure, why indicate a mixed lock icon at all?
     692                 :       I think we should always display an open lock icon, if the top level frameset is insecure.
     693                 :       
     694                 :       That's the way Netscape Communicator behaves, and I think we should do the same.
     695                 :       
     696                 :       The user will not know which parts are secure and which are not,
     697                 :       and any certificate information, displayed in the tooltip or in the "page info"
     698                 :       will only be relevant for some subframe(s), and the user will not know which ones,
     699                 :       so we shouldn't display it as a general attribute of the displayed page.
     700                 : 
     701                 :     Why are frames evil?
     702                 :     
     703                 :     Because the progress for the toplevel frame document is not easily distinguishable
     704                 :     from subframes. The same STATE bits are reported.
     705                 : 
     706                 :     While at first sight, when a new page load happens,
     707                 :     the toplevel frameset document has also the STATE_IS_NETWORK bit in it.
     708                 :     But this can't really be used. Because in case that document causes a http 302 redirect, 
     709                 :     the real top level frameset will no longer have that bit.
     710                 :     
     711                 :     But we need some way to distinguish top level frames from inner frames.
     712                 :     
     713                 :     I saw that the web progress we get delivered has a reference to the toplevel DOM window.
     714                 :     
     715                 :     I suggest, we look at all incoming requests.
     716                 :     If a request is NOT for the toplevel DOM window, we will always treat it as a subdocument request,
     717                 :     regardless of whether the load flags indicate a top level document.
     718                 :   */
     719                 : 
     720               0 :   nsCOMPtr<nsIDOMWindow> windowForProgress;
     721               0 :   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
     722                 : 
     723               0 :   nsCOMPtr<nsIDOMWindow> window;
     724                 :   bool isViewSource;
     725                 : 
     726               0 :   nsCOMPtr<nsINetUtil> ioService;
     727                 : 
     728                 :   {
     729               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     730               0 :     window = do_QueryReferent(mWindow);
     731               0 :     NS_ASSERTION(window, "Window has gone away?!");
     732               0 :     isViewSource = mIsViewSource;
     733               0 :     ioService = mIOService;
     734                 :   }
     735                 : 
     736               0 :   if (!ioService)
     737                 :   {
     738               0 :     ioService = do_GetService(NS_IOSERVICE_CONTRACTID);
     739               0 :     if (ioService)
     740                 :     {
     741               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
     742               0 :       mIOService = ioService;
     743                 :     }
     744                 :   }
     745                 : 
     746               0 :   bool isNoContentResponse = false;
     747               0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
     748               0 :   if (httpChannel) 
     749                 :   {
     750                 :     PRUint32 response;
     751               0 :     isNoContentResponse = NS_SUCCEEDED(httpChannel->GetResponseStatus(&response)) &&
     752               0 :         (response == 204 || response == 205);
     753                 :   }
     754               0 :   const bool isToplevelProgress = (windowForProgress.get() == window.get()) && !isNoContentResponse;
     755                 :   
     756                 : #ifdef PR_LOGGING
     757               0 :   if (windowForProgress)
     758                 :   {
     759               0 :     if (isToplevelProgress)
     760                 :     {
     761               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     762                 :              ("SecureUI:%p: OnStateChange: progress: for toplevel\n", this));
     763                 :     }
     764                 :     else
     765                 :     {
     766               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     767                 :              ("SecureUI:%p: OnStateChange: progress: for something else\n", this));
     768                 :     }
     769                 :   }
     770                 :   else
     771                 :   {
     772               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     773                 :              ("SecureUI:%p: OnStateChange: progress: no window known\n", this));
     774                 :   }
     775                 : #endif
     776                 : 
     777               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     778                 :          ("SecureUI:%p: OnStateChange\n", this));
     779                 : 
     780               0 :   if (isViewSource)
     781               0 :     return NS_OK;
     782                 : 
     783               0 :   if (!aRequest)
     784                 :   {
     785               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     786                 :            ("SecureUI:%p: OnStateChange with null request\n", this));
     787               0 :     return NS_ERROR_NULL_POINTER;
     788                 :   }
     789                 : 
     790                 : #ifdef PR_LOGGING
     791               0 :   if (PR_LOG_TEST(gSecureDocLog, PR_LOG_DEBUG)) {
     792               0 :     nsXPIDLCString reqname;
     793               0 :     aRequest->GetName(reqname);
     794               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     795                 :            ("SecureUI:%p: %p %p OnStateChange %x %s\n", this, aWebProgress,
     796                 :             aRequest, aProgressStateFlags, reqname.get()));
     797                 :   }
     798                 : #endif
     799                 : 
     800               0 :   nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
     801                 : 
     802               0 :   nsCOMPtr<nsIURI> uri;
     803               0 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
     804               0 :   if (channel) {
     805               0 :     channel->GetURI(getter_AddRefs(uri));
     806                 :   }
     807                 : 
     808               0 :   nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(aRequest));
     809               0 :   if (imgRequest) {
     810               0 :     NS_ASSERTION(!channel, "How did that happen, exactly?");
     811                 :     // for image requests, we get the URI from here
     812               0 :     imgRequest->GetURI(getter_AddRefs(uri));
     813                 :   }
     814                 :   
     815               0 :   if (uri) {
     816                 :     bool vs;
     817               0 :     if (NS_SUCCEEDED(uri->SchemeIs("javascript", &vs)) && vs) {
     818                 :       // We ignore the progress events for javascript URLs.
     819                 :       // If a document loading gets triggered, we will see more events.
     820               0 :       return NS_OK;
     821                 :     }
     822                 :   }
     823                 : 
     824               0 :   PRUint32 loadFlags = 0;
     825               0 :   aRequest->GetLoadFlags(&loadFlags);
     826                 : 
     827                 : #ifdef PR_LOGGING
     828               0 :   if (aProgressStateFlags & STATE_START
     829                 :       &&
     830                 :       aProgressStateFlags & STATE_IS_REQUEST
     831                 :       &&
     832                 :       isToplevelProgress
     833                 :       &&
     834                 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     835                 :   {
     836               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     837                 :            ("SecureUI:%p: OnStateChange: SOMETHING STARTS FOR TOPMOST DOCUMENT\n", this));
     838                 :   }
     839                 : 
     840               0 :   if (aProgressStateFlags & STATE_STOP
     841                 :       &&
     842                 :       aProgressStateFlags & STATE_IS_REQUEST
     843                 :       &&
     844                 :       isToplevelProgress
     845                 :       &&
     846                 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
     847                 :   {
     848               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     849                 :            ("SecureUI:%p: OnStateChange: SOMETHING STOPS FOR TOPMOST DOCUMENT\n", this));
     850                 :   }
     851                 : #endif
     852                 : 
     853               0 :   bool isSubDocumentRelevant = true;
     854                 : 
     855                 :   // We are only interested in requests that load in the browser window...
     856               0 :   if (!imgRequest) { // is not imgRequest
     857               0 :     nsCOMPtr<nsIHttpChannel> httpRequest(do_QueryInterface(aRequest));
     858               0 :     if (!httpRequest) {
     859               0 :       nsCOMPtr<nsIFileChannel> fileRequest(do_QueryInterface(aRequest));
     860               0 :       if (!fileRequest) {
     861               0 :         nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
     862               0 :         if (!wyciwygRequest) {
     863               0 :           nsCOMPtr<nsIFTPChannel> ftpRequest(do_QueryInterface(aRequest));
     864               0 :           if (!ftpRequest) {
     865               0 :             PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     866                 :                    ("SecureUI:%p: OnStateChange: not relevant for sub content\n", this));
     867               0 :             isSubDocumentRelevant = false;
     868                 :           }
     869                 :         }
     870                 :       }
     871                 :     }
     872                 :   }
     873                 : 
     874                 :   // This will ignore all resource, chrome, data, file, moz-icon, and anno
     875                 :   // protocols. Local resources are treated as trusted.
     876               0 :   if (uri && ioService) {
     877                 :     bool hasFlag;
     878                 :     nsresult rv = 
     879               0 :       ioService->URIChainHasFlags(uri, 
     880                 :                                   nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
     881               0 :                                   &hasFlag);
     882               0 :     if (NS_SUCCEEDED(rv) && hasFlag) {
     883               0 :       isSubDocumentRelevant = false;
     884                 :     }
     885                 :   }
     886                 : 
     887                 : #if defined(DEBUG)
     888               0 :   nsCString info2;
     889               0 :   PRUint32 testFlags = loadFlags;
     890                 : 
     891               0 :   if (testFlags & nsIChannel::LOAD_DOCUMENT_URI)
     892                 :   {
     893               0 :     testFlags -= nsIChannel::LOAD_DOCUMENT_URI;
     894               0 :     info2.Append("LOAD_DOCUMENT_URI ");
     895                 :   }
     896               0 :   if (testFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
     897                 :   {
     898               0 :     testFlags -= nsIChannel::LOAD_RETARGETED_DOCUMENT_URI;
     899               0 :     info2.Append("LOAD_RETARGETED_DOCUMENT_URI ");
     900                 :   }
     901               0 :   if (testFlags & nsIChannel::LOAD_REPLACE)
     902                 :   {
     903               0 :     testFlags -= nsIChannel::LOAD_REPLACE;
     904               0 :     info2.Append("LOAD_REPLACE ");
     905                 :   }
     906                 : 
     907               0 :   const char *_status = NS_SUCCEEDED(aStatus) ? "1" : "0";
     908                 : 
     909               0 :   nsCString info;
     910               0 :   PRUint32 f = aProgressStateFlags;
     911               0 :   if (f & nsIWebProgressListener::STATE_START)
     912                 :   {
     913               0 :     f -= nsIWebProgressListener::STATE_START;
     914               0 :     info.Append("START ");
     915                 :   }
     916               0 :   if (f & nsIWebProgressListener::STATE_REDIRECTING)
     917                 :   {
     918               0 :     f -= nsIWebProgressListener::STATE_REDIRECTING;
     919               0 :     info.Append("REDIRECTING ");
     920                 :   }
     921               0 :   if (f & nsIWebProgressListener::STATE_TRANSFERRING)
     922                 :   {
     923               0 :     f -= nsIWebProgressListener::STATE_TRANSFERRING;
     924               0 :     info.Append("TRANSFERRING ");
     925                 :   }
     926               0 :   if (f & nsIWebProgressListener::STATE_NEGOTIATING)
     927                 :   {
     928               0 :     f -= nsIWebProgressListener::STATE_NEGOTIATING;
     929               0 :     info.Append("NEGOTIATING ");
     930                 :   }
     931               0 :   if (f & nsIWebProgressListener::STATE_STOP)
     932                 :   {
     933               0 :     f -= nsIWebProgressListener::STATE_STOP;
     934               0 :     info.Append("STOP ");
     935                 :   }
     936               0 :   if (f & nsIWebProgressListener::STATE_IS_REQUEST)
     937                 :   {
     938               0 :     f -= nsIWebProgressListener::STATE_IS_REQUEST;
     939               0 :     info.Append("IS_REQUEST ");
     940                 :   }
     941               0 :   if (f & nsIWebProgressListener::STATE_IS_DOCUMENT)
     942                 :   {
     943               0 :     f -= nsIWebProgressListener::STATE_IS_DOCUMENT;
     944               0 :     info.Append("IS_DOCUMENT ");
     945                 :   }
     946               0 :   if (f & nsIWebProgressListener::STATE_IS_NETWORK)
     947                 :   {
     948               0 :     f -= nsIWebProgressListener::STATE_IS_NETWORK;
     949               0 :     info.Append("IS_NETWORK ");
     950                 :   }
     951               0 :   if (f & nsIWebProgressListener::STATE_IS_WINDOW)
     952                 :   {
     953               0 :     f -= nsIWebProgressListener::STATE_IS_WINDOW;
     954               0 :     info.Append("IS_WINDOW ");
     955                 :   }
     956               0 :   if (f & nsIWebProgressListener::STATE_IS_INSECURE)
     957                 :   {
     958               0 :     f -= nsIWebProgressListener::STATE_IS_INSECURE;
     959               0 :     info.Append("IS_INSECURE ");
     960                 :   }
     961               0 :   if (f & nsIWebProgressListener::STATE_IS_BROKEN)
     962                 :   {
     963               0 :     f -= nsIWebProgressListener::STATE_IS_BROKEN;
     964               0 :     info.Append("IS_BROKEN ");
     965                 :   }
     966               0 :   if (f & nsIWebProgressListener::STATE_IS_SECURE)
     967                 :   {
     968               0 :     f -= nsIWebProgressListener::STATE_IS_SECURE;
     969               0 :     info.Append("IS_SECURE ");
     970                 :   }
     971               0 :   if (f & nsIWebProgressListener::STATE_SECURE_HIGH)
     972                 :   {
     973               0 :     f -= nsIWebProgressListener::STATE_SECURE_HIGH;
     974               0 :     info.Append("SECURE_HIGH ");
     975                 :   }
     976               0 :   if (f & nsIWebProgressListener::STATE_SECURE_MED)
     977                 :   {
     978               0 :     f -= nsIWebProgressListener::STATE_SECURE_MED;
     979               0 :     info.Append("SECURE_MED ");
     980                 :   }
     981               0 :   if (f & nsIWebProgressListener::STATE_SECURE_LOW)
     982                 :   {
     983               0 :     f -= nsIWebProgressListener::STATE_SECURE_LOW;
     984               0 :     info.Append("SECURE_LOW ");
     985                 :   }
     986               0 :   if (f & nsIWebProgressListener::STATE_RESTORING)
     987                 :   {
     988               0 :     f -= nsIWebProgressListener::STATE_RESTORING;
     989               0 :     info.Append("STATE_RESTORING ");
     990                 :   }
     991                 : 
     992               0 :   if (f > 0)
     993                 :   {
     994               0 :     info.Append("f contains unknown flag!");
     995                 :   }
     996                 : 
     997               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
     998                 :          ("SecureUI:%p: OnStateChange: %s %s -- %s\n", this, _status, 
     999                 :           info.get(), info2.get()));
    1000                 : 
    1001               0 :   if (aProgressStateFlags & STATE_STOP
    1002                 :       &&
    1003               0 :       channel)
    1004                 :   {
    1005               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1006                 :            ("SecureUI:%p: OnStateChange: seeing STOP with security state: %d\n", this,
    1007                 :             GetSecurityStateFromSecurityInfo(securityInfo)
    1008                 :             ));
    1009                 :   }
    1010                 : #endif
    1011                 : 
    1012               0 :   if (aProgressStateFlags & STATE_TRANSFERRING
    1013                 :       &&
    1014                 :       aProgressStateFlags & STATE_IS_REQUEST)
    1015                 :   {
    1016                 :     // The listing of a request in mTransferringRequests
    1017                 :     // means, there has already been data transfered.
    1018                 : 
    1019               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1020               0 :     PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_ADD);
    1021                 :     
    1022               0 :     return NS_OK;
    1023                 :   }
    1024                 : 
    1025               0 :   bool requestHasTransferedData = false;
    1026                 : 
    1027               0 :   if (aProgressStateFlags & STATE_STOP
    1028                 :       &&
    1029                 :       aProgressStateFlags & STATE_IS_REQUEST)
    1030                 :   {
    1031                 :     { /* scope for the ReentrantMonitorAutoEnter */
    1032               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1033               0 :       PLDHashEntryHdr *entry = PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_LOOKUP);
    1034               0 :       if (PL_DHASH_ENTRY_IS_BUSY(entry))
    1035                 :       {
    1036               0 :         PL_DHashTableOperate(&mTransferringRequests, aRequest, PL_DHASH_REMOVE);
    1037                 : 
    1038               0 :         requestHasTransferedData = true;
    1039                 :       }
    1040                 :     }
    1041                 : 
    1042               0 :     if (!requestHasTransferedData) {
    1043                 :       // Because image loads doesn't support any TRANSFERRING notifications but
    1044                 :       // only START and STOP we must ask them directly whether content was
    1045                 :       // transferred.  See bug 432685 for details.
    1046                 :       nsCOMPtr<nsISecurityInfoProvider> securityInfoProvider =
    1047               0 :         do_QueryInterface(aRequest);
    1048                 :       // Guess true in all failure cases to be safe.  But if we're not
    1049                 :       // an nsISecurityInfoProvider, then we just haven't transferred
    1050                 :       // any data.
    1051                 :       bool hasTransferred;
    1052                 :       requestHasTransferedData =
    1053                 :         securityInfoProvider &&
    1054               0 :         (NS_FAILED(securityInfoProvider->GetHasTransferredData(&hasTransferred)) ||
    1055               0 :          hasTransferred);
    1056                 :     }
    1057                 :   }
    1058                 : 
    1059               0 :   bool allowSecurityStateChange = true;
    1060               0 :   if (loadFlags & nsIChannel::LOAD_RETARGETED_DOCUMENT_URI)
    1061                 :   {
    1062                 :     // The original consumer (this) is no longer the target of the load.
    1063                 :     // Ignore any events with this flag, do not allow them to update
    1064                 :     // our secure UI state.
    1065               0 :     allowSecurityStateChange = false;
    1066                 :   }
    1067                 : 
    1068               0 :   if (aProgressStateFlags & STATE_START
    1069                 :       &&
    1070                 :       aProgressStateFlags & STATE_IS_REQUEST
    1071                 :       &&
    1072                 :       isToplevelProgress
    1073                 :       &&
    1074                 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
    1075                 :   {
    1076                 :     bool inProgress;
    1077                 : 
    1078                 :     PRInt32 saveSubHigh;
    1079                 :     PRInt32 saveSubLow;
    1080                 :     PRInt32 saveSubBroken;
    1081                 :     PRInt32 saveSubNo;
    1082               0 :     nsCOMPtr<nsIAssociatedContentSecurity> prevContentSecurity;
    1083                 : 
    1084               0 :     PRInt32 newSubHigh = 0;
    1085               0 :     PRInt32 newSubLow = 0;
    1086               0 :     PRInt32 newSubBroken = 0;
    1087               0 :     PRInt32 newSubNo = 0;
    1088                 : 
    1089                 :     {
    1090               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1091               0 :       inProgress = (mDocumentRequestsInProgress!=0);
    1092                 : 
    1093               0 :       if (allowSecurityStateChange && !inProgress)
    1094                 :       {
    1095               0 :         saveSubHigh = mSubRequestsHighSecurity;
    1096               0 :         saveSubLow = mSubRequestsLowSecurity;
    1097               0 :         saveSubBroken = mSubRequestsBrokenSecurity;
    1098               0 :         saveSubNo = mSubRequestsNoSecurity;
    1099               0 :         prevContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo);
    1100                 :       }
    1101                 :     }
    1102                 : 
    1103               0 :     if (allowSecurityStateChange && !inProgress)
    1104                 :     {
    1105               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1106                 :              ("SecureUI:%p: OnStateChange: start for toplevel document\n", this
    1107                 :               ));
    1108                 : 
    1109               0 :       if (prevContentSecurity)
    1110                 :       {
    1111               0 :         PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1112                 :                ("SecureUI:%p: OnStateChange: start, saving current sub state\n", this
    1113                 :                 ));
    1114                 :   
    1115                 :         // before resetting our state, let's save information about
    1116                 :         // sub element loads, so we can restore it later
    1117               0 :         prevContentSecurity->SetCountSubRequestsHighSecurity(saveSubHigh);
    1118               0 :         prevContentSecurity->SetCountSubRequestsLowSecurity(saveSubLow);
    1119               0 :         prevContentSecurity->SetCountSubRequestsBrokenSecurity(saveSubBroken);
    1120               0 :         prevContentSecurity->SetCountSubRequestsNoSecurity(saveSubNo);
    1121               0 :         prevContentSecurity->Flush();
    1122               0 :         PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Saving subs in START to %p as %d,%d,%d,%d\n", 
    1123                 :           this, prevContentSecurity.get(), saveSubHigh, saveSubLow, saveSubBroken, saveSubNo));      
    1124                 :       }
    1125                 : 
    1126               0 :       bool retrieveAssociatedState = false;
    1127                 : 
    1128               0 :       if (securityInfo &&
    1129               0 :           (aProgressStateFlags & nsIWebProgressListener::STATE_RESTORING) != 0) {
    1130               0 :         retrieveAssociatedState = true;
    1131                 :       } else {
    1132               0 :         nsCOMPtr<nsIWyciwygChannel> wyciwygRequest(do_QueryInterface(aRequest));
    1133               0 :         if (wyciwygRequest) {
    1134               0 :           retrieveAssociatedState = true;
    1135                 :         }
    1136                 :       }
    1137                 : 
    1138               0 :       if (retrieveAssociatedState)
    1139                 :       {
    1140                 :         // When restoring from bfcache, we will not get events for the 
    1141                 :         // page's sub elements, so let's load the state of sub elements
    1142                 :         // from the cache.
    1143                 :     
    1144                 :         nsCOMPtr<nsIAssociatedContentSecurity> 
    1145               0 :           newContentSecurity(do_QueryInterface(securityInfo));
    1146                 :     
    1147               0 :         if (newContentSecurity)
    1148                 :         {
    1149               0 :           PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1150                 :                  ("SecureUI:%p: OnStateChange: start, loading old sub state\n", this
    1151                 :                   ));
    1152                 :     
    1153               0 :           newContentSecurity->GetCountSubRequestsHighSecurity(&newSubHigh);
    1154               0 :           newContentSecurity->GetCountSubRequestsLowSecurity(&newSubLow);
    1155               0 :           newContentSecurity->GetCountSubRequestsBrokenSecurity(&newSubBroken);
    1156               0 :           newContentSecurity->GetCountSubRequestsNoSecurity(&newSubNo);
    1157               0 :           PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Restoring subs in START from %p to %d,%d,%d,%d\n", 
    1158                 :             this, newContentSecurity.get(), newSubHigh, newSubLow, newSubBroken, newSubNo));      
    1159                 :         }
    1160                 :       }
    1161                 :       else
    1162                 :       {
    1163                 :         // If we don't get OnLocationChange for this top level load later,
    1164                 :         // it didn't get rendered.  But we reset the state to unknown and
    1165                 :         // mSubRequests* to zeros.  If we would have left these values after 
    1166                 :         // this top level load stoped, we would override the original top level
    1167                 :         // load with all zeros and break mixed content state on back and forward.
    1168               0 :         mRestoreSubrequests = true;
    1169                 :       }
    1170                 :     }
    1171                 : 
    1172                 :     {
    1173               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1174                 : 
    1175               0 :       if (allowSecurityStateChange && !inProgress)
    1176                 :       {
    1177               0 :         ResetStateTracking();
    1178               0 :         mSubRequestsHighSecurity = newSubHigh;
    1179               0 :         mSubRequestsLowSecurity = newSubLow;
    1180               0 :         mSubRequestsBrokenSecurity = newSubBroken;
    1181               0 :         mSubRequestsNoSecurity = newSubNo;
    1182               0 :         mNewToplevelSecurityStateKnown = false;
    1183                 :       }
    1184                 : 
    1185                 :       // By using a counter, this code also works when the toplevel
    1186                 :       // document get's redirected, but the STOP request for the 
    1187                 :       // previous toplevel document has not yet have been received.
    1188               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1189                 :              ("SecureUI:%p: OnStateChange: ++mDocumentRequestsInProgress\n", this
    1190                 :               ));
    1191               0 :       ++mDocumentRequestsInProgress;
    1192                 :     }
    1193                 : 
    1194               0 :     return NS_OK;
    1195                 :   }
    1196                 : 
    1197               0 :   if (aProgressStateFlags & STATE_STOP
    1198                 :       &&
    1199                 :       aProgressStateFlags & STATE_IS_REQUEST
    1200                 :       &&
    1201                 :       isToplevelProgress
    1202                 :       &&
    1203                 :       loadFlags & nsIChannel::LOAD_DOCUMENT_URI)
    1204                 :   {
    1205                 :     PRInt32 temp_DocumentRequestsInProgress;
    1206               0 :     nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
    1207                 : 
    1208                 :     {
    1209               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1210               0 :       temp_DocumentRequestsInProgress = mDocumentRequestsInProgress;
    1211               0 :       if (allowSecurityStateChange)
    1212                 :       {
    1213               0 :         temp_ToplevelEventSink = mToplevelEventSink;
    1214                 :       }
    1215                 :     }
    1216                 : 
    1217               0 :     if (temp_DocumentRequestsInProgress <= 0)
    1218                 :     {
    1219                 :       // Ignore stop requests unless a document load is in progress
    1220                 :       // Unfortunately on application start, see some stops without having seen any starts...
    1221               0 :       return NS_OK;
    1222                 :     }
    1223                 : 
    1224               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1225                 :            ("SecureUI:%p: OnStateChange: --mDocumentRequestsInProgress\n", this
    1226                 :             ));
    1227                 : 
    1228               0 :     if (!temp_ToplevelEventSink && channel)
    1229                 :     {
    1230               0 :       if (allowSecurityStateChange)
    1231                 :       {
    1232               0 :         ObtainEventSink(channel, temp_ToplevelEventSink);
    1233                 :       }
    1234                 :     }
    1235                 : 
    1236               0 :     bool sinkChanged = false;
    1237                 :     bool inProgress;
    1238                 :     {
    1239               0 :       ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1240               0 :       if (allowSecurityStateChange)
    1241                 :       {
    1242               0 :         sinkChanged = (mToplevelEventSink != temp_ToplevelEventSink);
    1243               0 :         mToplevelEventSink = temp_ToplevelEventSink;
    1244                 :       }
    1245               0 :       --mDocumentRequestsInProgress;
    1246               0 :       inProgress = mDocumentRequestsInProgress > 0;
    1247                 :     }
    1248                 : 
    1249               0 :     if (allowSecurityStateChange && requestHasTransferedData) {
    1250                 :       // Data has been transferred for the single toplevel
    1251                 :       // request. Evaluate the security state.
    1252                 : 
    1253                 :       // Do this only when the sink has changed.  We update and notify
    1254                 :       // the state from OnLacationChange, this is actually redundant.
    1255                 :       // But when the target sink changes between OnLocationChange and
    1256                 :       // OnStateChange, we have to fire the notification here (again).
    1257                 : 
    1258               0 :       if (sinkChanged)
    1259               0 :         return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false);
    1260                 :     }
    1261                 : 
    1262               0 :     if (mRestoreSubrequests && !inProgress)
    1263                 :     {
    1264                 :       // We get here when there were no OnLocationChange between 
    1265                 :       // OnStateChange(START) and OnStateChange(STOP).  Then the load has not
    1266                 :       // been rendered but has been retargeted in some other way then by external
    1267                 :       // app handler.  Restore mSubRequests* members to what the current security 
    1268                 :       // state info holds (it was reset to all zero in OnStateChange(START) 
    1269                 :       // before).
    1270               0 :       nsCOMPtr<nsIAssociatedContentSecurity> currentContentSecurity;
    1271                 :       {
    1272               0 :         ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1273               0 :         currentContentSecurity = do_QueryInterface(mCurrentToplevelSecurityInfo);
    1274                 : 
    1275                 :         // Drop this indication flag, the restore opration is just being
    1276                 :         // done.
    1277               0 :         mRestoreSubrequests = false;
    1278                 : 
    1279                 :         // We can do this since the state didn't actually change.
    1280               0 :         mNewToplevelSecurityStateKnown = true;
    1281                 :       }
    1282                 : 
    1283               0 :       PRInt32 subHigh = 0;
    1284               0 :       PRInt32 subLow = 0;
    1285               0 :       PRInt32 subBroken = 0;
    1286               0 :       PRInt32 subNo = 0;
    1287                 : 
    1288               0 :       if (currentContentSecurity)
    1289                 :       {
    1290               0 :         currentContentSecurity->GetCountSubRequestsHighSecurity(&subHigh);
    1291               0 :         currentContentSecurity->GetCountSubRequestsLowSecurity(&subLow);
    1292               0 :         currentContentSecurity->GetCountSubRequestsBrokenSecurity(&subBroken);
    1293               0 :         currentContentSecurity->GetCountSubRequestsNoSecurity(&subNo);
    1294               0 :         PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: Restoring subs in STOP from %p to %d,%d,%d,%d\n", 
    1295                 :           this, currentContentSecurity.get(), subHigh, subLow, subBroken, subNo));      
    1296                 :       }
    1297                 : 
    1298                 :       {
    1299               0 :         ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1300               0 :         mSubRequestsHighSecurity = subHigh;
    1301               0 :         mSubRequestsLowSecurity = subLow;
    1302               0 :         mSubRequestsBrokenSecurity = subBroken;
    1303               0 :         mSubRequestsNoSecurity = subNo;
    1304                 :       }
    1305                 :     }
    1306                 :     
    1307               0 :     return NS_OK;
    1308                 :   }
    1309                 :   
    1310               0 :   if (aProgressStateFlags & STATE_STOP
    1311                 :       &&
    1312                 :       aProgressStateFlags & STATE_IS_REQUEST)
    1313                 :   {
    1314               0 :     if (!isSubDocumentRelevant)
    1315               0 :       return NS_OK;
    1316                 :     
    1317                 :     // if we arrive here, LOAD_DOCUMENT_URI is not set
    1318                 :     
    1319                 :     // We only care for the security state of sub requests which have actually transfered data.
    1320                 : 
    1321               0 :     if (allowSecurityStateChange && requestHasTransferedData)
    1322                 :     {  
    1323               0 :       UpdateSubrequestMembers(securityInfo);
    1324                 :       
    1325                 :       // Care for the following scenario:
    1326                 :       // A new top level document load might have already started,
    1327                 :       // but the security state of the new top level document might not yet been known.
    1328                 :       // 
    1329                 :       // At this point, we are learning about the security state of a sub-document.
    1330                 :       // We must not update the security state based on the sub content,
    1331                 :       // if the new top level state is not yet known.
    1332                 :       //
    1333                 :       // We skip updating the security state in this case.
    1334                 : 
    1335                 :       bool temp_NewToplevelSecurityStateKnown;
    1336                 :       {
    1337               0 :         ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1338               0 :         temp_NewToplevelSecurityStateKnown = mNewToplevelSecurityStateKnown;
    1339                 :       }
    1340                 : 
    1341               0 :       if (temp_NewToplevelSecurityStateKnown)
    1342               0 :         return UpdateSecurityState(aRequest, false, false, false);
    1343                 :     }
    1344                 : 
    1345               0 :     return NS_OK;
    1346                 :   }
    1347                 : 
    1348               0 :   return NS_OK;
    1349                 : }
    1350                 : 
    1351                 : // I'm keeping this as a separate function, in order to simplify the review
    1352                 : // for bug 412456. We should inline this in a follow up patch.
    1353               0 : void nsSecureBrowserUIImpl::ObtainEventSink(nsIChannel *channel, 
    1354                 :                                             nsCOMPtr<nsISecurityEventSink> &sink)
    1355                 : {
    1356               0 :   if (!sink)
    1357               0 :     NS_QueryNotificationCallbacks(channel, sink);
    1358               0 : }
    1359                 : 
    1360               0 : nsresult nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest, 
    1361                 :                                                     bool withNewLocation, 
    1362                 :                                                     bool withUpdateStatus, 
    1363                 :                                                     bool withUpdateTooltip)
    1364                 : {
    1365               0 :   lockIconState warnSecurityState = lis_no_security;
    1366               0 :   bool showWarning = false;
    1367               0 :   nsresult rv = NS_OK;
    1368                 : 
    1369                 :   // both parameters are both input and outout
    1370               0 :   bool flagsChanged = UpdateMyFlags(showWarning, warnSecurityState);
    1371                 : 
    1372               0 :   if (flagsChanged || withNewLocation || withUpdateStatus || withUpdateTooltip)
    1373               0 :     rv = TellTheWorld(showWarning, warnSecurityState, aRequest);
    1374                 : 
    1375               0 :   return rv;
    1376                 : }
    1377                 : 
    1378                 : // must not fail, by definition, only trivial assignments
    1379                 : // or string operations are allowed
    1380                 : // returns true if our overall state has changed and we must send out notifications
    1381               0 : bool nsSecureBrowserUIImpl::UpdateMyFlags(bool &showWarning, lockIconState &warnSecurityState)
    1382                 : {
    1383               0 :   ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1384               0 :   bool mustTellTheWorld = false;
    1385                 : 
    1386                 :   lockIconState newSecurityState;
    1387                 : 
    1388               0 :   if (mNewToplevelSecurityState & STATE_IS_SECURE)
    1389                 :   {
    1390               0 :     if (mNewToplevelSecurityState & STATE_SECURE_LOW
    1391                 :         ||
    1392                 :         mNewToplevelSecurityState & STATE_SECURE_MED)
    1393                 :     {
    1394               0 :       if (mSubRequestsBrokenSecurity
    1395                 :           ||
    1396                 :           mSubRequestsNoSecurity)
    1397                 :       {
    1398               0 :         newSecurityState = lis_mixed_security;
    1399                 :       }
    1400                 :       else
    1401                 :       {
    1402               0 :         newSecurityState = lis_low_security;
    1403                 :       }
    1404                 :     }
    1405                 :     else
    1406                 :     {
    1407                 :       // toplevel is high security
    1408                 : 
    1409               0 :       if (mSubRequestsBrokenSecurity
    1410                 :           ||
    1411                 :           mSubRequestsNoSecurity)
    1412                 :       {
    1413               0 :         newSecurityState = lis_mixed_security;
    1414                 :       }
    1415               0 :       else if (mSubRequestsLowSecurity)
    1416                 :       {
    1417               0 :         newSecurityState = lis_low_security;
    1418                 :       }
    1419                 :       else
    1420                 :       {
    1421               0 :         newSecurityState = lis_high_security;
    1422                 :       }
    1423                 :     }
    1424                 :   }
    1425                 :   else
    1426               0 :   if (mNewToplevelSecurityState & STATE_IS_BROKEN)
    1427                 :   {
    1428                 :     // indicating BROKEN is more important than MIXED.
    1429                 :   
    1430               0 :     newSecurityState = lis_broken_security;
    1431                 :   }
    1432                 :   else
    1433                 :   {
    1434               0 :     newSecurityState = lis_no_security;
    1435                 :   }
    1436                 : 
    1437               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1438                 :          ("SecureUI:%p: UpdateSecurityState:  old-new  %d - %d\n", this,
    1439                 :          mNotifiedSecurityState, newSecurityState
    1440                 :           ));
    1441                 : 
    1442               0 :   if (mNotifiedSecurityState != newSecurityState)
    1443                 :   {
    1444               0 :     mustTellTheWorld = true;
    1445                 : 
    1446                 :     // we'll treat "broken" exactly like "insecure",
    1447                 :     // i.e. we do not show alerts when switching between broken and insecure
    1448                 : 
    1449                 :     /*
    1450                 :       from                 to           shows alert
    1451                 :     ------------------------------     ---------------
    1452                 : 
    1453                 :     no or broken -> no or broken    => <NOTHING SHOWN>
    1454                 : 
    1455                 :     no or broken -> mixed           => mixed alert
    1456                 :     no or broken -> low             => low alert
    1457                 :     no or broken -> high            => high alert
    1458                 :     
    1459                 :     mixed, high, low -> no, broken  => leaving secure
    1460                 : 
    1461                 :     mixed        -> low             => low alert
    1462                 :     mixed        -> high            => high alert
    1463                 : 
    1464                 :     high         -> low             => low alert
    1465                 :     high         -> mixed           => mixed
    1466                 :     
    1467                 :     low          -> high            => high
    1468                 :     low          -> mixed           => mixed
    1469                 : 
    1470                 : 
    1471                 :       security    icon
    1472                 :       ----------------
    1473                 :     
    1474                 :       no          open
    1475                 :       mixed       broken
    1476                 :       broken      broken
    1477                 :       low         low
    1478                 :       high        high
    1479                 :     */
    1480                 : 
    1481               0 :     showWarning = true;
    1482                 :     
    1483               0 :     switch (mNotifiedSecurityState)
    1484                 :     {
    1485                 :       case lis_no_security:
    1486                 :       case lis_broken_security:
    1487               0 :         switch (newSecurityState)
    1488                 :         {
    1489                 :           case lis_no_security:
    1490                 :           case lis_broken_security:
    1491               0 :             showWarning = false;
    1492               0 :             break;
    1493                 :           
    1494                 :           default:
    1495               0 :             break;
    1496                 :         }
    1497                 :       
    1498                 :       default:
    1499                 :         break;
    1500                 :     }
    1501                 : 
    1502               0 :     if (showWarning)
    1503                 :     {
    1504               0 :       warnSecurityState = newSecurityState;
    1505                 :     }
    1506                 :     
    1507               0 :     mNotifiedSecurityState = newSecurityState;
    1508                 : 
    1509               0 :     if (lis_no_security == newSecurityState)
    1510                 :     {
    1511               0 :       mSSLStatus = nsnull;
    1512               0 :       mInfoTooltip.Truncate();
    1513                 :     }
    1514                 :   }
    1515                 : 
    1516               0 :   if (mNotifiedToplevelIsEV != mNewToplevelIsEV) {
    1517               0 :     mustTellTheWorld = true;
    1518               0 :     mNotifiedToplevelIsEV = mNewToplevelIsEV;
    1519                 :   }
    1520                 : 
    1521               0 :   return mustTellTheWorld;
    1522                 : }
    1523                 : 
    1524               0 : nsresult nsSecureBrowserUIImpl::TellTheWorld(bool showWarning, 
    1525                 :                                              lockIconState warnSecurityState, 
    1526                 :                                              nsIRequest* aRequest)
    1527                 : {
    1528               0 :   nsCOMPtr<nsISecurityEventSink> temp_ToplevelEventSink;
    1529                 :   lockIconState temp_NotifiedSecurityState;
    1530                 :   bool temp_NotifiedToplevelIsEV;
    1531                 : 
    1532                 :   {
    1533               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1534               0 :     temp_ToplevelEventSink = mToplevelEventSink;
    1535               0 :     temp_NotifiedSecurityState = mNotifiedSecurityState;
    1536               0 :     temp_NotifiedToplevelIsEV = mNotifiedToplevelIsEV;
    1537                 :   }
    1538                 : 
    1539               0 :   if (temp_ToplevelEventSink)
    1540                 :   {
    1541               0 :     PRUint32 newState = STATE_IS_INSECURE;
    1542                 :     MapInternalToExternalState(&newState, 
    1543                 :                                temp_NotifiedSecurityState, 
    1544               0 :                                temp_NotifiedToplevelIsEV);
    1545                 : 
    1546               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1547                 :            ("SecureUI:%p: UpdateSecurityState: calling OnSecurityChange\n", this
    1548                 :             ));
    1549                 : 
    1550               0 :     temp_ToplevelEventSink->OnSecurityChange(aRequest, newState);
    1551                 :   }
    1552                 :   else
    1553                 :   {
    1554               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1555                 :            ("SecureUI:%p: UpdateSecurityState: NO mToplevelEventSink!\n", this
    1556                 :             ));
    1557                 : 
    1558                 :   }
    1559                 : 
    1560               0 :   if (showWarning)
    1561                 :   {
    1562               0 :     switch (warnSecurityState)
    1563                 :     {
    1564                 :       case lis_no_security:
    1565                 :       case lis_broken_security:
    1566               0 :         ConfirmLeavingSecure();
    1567               0 :         break;
    1568                 : 
    1569                 :       case lis_mixed_security:
    1570               0 :         ConfirmMixedMode();
    1571               0 :         break;
    1572                 : 
    1573                 :       case lis_low_security:
    1574               0 :         ConfirmEnteringWeak();
    1575               0 :         break;
    1576                 : 
    1577                 :       case lis_high_security:
    1578               0 :         ConfirmEnteringSecure();
    1579               0 :         break;
    1580                 :     }
    1581                 :   }
    1582                 : 
    1583               0 :   return NS_OK; 
    1584                 : }
    1585                 : 
    1586                 : NS_IMETHODIMP
    1587               0 : nsSecureBrowserUIImpl::OnLocationChange(nsIWebProgress* aWebProgress,
    1588                 :                                         nsIRequest* aRequest,
    1589                 :                                         nsIURI* aLocation,
    1590                 :                                         PRUint32 aFlags)
    1591                 : {
    1592                 : #ifdef DEBUG
    1593               0 :   nsAutoAtomic atomic(mOnStateLocationChangeReentranceDetection);
    1594               0 :   NS_ASSERTION(mOnStateLocationChangeReentranceDetection == 1,
    1595                 :                "unexpected parallel nsIWebProgress OnStateChange and/or OnLocationChange notification");
    1596                 : #endif
    1597               0 :   PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1598                 :          ("SecureUI:%p: OnLocationChange\n", this));
    1599                 : 
    1600               0 :   bool updateIsViewSource = false;
    1601               0 :   bool temp_IsViewSource = false;
    1602               0 :   nsCOMPtr<nsIDOMWindow> window;
    1603                 : 
    1604               0 :   if (aLocation)
    1605                 :   {
    1606                 :     bool vs;
    1607                 : 
    1608               0 :     nsresult rv = aLocation->SchemeIs("view-source", &vs);
    1609               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1610                 : 
    1611               0 :     if (vs) {
    1612               0 :       PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1613                 :              ("SecureUI:%p: OnLocationChange: view-source\n", this));
    1614                 :     }
    1615                 : 
    1616               0 :     updateIsViewSource = true;
    1617               0 :     temp_IsViewSource = vs;
    1618                 :   }
    1619                 : 
    1620                 :   {
    1621               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1622               0 :     if (updateIsViewSource) {
    1623               0 :       mIsViewSource = temp_IsViewSource;
    1624                 :     }
    1625               0 :     mCurrentURI = aLocation;
    1626               0 :     window = do_QueryReferent(mWindow);
    1627               0 :     NS_ASSERTION(window, "Window has gone away?!");
    1628                 :   }
    1629                 : 
    1630                 :   // When |aRequest| is null, basically we don't trust that document. But if
    1631                 :   // docshell insists that the document has not changed at all, we will reuse
    1632                 :   // the previous security state, no matter what |aRequest| may be.
    1633               0 :   if (aFlags & LOCATION_CHANGE_SAME_DOCUMENT)
    1634               0 :     return NS_OK;
    1635                 : 
    1636                 :   // The location bar has changed, so we must update the security state.  The
    1637                 :   // only concern with doing this here is that a page may transition from being
    1638                 :   // reported as completely secure to being reported as partially secure
    1639                 :   // (mixed).  This may be confusing for users, and it may bother users who
    1640                 :   // like seeing security dialogs.  However, it seems prudent given that page
    1641                 :   // loading may never end in some edge cases (perhaps by a site with malicious
    1642                 :   // intent).
    1643                 : 
    1644               0 :   nsCOMPtr<nsIDOMWindow> windowForProgress;
    1645               0 :   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
    1646                 : 
    1647               0 :   nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
    1648                 : 
    1649               0 :   if (windowForProgress.get() == window.get()) {
    1650                 :     // For toplevel channels, update the security state right away.
    1651               0 :     return EvaluateAndUpdateSecurityState(aRequest, securityInfo, true);
    1652                 :   }
    1653                 : 
    1654                 :   // For channels in subdocuments we only update our subrequest state members.
    1655               0 :   UpdateSubrequestMembers(securityInfo);
    1656                 : 
    1657                 :   // Care for the following scenario:
    1658                 : 
    1659                 :   // A new toplevel document load might have already started, but the security
    1660                 :   // state of the new toplevel document might not yet be known.
    1661                 :   // 
    1662                 :   // At this point, we are learning about the security state of a sub-document.
    1663                 :   // We must not update the security state based on the sub content, if the new
    1664                 :   // top level state is not yet known.
    1665                 :   //
    1666                 :   // We skip updating the security state in this case.
    1667                 : 
    1668                 :   bool temp_NewToplevelSecurityStateKnown;
    1669                 :   {
    1670               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1671               0 :     temp_NewToplevelSecurityStateKnown = mNewToplevelSecurityStateKnown;
    1672                 :   }
    1673                 : 
    1674               0 :   if (temp_NewToplevelSecurityStateKnown)
    1675               0 :     return UpdateSecurityState(aRequest, true, false, false);
    1676                 : 
    1677               0 :   return NS_OK;
    1678                 : }
    1679                 : 
    1680                 : NS_IMETHODIMP
    1681               0 : nsSecureBrowserUIImpl::OnStatusChange(nsIWebProgress* aWebProgress,
    1682                 :                                       nsIRequest* aRequest,
    1683                 :                                       nsresult aStatus,
    1684                 :                                       const PRUnichar* aMessage)
    1685                 : {
    1686               0 :   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
    1687               0 :   return NS_OK;
    1688                 : }
    1689                 : 
    1690                 : nsresult
    1691               0 : nsSecureBrowserUIImpl::OnSecurityChange(nsIWebProgress *aWebProgress,
    1692                 :                                         nsIRequest *aRequest,
    1693                 :                                         PRUint32 state)
    1694                 : {
    1695                 : #if defined(DEBUG)
    1696               0 :   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
    1697               0 :   if (!channel)
    1698               0 :     return NS_OK;
    1699                 : 
    1700               0 :   nsCOMPtr<nsIURI> aURI;
    1701               0 :   channel->GetURI(getter_AddRefs(aURI));
    1702                 :   
    1703               0 :   if (aURI) {
    1704               0 :     nsCAutoString temp;
    1705               0 :     aURI->GetSpec(temp);
    1706               0 :     PR_LOG(gSecureDocLog, PR_LOG_DEBUG,
    1707                 :            ("SecureUI:%p: OnSecurityChange: (%x) %s\n", this,
    1708                 :             state, temp.get()));
    1709                 :   }
    1710                 : #endif
    1711                 : 
    1712               0 :   return NS_OK;
    1713                 : }
    1714                 : 
    1715                 : // nsISSLStatusProvider methods
    1716                 : NS_IMETHODIMP
    1717               0 : nsSecureBrowserUIImpl::GetSSLStatus(nsISSLStatus** _result)
    1718                 : {
    1719               0 :   NS_ENSURE_ARG_POINTER(_result);
    1720                 : 
    1721               0 :   ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1722                 : 
    1723               0 :   switch (mNotifiedSecurityState)
    1724                 :   {
    1725                 :     case lis_mixed_security:
    1726                 :     case lis_low_security:
    1727                 :     case lis_high_security:
    1728                 :       break;
    1729                 : 
    1730                 :     default:
    1731               0 :       NS_NOTREACHED("if this is reached you must add more entries to the switch");
    1732                 :     case lis_no_security:
    1733                 :     case lis_broken_security:
    1734               0 :       *_result = nsnull;
    1735               0 :       return NS_OK;
    1736                 :   }
    1737                 :  
    1738               0 :   *_result = mSSLStatus;
    1739               0 :   NS_IF_ADDREF(*_result);
    1740                 : 
    1741               0 :   return NS_OK;
    1742                 : }
    1743                 : 
    1744                 : nsresult
    1745               0 : nsSecureBrowserUIImpl::IsURLHTTPS(nsIURI* aURL, bool* value)
    1746                 : {
    1747               0 :   *value = false;
    1748                 : 
    1749               0 :   if (!aURL)
    1750               0 :     return NS_OK;
    1751                 : 
    1752               0 :   return aURL->SchemeIs("https", value);
    1753                 : }
    1754                 : 
    1755                 : nsresult
    1756               0 : nsSecureBrowserUIImpl::IsURLJavaScript(nsIURI* aURL, bool* value)
    1757                 : {
    1758               0 :   *value = false;
    1759                 : 
    1760               0 :   if (!aURL)
    1761               0 :     return NS_OK;
    1762                 : 
    1763               0 :   return aURL->SchemeIs("javascript", value);
    1764                 : }
    1765                 : 
    1766                 : void
    1767               0 : nsSecureBrowserUIImpl::GetBundleString(const PRUnichar* name,
    1768                 :                                        nsAString &outString)
    1769                 : {
    1770               0 :   nsCOMPtr<nsIStringBundle> temp_StringBundle;
    1771                 : 
    1772                 :   {
    1773               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1774               0 :     temp_StringBundle = mStringBundle;
    1775                 :   }
    1776                 : 
    1777               0 :   if (temp_StringBundle && name) {
    1778               0 :     PRUnichar *ptrv = nsnull;
    1779               0 :     if (NS_SUCCEEDED(temp_StringBundle->GetStringFromName(name,
    1780                 :                                                           &ptrv)))
    1781               0 :       outString = ptrv;
    1782                 :     else
    1783               0 :       outString.SetLength(0);
    1784                 : 
    1785               0 :     nsMemory::Free(ptrv);
    1786                 : 
    1787                 :   } else {
    1788               0 :     outString.SetLength(0);
    1789                 :   }
    1790               0 : }
    1791                 : 
    1792                 : nsresult
    1793               0 : nsSecureBrowserUIImpl::CheckPost(nsIURI *formURL, nsIURI *actionURL, bool *okayToPost)
    1794                 : {
    1795                 :   bool formSecure, actionSecure, actionJavaScript;
    1796               0 :   *okayToPost = true;
    1797                 : 
    1798               0 :   nsresult rv = IsURLHTTPS(formURL, &formSecure);
    1799               0 :   if (NS_FAILED(rv))
    1800               0 :     return rv;
    1801                 : 
    1802               0 :   rv = IsURLHTTPS(actionURL, &actionSecure);
    1803               0 :   if (NS_FAILED(rv))
    1804               0 :     return rv;
    1805                 : 
    1806               0 :   rv = IsURLJavaScript(actionURL, &actionJavaScript);
    1807               0 :   if (NS_FAILED(rv))
    1808               0 :     return rv;
    1809                 : 
    1810                 :   // If we are posting to a secure link, all is okay.
    1811                 :   // It doesn't matter whether the currently viewed page is secure or not,
    1812                 :   // because the data will be sent to a secure URL.
    1813               0 :   if (actionSecure) {
    1814               0 :     return NS_OK;
    1815                 :   }
    1816                 : 
    1817                 :   // Action is a JavaScript call, not an actual post. That's okay too.
    1818               0 :   if (actionJavaScript) {
    1819               0 :     return NS_OK;
    1820                 :   }
    1821                 : 
    1822                 :   // posting to insecure webpage from a secure webpage.
    1823               0 :   if (formSecure) {
    1824               0 :     *okayToPost = ConfirmPostToInsecureFromSecure();
    1825                 :   } else {
    1826               0 :     *okayToPost = ConfirmPostToInsecure();
    1827                 :   }
    1828                 : 
    1829               0 :   return NS_OK;
    1830                 : }
    1831                 : 
    1832                 : //
    1833                 : // Implementation of an nsIInterfaceRequestor for use
    1834                 : // as context for NSS calls
    1835                 : //
    1836                 : class nsUIContext : public nsIInterfaceRequestor
    1837                 : {
    1838                 : public:
    1839                 :   NS_DECL_ISUPPORTS
    1840                 :   NS_DECL_NSIINTERFACEREQUESTOR
    1841                 : 
    1842                 :   nsUIContext(nsIDOMWindow *window);
    1843                 :   virtual ~nsUIContext();
    1844                 : 
    1845                 : private:
    1846                 :   nsCOMPtr<nsIDOMWindow> mWindow;
    1847                 : };
    1848                 : 
    1849               0 : NS_IMPL_ISUPPORTS1(nsUIContext, nsIInterfaceRequestor)
    1850                 : 
    1851               0 : nsUIContext::nsUIContext(nsIDOMWindow *aWindow)
    1852               0 : : mWindow(aWindow)
    1853                 : {
    1854               0 : }
    1855                 : 
    1856               0 : nsUIContext::~nsUIContext()
    1857                 : {
    1858               0 : }
    1859                 : 
    1860                 : /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
    1861               0 : NS_IMETHODIMP nsUIContext::GetInterface(const nsIID & uuid, void * *result)
    1862                 : {
    1863               0 :   NS_ENSURE_TRUE(mWindow, NS_ERROR_FAILURE);
    1864                 :   nsresult rv;
    1865                 : 
    1866               0 :   if (uuid.Equals(NS_GET_IID(nsIPrompt))) {
    1867               0 :     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mWindow, &rv);
    1868               0 :     if (NS_FAILED(rv)) return rv;
    1869                 : 
    1870                 :     nsIPrompt *prompt;
    1871                 : 
    1872               0 :     rv = window->GetPrompter(&prompt);
    1873               0 :     *result = prompt;
    1874               0 :   } else if (uuid.Equals(NS_GET_IID(nsIDOMWindow))) {
    1875               0 :     *result = mWindow;
    1876               0 :     NS_ADDREF ((nsISupports*) *result);
    1877               0 :     rv = NS_OK;
    1878                 :   } else {
    1879               0 :     rv = NS_ERROR_NO_INTERFACE;
    1880                 :   }
    1881                 : 
    1882               0 :   return rv;
    1883                 : }
    1884                 : 
    1885                 : bool
    1886               0 : nsSecureBrowserUIImpl::GetNSSDialogs(nsCOMPtr<nsISecurityWarningDialogs> & dialogs,
    1887                 :                                      nsCOMPtr<nsIInterfaceRequestor> & ctx)
    1888                 : {
    1889               0 :   if (!NS_IsMainThread()) {
    1890               0 :     NS_ERROR("nsSecureBrowserUIImpl::GetNSSDialogs called off the main thread");
    1891               0 :     return false;
    1892                 :   }
    1893                 : 
    1894               0 :   dialogs = do_GetService(NS_SECURITYWARNINGDIALOGS_CONTRACTID);
    1895               0 :   if (!dialogs)
    1896               0 :     return false;
    1897                 : 
    1898               0 :   nsCOMPtr<nsIDOMWindow> window;
    1899                 :   {
    1900               0 :     ReentrantMonitorAutoEnter lock(mReentrantMonitor);
    1901               0 :     window = do_QueryReferent(mWindow);
    1902               0 :     NS_ASSERTION(window, "Window has gone away?!");
    1903                 :   }
    1904               0 :   ctx = new nsUIContext(window);
    1905                 :   
    1906               0 :   return true;
    1907                 : }
    1908                 : 
    1909               0 : bool nsSecureBrowserUIImpl::
    1910                 : ConfirmEnteringSecure()
    1911                 : {
    1912               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    1913               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    1914                 : 
    1915               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    1916               0 :     return false; // Should this allow true for unimplemented?
    1917                 :   }
    1918                 : 
    1919                 :   bool confirms;
    1920               0 :   dialogs->ConfirmEnteringSecure(ctx, &confirms);
    1921                 : 
    1922               0 :   return confirms;
    1923                 : }
    1924                 : 
    1925               0 : bool nsSecureBrowserUIImpl::
    1926                 : ConfirmEnteringWeak()
    1927                 : {
    1928               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    1929               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    1930                 : 
    1931               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    1932               0 :     return false; // Should this allow true for unimplemented?
    1933                 :   }
    1934                 : 
    1935                 :   bool confirms;
    1936               0 :   dialogs->ConfirmEnteringWeak(ctx, &confirms);
    1937                 : 
    1938               0 :   return confirms;
    1939                 : }
    1940                 : 
    1941               0 : bool nsSecureBrowserUIImpl::
    1942                 : ConfirmLeavingSecure()
    1943                 : {
    1944               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    1945               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    1946                 : 
    1947               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    1948               0 :     return false; // Should this allow true for unimplemented?
    1949                 :   }
    1950                 : 
    1951                 :   bool confirms;
    1952               0 :   dialogs->ConfirmLeavingSecure(ctx, &confirms);
    1953                 : 
    1954               0 :   return confirms;
    1955                 : }
    1956                 : 
    1957               0 : bool nsSecureBrowserUIImpl::
    1958                 : ConfirmMixedMode()
    1959                 : {
    1960               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    1961               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    1962                 : 
    1963               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    1964               0 :     return false; // Should this allow true for unimplemented?
    1965                 :   }
    1966                 : 
    1967                 :   bool confirms;
    1968               0 :   dialogs->ConfirmMixedMode(ctx, &confirms);
    1969                 : 
    1970               0 :   return confirms;
    1971                 : }
    1972                 : 
    1973                 : /**
    1974                 :  * ConfirmPostToInsecure - returns true if
    1975                 :  *   the user approves the submit (or doesn't care).
    1976                 :  *   returns false on errors.
    1977                 :  */
    1978               0 : bool nsSecureBrowserUIImpl::
    1979                 : ConfirmPostToInsecure()
    1980                 : {
    1981               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    1982               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    1983                 : 
    1984               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    1985               0 :     return false; // Should this allow true for unimplemented?
    1986                 :   }
    1987                 : 
    1988                 :   bool result;
    1989                 : 
    1990               0 :   nsresult rv = dialogs->ConfirmPostToInsecure(ctx, &result);
    1991               0 :   if (NS_FAILED(rv)) return false;
    1992                 : 
    1993               0 :   return result;
    1994                 : }
    1995                 : 
    1996                 : /**
    1997                 :  * ConfirmPostToInsecureFromSecure - returns true if
    1998                 :  *   the user approves the submit (or doesn't care).
    1999                 :  *   returns false on errors.
    2000                 :  */
    2001               0 : bool nsSecureBrowserUIImpl::
    2002                 : ConfirmPostToInsecureFromSecure()
    2003                 : {
    2004               0 :   nsCOMPtr<nsISecurityWarningDialogs> dialogs;
    2005               0 :   nsCOMPtr<nsIInterfaceRequestor> ctx;
    2006                 : 
    2007               0 :   if (!GetNSSDialogs(dialogs, ctx)) {
    2008               0 :     return false; // Should this allow true for unimplemented?
    2009                 :   }
    2010                 : 
    2011                 :   bool result;
    2012                 : 
    2013               0 :   nsresult rv = dialogs->ConfirmPostToInsecureFromSecure(ctx, &result);
    2014               0 :   if (NS_FAILED(rv)) return false;
    2015                 : 
    2016               0 :   return result;
    2017                 : }

Generated by: LCOV version 1.7