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

Generated by: LCOV version 1.7